use crate::engine::{Durability, KvEngine, WriteTx};
use crate::error::{StoreError, StoreResult};
use crate::table::Table;
pub const META_TABLE: &str = "_meta";
pub const STORE_VERSION_KEY: &str = "store_format_version";
pub const STORE_FORMAT_VERSION: u32 = 2;
fn meta_table() -> Table<String, u32> {
Table::new(META_TABLE)
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum MetaStatus {
Initialized,
Current,
Migrated { from: u32 },
}
pub trait Migration<E: KvEngine>: Send + Sync {
fn from_version(&self) -> u32;
fn apply(&self, engine: &E) -> StoreResult<()>;
}
pub fn read_store_version<E: KvEngine>(engine: &E) -> StoreResult<Option<u32>> {
let r = engine.begin_read()?;
meta_table().get(&r, &STORE_VERSION_KEY.to_string())
}
pub fn write_store_version<E: KvEngine>(engine: &E, version: u32) -> StoreResult<()> {
let mut w = engine.begin_write(Durability::Immediate)?;
meta_table().put(&mut w, &STORE_VERSION_KEY.to_string(), &version)?;
w.commit()
}
pub struct PrefixedValuesStamp;
impl<E: KvEngine> Migration<E> for PrefixedValuesStamp {
fn from_version(&self) -> u32 {
1
}
fn apply(&self, _engine: &E) -> StoreResult<()> {
Ok(())
}
}
pub fn open_meta<E: KvEngine>(engine: &E) -> StoreResult<MetaStatus> {
open_meta_with(engine, STORE_FORMAT_VERSION, &[&PrefixedValuesStamp])
}
pub fn open_meta_with<E: KvEngine>(
engine: &E,
current_version: u32,
migrations: &[&dyn Migration<E>],
) -> StoreResult<MetaStatus> {
match read_store_version(engine)? {
None => {
write_store_version(engine, current_version)?;
Ok(MetaStatus::Initialized)
}
Some(v) if v == current_version => Ok(MetaStatus::Current),
Some(v) if v > current_version => Err(StoreError::SchemaTooNew {
found: v,
supported: current_version,
}),
Some(v) => {
for from in v..current_version {
let step = migrations
.iter()
.find(|m| m.from_version() == from)
.ok_or_else(|| {
StoreError::Schema(format!(
"no migration registered from store format version {from}"
))
})?;
step.apply(engine)?;
}
write_store_version(engine, current_version)?;
Ok(MetaStatus::Migrated { from: v })
}
}
}