3077: Don't remove DB if unreadable r=irevoire a=dureuill

# Pull Request

## Related issue
Related to #3069

Will fix it after merging into `main`

## What does this PR do?

### User standpoint

- When the DB cannot be read after opening it, Meilisearch exits with an error message like previously, but it now leaves the DB untouched
- When the DB cannot be read after importing it from a snapshot or dump, it is still removed, like previously.

### Dev standpoint

- Add new local enum `OnFailure` that is used as a parameter to the `meilisearch_builder` closure to control when to keep or remove the DB in case of failure.

## PR checklist
Please check if your PR fulfills the following requirements:
- [x] Does this PR fix an existing issue, or have you listed the changes applied in the PR description (and why they are needed)?
- [x] Have you read the contributing guidelines?
- [x] Have you made sure that the title is accurate and descriptive of the changes?

Thank you so much for contributing to Meilisearch!


Co-authored-by: Louis Dureuil <louis@meilisearch.com>
This commit is contained in:
bors[bot] 2022-11-17 09:38:27 +00:00 committed by GitHub
commit 877d1735b1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -128,7 +128,13 @@ pub fn setup_meilisearch(opt: &Opt) -> anyhow::Result<(Arc<IndexScheduler>, Auth
autobatching_enabled: !opt.scheduler_options.disable_auto_batching, autobatching_enabled: !opt.scheduler_options.disable_auto_batching,
}) })
}; };
let meilisearch_builder = || -> anyhow::Result<_> {
enum OnFailure {
RemoveDb,
KeepDb,
}
let meilisearch_builder = |on_failure: OnFailure| -> anyhow::Result<_> {
// if anything wrong happens we delete the `data.ms` entirely. // if anything wrong happens we delete the `data.ms` entirely.
match ( match (
index_scheduler_builder().map_err(anyhow::Error::from), index_scheduler_builder().map_err(anyhow::Error::from),
@ -137,7 +143,9 @@ pub fn setup_meilisearch(opt: &Opt) -> anyhow::Result<(Arc<IndexScheduler>, Auth
) { ) {
(Ok(i), Ok(a), Ok(())) => Ok((i, a)), (Ok(i), Ok(a), Ok(())) => Ok((i, a)),
(Err(e), _, _) | (_, Err(e), _) | (_, _, Err(e)) => { (Err(e), _, _) | (_, Err(e), _) | (_, _, Err(e)) => {
std::fs::remove_dir_all(&opt.db_path)?; if matches!(on_failure, OnFailure::RemoveDb) {
std::fs::remove_dir_all(&opt.db_path)?;
}
Err(e) Err(e)
} }
} }
@ -148,7 +156,7 @@ pub fn setup_meilisearch(opt: &Opt) -> anyhow::Result<(Arc<IndexScheduler>, Auth
let snapshot_path_exists = snapshot_path.exists(); let snapshot_path_exists = snapshot_path.exists();
if empty_db && snapshot_path_exists { if empty_db && snapshot_path_exists {
match compression::from_tar_gz(snapshot_path, &opt.db_path) { match compression::from_tar_gz(snapshot_path, &opt.db_path) {
Ok(()) => meilisearch_builder()?, Ok(()) => meilisearch_builder(OnFailure::RemoveDb)?,
Err(e) => { Err(e) => {
std::fs::remove_dir_all(&opt.db_path)?; std::fs::remove_dir_all(&opt.db_path)?;
return Err(e); return Err(e);
@ -162,12 +170,13 @@ pub fn setup_meilisearch(opt: &Opt) -> anyhow::Result<(Arc<IndexScheduler>, Auth
} else if !snapshot_path_exists && !opt.ignore_missing_snapshot { } else if !snapshot_path_exists && !opt.ignore_missing_snapshot {
bail!("snapshot doesn't exist at {}", snapshot_path.display()) bail!("snapshot doesn't exist at {}", snapshot_path.display())
} else { } else {
meilisearch_builder()? meilisearch_builder(OnFailure::RemoveDb)?
} }
} else if let Some(ref path) = opt.import_dump { } else if let Some(ref path) = opt.import_dump {
let src_path_exists = path.exists(); let src_path_exists = path.exists();
if empty_db && src_path_exists { if empty_db && src_path_exists {
let (mut index_scheduler, mut auth_controller) = meilisearch_builder()?; let (mut index_scheduler, mut auth_controller) =
meilisearch_builder(OnFailure::RemoveDb)?;
match import_dump(&opt.db_path, path, &mut index_scheduler, &mut auth_controller) { match import_dump(&opt.db_path, path, &mut index_scheduler, &mut auth_controller) {
Ok(()) => (index_scheduler, auth_controller), Ok(()) => (index_scheduler, auth_controller),
Err(e) => { Err(e) => {
@ -183,7 +192,8 @@ pub fn setup_meilisearch(opt: &Opt) -> anyhow::Result<(Arc<IndexScheduler>, Auth
} else if !src_path_exists && !opt.ignore_missing_dump { } else if !src_path_exists && !opt.ignore_missing_dump {
bail!("dump doesn't exist at {:?}", path) bail!("dump doesn't exist at {:?}", path)
} else { } else {
let (mut index_scheduler, mut auth_controller) = meilisearch_builder()?; let (mut index_scheduler, mut auth_controller) =
meilisearch_builder(OnFailure::RemoveDb)?;
match import_dump(&opt.db_path, path, &mut index_scheduler, &mut auth_controller) { match import_dump(&opt.db_path, path, &mut index_scheduler, &mut auth_controller) {
Ok(()) => (index_scheduler, auth_controller), Ok(()) => (index_scheduler, auth_controller),
Err(e) => { Err(e) => {
@ -196,7 +206,7 @@ pub fn setup_meilisearch(opt: &Opt) -> anyhow::Result<(Arc<IndexScheduler>, Auth
if !empty_db { if !empty_db {
check_version_file(&opt.db_path)?; check_version_file(&opt.db_path)?;
} }
meilisearch_builder()? meilisearch_builder(OnFailure::KeepDb)?
}; };
// We create a loop in a thread that registers snapshotCreation tasks // We create a loop in a thread that registers snapshotCreation tasks