milli_core/update/upgrade/
mod.rs

1mod v1_12;
2mod v1_13;
3mod v1_14;
4mod v1_15;
5use heed::RwTxn;
6use v1_12::{V1_12_3_To_V1_13_0, V1_12_To_V1_12_3};
7use v1_13::{V1_13_0_To_V1_13_1, V1_13_1_To_Latest_V1_13};
8use v1_14::Latest_V1_13_To_Latest_V1_14;
9use v1_15::Latest_V1_14_To_Latest_V1_15;
10
11use crate::constants::{VERSION_MAJOR, VERSION_MINOR, VERSION_PATCH};
12use crate::progress::{Progress, VariableNameStep};
13use crate::{Index, InternalError, Result};
14
15trait UpgradeIndex {
16    /// Returns `true` if the index scheduler must regenerate its cached stats.
17    fn upgrade(
18        &self,
19        wtxn: &mut RwTxn,
20        index: &Index,
21        original: (u32, u32, u32),
22        progress: Progress,
23    ) -> Result<bool>;
24    fn target_version(&self) -> (u32, u32, u32);
25}
26
27/// Return true if the cached stats of the index must be regenerated
28pub fn upgrade<MSP>(
29    wtxn: &mut RwTxn,
30    index: &Index,
31    db_version: (u32, u32, u32),
32    must_stop_processing: MSP,
33    progress: Progress,
34) -> Result<bool>
35where
36    MSP: Fn() -> bool + Sync,
37{
38    let from = index.get_version(wtxn)?.unwrap_or(db_version);
39    let upgrade_functions: &[&dyn UpgradeIndex] = &[
40        &V1_12_To_V1_12_3 {},
41        &V1_12_3_To_V1_13_0 {},
42        &V1_13_0_To_V1_13_1 {},
43        &V1_13_1_To_Latest_V1_13 {},
44        &Latest_V1_13_To_Latest_V1_14 {},
45        &Latest_V1_14_To_Latest_V1_15 {},
46        // This is the last upgrade function, it will be called when the index is up to date.
47        // any other upgrade function should be added before this one.
48        &ToCurrentNoOp {},
49    ];
50
51    let start = match from {
52        (1, 12, 0..=2) => 0,
53        (1, 12, 3..) => 1,
54        (1, 13, 0) => 2,
55        (1, 13, _) => 4,
56        (1, 14, _) => 5,
57        // We must handle the current version in the match because in case of a failure some index may have been upgraded but not other.
58        (1, 15, _) => 6,
59        (major, minor, patch) => {
60            return Err(InternalError::CannotUpgradeToVersion(major, minor, patch).into())
61        }
62    };
63
64    enum UpgradeVersion {}
65    let upgrade_path = &upgrade_functions[start..];
66
67    let mut current_version = from;
68    let mut regenerate_stats = false;
69    for (i, upgrade) in upgrade_path.iter().enumerate() {
70        if (must_stop_processing)() {
71            return Err(crate::Error::InternalError(InternalError::AbortedIndexation));
72        }
73        let target = upgrade.target_version();
74        progress.update_progress(VariableNameStep::<UpgradeVersion>::new(
75            format!(
76                "Upgrading from v{}.{}.{} to v{}.{}.{}",
77                current_version.0,
78                current_version.1,
79                current_version.2,
80                target.0,
81                target.1,
82                target.2
83            ),
84            i as u32,
85            upgrade_path.len() as u32,
86        ));
87        regenerate_stats |= upgrade.upgrade(wtxn, index, from, progress.clone())?;
88        index.put_version(wtxn, target)?;
89        current_version = target;
90    }
91
92    Ok(regenerate_stats)
93}
94
95#[allow(non_camel_case_types)]
96struct ToCurrentNoOp {}
97
98impl UpgradeIndex for ToCurrentNoOp {
99    fn upgrade(
100        &self,
101        _wtxn: &mut RwTxn,
102        _index: &Index,
103        _original: (u32, u32, u32),
104        _progress: Progress,
105    ) -> Result<bool> {
106        Ok(false)
107    }
108
109    fn target_version(&self) -> (u32, u32, u32) {
110        (VERSION_MAJOR, VERSION_MINOR, VERSION_PATCH)
111    }
112}