mirror of
https://github.com/meilisearch/MeiliSearch
synced 2025-01-11 14:04:31 +01:00
implement list indexes
This commit is contained in:
parent
d9254c4355
commit
281a445998
@ -82,8 +82,8 @@ impl Data {
|
|||||||
self.index_controller.settings(index_uid.as_ref().to_string()).await
|
self.index_controller.settings(index_uid.as_ref().to_string()).await
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn list_indexes(&self) -> anyhow::Result<Vec<IndexMetadata>> {
|
pub async fn list_indexes(&self) -> anyhow::Result<Vec<IndexMetadata>> {
|
||||||
self.index_controller.list_indexes()
|
self.index_controller.list_indexes().await
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn index(&self, name: impl AsRef<str>) -> anyhow::Result<Option<IndexMetadata>> {
|
pub fn index(&self, name: impl AsRef<str>) -> anyhow::Result<Option<IndexMetadata>> {
|
||||||
|
@ -1,18 +1,19 @@
|
|||||||
use std::collections::{hash_map::Entry, HashMap};
|
use std::collections::{hash_map::Entry, HashMap};
|
||||||
use std::fs::{create_dir_all, File, remove_dir_all};
|
use std::fs::{create_dir_all, remove_dir_all, File};
|
||||||
|
use std::future::Future;
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use async_stream::stream;
|
use async_stream::stream;
|
||||||
use chrono::Utc;
|
use chrono::{Utc, DateTime};
|
||||||
use futures::pin_mut;
|
use futures::pin_mut;
|
||||||
use futures::stream::StreamExt;
|
use futures::stream::StreamExt;
|
||||||
use heed::EnvOpenOptions;
|
use heed::EnvOpenOptions;
|
||||||
use log::info;
|
use log::info;
|
||||||
use std::future::Future;
|
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
use tokio::sync::{mpsc, oneshot, RwLock};
|
use tokio::sync::{mpsc, oneshot, RwLock};
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
|
use serde::{Serialize, Deserialize};
|
||||||
|
|
||||||
use super::get_arc_ownership_blocking;
|
use super::get_arc_ownership_blocking;
|
||||||
use super::update_handler::UpdateHandler;
|
use super::update_handler::UpdateHandler;
|
||||||
@ -20,7 +21,7 @@ use crate::index::UpdateResult as UResult;
|
|||||||
use crate::index::{Document, Index, SearchQuery, SearchResult, Settings};
|
use crate::index::{Document, Index, SearchQuery, SearchResult, Settings};
|
||||||
use crate::index_controller::{
|
use crate::index_controller::{
|
||||||
updates::{Failed, Processed, Processing},
|
updates::{Failed, Processed, Processing},
|
||||||
IndexMetadata, UpdateMeta,
|
UpdateMeta,
|
||||||
};
|
};
|
||||||
use crate::option::IndexerOpts;
|
use crate::option::IndexerOpts;
|
||||||
|
|
||||||
@ -28,11 +29,20 @@ pub type Result<T> = std::result::Result<T, IndexError>;
|
|||||||
type AsyncMap<K, V> = Arc<RwLock<HashMap<K, V>>>;
|
type AsyncMap<K, V> = Arc<RwLock<HashMap<K, V>>>;
|
||||||
type UpdateResult = std::result::Result<Processed<UpdateMeta, UResult>, Failed<UpdateMeta, String>>;
|
type UpdateResult = std::result::Result<Processed<UpdateMeta, UResult>, Failed<UpdateMeta, String>>;
|
||||||
|
|
||||||
|
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
|
pub struct IndexMeta{
|
||||||
|
uuid: Uuid,
|
||||||
|
created_at: DateTime<Utc>,
|
||||||
|
updated_at: DateTime<Utc>,
|
||||||
|
primary_key: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
enum IndexMsg {
|
enum IndexMsg {
|
||||||
CreateIndex {
|
CreateIndex {
|
||||||
uuid: Uuid,
|
uuid: Uuid,
|
||||||
primary_key: Option<String>,
|
primary_key: Option<String>,
|
||||||
ret: oneshot::Sender<Result<IndexMetadata>>,
|
ret: oneshot::Sender<Result<IndexMeta>>,
|
||||||
},
|
},
|
||||||
Update {
|
Update {
|
||||||
meta: Processing<UpdateMeta>,
|
meta: Processing<UpdateMeta>,
|
||||||
@ -65,6 +75,10 @@ enum IndexMsg {
|
|||||||
uuid: Uuid,
|
uuid: Uuid,
|
||||||
ret: oneshot::Sender<Result<()>>,
|
ret: oneshot::Sender<Result<()>>,
|
||||||
},
|
},
|
||||||
|
GetMeta {
|
||||||
|
uuid: Uuid,
|
||||||
|
ret: oneshot::Sender<Result<Option<IndexMeta>>>,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
struct IndexActor<S> {
|
struct IndexActor<S> {
|
||||||
@ -84,10 +98,11 @@ pub enum IndexError {
|
|||||||
|
|
||||||
#[async_trait::async_trait]
|
#[async_trait::async_trait]
|
||||||
trait IndexStore {
|
trait IndexStore {
|
||||||
async fn create_index(&self, uuid: Uuid, primary_key: Option<String>) -> Result<IndexMetadata>;
|
async fn create_index(&self, uuid: Uuid, primary_key: Option<String>) -> Result<IndexMeta>;
|
||||||
async fn get_or_create(&self, uuid: Uuid) -> Result<Index>;
|
async fn get_or_create(&self, uuid: Uuid) -> Result<Index>;
|
||||||
async fn get(&self, uuid: Uuid) -> Result<Option<Index>>;
|
async fn get(&self, uuid: Uuid) -> Result<Option<Index>>;
|
||||||
async fn delete(&self, uuid: &Uuid) -> Result<Option<Index>>;
|
async fn delete(&self, uuid: &Uuid) -> Result<Option<Index>>;
|
||||||
|
async fn get_meta(&self, uuid: &Uuid) -> Result<Option<IndexMeta>>;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S: IndexStore + Sync + Send> IndexActor<S> {
|
impl<S: IndexStore + Sync + Send> IndexActor<S> {
|
||||||
@ -150,10 +165,6 @@ impl<S: IndexStore + Sync + Send> IndexActor<S> {
|
|||||||
let fut1: Box<dyn Future<Output = ()> + Unpin + Send> = Box::new(fut1);
|
let fut1: Box<dyn Future<Output = ()> + Unpin + Send> = Box::new(fut1);
|
||||||
let fut2: Box<dyn Future<Output = ()> + Unpin + Send> = Box::new(fut2);
|
let fut2: Box<dyn Future<Output = ()> + Unpin + Send> = Box::new(fut2);
|
||||||
|
|
||||||
//let futures = futures::stream::futures_unordered::FuturesUnordered::new();
|
|
||||||
//futures.push(fut1);
|
|
||||||
//futures.push(fut2);
|
|
||||||
//futures.for_each(f)
|
|
||||||
tokio::join!(fut1, fut2);
|
tokio::join!(fut1, fut2);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -189,7 +200,10 @@ impl<S: IndexStore + Sync + Send> IndexActor<S> {
|
|||||||
}
|
}
|
||||||
Delete { uuid, ret } => {
|
Delete { uuid, ret } => {
|
||||||
let _ = ret.send(self.handle_delete(uuid).await);
|
let _ = ret.send(self.handle_delete(uuid).await);
|
||||||
},
|
}
|
||||||
|
GetMeta { uuid, ret } => {
|
||||||
|
let _ = ret.send(self.handle_get_meta(uuid).await);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -210,7 +224,7 @@ impl<S: IndexStore + Sync + Send> IndexActor<S> {
|
|||||||
&self,
|
&self,
|
||||||
uuid: Uuid,
|
uuid: Uuid,
|
||||||
primary_key: Option<String>,
|
primary_key: Option<String>,
|
||||||
ret: oneshot::Sender<Result<IndexMetadata>>,
|
ret: oneshot::Sender<Result<IndexMeta>>,
|
||||||
) {
|
) {
|
||||||
let result = self.store.create_index(uuid, primary_key).await;
|
let result = self.store.create_index(uuid, primary_key).await;
|
||||||
let _ = ret.send(result);
|
let _ = ret.send(result);
|
||||||
@ -293,6 +307,11 @@ impl<S: IndexStore + Sync + Send> IndexActor<S> {
|
|||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn handle_get_meta(&self, uuid: Uuid) -> Result<Option<IndexMeta>> {
|
||||||
|
let result = self.store.get_meta(&uuid).await?;
|
||||||
|
Ok(result)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
@ -319,7 +338,7 @@ impl IndexActorHandle {
|
|||||||
&self,
|
&self,
|
||||||
uuid: Uuid,
|
uuid: Uuid,
|
||||||
primary_key: Option<String>,
|
primary_key: Option<String>,
|
||||||
) -> Result<IndexMetadata> {
|
) -> Result<IndexMeta> {
|
||||||
let (ret, receiver) = oneshot::channel();
|
let (ret, receiver) = oneshot::channel();
|
||||||
let msg = IndexMsg::CreateIndex {
|
let msg = IndexMsg::CreateIndex {
|
||||||
ret,
|
ret,
|
||||||
@ -393,20 +412,27 @@ impl IndexActorHandle {
|
|||||||
let _ = self.read_sender.send(msg).await;
|
let _ = self.read_sender.send(msg).await;
|
||||||
Ok(receiver.await.expect("IndexActor has been killed")?)
|
Ok(receiver.await.expect("IndexActor has been killed")?)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn get_index_meta(&self, uuid: Uuid) -> Result<Option<IndexMeta>> {
|
||||||
|
let (ret, receiver) = oneshot::channel();
|
||||||
|
let msg = IndexMsg::GetMeta { uuid, ret };
|
||||||
|
let _ = self.read_sender.send(msg).await;
|
||||||
|
Ok(receiver.await.expect("IndexActor has been killed")?)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct MapIndexStore {
|
struct MapIndexStore {
|
||||||
root: PathBuf,
|
root: PathBuf,
|
||||||
meta_store: AsyncMap<Uuid, IndexMetadata>,
|
meta_store: AsyncMap<Uuid, IndexMeta>,
|
||||||
index_store: AsyncMap<Uuid, Index>,
|
index_store: AsyncMap<Uuid, Index>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait::async_trait]
|
#[async_trait::async_trait]
|
||||||
impl IndexStore for MapIndexStore {
|
impl IndexStore for MapIndexStore {
|
||||||
async fn create_index(&self, uuid: Uuid, primary_key: Option<String>) -> Result<IndexMetadata> {
|
async fn create_index(&self, uuid: Uuid, primary_key: Option<String>) -> Result<IndexMeta> {
|
||||||
let meta = match self.meta_store.write().await.entry(uuid.clone()) {
|
let meta = match self.meta_store.write().await.entry(uuid.clone()) {
|
||||||
Entry::Vacant(entry) => {
|
Entry::Vacant(entry) => {
|
||||||
let meta = IndexMetadata {
|
let meta = IndexMeta{
|
||||||
uuid,
|
uuid,
|
||||||
created_at: Utc::now(),
|
created_at: Utc::now(),
|
||||||
updated_at: Utc::now(),
|
updated_at: Utc::now(),
|
||||||
@ -464,6 +490,10 @@ impl IndexStore for MapIndexStore {
|
|||||||
}
|
}
|
||||||
Ok(index)
|
Ok(index)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn get_meta(&self, uuid: &Uuid) -> Result<Option<IndexMeta>> {
|
||||||
|
Ok(self.meta_store.read().await.get(uuid).cloned())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MapIndexStore {
|
impl MapIndexStore {
|
||||||
|
@ -11,7 +11,6 @@ use std::time::Duration;
|
|||||||
|
|
||||||
use actix_web::web::{Bytes, Payload};
|
use actix_web::web::{Bytes, Payload};
|
||||||
use anyhow::Context;
|
use anyhow::Context;
|
||||||
use chrono::{DateTime, Utc};
|
|
||||||
use futures::stream::StreamExt;
|
use futures::stream::StreamExt;
|
||||||
use milli::update::{IndexDocumentsMethod, UpdateFormat};
|
use milli::update::{IndexDocumentsMethod, UpdateFormat};
|
||||||
use serde::{Serialize, Deserialize};
|
use serde::{Serialize, Deserialize};
|
||||||
@ -28,10 +27,9 @@ pub type UpdateStatus = updates::UpdateStatus<UpdateMeta, UpdateResult, String>;
|
|||||||
#[derive(Debug, Serialize, Deserialize, Clone)]
|
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct IndexMetadata {
|
pub struct IndexMetadata {
|
||||||
uuid: Uuid,
|
name: String,
|
||||||
created_at: DateTime<Utc>,
|
#[serde(flatten)]
|
||||||
updated_at: DateTime<Utc>,
|
meta: index_actor::IndexMeta,
|
||||||
primary_key: Option<String>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
@ -144,9 +142,12 @@ impl IndexController {
|
|||||||
|
|
||||||
pub async fn create_index(&self, index_settings: IndexSettings) -> anyhow::Result<IndexMetadata> {
|
pub async fn create_index(&self, index_settings: IndexSettings) -> anyhow::Result<IndexMetadata> {
|
||||||
let IndexSettings { name, primary_key } = index_settings;
|
let IndexSettings { name, primary_key } = index_settings;
|
||||||
let uuid = self.uuid_resolver.create(name.unwrap()).await?;
|
let name = name.unwrap();
|
||||||
let index_meta = self.index_handle.create_index(uuid, primary_key).await?;
|
let uuid = self.uuid_resolver.create(name.clone()).await?;
|
||||||
Ok(index_meta)
|
let meta = self.index_handle.create_index(uuid, primary_key).await?;
|
||||||
|
let meta = IndexMetadata { name, meta };
|
||||||
|
|
||||||
|
Ok(meta)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn delete_index(&self, index_uid: String) -> anyhow::Result<()> {
|
pub async fn delete_index(&self, index_uid: String) -> anyhow::Result<()> {
|
||||||
@ -176,8 +177,19 @@ impl IndexController {
|
|||||||
Ok(result)
|
Ok(result)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn list_indexes(&self) -> anyhow::Result<Vec<IndexMetadata>> {
|
pub async fn list_indexes(&self) -> anyhow::Result<Vec<IndexMetadata>> {
|
||||||
todo!()
|
let uuids = self.uuid_resolver.list().await?;
|
||||||
|
|
||||||
|
let mut ret = Vec::new();
|
||||||
|
|
||||||
|
for (name, uuid) in uuids {
|
||||||
|
if let Some(meta) = self.index_handle.get_index_meta(uuid).await? {
|
||||||
|
let meta = IndexMetadata { name, meta };
|
||||||
|
ret.push(meta);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(ret)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn settings(&self, index: String) -> anyhow::Result<Settings> {
|
pub async fn settings(&self, index: String) -> anyhow::Result<Settings> {
|
||||||
|
@ -26,6 +26,9 @@ enum UuidResolveMsg {
|
|||||||
name: String,
|
name: String,
|
||||||
ret: oneshot::Sender<Result<Option<Uuid>>>,
|
ret: oneshot::Sender<Result<Option<Uuid>>>,
|
||||||
},
|
},
|
||||||
|
List {
|
||||||
|
ret: oneshot::Sender<Result<Vec<(String, Uuid)>>>,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
struct UuidResolverActor<S> {
|
struct UuidResolverActor<S> {
|
||||||
@ -50,6 +53,9 @@ impl<S: UuidStore> UuidResolverActor<S> {
|
|||||||
Some(GetOrCreate { name, ret }) => self.handle_get_or_create(name, ret).await,
|
Some(GetOrCreate { name, ret }) => self.handle_get_or_create(name, ret).await,
|
||||||
Some(Resolve { name, ret }) => self.handle_resolve(name, ret).await,
|
Some(Resolve { name, ret }) => self.handle_resolve(name, ret).await,
|
||||||
Some(Delete { name, ret }) => self.handle_delete(name, ret).await,
|
Some(Delete { name, ret }) => self.handle_delete(name, ret).await,
|
||||||
|
Some(List { ret }) => {
|
||||||
|
let _ = ret.send(self.handle_list().await);
|
||||||
|
}
|
||||||
// all senders have been dropped, need to quit.
|
// all senders have been dropped, need to quit.
|
||||||
None => break,
|
None => break,
|
||||||
}
|
}
|
||||||
@ -77,6 +83,11 @@ impl<S: UuidStore> UuidResolverActor<S> {
|
|||||||
let result = self.store.delete(&name).await;
|
let result = self.store.delete(&name).await;
|
||||||
let _ = ret.send(result);
|
let _ = ret.send(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn handle_list(&self) -> Result<Vec<(String, Uuid)>> {
|
||||||
|
let result = self.store.list().await?;
|
||||||
|
Ok(result)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
@ -120,6 +131,13 @@ impl UuidResolverHandle {
|
|||||||
let _ = self.sender.send(msg).await;
|
let _ = self.sender.send(msg).await;
|
||||||
Ok(receiver.await.expect("Uuid resolver actor has been killed")?)
|
Ok(receiver.await.expect("Uuid resolver actor has been killed")?)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn list(&self) -> anyhow::Result<Vec<(String, Uuid)>> {
|
||||||
|
let (ret, receiver) = oneshot::channel();
|
||||||
|
let msg = UuidResolveMsg::List { ret };
|
||||||
|
let _ = self.sender.send(msg).await;
|
||||||
|
Ok(receiver.await.expect("Uuid resolver actor has been killed")?)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Error)]
|
#[derive(Clone, Debug, Error)]
|
||||||
@ -135,6 +153,7 @@ trait UuidStore {
|
|||||||
async fn create_uuid(&self, name: String, err: bool) -> Result<Uuid>;
|
async fn create_uuid(&self, name: String, err: bool) -> Result<Uuid>;
|
||||||
async fn get_uuid(&self, name: &str) -> Result<Option<Uuid>>;
|
async fn get_uuid(&self, name: &str) -> Result<Option<Uuid>>;
|
||||||
async fn delete(&self, name: &str) -> Result<Option<Uuid>>;
|
async fn delete(&self, name: &str) -> Result<Option<Uuid>>;
|
||||||
|
async fn list(&self) -> Result<Vec<(String, Uuid)>>;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct MapUuidStore(Arc<RwLock<HashMap<String, Uuid>>>);
|
struct MapUuidStore(Arc<RwLock<HashMap<String, Uuid>>>);
|
||||||
@ -165,4 +184,9 @@ impl UuidStore for MapUuidStore {
|
|||||||
async fn delete(&self, name: &str) -> Result<Option<Uuid>> {
|
async fn delete(&self, name: &str) -> Result<Option<Uuid>> {
|
||||||
Ok(self.0.write().await.remove(name))
|
Ok(self.0.write().await.remove(name))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn list(&self) -> Result<Vec<(String, Uuid)>> {
|
||||||
|
let list = self.0.read().await.iter().map(|(name, uuid)| (name.to_owned(), uuid.clone())).collect();
|
||||||
|
Ok(list)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -21,7 +21,7 @@ pub fn services(cfg: &mut web::ServiceConfig) {
|
|||||||
|
|
||||||
#[get("/indexes", wrap = "Authentication::Private")]
|
#[get("/indexes", wrap = "Authentication::Private")]
|
||||||
async fn list_indexes(data: web::Data<Data>) -> Result<HttpResponse, ResponseError> {
|
async fn list_indexes(data: web::Data<Data>) -> Result<HttpResponse, ResponseError> {
|
||||||
match data.list_indexes() {
|
match data.list_indexes().await {
|
||||||
Ok(indexes) => {
|
Ok(indexes) => {
|
||||||
let json = serde_json::to_string(&indexes).unwrap();
|
let json = serde_json::to_string(&indexes).unwrap();
|
||||||
Ok(HttpResponse::Ok().body(&json))
|
Ok(HttpResponse::Ok().body(&json))
|
||||||
|
Loading…
x
Reference in New Issue
Block a user