From bfe3bb0eebe2e42ea74ec2637403de83e13d538f Mon Sep 17 00:00:00 2001 From: qdequele Date: Tue, 8 Sep 2020 19:16:17 +0200 Subject: [PATCH] create an helper to allow to delete the index on error --- Cargo.lock | 6 +- meilisearch-http/src/data.rs | 59 ++++++++++++- meilisearch-http/src/routes/document.rs | 94 +++++++-------------- meilisearch-http/src/routes/setting.rs | 107 +++++++++++++----------- 4 files changed, 149 insertions(+), 117 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 3abc34c71..196deb1bb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1914,7 +1914,8 @@ checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e" [[package]] name = "pest" version = "2.1.3" -source = "git+https://github.com/pest-parser/pest.git?rev=51fd1d49f1041f7839975664ef71fe15c7dcaf67#51fd1d49f1041f7839975664ef71fe15c7dcaf67" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10f4872ae94d7b90ae48754df22fd42ad52ce740b8f370b03da4835417403e53" dependencies = [ "ucd-trie", ] @@ -1922,8 +1923,7 @@ dependencies = [ [[package]] name = "pest" version = "2.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10f4872ae94d7b90ae48754df22fd42ad52ce740b8f370b03da4835417403e53" +source = "git+https://github.com/MarinPostma/pest.git?tag=meilisearch-patch1#e1031ad0134d5e9893c470dbea50811b2b746926" dependencies = [ "ucd-trie", ] diff --git a/meilisearch-http/src/data.rs b/meilisearch-http/src/data.rs index ae90e2a03..b552e7f6e 100644 --- a/meilisearch-http/src/data.rs +++ b/meilisearch-http/src/data.rs @@ -3,9 +3,10 @@ use std::ops::Deref; use std::path::PathBuf; use std::sync::Arc; -use meilisearch_core::{Database, DatabaseOptions}; +use meilisearch_core::{Database, DatabaseOptions, Index}; use sha2::Digest; +use crate::error::{Error as MSError, ResponseError}; use crate::index_update_callback; use crate::option::Opt; @@ -102,4 +103,60 @@ impl Data { Ok(data) } + + fn create_index(&self, uid: &str) -> Result { + if !uid + .chars() + .all(|x| x.is_ascii_alphanumeric() || x == '-' || x == '_') + { + return Err(MSError::InvalidIndexUid.into()); + } + + let created_index = self.db.create_index(&uid).map_err(|e| match e { + meilisearch_core::Error::IndexAlreadyExists => e.into(), + _ => ResponseError::from(MSError::create_index(e)), + })?; + + self.db.main_write::<_, _, ResponseError>(|mut writer| { + created_index.main.put_name(&mut writer, uid)?; + + created_index + .main + .created_at(&writer)? + .ok_or(MSError::internal("Impossible to read created at"))?; + + created_index + .main + .updated_at(&writer)? + .ok_or(MSError::internal("Impossible to read updated at"))?; + Ok(()) + })?; + + Ok(created_index) + } + + pub fn get_or_create_index(&self, uid: &str, f: F) -> Result + where + F: FnOnce(&Index) -> Result, + { + let mut index_has_been_created = false; + + let index = match self.db.open_index(&uid) { + Some(index) => index, + None => { + index_has_been_created = true; + self.create_index(&uid)? + } + }; + + match f(&index) { + Ok(r) => Ok(r), + Err(err) => { + if index_has_been_created { + let _ = self.db.delete_index(&uid); + } + Err(err) + } + } + } } diff --git a/meilisearch-http/src/routes/document.rs b/meilisearch-http/src/routes/document.rs index 9290a8710..f565c1e6b 100644 --- a/meilisearch-http/src/routes/document.rs +++ b/meilisearch-http/src/routes/document.rs @@ -160,37 +160,6 @@ struct UpdateDocumentsQuery { primary_key: Option, } -fn create_index(data: &Data, uid: &str) -> Result { - if !uid - .chars() - .all(|x| x.is_ascii_alphanumeric() || x == '-' || x == '_') - { - return Err(Error::InvalidIndexUid.into()); - } - - let created_index = data.db.create_index(&uid).map_err(|e| match e { - meilisearch_core::Error::IndexAlreadyExists => e.into(), - _ => ResponseError::from(Error::create_index(e)), - })?; - - data.db.main_write::<_, _, ResponseError>(|mut writer| { - created_index.main.put_name(&mut writer, uid)?; - - created_index - .main - .created_at(&writer)? - .ok_or(Error::internal("Impossible to read created at"))?; - - created_index - .main - .updated_at(&writer)? - .ok_or(Error::internal("Impossible to read updated at"))?; - Ok(()) - })?; - - Ok(created_index) -} - async fn update_multiple_documents( data: web::Data, path: web::Path, @@ -198,46 +167,41 @@ async fn update_multiple_documents( body: web::Json>, is_partial: bool, ) -> Result { - let index = data - .db - .open_index(&path.index_uid) - .ok_or(Error::index_not_found(&path.index_uid)) - .or(create_index(&data, &path.index_uid))?; + let update_id = data.get_or_create_index(&path.index_uid, |index| { + let reader = data.db.main_read_txn()?; - let reader = data.db.main_read_txn()?; + let mut schema = index + .main + .schema(&reader)? + .ok_or(meilisearch_core::Error::SchemaMissing)?; - let mut schema = index - .main - .schema(&reader)? - .ok_or(meilisearch_core::Error::SchemaMissing)?; + if schema.primary_key().is_none() { + let id = match ¶ms.primary_key { + Some(id) => id.to_string(), + None => body + .first() + .and_then(find_primary_key) + .ok_or(meilisearch_core::Error::MissingPrimaryKey)?, + }; - if schema.primary_key().is_none() { - let id = match ¶ms.primary_key { - Some(id) => id.to_string(), - None => body - .first() - .and_then(find_primary_key) - .ok_or(meilisearch_core::Error::MissingPrimaryKey)?, + schema.set_primary_key(&id).map_err(Error::bad_request)?; + + data.db.main_write(|w| index.main.put_schema(w, &schema))?; + } + + let mut document_addition = if is_partial { + index.documents_partial_addition() + } else { + index.documents_addition() }; - schema.set_primary_key(&id).map_err(Error::bad_request)?; + for document in body.into_inner() { + document_addition.update_document(document); + } - data.db.main_write(|w| index.main.put_schema(w, &schema))?; - } - - let mut document_addition = if is_partial { - index.documents_partial_addition() - } else { - index.documents_addition() - }; - - for document in body.into_inner() { - document_addition.update_document(document); - } - - let update_id = data.db.update_write(|w| document_addition.finalize(w))?; - - Ok(HttpResponse::Accepted().json(IndexUpdateResponse::with_id(update_id))) + Ok(data.db.update_write(|w| document_addition.finalize(w))?) + })?; + return Ok(HttpResponse::Accepted().json(IndexUpdateResponse::with_id(update_id))); } #[post("/indexes/{index_uid}/documents", wrap = "Authentication::Private")] diff --git a/meilisearch-http/src/routes/setting.rs b/meilisearch-http/src/routes/setting.rs index 77067d9dd..3ec273008 100644 --- a/meilisearch-http/src/routes/setting.rs +++ b/meilisearch-http/src/routes/setting.rs @@ -53,13 +53,12 @@ async fn update_all( path: web::Path, body: web::Json, ) -> Result { - let settings = body - .into_inner() - .to_update() - .map_err(Error::bad_request)?; - - let update_id = data.db.update_write::<_, _, Error>(|writer| { - update_all_settings_txn(&data, settings, &path.index_uid, writer) + let update_id = data.get_or_create_index(&path.index_uid, |index| { + Ok(data.db.update_write::<_, _, ResponseError>(|writer| { + let settings = body.into_inner().to_update().map_err(Error::bad_request)?; + let update_id = index.settings_update(writer, settings)?; + Ok(update_id) + })?) })?; Ok(HttpResponse::Accepted().json(IndexUpdateResponse::with_id(update_id))) @@ -71,11 +70,7 @@ pub fn get_all_sync(data: &web::Data, reader: &MainReader, index_uid: &str .open_index(index_uid) .ok_or(Error::index_not_found(index_uid))?; - let stop_words: BTreeSet = index - .main - .stop_words(reader)? - .into_iter() - .collect(); + let stop_words: BTreeSet = index.main.stop_words(&reader)?.into_iter().collect(); let synonyms_list = index.main.synonyms(reader)?; @@ -94,22 +89,19 @@ pub fn get_all_sync(data: &web::Data, reader: &MainReader, index_uid: &str .map(|r| r.to_string()) .collect(); - - let schema = index.main.schema(reader)?; + let schema = index.main.schema(&reader)?; let distinct_attribute = match (index.main.distinct_attribute(reader)?, &schema) { (Some(id), Some(schema)) => schema.name(id).map(str::to_string), _ => None, }; - let attributes_for_faceting = match (&schema, &index.main.attributes_for_faceting(reader)?) { - (Some(schema), Some(attrs)) => { - attrs - .iter() - .filter_map(|&id| schema.name(id)) - .map(str::to_string) - .collect() - } + let attributes_for_faceting = match (&schema, &index.main.attributes_for_faceting(&reader)?) { + (Some(schema), Some(attrs)) => attrs + .iter() + .filter_map(|&id| schema.name(id)) + .map(str::to_string) + .collect(), _ => vec![], }; @@ -159,7 +151,9 @@ async fn delete_all( attributes_for_faceting: UpdateState::Clear, }; - let update_id = data.db.update_write(|w| index.settings_update(w, settings))?; + let update_id = data + .db + .update_write(|w| index.settings_update(w, settings))?; Ok(HttpResponse::Accepted().json(IndexUpdateResponse::with_id(update_id))) } @@ -209,7 +203,9 @@ async fn update_rules( }; let settings = settings.to_update().map_err(Error::bad_request)?; - let update_id = data.db.update_write(|w| index.settings_update(w, settings))?; + let update_id = data + .db + .update_write(|w| index.settings_update(w, settings))?; Ok(HttpResponse::Accepted().json(IndexUpdateResponse::with_id(update_id))) } @@ -232,7 +228,9 @@ async fn delete_rules( ..SettingsUpdate::default() }; - let update_id = data.db.update_write(|w| index.settings_update(w, settings))?; + let update_id = data + .db + .update_write(|w| index.settings_update(w, settings))?; Ok(HttpResponse::Accepted().json(IndexUpdateResponse::with_id(update_id))) } @@ -280,7 +278,9 @@ async fn update_distinct( }; let settings = settings.to_update().map_err(Error::bad_request)?; - let update_id = data.db.update_write(|w| index.settings_update(w, settings))?; + let update_id = data + .db + .update_write(|w| index.settings_update(w, settings))?; Ok(HttpResponse::Accepted().json(IndexUpdateResponse::with_id(update_id))) } @@ -303,7 +303,9 @@ async fn delete_distinct( ..SettingsUpdate::default() }; - let update_id = data.db.update_write(|w| index.settings_update(w, settings))?; + let update_id = data + .db + .update_write(|w| index.settings_update(w, settings))?; Ok(HttpResponse::Accepted().json(IndexUpdateResponse::with_id(update_id))) } @@ -322,8 +324,7 @@ async fn get_searchable( .ok_or(Error::index_not_found(&path.index_uid))?; let reader = data.db.main_read_txn()?; let schema = index.main.schema(&reader)?; - let searchable_attributes: Option> = - schema.as_ref().map(get_indexed_attributes); + let searchable_attributes: Option> = schema.as_ref().map(get_indexed_attributes); Ok(HttpResponse::Ok().json(searchable_attributes)) } @@ -349,7 +350,9 @@ async fn update_searchable( let settings = settings.to_update().map_err(Error::bad_request)?; - let update_id = data.db.update_write(|w| index.settings_update(w, settings))?; + let update_id = data + .db + .update_write(|w| index.settings_update(w, settings))?; Ok(HttpResponse::Accepted().json(IndexUpdateResponse::with_id(update_id))) } @@ -372,7 +375,9 @@ async fn delete_searchable( ..SettingsUpdate::default() }; - let update_id = data.db.update_write(|w| index.settings_update(w, settings))?; + let update_id = data + .db + .update_write(|w| index.settings_update(w, settings))?; Ok(HttpResponse::Accepted().json(IndexUpdateResponse::with_id(update_id))) } @@ -418,7 +423,9 @@ async fn update_displayed( }; let settings = settings.to_update().map_err(Error::bad_request)?; - let update_id = data.db.update_write(|w| index.settings_update(w, settings))?; + let update_id = data + .db + .update_write(|w| index.settings_update(w, settings))?; Ok(HttpResponse::Accepted().json(IndexUpdateResponse::with_id(update_id))) } @@ -441,7 +448,9 @@ async fn delete_displayed( ..SettingsUpdate::default() }; - let update_id = data.db.update_write(|w| index.settings_update(w, settings))?; + let update_id = data + .db + .update_write(|w| index.settings_update(w, settings))?; Ok(HttpResponse::Accepted().json(IndexUpdateResponse::with_id(update_id))) } @@ -459,20 +468,16 @@ async fn get_attributes_for_faceting( .open_index(&path.index_uid) .ok_or(Error::index_not_found(&path.index_uid))?; - let attributes_for_faceting = data - .db - .main_read::<_, _, ResponseError>(|reader| { + let attributes_for_faceting = data.db.main_read::<_, _, ResponseError>(|reader| { let schema = index.main.schema(reader)?; let attrs = index.main.attributes_for_faceting(reader)?; let attr_names = match (&schema, &attrs) { - (Some(schema), Some(attrs)) => { - attrs - .iter() - .filter_map(|&id| schema.name(id)) - .map(str::to_string) - .collect() - } - _ => vec![] + (Some(schema), Some(attrs)) => attrs + .iter() + .filter_map(|&id| schema.name(id)) + .map(str::to_string) + .collect(), + _ => vec![], }; Ok(attr_names) })?; @@ -500,7 +505,9 @@ async fn update_attributes_for_faceting( }; let settings = settings.to_update().map_err(Error::bad_request)?; - let update_id = data.db.update_write(|w| index.settings_update(w, settings))?; + let update_id = data + .db + .update_write(|w| index.settings_update(w, settings))?; Ok(HttpResponse::Accepted().json(IndexUpdateResponse::with_id(update_id))) } @@ -523,7 +530,9 @@ async fn delete_attributes_for_faceting( ..SettingsUpdate::default() }; - let update_id = data.db.update_write(|w| index.settings_update(w, settings))?; + let update_id = data + .db + .update_write(|w| index.settings_update(w, settings))?; Ok(HttpResponse::Accepted().json(IndexUpdateResponse::with_id(update_id))) } @@ -532,7 +541,8 @@ fn get_indexed_attributes(schema: &Schema) -> Vec { if schema.is_indexed_all() { ["*"].iter().map(|s| s.to_string()).collect() } else { - schema.indexed_name() + schema + .indexed_name() .iter() .map(|s| s.to_string()) .collect() @@ -543,7 +553,8 @@ fn get_displayed_attributes(schema: &Schema) -> HashSet { if schema.is_displayed_all() { ["*"].iter().map(|s| s.to_string()).collect() } else { - schema.displayed_name() + schema + .displayed_name() .iter() .map(|s| s.to_string()) .collect()