fabaccess-bffh/bffhd/resources/state/db.rs

117 lines
3.6 KiB
Rust
Raw Normal View History

2022-03-16 18:10:59 +01:00
use crate::db;
use crate::db::{ArchivedValue, RawDB, DB, AlignedAdapter};
use lmdb::{
DatabaseFlags, Environment, EnvironmentFlags, RoTransaction, RwTransaction, Transaction,
2021-10-07 16:44:01 +02:00
WriteFlags,
};
2022-03-16 18:10:59 +01:00
use std::{path::Path, sync::Arc};
2021-10-07 16:44:01 +02:00
2022-03-10 20:52:34 +01:00
use crate::resources::state::State;
2022-03-16 18:10:59 +01:00
#[derive(Debug, Clone)]
2021-10-07 16:44:01 +02:00
pub struct StateDB {
env: Arc<Environment>,
2022-03-16 18:10:59 +01:00
db: DB<AlignedAdapter<State>>,
}
impl StateDB {
2022-03-13 22:50:37 +01:00
pub fn open_env<P: AsRef<Path>>(path: P) -> lmdb::Result<Arc<Environment>> {
2021-10-07 16:44:01 +02:00
Environment::new()
2022-03-16 18:10:59 +01:00
.set_flags(
EnvironmentFlags::WRITE_MAP
| EnvironmentFlags::NO_SUB_DIR
| EnvironmentFlags::NO_TLS
| EnvironmentFlags::NO_READAHEAD,
)
2022-03-16 19:01:09 +01:00
.set_max_dbs(8)
2021-10-07 16:44:01 +02:00
.open(path.as_ref())
2022-03-13 22:50:37 +01:00
.map(Arc::new)
}
2022-03-16 18:10:59 +01:00
fn new(env: Arc<Environment>, db: RawDB) -> Self {
let db = DB::new(db);
Self { env, db }
}
pub fn open_with_env(env: Arc<Environment>) -> lmdb::Result<Self> {
let db = unsafe { RawDB::open(&env, Some("state"))? };
Ok(Self::new(env, db))
}
pub fn open<P: AsRef<Path>>(path: P) -> lmdb::Result<Self> {
2021-10-07 16:44:01 +02:00
let env = Self::open_env(path)?;
2022-03-16 18:10:59 +01:00
Self::open_with_env(env)
2021-10-07 16:44:01 +02:00
}
2022-03-13 22:50:37 +01:00
pub fn create_with_env(env: Arc<Environment>) -> lmdb::Result<Self> {
2021-10-20 18:37:50 +02:00
let flags = DatabaseFlags::empty();
2022-03-16 18:10:59 +01:00
let db = unsafe { RawDB::create(&env, Some("state"), flags)? };
2021-10-20 18:37:50 +02:00
2022-03-16 18:10:59 +01:00
Ok(Self::new(env, db))
2021-10-20 18:37:50 +02:00
}
2022-03-13 22:50:37 +01:00
pub fn create<P: AsRef<Path>>(path: P) -> lmdb::Result<Self> {
let env = Self::open_env(path)?;
Self::create_with_env(env)
}
2022-03-16 18:10:59 +01:00
pub fn begin_ro_txn(&self) -> Result<impl Transaction + '_, db::Error> {
self.env.begin_ro_txn()
}
2022-03-16 18:10:59 +01:00
pub fn get(&self, key: impl AsRef<[u8]>) -> Result<Option<ArchivedValue<State>>, db::Error> {
let txn = self.env.begin_ro_txn()?;
self.db.get(&txn, &key.as_ref())
}
2022-03-16 18:10:59 +01:00
pub fn get_all<'txn, T: Transaction>(
&self,
txn: &'txn T,
) -> Result<impl IntoIterator<Item = (&'txn [u8], ArchivedValue<State>)>, db::Error, > {
self.db.get_all(txn)
}
2022-03-16 18:10:59 +01:00
pub fn put(&self, key: &impl AsRef<[u8]>, val: &ArchivedValue<State>) -> Result<(), db::Error> {
let mut txn = self.env.begin_rw_txn()?;
let flags = WriteFlags::empty();
self.db.put(&mut txn, key, val, flags)?;
txn.commit()
}
}
2021-10-18 11:27:42 +02:00
#[cfg(test)]
mod tests {
use super::*;
2021-11-26 02:25:48 +01:00
use crate::resource::state::value::Vec3u8;
2022-03-16 18:10:59 +01:00
use crate::resource::state::value::{OID_COLOUR, OID_INTENSITY, OID_POWERED};
2021-10-18 11:27:42 +02:00
use std::ops::Deref;
#[test]
fn construct_state() {
2021-10-18 11:27:42 +02:00
let tmpdir = tempfile::tempdir().unwrap();
let mut tmppath = tmpdir.path().to_owned();
tmppath.push("db");
2022-03-13 20:11:37 +01:00
let db = StateDB::create(tmppath).unwrap();
let b = State::build()
2022-03-16 18:10:59 +01:00
.add(OID_COLOUR.clone(), Box::new(Vec3u8 { a: 1, b: 2, c: 3 }))
2021-10-18 11:27:42 +02:00
.add(OID_POWERED.clone(), Box::new(true))
.add(OID_INTENSITY.clone(), Box::new(1023))
.finish();
println!("({}) {:?}", b.hash(), b);
2021-10-18 11:27:42 +02:00
let c = State::build()
2022-03-16 18:10:59 +01:00
.add(OID_COLOUR.clone(), Box::new(Vec3u8 { a: 1, b: 2, c: 3 }))
2021-10-18 11:27:42 +02:00
.add(OID_POWERED.clone(), Box::new(true))
.add(OID_INTENSITY.clone(), Box::new(1023))
.finish();
2021-10-18 11:27:42 +02:00
let key = rand::random();
db.update(key, &b, &c).unwrap();
let d = db.get_input(key).unwrap().unwrap();
let e = db.get_output(key).unwrap().unwrap();
assert_eq!(&b, d.deref());
assert_eq!(&c, e.deref());
}
}