diff --git a/meilidb-core/examples/from_file.rs b/meilidb-core/examples/from_file.rs index a13db568c..5162911b7 100644 --- a/meilidb-core/examples/from_file.rs +++ b/meilidb-core/examples/from_file.rs @@ -12,7 +12,7 @@ use serde::{Serialize, Deserialize}; use structopt::StructOpt; use termcolor::{Color, ColorChoice, ColorSpec, StandardStream, WriteColor}; -use meilidb_core::{Highlight, Database, UpdateResult, BoxUpdateFn}; +use meilidb_core::{Highlight, Database, UpdateResult}; use meilidb_schema::SchemaAttr; const INDEX_NAME: &str = "default"; @@ -86,7 +86,14 @@ fn index_command(command: IndexCommand, database: Database) -> Result<(), Box index, + None => database.create_index(INDEX_NAME).unwrap() + }; + + let done = database.set_update_callback(INDEX_NAME, Box::new(update_fn)); + assert!(done, "could not set the index update function"); + let rkv = database.rkv.read().unwrap(); let schema = { @@ -256,8 +263,7 @@ fn crop_text( fn search_command(command: SearchCommand, database: Database) -> Result<(), Box> { let rkv = database.rkv.read().unwrap(); - let update_fn = None as Option::; - let index = database.open_index(INDEX_NAME, update_fn)?; + let index = database.open_index(INDEX_NAME).expect("Could not find index"); let reader = rkv.read().unwrap(); let schema = index.main.schema(&reader)?; diff --git a/meilidb-core/src/database.rs b/meilidb-core/src/database.rs index c74bfcc7a..e44d29637 100644 --- a/meilidb-core/src/database.rs +++ b/meilidb-core/src/database.rs @@ -1,4 +1,4 @@ -use std::collections::HashMap; +use std::collections::hash_map::{HashMap, Entry}; use std::path::Path; use std::sync::{Arc, RwLock}; use std::{fs, thread}; @@ -116,53 +116,64 @@ impl Database { Ok(Database { rkv, main_store, indexes_store, indexes: RwLock::new(indexes) }) } - pub fn open_index( - &self, - name: impl Into, - update_fn: Option, - ) -> MResult - { + pub fn open_index(&self, name: impl AsRef) -> Option { let indexes_lock = self.indexes.read().unwrap(); - let name = name.into(); + match indexes_lock.get(name.as_ref()) { + Some((index, ..)) => Some(index.clone()), + None => None, + } + } - match indexes_lock.get(&name) { - Some((index, old_update_fn, _)) => { - old_update_fn.swap(update_fn.map(Arc::new)); - Ok(index.clone()) - }, - None => { - drop(indexes_lock); + pub fn create_index(&self, name: impl AsRef) -> MResult { + let name = name.as_ref(); + let mut indexes_lock = self.indexes.write().unwrap(); + match indexes_lock.entry(name.to_owned()) { + Entry::Occupied(_) => Err(crate::Error::IndexAlreadyExists), + Entry::Vacant(entry) => { let rkv_lock = self.rkv.read().unwrap(); let (sender, receiver) = crossbeam_channel::bounded(100); - let index = store::create(&rkv_lock, &name, sender)?; + let index = store::create(&rkv_lock, name, sender)?; let mut writer = rkv_lock.write()?; let value = rkv::Value::Blob(&[]); - self.indexes_store.put(&mut writer, &name, &value)?; + self.indexes_store.put(&mut writer, name, &value)?; - { - let mut indexes_write = self.indexes.write().unwrap(); - indexes_write.entry(name).or_insert_with(|| { - let rkv_clone = self.rkv.clone(); - let index_clone = index.clone(); + let rkv_clone = self.rkv.clone(); + let index_clone = index.clone(); - let update_fn = update_fn.map(Arc::new); - let update_fn = Arc::new(ArcSwapFn::new(update_fn)); - let update_fn_clone = update_fn.clone(); + let no_update_fn = Arc::new(ArcSwapFn::empty()); + let no_update_fn_clone = no_update_fn.clone(); - let handle = thread::spawn(move || { - update_awaiter(receiver, rkv_clone, update_fn_clone, index_clone) - }); - - (index.clone(), update_fn, handle) - }); - } + let handle = thread::spawn(move || { + update_awaiter(receiver, rkv_clone, no_update_fn_clone, index_clone) + }); writer.commit()?; + entry.insert((index.clone(), no_update_fn, handle)); Ok(index) + } + } + } + + pub fn set_update_callback(&self, name: impl AsRef, update_fn: BoxUpdateFn) -> bool { + let indexes_lock = self.indexes.read().unwrap(); + match indexes_lock.get(name.as_ref()) { + Some((_, current_update_fn, _)) => { + let update_fn = Some(Arc::new(update_fn)); + current_update_fn.swap(update_fn); + true }, + None => false, + } + } + + pub fn unset_update_callback(&self, name: impl AsRef) -> bool { + let indexes_lock = self.indexes.read().unwrap(); + match indexes_lock.get(name.as_ref()) { + Some((_, current_update_fn, _)) => { current_update_fn.swap(None); true }, + None => false, } } diff --git a/meilidb-core/src/error.rs b/meilidb-core/src/error.rs index db83e39fd..cc600b388 100644 --- a/meilidb-core/src/error.rs +++ b/meilidb-core/src/error.rs @@ -6,6 +6,7 @@ pub type MResult = Result; #[derive(Debug)] pub enum Error { Io(io::Error), + IndexAlreadyExists, SchemaDiffer, SchemaMissing, WordIndexMissing, @@ -79,6 +80,7 @@ impl fmt::Display for Error { use self::Error::*; match self { Io(e) => write!(f, "{}", e), + IndexAlreadyExists => write!(f, "index already exists"), SchemaDiffer => write!(f, "schemas differ"), SchemaMissing => write!(f, "this index does not have a schema"), WordIndexMissing => write!(f, "this index does not have a word index"), diff --git a/meilidb-core/src/query_builder.rs b/meilidb-core/src/query_builder.rs index 718fa820c..c46093ce9 100644 --- a/meilidb-core/src/query_builder.rs +++ b/meilidb-core/src/query_builder.rs @@ -551,7 +551,7 @@ mod tests { use tempfile::TempDir; use crate::automaton::normalize_str; - use crate::database::{Database, BoxUpdateFn}; + use crate::database::Database; use crate::DocIndex; use crate::store::Index; @@ -646,8 +646,7 @@ mod tests { fn from_iter>(iter: I) -> Self { let tempdir = TempDir::new().unwrap(); let database = Database::open_or_create(&tempdir).unwrap(); - let update_fn = None as Option::; - let index = database.open_index("default", update_fn).unwrap(); + let index = database.create_index("default").unwrap(); let rkv = database.rkv.read().unwrap(); let mut writer = rkv.write().unwrap();