mirror of
https://github.com/meilisearch/meilisearch.git
synced 2024-12-02 01:55:03 +08:00
fix test bug with tempdir
This commit is contained in:
parent
2ae90f9c5d
commit
1fad72e019
@ -1,4 +1,4 @@
|
|||||||
use std::collections::{hash_map::Entry, HashMap};
|
use std::collections::HashMap;
|
||||||
use std::fs::{create_dir_all, remove_dir_all, File};
|
use std::fs::{create_dir_all, remove_dir_all, File};
|
||||||
use std::future::Future;
|
use std::future::Future;
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
@ -8,11 +8,15 @@ use async_stream::stream;
|
|||||||
use chrono::{DateTime, Utc};
|
use chrono::{DateTime, Utc};
|
||||||
use futures::pin_mut;
|
use futures::pin_mut;
|
||||||
use futures::stream::StreamExt;
|
use futures::stream::StreamExt;
|
||||||
use heed::EnvOpenOptions;
|
use heed::{
|
||||||
use log::info;
|
types::{ByteSlice, SerdeBincode},
|
||||||
|
Database, Env, EnvOpenOptions,
|
||||||
|
};
|
||||||
|
use log::debug;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
use tokio::sync::{mpsc, oneshot, RwLock};
|
use tokio::{sync::{mpsc, oneshot, RwLock}};
|
||||||
|
use tokio::task::spawn_blocking;
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
|
|
||||||
use super::get_arc_ownership_blocking;
|
use super::get_arc_ownership_blocking;
|
||||||
@ -96,6 +100,8 @@ pub enum IndexError {
|
|||||||
IndexAlreadyExists,
|
IndexAlreadyExists,
|
||||||
#[error("Index doesn't exists")]
|
#[error("Index doesn't exists")]
|
||||||
UnexistingIndex,
|
UnexistingIndex,
|
||||||
|
#[error("Heed error: {0}")]
|
||||||
|
HeedError(#[from] heed::Error),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait::async_trait]
|
#[async_trait::async_trait]
|
||||||
@ -105,10 +111,9 @@ trait IndexStore {
|
|||||||
where
|
where
|
||||||
F: FnOnce(Index) -> Result<R> + Send + Sync + 'static,
|
F: FnOnce(Index) -> Result<R> + Send + Sync + 'static,
|
||||||
R: Sync + Send + 'static;
|
R: Sync + Send + 'static;
|
||||||
async fn get_or_create(&self, uuid: Uuid, primary_key: Option<String>) -> 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>>;
|
async fn get_meta(&self, uuid: Uuid) -> Result<Option<IndexMeta>>;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S: IndexStore + Sync + Send> IndexActor<S> {
|
impl<S: IndexStore + Sync + Send> IndexActor<S> {
|
||||||
@ -118,8 +123,8 @@ impl<S: IndexStore + Sync + Send> IndexActor<S> {
|
|||||||
store: S,
|
store: S,
|
||||||
) -> Result<Self> {
|
) -> Result<Self> {
|
||||||
let options = IndexerOpts::default();
|
let options = IndexerOpts::default();
|
||||||
let update_handler = UpdateHandler::new(&options)
|
let update_handler =
|
||||||
.map_err(|e| IndexError::Error(e.into()))?;
|
UpdateHandler::new(&options).map_err(|e| IndexError::Error(e.into()))?;
|
||||||
let update_handler = Arc::new(update_handler);
|
let update_handler = Arc::new(update_handler);
|
||||||
let read_receiver = Some(read_receiver);
|
let read_receiver = Some(read_receiver);
|
||||||
let write_receiver = Some(write_receiver);
|
let write_receiver = Some(write_receiver);
|
||||||
@ -227,11 +232,12 @@ impl<S: IndexStore + Sync + Send> IndexActor<S> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async fn handle_search(&self, uuid: Uuid, query: SearchQuery) -> anyhow::Result<SearchResult> {
|
async fn handle_search(&self, uuid: Uuid, query: SearchQuery) -> anyhow::Result<SearchResult> {
|
||||||
let index = self.store
|
let index = self
|
||||||
|
.store
|
||||||
.get(uuid)
|
.get(uuid)
|
||||||
.await?
|
.await?
|
||||||
.ok_or(IndexError::UnexistingIndex)?;
|
.ok_or(IndexError::UnexistingIndex)?;
|
||||||
tokio::task::spawn_blocking(move || index.perform_search(query)).await?
|
spawn_blocking(move || index.perform_search(query)).await?
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn handle_create_index(
|
async fn handle_create_index(
|
||||||
@ -247,15 +253,14 @@ impl<S: IndexStore + Sync + Send> IndexActor<S> {
|
|||||||
meta: Processing<UpdateMeta>,
|
meta: Processing<UpdateMeta>,
|
||||||
data: File,
|
data: File,
|
||||||
) -> Result<UpdateResult> {
|
) -> Result<UpdateResult> {
|
||||||
info!("Processing update {}", meta.id());
|
debug!("Processing update {}", meta.id());
|
||||||
let uuid = meta.index_uuid().clone();
|
let uuid = meta.index_uuid().clone();
|
||||||
let update_handler = self.update_handler.clone();
|
let update_handler = self.update_handler.clone();
|
||||||
let handle = self
|
let handle = self
|
||||||
.store
|
.store
|
||||||
.update_index(uuid, |index| {
|
.update_index(uuid, |index| {
|
||||||
let handle = tokio::task::spawn_blocking(move || {
|
let handle =
|
||||||
update_handler.handle_update(meta, data, index)
|
spawn_blocking(move || update_handler.handle_update(meta, data, index));
|
||||||
});
|
|
||||||
Ok(handle)
|
Ok(handle)
|
||||||
})
|
})
|
||||||
.await?;
|
.await?;
|
||||||
@ -264,11 +269,12 @@ impl<S: IndexStore + Sync + Send> IndexActor<S> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async fn handle_settings(&self, uuid: Uuid) -> Result<Settings> {
|
async fn handle_settings(&self, uuid: Uuid) -> Result<Settings> {
|
||||||
let index = self.store
|
let index = self
|
||||||
|
.store
|
||||||
.get(uuid)
|
.get(uuid)
|
||||||
.await?
|
.await?
|
||||||
.ok_or(IndexError::UnexistingIndex)?;
|
.ok_or(IndexError::UnexistingIndex)?;
|
||||||
tokio::task::spawn_blocking(move || index.settings().map_err(|e| IndexError::Error(e)))
|
spawn_blocking(move || index.settings().map_err(|e| IndexError::Error(e)))
|
||||||
.await
|
.await
|
||||||
.map_err(|e| IndexError::Error(e.into()))?
|
.map_err(|e| IndexError::Error(e.into()))?
|
||||||
}
|
}
|
||||||
@ -280,10 +286,12 @@ impl<S: IndexStore + Sync + Send> IndexActor<S> {
|
|||||||
limit: usize,
|
limit: usize,
|
||||||
attributes_to_retrieve: Option<Vec<String>>,
|
attributes_to_retrieve: Option<Vec<String>>,
|
||||||
) -> Result<Vec<Document>> {
|
) -> Result<Vec<Document>> {
|
||||||
let index = self.store.get(uuid)
|
let index = self
|
||||||
|
.store
|
||||||
|
.get(uuid)
|
||||||
.await?
|
.await?
|
||||||
.ok_or(IndexError::UnexistingIndex)?;
|
.ok_or(IndexError::UnexistingIndex)?;
|
||||||
tokio::task::spawn_blocking(move || {
|
spawn_blocking(move || {
|
||||||
index
|
index
|
||||||
.retrieve_documents(offset, limit, attributes_to_retrieve)
|
.retrieve_documents(offset, limit, attributes_to_retrieve)
|
||||||
.map_err(|e| IndexError::Error(e))
|
.map_err(|e| IndexError::Error(e))
|
||||||
@ -303,7 +311,7 @@ impl<S: IndexStore + Sync + Send> IndexActor<S> {
|
|||||||
.get(uuid)
|
.get(uuid)
|
||||||
.await?
|
.await?
|
||||||
.ok_or(IndexError::UnexistingIndex)?;
|
.ok_or(IndexError::UnexistingIndex)?;
|
||||||
tokio::task::spawn_blocking(move || {
|
spawn_blocking(move || {
|
||||||
index
|
index
|
||||||
.retrieve_document(doc_id, attributes_to_retrieve)
|
.retrieve_document(doc_id, attributes_to_retrieve)
|
||||||
.map_err(|e| IndexError::Error(e))
|
.map_err(|e| IndexError::Error(e))
|
||||||
@ -313,15 +321,15 @@ impl<S: IndexStore + Sync + Send> IndexActor<S> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async fn handle_delete(&self, uuid: Uuid) -> Result<()> {
|
async fn handle_delete(&self, uuid: Uuid) -> Result<()> {
|
||||||
let index = self.store.delete(&uuid).await?;
|
let index = self.store.delete(uuid).await?;
|
||||||
|
|
||||||
if let Some(index) = index {
|
if let Some(index) = index {
|
||||||
tokio::task::spawn(async move {
|
tokio::task::spawn(async move {
|
||||||
let index = index.0;
|
let index = index.0;
|
||||||
let store = get_arc_ownership_blocking(index).await;
|
let store = get_arc_ownership_blocking(index).await;
|
||||||
tokio::task::spawn_blocking(move || {
|
spawn_blocking(move || {
|
||||||
store.prepare_for_closing().wait();
|
store.prepare_for_closing().wait();
|
||||||
info!("Index {} was closed.", uuid);
|
debug!("Index closed");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -330,7 +338,7 @@ impl<S: IndexStore + Sync + Send> IndexActor<S> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async fn handle_get_meta(&self, uuid: Uuid) -> Result<Option<IndexMeta>> {
|
async fn handle_get_meta(&self, uuid: Uuid) -> Result<Option<IndexMeta>> {
|
||||||
let result = self.store.get_meta(&uuid).await?;
|
let result = self.store.get_meta(uuid).await?;
|
||||||
Ok(result)
|
Ok(result)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -346,7 +354,7 @@ impl IndexActorHandle {
|
|||||||
let (read_sender, read_receiver) = mpsc::channel(100);
|
let (read_sender, read_receiver) = mpsc::channel(100);
|
||||||
let (write_sender, write_receiver) = mpsc::channel(100);
|
let (write_sender, write_receiver) = mpsc::channel(100);
|
||||||
|
|
||||||
let store = MapIndexStore::new(path);
|
let store = HeedIndexStore::new(path)?;
|
||||||
let actor = IndexActor::new(read_receiver, write_receiver, store)?;
|
let actor = IndexActor::new(read_receiver, write_receiver, store)?;
|
||||||
tokio::task::spawn(actor.run());
|
tokio::task::spawn(actor.run());
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
@ -442,149 +450,165 @@ impl IndexActorHandle {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct MapIndexStore {
|
struct HeedIndexStore {
|
||||||
root: PathBuf,
|
env: Env,
|
||||||
meta_store: AsyncMap<Uuid, IndexMeta>,
|
db: Database<ByteSlice, SerdeBincode<IndexMeta>>,
|
||||||
index_store: AsyncMap<Uuid, Index>,
|
index_store: AsyncMap<Uuid, Index>,
|
||||||
|
path: PathBuf,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl HeedIndexStore {
|
||||||
|
fn new(path: impl AsRef<Path>) -> anyhow::Result<Self> {
|
||||||
|
let mut options = EnvOpenOptions::new();
|
||||||
|
options.map_size(1_073_741_824); //1GB
|
||||||
|
let path = path.as_ref().join("indexes/");
|
||||||
|
create_dir_all(&path)?;
|
||||||
|
let env = options.open(&path)?;
|
||||||
|
let db = env.create_database(None)?;
|
||||||
|
let index_store = Arc::new(RwLock::new(HashMap::new()));
|
||||||
|
Ok(Self {
|
||||||
|
env,
|
||||||
|
db,
|
||||||
|
index_store,
|
||||||
|
path,
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait::async_trait]
|
#[async_trait::async_trait]
|
||||||
impl IndexStore for MapIndexStore {
|
impl IndexStore for HeedIndexStore {
|
||||||
async fn create_index(&self, uuid: Uuid, primary_key: Option<String>) -> Result<IndexMeta> {
|
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 path = self.path.join(format!("index-{}", uuid));
|
||||||
Entry::Vacant(entry) => {
|
|
||||||
|
if path.exists() {
|
||||||
|
return Err(IndexError::IndexAlreadyExists);
|
||||||
|
}
|
||||||
|
|
||||||
|
let env = self.env.clone();
|
||||||
|
let db = self.db.clone();
|
||||||
|
let (index, meta) = spawn_blocking(move || -> Result<(Index, IndexMeta)> {
|
||||||
let now = Utc::now();
|
let now = Utc::now();
|
||||||
let meta = IndexMeta {
|
let meta = IndexMeta {
|
||||||
uuid,
|
uuid: uuid.clone(),
|
||||||
created_at: now.clone(),
|
created_at: now.clone(),
|
||||||
updated_at: now,
|
updated_at: now,
|
||||||
primary_key,
|
primary_key,
|
||||||
};
|
};
|
||||||
entry.insert(meta).clone()
|
let mut txn = env.write_txn()?;
|
||||||
}
|
db.put(&mut txn, uuid.as_bytes(), &meta)?;
|
||||||
Entry::Occupied(_) => return Err(IndexError::IndexAlreadyExists),
|
txn.commit()?;
|
||||||
};
|
|
||||||
|
|
||||||
let db_path = self.root.join(format!("index-{}", meta.uuid));
|
let index = open_index(&path, 4096 * 100_000)?;
|
||||||
|
|
||||||
let index: Result<Index> = tokio::task::spawn_blocking(move || {
|
Ok((index, meta))
|
||||||
create_dir_all(&db_path).expect("can't create db");
|
|
||||||
let mut options = EnvOpenOptions::new();
|
|
||||||
options.map_size(4096 * 100_000);
|
|
||||||
let index = milli::Index::new(options, &db_path).map_err(|e| IndexError::Error(e))?;
|
|
||||||
let index = Index(Arc::new(index));
|
|
||||||
Ok(index)
|
|
||||||
})
|
})
|
||||||
.await
|
.await
|
||||||
.expect("thread died");
|
.expect("thread died")?;
|
||||||
|
|
||||||
self.index_store
|
self.index_store.write().await.insert(uuid.clone(), index);
|
||||||
.write()
|
|
||||||
.await
|
|
||||||
.insert(meta.uuid.clone(), index?);
|
|
||||||
|
|
||||||
Ok(meta)
|
Ok(meta)
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn get_or_create(&self, uuid: Uuid, primary_key: Option<String>) -> Result<Index> {
|
|
||||||
match self.index_store.write().await.entry(uuid.clone()) {
|
|
||||||
Entry::Vacant(index_entry) => match self.meta_store.write().await.entry(uuid.clone()) {
|
|
||||||
Entry::Vacant(meta_entry) => {
|
|
||||||
let now = Utc::now();
|
|
||||||
let meta = IndexMeta {
|
|
||||||
uuid,
|
|
||||||
created_at: now.clone(),
|
|
||||||
updated_at: now,
|
|
||||||
primary_key,
|
|
||||||
};
|
|
||||||
let meta = meta_entry.insert(meta);
|
|
||||||
let db_path = self.root.join(format!("index-{}", meta.uuid));
|
|
||||||
|
|
||||||
let index: Result<Index> = tokio::task::spawn_blocking(move || {
|
|
||||||
create_dir_all(&db_path).expect("can't create db");
|
|
||||||
let mut options = EnvOpenOptions::new();
|
|
||||||
options.map_size(4096 * 100_000);
|
|
||||||
let index = milli::Index::new(options, &db_path)
|
|
||||||
.map_err(|e| IndexError::Error(e))?;
|
|
||||||
let index = Index(Arc::new(index));
|
|
||||||
Ok(index)
|
|
||||||
})
|
|
||||||
.await
|
|
||||||
.expect("thread died");
|
|
||||||
|
|
||||||
Ok(index_entry.insert(index?).clone())
|
|
||||||
}
|
|
||||||
Entry::Occupied(entry) => {
|
|
||||||
let meta = entry.get();
|
|
||||||
let db_path = self.root.join(format!("index-{}", meta.uuid));
|
|
||||||
|
|
||||||
let index: Result<Index> = tokio::task::spawn_blocking(move || {
|
|
||||||
create_dir_all(&db_path).expect("can't create db");
|
|
||||||
let mut options = EnvOpenOptions::new();
|
|
||||||
options.map_size(4096 * 100_000);
|
|
||||||
let index = milli::Index::new(options, &db_path)
|
|
||||||
.map_err(|e| IndexError::Error(e))?;
|
|
||||||
let index = Index(Arc::new(index));
|
|
||||||
Ok(index)
|
|
||||||
})
|
|
||||||
.await
|
|
||||||
.expect("thread died");
|
|
||||||
|
|
||||||
Ok(index_entry.insert(index?).clone())
|
|
||||||
}
|
|
||||||
},
|
|
||||||
Entry::Occupied(entry) => Ok(entry.get().clone()),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn get(&self, uuid: Uuid) -> Result<Option<Index>> {
|
|
||||||
Ok(self.index_store.read().await.get(&uuid).cloned())
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn delete(&self, uuid: &Uuid) -> Result<Option<Index>> {
|
|
||||||
let index = self.index_store.write().await.remove(&uuid);
|
|
||||||
if index.is_some() {
|
|
||||||
let db_path = self.root.join(format!("index-{}", uuid));
|
|
||||||
remove_dir_all(db_path).unwrap();
|
|
||||||
}
|
|
||||||
Ok(index)
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn get_meta(&self, uuid: &Uuid) -> Result<Option<IndexMeta>> {
|
|
||||||
Ok(self.meta_store.read().await.get(uuid).cloned())
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn update_index<R, F>(&self, uuid: Uuid, f: F) -> Result<R>
|
async fn update_index<R, F>(&self, uuid: Uuid, f: F) -> Result<R>
|
||||||
where
|
where
|
||||||
F: FnOnce(Index) -> Result<R> + Send + Sync + 'static,
|
F: FnOnce(Index) -> Result<R> + Send + Sync + 'static,
|
||||||
R: Sync + Send + 'static,
|
R: Sync + Send + 'static,
|
||||||
{
|
{
|
||||||
let index = self.get_or_create(uuid.clone(), None).await?;
|
let guard = self.index_store.read().await;
|
||||||
let mut meta = self
|
let index = match guard.get(&uuid) {
|
||||||
.get_meta(&uuid)
|
Some(index) => index.clone(),
|
||||||
.await?
|
None => {
|
||||||
.ok_or(IndexError::UnexistingIndex)?;
|
drop(guard);
|
||||||
|
self.create_index(uuid.clone(), None).await?;
|
||||||
|
self.index_store
|
||||||
|
.read()
|
||||||
|
.await
|
||||||
|
.get(&uuid)
|
||||||
|
.expect("Index should exist")
|
||||||
|
.clone()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let env = self.env.clone();
|
||||||
|
let db = self.db.clone();
|
||||||
|
spawn_blocking(move || {
|
||||||
|
let mut txn = env.write_txn()?;
|
||||||
|
let mut meta = db.get(&txn, uuid.as_bytes())?.expect("unexisting index");
|
||||||
match f(index) {
|
match f(index) {
|
||||||
Ok(r) => {
|
Ok(r) => {
|
||||||
meta.updated_at = Utc::now();
|
meta.updated_at = Utc::now();
|
||||||
self.meta_store.write().await.insert(uuid, meta);
|
db.put(&mut txn, uuid.as_bytes(), &meta)?;
|
||||||
|
txn.commit()?;
|
||||||
Ok(r)
|
Ok(r)
|
||||||
}
|
}
|
||||||
Err(e) => Err(e),
|
Err(e) => Err(e),
|
||||||
}
|
}
|
||||||
|
})
|
||||||
|
.await
|
||||||
|
.expect("thread died")
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn get(&self, uuid: Uuid) -> Result<Option<Index>> {
|
||||||
|
let guard = self.index_store.read().await;
|
||||||
|
match guard.get(&uuid) {
|
||||||
|
Some(index) => Ok(Some(index.clone())),
|
||||||
|
None => {
|
||||||
|
// drop the guard here so we can perform the write after without deadlocking;
|
||||||
|
drop(guard);
|
||||||
|
let path = self.path.join(format!("index-{}", uuid));
|
||||||
|
if !path.exists() {
|
||||||
|
return Ok(None);
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: set this info from the database
|
||||||
|
let index = spawn_blocking(|| open_index(path, 4096 * 100_000))
|
||||||
|
.await
|
||||||
|
.expect("thread died")?;
|
||||||
|
self.index_store
|
||||||
|
.write()
|
||||||
|
.await
|
||||||
|
.insert(uuid.clone(), index.clone());
|
||||||
|
println!("here");
|
||||||
|
Ok(Some(index))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn delete(&self, uuid: Uuid) -> Result<Option<Index>> {
|
||||||
|
let env = self.env.clone();
|
||||||
|
let db = self.db.clone();
|
||||||
|
let db_path = self.path.join(format!("index-{}", uuid));
|
||||||
|
spawn_blocking(move || -> Result<()> {
|
||||||
|
let mut txn = env.write_txn()?;
|
||||||
|
db.delete(&mut txn, uuid.as_bytes())?;
|
||||||
|
txn.commit()?;
|
||||||
|
remove_dir_all(db_path).unwrap();
|
||||||
|
Ok(())
|
||||||
|
})
|
||||||
|
.await
|
||||||
|
.expect("thread died")?;
|
||||||
|
let index = self.index_store.write().await.remove(&uuid);
|
||||||
|
Ok(index)
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn get_meta(&self, uuid: Uuid) -> Result<Option<IndexMeta>> {
|
||||||
|
let env = self.env.clone();
|
||||||
|
let db = self.db.clone();
|
||||||
|
spawn_blocking(move || {
|
||||||
|
let txn = env.read_txn()?;
|
||||||
|
let meta = db.get(&txn, uuid.as_bytes())?;
|
||||||
|
Ok(meta)
|
||||||
|
})
|
||||||
|
.await
|
||||||
|
.expect("thread died")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MapIndexStore {
|
fn open_index(path: impl AsRef<Path>, size: usize) -> Result<Index> {
|
||||||
fn new(root: impl AsRef<Path>) -> Self {
|
create_dir_all(&path).expect("can't create db");
|
||||||
let mut root = root.as_ref().to_owned();
|
let mut options = EnvOpenOptions::new();
|
||||||
root.push("indexes/");
|
options.map_size(size);
|
||||||
let meta_store = Arc::new(RwLock::new(HashMap::new()));
|
let index = milli::Index::new(options, &path).map_err(|e| IndexError::Error(e))?;
|
||||||
let index_store = Arc::new(RwLock::new(HashMap::new()));
|
Ok(Index(Arc::new(index)))
|
||||||
Self {
|
|
||||||
meta_store,
|
|
||||||
index_store,
|
|
||||||
root,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -12,8 +12,7 @@ use heed::{
|
|||||||
};
|
};
|
||||||
use log::{error, info};
|
use log::{error, info};
|
||||||
use milli::Index;
|
use milli::Index;
|
||||||
use rayon::ThreadPool;
|
use rayon::ThreadPool; use serde::{Deserialize, Serialize};
|
||||||
use serde::{Deserialize, Serialize};
|
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
|
|
||||||
use super::update_handler::UpdateHandler;
|
use super::update_handler::UpdateHandler;
|
||||||
|
@ -71,7 +71,7 @@ impl IndexController {
|
|||||||
pub fn new(path: impl AsRef<Path>) -> anyhow::Result<Self> {
|
pub fn new(path: impl AsRef<Path>) -> anyhow::Result<Self> {
|
||||||
let uuid_resolver = uuid_resolver::UuidResolverHandle::new(&path)?;
|
let uuid_resolver = uuid_resolver::UuidResolverHandle::new(&path)?;
|
||||||
let index_actor = index_actor::IndexActorHandle::new(&path)?;
|
let index_actor = index_actor::IndexActorHandle::new(&path)?;
|
||||||
let update_handle = update_actor::UpdateActorHandle::new(index_actor.clone(), &path);
|
let update_handle = update_actor::UpdateActorHandle::new(index_actor.clone(), &path)?;
|
||||||
Ok(Self { uuid_resolver, index_handle: index_actor, update_handle })
|
Ok(Self { uuid_resolver, index_handle: index_actor, update_handle })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -68,10 +68,11 @@ where
|
|||||||
D: AsRef<[u8]> + Sized + 'static,
|
D: AsRef<[u8]> + Sized + 'static,
|
||||||
S: UpdateStoreStore,
|
S: UpdateStoreStore,
|
||||||
{
|
{
|
||||||
fn new(store: S, inbox: mpsc::Receiver<UpdateMsg<D>>, path: impl AsRef<Path>) -> Self {
|
fn new(store: S, inbox: mpsc::Receiver<UpdateMsg<D>>, path: impl AsRef<Path>) -> anyhow::Result<Self> {
|
||||||
let path = path.as_ref().to_owned().join("update_files");
|
let path = path.as_ref().to_owned().join("update_files");
|
||||||
create_dir_all(&path).unwrap();
|
create_dir_all(&path)?;
|
||||||
Self { store, inbox, path }
|
assert!(path.exists());
|
||||||
|
Ok(Self { store, inbox, path })
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn run(mut self) {
|
async fn run(mut self) {
|
||||||
@ -211,15 +212,15 @@ impl<D> UpdateActorHandle<D>
|
|||||||
where
|
where
|
||||||
D: AsRef<[u8]> + Sized + 'static + Sync + Send,
|
D: AsRef<[u8]> + Sized + 'static + Sync + Send,
|
||||||
{
|
{
|
||||||
pub fn new(index_handle: IndexActorHandle, path: impl AsRef<Path>) -> Self {
|
pub fn new(index_handle: IndexActorHandle, path: impl AsRef<Path>) -> anyhow::Result<Self> {
|
||||||
let path = path.as_ref().to_owned().join("updates");
|
let path = path.as_ref().to_owned().join("updates");
|
||||||
let (sender, receiver) = mpsc::channel(100);
|
let (sender, receiver) = mpsc::channel(100);
|
||||||
let store = MapUpdateStoreStore::new(index_handle, &path);
|
let store = MapUpdateStoreStore::new(index_handle, &path);
|
||||||
let actor = UpdateActor::new(store, receiver, path);
|
let actor = UpdateActor::new(store, receiver, path)?;
|
||||||
|
|
||||||
tokio::task::spawn(actor.run());
|
tokio::task::spawn(actor.run());
|
||||||
|
|
||||||
Self { sender }
|
Ok(Self { sender })
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn update(
|
pub async fn update(
|
||||||
|
@ -277,8 +277,7 @@ impl UuidStore for HeedUuidStore {
|
|||||||
entries.push((name.to_owned(), uuid))
|
entries.push((name.to_owned(), uuid))
|
||||||
}
|
}
|
||||||
Ok(entries)
|
Ok(entries)
|
||||||
}).await?
|
}).await? }
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
@ -12,15 +12,17 @@ use super::service::Service;
|
|||||||
|
|
||||||
pub struct Server {
|
pub struct Server {
|
||||||
pub service: Service,
|
pub service: Service,
|
||||||
|
// hod ownership to the tempdir while we use the server instance.
|
||||||
|
_dir: tempdir::TempDir,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Server {
|
impl Server {
|
||||||
pub async fn new() -> Self {
|
pub async fn new() -> Self {
|
||||||
let tmp_dir = TempDir::new("meilisearch").unwrap();
|
let dir = TempDir::new("meilisearch").unwrap();
|
||||||
|
|
||||||
let opt = Opt {
|
let opt = Opt {
|
||||||
db_path: tmp_dir.path().join("db"),
|
db_path: dir.path().join("db"),
|
||||||
dumps_dir: tmp_dir.path().join("dump"),
|
dumps_dir: dir.path().join("dump"),
|
||||||
dump_batch_size: 16,
|
dump_batch_size: 16,
|
||||||
http_addr: "127.0.0.1:7700".to_owned(),
|
http_addr: "127.0.0.1:7700".to_owned(),
|
||||||
master_key: None,
|
master_key: None,
|
||||||
@ -55,6 +57,7 @@ impl Server {
|
|||||||
|
|
||||||
Server {
|
Server {
|
||||||
service,
|
service,
|
||||||
|
_dir: dir,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -35,7 +35,8 @@ async fn update_settings_unknown_field() {
|
|||||||
async fn test_partial_update() {
|
async fn test_partial_update() {
|
||||||
let server = Server::new().await;
|
let server = Server::new().await;
|
||||||
let index = server.index("test");
|
let index = server.index("test");
|
||||||
index.update_settings(json!({"displayedAttributes": ["foo"]})).await;
|
let (response, _code) = index.update_settings(json!({"displayedAttributes": ["foo"]})).await;
|
||||||
|
println!("response: {}", response);
|
||||||
index.wait_update_id(0).await;
|
index.wait_update_id(0).await;
|
||||||
let (response, code) = index.settings().await;
|
let (response, code) = index.settings().await;
|
||||||
assert_eq!(code, 200);
|
assert_eq!(code, 200);
|
||||||
|
Loading…
Reference in New Issue
Block a user