use super::types::{SystemCatalog, catalog_err};
pub const SURROGATE_HWM: redb::TableDefinition<&str, u32> =
redb::TableDefinition::new("_system.surrogate_hwm");
pub const SURROGATE_RESERVE_INDEX: redb::TableDefinition<&str, u64> =
redb::TableDefinition::new("_system.surrogate_reserve_index");
const HWM_KEY: &str = "global";
impl SystemCatalog {
pub fn put_surrogate_hwm(&self, hwm: u32) -> crate::Result<()> {
let txn = self
.db
.begin_write()
.map_err(|e| catalog_err("surrogate_hwm write txn", e))?;
{
let mut table = txn
.open_table(SURROGATE_HWM)
.map_err(|e| catalog_err("open surrogate_hwm", e))?;
table
.insert(HWM_KEY, hwm)
.map_err(|e| catalog_err("insert surrogate_hwm", e))?;
}
txn.commit()
.map_err(|e| catalog_err("surrogate_hwm commit", e))
}
pub fn put_surrogate_reserve_state(&self, hwm: u32, reserve_index: u64) -> crate::Result<()> {
let txn = self
.db
.begin_write()
.map_err(|e| catalog_err("surrogate_reserve_state write txn", e))?;
{
let mut hwm_table = txn
.open_table(SURROGATE_HWM)
.map_err(|e| catalog_err("open surrogate_hwm", e))?;
hwm_table
.insert(HWM_KEY, hwm)
.map_err(|e| catalog_err("insert surrogate_hwm", e))?;
let mut idx_table = txn
.open_table(SURROGATE_RESERVE_INDEX)
.map_err(|e| catalog_err("open surrogate_reserve_index", e))?;
idx_table
.insert(HWM_KEY, reserve_index)
.map_err(|e| catalog_err("insert surrogate_reserve_index", e))?;
}
txn.commit()
.map_err(|e| catalog_err("surrogate_reserve_state commit", e))
}
pub fn get_surrogate_reserve_index(&self) -> crate::Result<u64> {
let txn = self
.db
.begin_read()
.map_err(|e| catalog_err("surrogate_reserve_index read txn", e))?;
let table = txn
.open_table(SURROGATE_RESERVE_INDEX)
.map_err(|e| catalog_err("open surrogate_reserve_index", e))?;
match table
.get(HWM_KEY)
.map_err(|e| catalog_err("get surrogate_reserve_index", e))?
{
Some(v) => Ok(v.value()),
None => Ok(0),
}
}
pub fn get_surrogate_hwm(&self) -> crate::Result<u32> {
let txn = self
.db
.begin_read()
.map_err(|e| catalog_err("surrogate_hwm read txn", e))?;
let table = txn
.open_table(SURROGATE_HWM)
.map_err(|e| catalog_err("open surrogate_hwm", e))?;
match table
.get(HWM_KEY)
.map_err(|e| catalog_err("get surrogate_hwm", e))?
{
Some(v) => Ok(v.value()),
None => Ok(0),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn fresh_returns_zero() {
let dir = tempfile::tempdir().unwrap();
let path = dir.path().join("system.redb");
let catalog = SystemCatalog::open(&path).unwrap();
assert_eq!(catalog.get_surrogate_hwm().unwrap(), 0);
}
#[test]
fn put_then_get_roundtrip() {
let dir = tempfile::tempdir().unwrap();
let path = dir.path().join("system.redb");
let catalog = SystemCatalog::open(&path).unwrap();
catalog.put_surrogate_hwm(42).unwrap();
assert_eq!(catalog.get_surrogate_hwm().unwrap(), 42);
catalog.put_surrogate_hwm(1_000_000).unwrap();
assert_eq!(catalog.get_surrogate_hwm().unwrap(), 1_000_000);
}
#[test]
fn reserve_state_fresh_returns_zero() {
let dir = tempfile::tempdir().unwrap();
let path = dir.path().join("system.redb");
let catalog = SystemCatalog::open(&path).unwrap();
assert_eq!(catalog.get_surrogate_reserve_index().unwrap(), 0);
}
#[test]
fn reserve_state_atomic_roundtrip_and_reopen() {
let dir = tempfile::tempdir().unwrap();
let path = dir.path().join("system.redb");
{
let catalog = SystemCatalog::open(&path).unwrap();
catalog.put_surrogate_reserve_state(8192, 42).unwrap();
assert_eq!(catalog.get_surrogate_hwm().unwrap(), 8192);
assert_eq!(catalog.get_surrogate_reserve_index().unwrap(), 42);
}
let catalog = SystemCatalog::open(&path).unwrap();
assert_eq!(catalog.get_surrogate_hwm().unwrap(), 8192);
assert_eq!(catalog.get_surrogate_reserve_index().unwrap(), 42);
}
#[test]
fn persists_across_reopen() {
let dir = tempfile::tempdir().unwrap();
let path = dir.path().join("system.redb");
{
let catalog = SystemCatalog::open(&path).unwrap();
catalog.put_surrogate_hwm(7777).unwrap();
}
let catalog = SystemCatalog::open(&path).unwrap();
assert_eq!(catalog.get_surrogate_hwm().unwrap(), 7777);
}
}