mirror of
https://github.com/meilisearch/meilisearch.git
synced 2024-11-26 20:15:07 +08:00
create uuid on successful update addition
also change resolve to get in uuid resolver
This commit is contained in:
parent
1640d9ea91
commit
147756750b
2
Cargo.lock
generated
2
Cargo.lock
generated
@ -1786,7 +1786,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "meilisearch-http"
|
name = "meilisearch-http"
|
||||||
version = "0.21.0-alpha"
|
version = "0.21.0-alpha.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"actix-cors",
|
"actix-cors",
|
||||||
"actix-http 3.0.0-beta.4",
|
"actix-http 3.0.0-beta.4",
|
||||||
|
@ -16,10 +16,12 @@ 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};
|
||||||
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>;
|
||||||
|
|
||||||
@ -83,38 +85,49 @@ impl IndexController {
|
|||||||
mut payload: Payload,
|
mut 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_udpate = |uuid| async move {
|
||||||
let meta = UpdateMeta::DocumentsAddition {
|
let meta = UpdateMeta::DocumentsAddition {
|
||||||
method,
|
method,
|
||||||
format,
|
format,
|
||||||
primary_key,
|
primary_key,
|
||||||
};
|
};
|
||||||
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 senf 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 {
|
while let Some(bytes) = payload.next().await {
|
||||||
match bytes {
|
match bytes {
|
||||||
Ok(bytes) => {
|
Ok(bytes) => {
|
||||||
let _ = sender.send(Ok(bytes)).await;
|
let _ = sender.send(Ok(bytes)).await;
|
||||||
}
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
let error: Box<dyn std::error::Error + Sync + Send + 'static> = Box::new(e);
|
let error: Box<dyn std::error::Error + Sync + Send + 'static> = Box::new(e);
|
||||||
let _ = sender.send(Err(error)).await;
|
let _ = sender.send(Err(error)).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
|
||||||
Ok(status)
|
};
|
||||||
|
|
||||||
|
match self.uuid_resolver.get(uid).await {
|
||||||
|
Ok(uuid) => Ok(perform_udpate(uuid).await?),
|
||||||
|
Err(UuidError::UnexistingIndex(name)) => {
|
||||||
|
let uuid = Uuid::new_v4();
|
||||||
|
let status = perform_udpate(uuid).await?;
|
||||||
|
self.uuid_resolver.insert(name, uuid).await?;
|
||||||
|
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?;
|
||||||
@ -126,7 +139,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);
|
||||||
|
|
||||||
@ -146,26 +159,23 @@ 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?;
|
let meta = UpdateMeta::Settings(settings);
|
||||||
// We need to create the index upfront, since it would otherwise only be created when
|
// Nothing so send, drop the sender right away, as not to block the update actor.
|
||||||
// the update is processed. This would make calls to GET index to fail until the update
|
let (_, receiver) = mpsc::channel(1);
|
||||||
// is complete. Since this is get or create, we ignore the error when the index already
|
self.update_handle.update(meta, receiver, uuid).await
|
||||||
// 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);
|
|
||||||
// Nothing so send, drop the sender right away, as not to block the update actor.
|
|
||||||
let (_, receiver) = mpsc::channel(1);
|
|
||||||
|
|
||||||
let status = self.update_handle.update(meta, receiver, uuid).await?;
|
match self.uuid_resolver.get(uid).await {
|
||||||
Ok(status)
|
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)
|
||||||
|
}
|
||||||
|
Err(e) => Err(e.into()),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn create_index(
|
pub async fn create_index(
|
||||||
@ -190,13 +200,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)
|
||||||
}
|
}
|
||||||
@ -216,7 +226,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)
|
||||||
}
|
}
|
||||||
@ -228,7 +238,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)
|
||||||
@ -242,7 +252,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)
|
||||||
@ -259,20 +269,20 @@ 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 { name: uid.clone(), uid, meta };
|
let meta = IndexMetadata { name: uid.clone(), uid, meta };
|
||||||
Ok(meta)
|
Ok(meta)
|
||||||
}
|
}
|
||||||
|
|
||||||
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 { name: uid.clone(), uid, meta };
|
let meta = IndexMetadata { name: uid.clone(), uid, meta };
|
||||||
Ok(meta)
|
Ok(meta)
|
||||||
|
@ -13,11 +13,7 @@ pub type Result<T> = std::result::Result<T, UuidError>;
|
|||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
enum UuidResolveMsg {
|
enum UuidResolveMsg {
|
||||||
Resolve {
|
Get {
|
||||||
uid: String,
|
|
||||||
ret: oneshot::Sender<Result<Uuid>>,
|
|
||||||
},
|
|
||||||
GetOrCreate {
|
|
||||||
uid: String,
|
uid: String,
|
||||||
ret: oneshot::Sender<Result<Uuid>>,
|
ret: oneshot::Sender<Result<Uuid>>,
|
||||||
},
|
},
|
||||||
@ -32,6 +28,11 @@ enum UuidResolveMsg {
|
|||||||
List {
|
List {
|
||||||
ret: oneshot::Sender<Result<Vec<(String, Uuid)>>>,
|
ret: oneshot::Sender<Result<Vec<(String, Uuid)>>>,
|
||||||
},
|
},
|
||||||
|
Insert {
|
||||||
|
uuid: Uuid,
|
||||||
|
name: String,
|
||||||
|
ret: oneshot::Sender<Result<()>>,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct UuidResolverActor<S> {
|
struct UuidResolverActor<S> {
|
||||||
@ -54,11 +55,8 @@ impl<S: UuidStore> UuidResolverActor<S> {
|
|||||||
Some(Create { uid: name, ret }) => {
|
Some(Create { uid: name, ret }) => {
|
||||||
let _ = ret.send(self.handle_create(name).await);
|
let _ = ret.send(self.handle_create(name).await);
|
||||||
}
|
}
|
||||||
Some(GetOrCreate { uid: name, ret }) => {
|
Some(Get { uid: name, ret }) => {
|
||||||
let _ = ret.send(self.handle_get_or_create(name).await);
|
let _ = ret.send(self.handle_get(name).await);
|
||||||
}
|
|
||||||
Some(Resolve { uid: name, ret }) => {
|
|
||||||
let _ = ret.send(self.handle_resolve(name).await);
|
|
||||||
}
|
}
|
||||||
Some(Delete { uid: name, ret }) => {
|
Some(Delete { uid: name, ret }) => {
|
||||||
let _ = ret.send(self.handle_delete(name).await);
|
let _ = ret.send(self.handle_delete(name).await);
|
||||||
@ -66,6 +64,9 @@ impl<S: UuidStore> UuidResolverActor<S> {
|
|||||||
Some(List { ret }) => {
|
Some(List { ret }) => {
|
||||||
let _ = ret.send(self.handle_list().await);
|
let _ = ret.send(self.handle_list().await);
|
||||||
}
|
}
|
||||||
|
Some(Insert { ret, uuid, name }) => {
|
||||||
|
let _ = ret.send(self.handle_insert(name, uuid).await);
|
||||||
|
}
|
||||||
// all senders have been dropped, need to quit.
|
// all senders have been dropped, need to quit.
|
||||||
None => break,
|
None => break,
|
||||||
}
|
}
|
||||||
@ -81,14 +82,7 @@ impl<S: UuidStore> UuidResolverActor<S> {
|
|||||||
self.store.create_uuid(uid, true).await
|
self.store.create_uuid(uid, true).await
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn handle_get_or_create(&self, uid: String) -> Result<Uuid> {
|
async fn handle_get(&self, uid: String) -> Result<Uuid> {
|
||||||
if !is_index_uid_valid(&uid) {
|
|
||||||
return Err(UuidError::BadlyFormatted(uid));
|
|
||||||
}
|
|
||||||
self.store.create_uuid(uid, false).await
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn handle_resolve(&self, uid: String) -> Result<Uuid> {
|
|
||||||
self.store
|
self.store
|
||||||
.get_uuid(uid.clone())
|
.get_uuid(uid.clone())
|
||||||
.await?
|
.await?
|
||||||
@ -106,6 +100,14 @@ impl<S: UuidStore> UuidResolverActor<S> {
|
|||||||
let result = self.store.list().await?;
|
let result = self.store.list().await?;
|
||||||
Ok(result)
|
Ok(result)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn handle_insert(&self, uid: String, uuid: Uuid) -> Result<()> {
|
||||||
|
if !is_index_uid_valid(&uid) {
|
||||||
|
return Err(UuidError::BadlyFormatted(uid));
|
||||||
|
}
|
||||||
|
self.store.insert(uid, uuid).await?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_index_uid_valid(uid: &str) -> bool {
|
fn is_index_uid_valid(uid: &str) -> bool {
|
||||||
@ -127,18 +129,9 @@ impl UuidResolverHandle {
|
|||||||
Ok(Self { sender })
|
Ok(Self { sender })
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn resolve(&self, name: String) -> anyhow::Result<Uuid> {
|
pub async fn get(&self, name: String) -> Result<Uuid> {
|
||||||
let (ret, receiver) = oneshot::channel();
|
let (ret, receiver) = oneshot::channel();
|
||||||
let msg = UuidResolveMsg::Resolve { uid: name, ret };
|
let msg = UuidResolveMsg::Get { uid: name, ret };
|
||||||
let _ = self.sender.send(msg).await;
|
|
||||||
Ok(receiver
|
|
||||||
.await
|
|
||||||
.expect("Uuid resolver actor has been killed")?)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn get_or_create(&self, name: String) -> Result<Uuid> {
|
|
||||||
let (ret, receiver) = oneshot::channel();
|
|
||||||
let msg = UuidResolveMsg::GetOrCreate { uid: name, ret };
|
|
||||||
let _ = self.sender.send(msg).await;
|
let _ = self.sender.send(msg).await;
|
||||||
Ok(receiver
|
Ok(receiver
|
||||||
.await
|
.await
|
||||||
@ -171,6 +164,15 @@ impl UuidResolverHandle {
|
|||||||
.await
|
.await
|
||||||
.expect("Uuid resolver actor has been killed")?)
|
.expect("Uuid resolver actor has been killed")?)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn insert(&self, name: String, uuid: Uuid) -> anyhow::Result<()> {
|
||||||
|
let (ret, receiver) = oneshot::channel();
|
||||||
|
let msg = UuidResolveMsg::Insert { ret, name, uuid };
|
||||||
|
let _ = self.sender.send(msg).await;
|
||||||
|
Ok(receiver
|
||||||
|
.await
|
||||||
|
.expect("Uuid resolver actor has been killed")?)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Error)]
|
#[derive(Debug, Error)]
|
||||||
@ -197,6 +199,7 @@ trait UuidStore {
|
|||||||
async fn get_uuid(&self, uid: String) -> Result<Option<Uuid>>;
|
async fn get_uuid(&self, uid: String) -> Result<Option<Uuid>>;
|
||||||
async fn delete(&self, uid: String) -> Result<Option<Uuid>>;
|
async fn delete(&self, uid: String) -> Result<Option<Uuid>>;
|
||||||
async fn list(&self) -> Result<Vec<(String, Uuid)>>;
|
async fn list(&self) -> Result<Vec<(String, Uuid)>>;
|
||||||
|
async fn insert(&self, name: String, uuid: Uuid) -> Result<()>;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct HeedUuidStore {
|
struct HeedUuidStore {
|
||||||
@ -292,4 +295,16 @@ impl UuidStore for HeedUuidStore {
|
|||||||
})
|
})
|
||||||
.await?
|
.await?
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn insert(&self, name: String, uuid: Uuid) -> Result<()> {
|
||||||
|
let env = self.env.clone();
|
||||||
|
let db = self.db;
|
||||||
|
tokio::task::spawn_blocking(move || {
|
||||||
|
let mut txn = env.write_txn()?;
|
||||||
|
db.put(&mut txn, &name, uuid.as_bytes())?;
|
||||||
|
txn.commit()?;
|
||||||
|
Ok(())
|
||||||
|
})
|
||||||
|
.await?
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user