mirror of
https://github.com/meilisearch/meilisearch.git
synced 2025-09-25 22:36:33 +00:00
180 lines
5.4 KiB
Rust
180 lines
5.4 KiB
Rust
mod v1_12;
|
|
mod v1_13;
|
|
mod v1_14;
|
|
mod v1_15;
|
|
mod v1_16;
|
|
|
|
use heed::RwTxn;
|
|
use v1_12::{V1_12_3_To_V1_13_0, V1_12_To_V1_12_3};
|
|
use v1_13::{V1_13_0_To_V1_13_1, V1_13_1_To_Latest_V1_13};
|
|
use v1_14::Latest_V1_13_To_Latest_V1_14;
|
|
use v1_15::Latest_V1_14_To_Latest_V1_15;
|
|
use v1_16::Latest_V1_15_To_V1_16_0;
|
|
|
|
use crate::constants::{VERSION_MAJOR, VERSION_MINOR, VERSION_PATCH};
|
|
use crate::progress::{Progress, VariableNameStep};
|
|
use crate::{Index, InternalError, Result};
|
|
|
|
trait UpgradeIndex {
|
|
/// Returns `true` if the index scheduler must regenerate its cached stats.
|
|
fn upgrade(
|
|
&self,
|
|
wtxn: &mut RwTxn,
|
|
index: &Index,
|
|
original: (u32, u32, u32),
|
|
progress: Progress,
|
|
) -> Result<bool>;
|
|
fn target_version(&self) -> (u32, u32, u32);
|
|
}
|
|
|
|
const UPGRADE_FUNCTIONS: &[&dyn UpgradeIndex] = &[
|
|
&V1_12_To_V1_12_3 {},
|
|
&V1_12_3_To_V1_13_0 {},
|
|
&V1_13_0_To_V1_13_1 {},
|
|
&V1_13_1_To_Latest_V1_13 {},
|
|
&Latest_V1_13_To_Latest_V1_14 {},
|
|
&Latest_V1_14_To_Latest_V1_15 {},
|
|
&Latest_V1_15_To_V1_16_0 {},
|
|
&ToTargetNoOp { target: (1, 18, 0) },
|
|
&ToTargetNoOp { target: (1, 19, 0) },
|
|
&ToTargetNoOp { target: (1, 20, 0) },
|
|
&ToTargetNoOp { target: (1, 21, 0) },
|
|
&ToTargetNoOp { target: (1, 22, 0) },
|
|
// This is the last upgrade function, it will be called when the index is up to date.
|
|
// any other upgrade function should be added before this one.
|
|
&ToCurrentNoOp {},
|
|
];
|
|
|
|
/// Causes a compile-time error if the argument is not in range of `0..UPGRADE_FUNCTIONS.len()`
|
|
macro_rules! function_index {
|
|
($start:expr) => {{
|
|
const _CHECK_INDEX: () = {
|
|
if $start >= $crate::update::upgrade::UPGRADE_FUNCTIONS.len() {
|
|
panic!("upgrade functions out of range")
|
|
}
|
|
};
|
|
|
|
$start
|
|
}};
|
|
}
|
|
|
|
const fn start(from: (u32, u32, u32)) -> Option<usize> {
|
|
let start = match from {
|
|
(1, 12, 0..=2) => function_index!(0),
|
|
(1, 12, 3..) => function_index!(1),
|
|
(1, 13, 0) => function_index!(2),
|
|
(1, 13, _) => function_index!(4),
|
|
(1, 14, _) => function_index!(5),
|
|
// We must handle the current version in the match because in case of a failure some index may have been upgraded but not other.
|
|
(1, 15, _) => function_index!(6),
|
|
(1, 16, _) | (1, 17, _) => function_index!(7),
|
|
(1, 18, _) => function_index!(8),
|
|
(1, 19, _) => function_index!(9),
|
|
(1, 20, _) => function_index!(10),
|
|
(1, 21, _) => function_index!(11),
|
|
(1, 22, _) => function_index!(12),
|
|
// We deliberately don't add a placeholder with (VERSION_MAJOR, VERSION_MINOR, VERSION_PATCH) here to force manually
|
|
// considering dumpless upgrade.
|
|
(_major, _minor, _patch) => return None,
|
|
};
|
|
|
|
Some(start)
|
|
}
|
|
|
|
/// Causes a compile-time error if the latest package cannot be upgraded.
|
|
///
|
|
/// This serves as a reminder to consider the proper dumpless upgrade implementation when changing the package version.
|
|
const _CHECK_PACKAGE_CAN_UPGRADE: () = {
|
|
if start((VERSION_MAJOR, VERSION_MINOR, VERSION_PATCH)).is_none() {
|
|
panic!("cannot upgrade from latest package version")
|
|
}
|
|
};
|
|
|
|
/// Return true if the cached stats of the index must be regenerated
|
|
pub fn upgrade<MSP>(
|
|
wtxn: &mut RwTxn,
|
|
index: &Index,
|
|
db_version: (u32, u32, u32),
|
|
must_stop_processing: MSP,
|
|
progress: Progress,
|
|
) -> Result<bool>
|
|
where
|
|
MSP: Fn() -> bool + Sync,
|
|
{
|
|
let from = index.get_version(wtxn)?.unwrap_or(db_version);
|
|
|
|
let start =
|
|
start(from).ok_or_else(|| InternalError::CannotUpgradeToVersion(from.0, from.1, from.2))?;
|
|
|
|
enum UpgradeVersion {}
|
|
let upgrade_path = &UPGRADE_FUNCTIONS[start..];
|
|
|
|
let mut current_version = from;
|
|
let mut regenerate_stats = false;
|
|
for (i, upgrade) in upgrade_path.iter().enumerate() {
|
|
if (must_stop_processing)() {
|
|
return Err(crate::Error::InternalError(InternalError::AbortedIndexation));
|
|
}
|
|
let target = upgrade.target_version();
|
|
progress.update_progress(VariableNameStep::<UpgradeVersion>::new(
|
|
format!(
|
|
"Upgrading from v{}.{}.{} to v{}.{}.{}",
|
|
current_version.0,
|
|
current_version.1,
|
|
current_version.2,
|
|
target.0,
|
|
target.1,
|
|
target.2
|
|
),
|
|
i as u32,
|
|
upgrade_path.len() as u32,
|
|
));
|
|
regenerate_stats |= upgrade.upgrade(wtxn, index, from, progress.clone())?;
|
|
index.put_version(wtxn, target)?;
|
|
current_version = target;
|
|
}
|
|
|
|
Ok(regenerate_stats)
|
|
}
|
|
|
|
#[allow(non_camel_case_types)]
|
|
struct ToCurrentNoOp {}
|
|
|
|
impl UpgradeIndex for ToCurrentNoOp {
|
|
fn upgrade(
|
|
&self,
|
|
_wtxn: &mut RwTxn,
|
|
_index: &Index,
|
|
_original: (u32, u32, u32),
|
|
_progress: Progress,
|
|
) -> Result<bool> {
|
|
Ok(false)
|
|
}
|
|
|
|
fn target_version(&self) -> (u32, u32, u32) {
|
|
(VERSION_MAJOR, VERSION_MINOR, VERSION_PATCH)
|
|
}
|
|
}
|
|
|
|
/// Perform no operation during the upgrade except changing to the specified target version.
|
|
#[allow(non_camel_case_types)]
|
|
struct ToTargetNoOp {
|
|
pub target: (u32, u32, u32),
|
|
}
|
|
|
|
impl UpgradeIndex for ToTargetNoOp {
|
|
fn upgrade(
|
|
&self,
|
|
_wtxn: &mut RwTxn,
|
|
_index: &Index,
|
|
_original: (u32, u32, u32),
|
|
_progress: Progress,
|
|
) -> Result<bool> {
|
|
Ok(false)
|
|
}
|
|
|
|
fn target_version(&self) -> (u32, u32, u32) {
|
|
self.target
|
|
}
|
|
}
|