use std::path::{Path, PathBuf};
use heed::{RoTxn, RwTxn, WithoutTls};
use super::lmdb_db::LmdbDb;
use super::lmdb_env::{LmdbEnv, copy_lmdb_env_to_dir};
use super::lmdb_error::LmdbLayerError;
use super::txn::{with_read_txn, with_write_txn};
#[allow(dead_code)]
pub(crate) trait LmdbStore {
fn lmdb_env(&self) -> &LmdbEnv;
fn lmdb_db(&self) -> &LmdbDb;
fn read<R, E>(
&self,
f: impl FnOnce(&LmdbDb, &RoTxn<'_, WithoutTls>) -> Result<R, E>,
) -> Result<R, E>
where
E: From<LmdbLayerError>,
{
with_read_txn(self.lmdb_env(), |txn| f(self.lmdb_db(), txn))
}
fn write<R, E>(&self, f: impl FnOnce(&LmdbDb, &mut RwTxn<'_>) -> Result<R, E>) -> Result<R, E>
where
E: From<LmdbLayerError>,
{
with_write_txn(self.lmdb_env(), |txn| f(self.lmdb_db(), txn))
}
fn snapshot_to(&self, dst_dir: &Path) -> Result<PathBuf, LmdbLayerError> {
copy_lmdb_env_to_dir(self.lmdb_env(), dst_dir)
}
}
#[cfg(test)]
mod tests {
use bytesize::ByteSize;
use tempfile::TempDir;
use super::*;
use crate::lmdb::lmdb_env::{LmdbEnvConfig, open_lmdb_env};
struct TestStore {
lmdb_env: LmdbEnv,
db: LmdbDb,
}
impl LmdbStore for TestStore {
fn lmdb_env(&self) -> &LmdbEnv {
&self.lmdb_env
}
fn lmdb_db(&self) -> &LmdbDb {
&self.db
}
}
fn test_store() -> (TempDir, TestStore) {
let dir = tempfile::tempdir().expect("create temp dir");
let lmdb_env =
open_lmdb_env(dir.path(), &LmdbEnvConfig::new(1, ByteSize::mib(16))).expect("open env");
let db =
with_write_txn(&lmdb_env, |txn| LmdbDb::open(&lmdb_env, txn, "data")).expect("open db");
(dir, TestStore { lmdb_env, db })
}
#[test]
fn read_and_write_go_through_the_brackets() {
let (_dir, store) = test_store();
store
.write(|db, txn| db.put(txn, b"key", b"value"))
.expect("write");
let value = store
.read(|db, txn| db.get(txn, b"key"))
.expect("read")
.expect("value present");
assert_eq!(value.as_ref(), b"value");
}
#[test]
fn snapshot_to_copies_committed_state() {
let (_dir, store) = test_store();
store
.write(|db, txn| db.put(txn, b"key", b"value"))
.expect("write");
let dst = tempfile::tempdir().expect("create temp dir");
let data_file = store.snapshot_to(dst.path()).expect("snapshot");
assert!(data_file.exists());
let copied = open_lmdb_env(dst.path(), &LmdbEnvConfig::new(1, ByteSize::mib(16)))
.expect("open snapshot");
let copied_db =
with_write_txn(&copied, |txn| LmdbDb::open(&copied, txn, "data")).expect("open db");
let value = with_read_txn(&copied, |txn| copied_db.get(txn, b"key"))
.expect("read")
.expect("value present");
assert_eq!(value.as_ref(), b"value");
}
}