Merge remote-tracking branch 'origin/main' into snapshots

This commit is contained in:
mpostma 2021-03-25 13:45:07 +01:00
commit f3dc853be3
No known key found for this signature in database
GPG Key ID: CBC8A7C1D7A28C3A
2 changed files with 65 additions and 54 deletions

View File

@ -41,6 +41,7 @@ pub struct SearchQuery {
pub struct SearchResult { pub struct SearchResult {
pub hits: Vec<Map<String, Value>>, pub hits: Vec<Map<String, Value>>,
pub nb_hits: u64, pub nb_hits: u64,
pub exhaustive_nb_hits: bool,
pub query: String, pub query: String,
pub limit: usize, pub limit: usize,
pub offset: usize, pub offset: usize,
@ -107,6 +108,7 @@ impl Index {
}; };
let result = SearchResult { let result = SearchResult {
exhaustive_nb_hits: false, // not implemented yet
hits: documents, hits: documents,
nb_hits, nb_hits,
query: query.q.clone().unwrap_or_default(), query: query.q.clone().unwrap_or_default(),

View File

@ -17,6 +17,7 @@ use milli::update::{IndexDocumentsMethod, UpdateFormat};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use tokio::sync::mpsc; use tokio::sync::mpsc;
use tokio::time::sleep; use tokio::time::sleep;
use uuid::Uuid;
use crate::index::{Document, SearchQuery, SearchResult}; use crate::index::{Document, SearchQuery, SearchResult};
use crate::index::{Facets, Settings, UpdateResult}; use crate::index::{Facets, Settings, UpdateResult};
@ -29,6 +30,7 @@ use uuid_resolver::UuidResolverHandle;
use snapshot::SnapshotService; use snapshot::SnapshotService;
pub use updates::{Failed, Processed, Processing}; pub use updates::{Failed, Processed, Processing};
use uuid_resolver::UuidError;
pub type UpdateStatus = updates::UpdateStatus<UpdateMeta, UpdateResult, String>; pub type UpdateStatus = updates::UpdateStatus<UpdateMeta, UpdateResult, String>;
@ -119,10 +121,10 @@ impl IndexController {
uid: String, uid: String,
method: milli::update::IndexDocumentsMethod, method: milli::update::IndexDocumentsMethod,
format: milli::update::UpdateFormat, format: milli::update::UpdateFormat,
mut payload: Payload, payload: Payload,
primary_key: Option<String>, primary_key: Option<String>,
) -> anyhow::Result<UpdateStatus> { ) -> anyhow::Result<UpdateStatus> {
let uuid = self.uuid_resolver.get_or_create(uid).await?; let perform_update = |uuid| async move {
let meta = UpdateMeta::DocumentsAddition { let meta = UpdateMeta::DocumentsAddition {
method, method,
format, format,
@ -130,30 +132,40 @@ impl IndexController {
}; };
let (sender, receiver) = mpsc::channel(10); let (sender, receiver) = mpsc::channel(10);
// It is necessary to spawn a local task to senf the payload to the update handle to // It is necessary to spawn a local task to send the payload to the update handle to
// prevent dead_locking between the update_handle::update that waits for the update to be // prevent dead_locking between the update_handle::update that waits for the update to be
// registered and the update_actor that waits for the the payload to be sent to it. // registered and the update_actor that waits for the the payload to be sent to it.
tokio::task::spawn_local(async move { tokio::task::spawn_local(async move {
while let Some(bytes) = payload.next().await { payload
match bytes { .map(|bytes| {
Ok(bytes) => { bytes.map_err(|e| {
let _ = sender.send(Ok(bytes)).await; Box::new(e) as Box<dyn std::error::Error + Sync + Send + 'static>
} })
Err(e) => { })
let error: Box<dyn std::error::Error + Sync + Send + 'static> = Box::new(e); .for_each(|r| async {
let _ = sender.send(Err(error)).await; let _ = sender.send(r).await;
} })
} .await
}
}); });
// This must be done *AFTER* spawning the task. // This must be done *AFTER* spawning the task.
let status = self.update_handle.update(meta, receiver, uuid).await?; self.update_handle.update(meta, receiver, uuid).await
};
match self.uuid_resolver.get(uid).await {
Ok(uuid) => Ok(perform_update(uuid).await?),
Err(UuidError::UnexistingIndex(name)) => {
let uuid = Uuid::new_v4();
let status = perform_update(uuid).await?;
self.uuid_resolver.insert(name, uuid).await?;
Ok(status) Ok(status)
} }
Err(e) => Err(e.into()),
}
}
pub async fn clear_documents(&self, uid: String) -> anyhow::Result<UpdateStatus> { pub async fn clear_documents(&self, uid: String) -> anyhow::Result<UpdateStatus> {
let uuid = self.uuid_resolver.resolve(uid).await?; let uuid = self.uuid_resolver.get(uid).await?;
let meta = UpdateMeta::ClearDocuments; let meta = UpdateMeta::ClearDocuments;
let (_, receiver) = mpsc::channel(1); let (_, receiver) = mpsc::channel(1);
let status = self.update_handle.update(meta, receiver, uuid).await?; let status = self.update_handle.update(meta, receiver, uuid).await?;
@ -165,7 +177,7 @@ impl IndexController {
uid: String, uid: String,
document_ids: Vec<String>, document_ids: Vec<String>,
) -> anyhow::Result<UpdateStatus> { ) -> anyhow::Result<UpdateStatus> {
let uuid = self.uuid_resolver.resolve(uid).await?; let uuid = self.uuid_resolver.get(uid).await?;
let meta = UpdateMeta::DeleteDocuments; let meta = UpdateMeta::DeleteDocuments;
let (sender, receiver) = mpsc::channel(10); let (sender, receiver) = mpsc::channel(10);
@ -185,27 +197,24 @@ impl IndexController {
settings: Settings, settings: Settings,
create: bool, create: bool,
) -> anyhow::Result<UpdateStatus> { ) -> anyhow::Result<UpdateStatus> {
let uuid = if create { let perform_udpate = |uuid| async move {
let uuid = self.uuid_resolver.get_or_create(uid).await?;
// We need to create the index upfront, since it would otherwise only be created when
// the update is processed. This would make calls to GET index to fail until the update
// is complete. Since this is get or create, we ignore the error when the index already
// exists.
match self.index_handle.create_index(uuid, None).await {
Ok(_) | Err(index_actor::IndexError::IndexAlreadyExists) => (),
Err(e) => return Err(e.into()),
}
uuid
} else {
self.uuid_resolver.resolve(uid).await?
};
let meta = UpdateMeta::Settings(settings); let meta = UpdateMeta::Settings(settings);
// Nothing so send, drop the sender right away, as not to block the update actor. // Nothing so send, drop the sender right away, as not to block the update actor.
let (_, receiver) = mpsc::channel(1); let (_, receiver) = mpsc::channel(1);
self.update_handle.update(meta, receiver, uuid).await
};
let status = self.update_handle.update(meta, receiver, uuid).await?; match self.uuid_resolver.get(uid).await {
Ok(uuid) => Ok(perform_udpate(uuid).await?),
Err(UuidError::UnexistingIndex(name)) if create => {
let uuid = Uuid::new_v4();
let status = perform_udpate(uuid).await?;
self.uuid_resolver.insert(name, uuid).await?;
Ok(status) Ok(status)
} }
Err(e) => Err(e.into()),
}
}
pub async fn create_index( pub async fn create_index(
&self, &self,
@ -233,13 +242,13 @@ impl IndexController {
} }
pub async fn update_status(&self, uid: String, id: u64) -> anyhow::Result<UpdateStatus> { pub async fn update_status(&self, uid: String, id: u64) -> anyhow::Result<UpdateStatus> {
let uuid = self.uuid_resolver.resolve(uid).await?; let uuid = self.uuid_resolver.get(uid).await?;
let result = self.update_handle.update_status(uuid, id).await?; let result = self.update_handle.update_status(uuid, id).await?;
Ok(result) Ok(result)
} }
pub async fn all_update_status(&self, uid: String) -> anyhow::Result<Vec<UpdateStatus>> { pub async fn all_update_status(&self, uid: String) -> anyhow::Result<Vec<UpdateStatus>> {
let uuid = self.uuid_resolver.resolve(uid).await?; let uuid = self.uuid_resolver.get(uid).await?;
let result = self.update_handle.get_all_updates_status(uuid).await?; let result = self.update_handle.get_all_updates_status(uuid).await?;
Ok(result) Ok(result)
} }
@ -263,7 +272,7 @@ impl IndexController {
} }
pub async fn settings(&self, uid: String) -> anyhow::Result<Settings> { pub async fn settings(&self, uid: String) -> anyhow::Result<Settings> {
let uuid = self.uuid_resolver.resolve(uid.clone()).await?; let uuid = self.uuid_resolver.get(uid.clone()).await?;
let settings = self.index_handle.settings(uuid).await?; let settings = self.index_handle.settings(uuid).await?;
Ok(settings) Ok(settings)
} }
@ -275,7 +284,7 @@ impl IndexController {
limit: usize, limit: usize,
attributes_to_retrieve: Option<Vec<String>>, attributes_to_retrieve: Option<Vec<String>>,
) -> anyhow::Result<Vec<Document>> { ) -> anyhow::Result<Vec<Document>> {
let uuid = self.uuid_resolver.resolve(uid.clone()).await?; let uuid = self.uuid_resolver.get(uid.clone()).await?;
let documents = self let documents = self
.index_handle .index_handle
.documents(uuid, offset, limit, attributes_to_retrieve) .documents(uuid, offset, limit, attributes_to_retrieve)
@ -289,7 +298,7 @@ impl IndexController {
doc_id: String, doc_id: String,
attributes_to_retrieve: Option<Vec<String>>, attributes_to_retrieve: Option<Vec<String>>,
) -> anyhow::Result<Document> { ) -> anyhow::Result<Document> {
let uuid = self.uuid_resolver.resolve(uid.clone()).await?; let uuid = self.uuid_resolver.get(uid.clone()).await?;
let document = self let document = self
.index_handle .index_handle
.document(uuid, doc_id, attributes_to_retrieve) .document(uuid, doc_id, attributes_to_retrieve)
@ -306,7 +315,7 @@ impl IndexController {
bail!("Can't change the index uid.") bail!("Can't change the index uid.")
} }
let uuid = self.uuid_resolver.resolve(uid.clone()).await?; let uuid = self.uuid_resolver.get(uid.clone()).await?;
let meta = self.index_handle.update_index(uuid, index_settings).await?; let meta = self.index_handle.update_index(uuid, index_settings).await?;
let meta = IndexMetadata { let meta = IndexMetadata {
name: uid.clone(), name: uid.clone(),
@ -317,13 +326,13 @@ impl IndexController {
} }
pub async fn search(&self, uid: String, query: SearchQuery) -> anyhow::Result<SearchResult> { pub async fn search(&self, uid: String, query: SearchQuery) -> anyhow::Result<SearchResult> {
let uuid = self.uuid_resolver.resolve(uid).await?; let uuid = self.uuid_resolver.get(uid).await?;
let result = self.index_handle.search(uuid, query).await?; let result = self.index_handle.search(uuid, query).await?;
Ok(result) Ok(result)
} }
pub async fn get_index(&self, uid: String) -> anyhow::Result<IndexMetadata> { pub async fn get_index(&self, uid: String) -> anyhow::Result<IndexMetadata> {
let uuid = self.uuid_resolver.resolve(uid.clone()).await?; let uuid = self.uuid_resolver.get(uid.clone()).await?;
let meta = self.index_handle.get_index_meta(uuid).await?; let meta = self.index_handle.get_index_meta(uuid).await?;
let meta = IndexMetadata { let meta = IndexMetadata {
name: uid.clone(), name: uid.clone(),