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

156 lines
4.5 KiB
Rust
Raw Normal View History

2021-10-07 16:44:01 +02:00
use std::{
sync::Arc,
2021-10-07 16:44:01 +02:00
path::Path,
};
2021-12-06 21:53:42 +01:00
use rkyv::Archived;
2021-10-07 16:44:01 +02:00
2021-11-26 21:01:43 +01:00
use crate::db::{
2021-10-07 16:44:01 +02:00
DB,
Environment,
EnvironmentFlags,
DatabaseFlags,
WriteFlags,
Adapter,
AllocAdapter,
DBError,
2021-10-07 16:44:01 +02:00
Transaction,
RoTransaction,
2021-10-07 16:44:01 +02:00
RwTransaction,
};
2021-10-07 16:44:01 +02:00
2022-03-10 20:52:34 +01:00
use crate::resources::state::State;
type StateAdapter = AllocAdapter<State>;
2021-10-07 16:44:01 +02:00
/// State Database containing the currently set state
2022-03-13 20:11:37 +01:00
#[derive(Debug)]
2021-10-07 16:44:01 +02:00
pub struct StateDB {
/// The environment for all the databases below
env: Arc<Environment>,
2021-10-07 16:44:01 +02:00
input: DB<StateAdapter>,
output: DB<StateAdapter>,
2022-03-10 20:52:34 +01:00
// TODO: Index resources name/id/uuid -> u64
}
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-15 21:24:21 +01:00
.set_flags( EnvironmentFlags::WRITE_MAP
| EnvironmentFlags::NO_SUB_DIR
2021-10-07 16:44:01 +02:00
| EnvironmentFlags::NO_TLS
| EnvironmentFlags::NO_READAHEAD)
2022-03-15 19:56:41 +01:00
.set_max_dbs(4)
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-13 22:50:37 +01:00
fn new(env: Arc<Environment>, input: DB<StateAdapter>, output: DB<StateAdapter>) -> Self {
Self { env: env, input, output }
}
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)?;
let input = unsafe { DB::open(&env, Some("input"))? };
let output = unsafe { DB::open(&env, Some("output"))? };
2021-10-07 16:44:01 +02:00
Ok(Self::new(env, input, output))
}
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();
let input = unsafe { DB::create(&env, Some("input"), flags)? };
let output = unsafe { DB::create(&env, Some("output"), flags)? };
Ok(Self::new(env, input, output))
}
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-13 20:11:37 +01:00
fn update_txn(&self, txn: &mut RwTransaction, key: impl AsRef<[u8]>, input: &State, output: &State)
-> Result<(), DBError>
2021-10-07 16:44:01 +02:00
{
let flags = WriteFlags::empty();
2022-03-13 20:11:37 +01:00
let k = key.as_ref();
2021-10-07 16:44:01 +02:00
self.input.put(txn, &k, input, flags)?;
self.output.put(txn, &k, output, flags)?;
Ok(())
}
2022-03-13 20:11:37 +01:00
pub fn update(&self, key: impl AsRef<[u8]>, input: &State, output: &State)
-> Result<(), DBError>
{
2021-10-07 16:44:01 +02:00
let mut txn = self.env.begin_rw_txn().map_err(StateAdapter::from_db_err)?;
self.update_txn(&mut txn, key, input, output)?;
2021-10-07 16:44:01 +02:00
txn.commit().map_err(StateAdapter::from_db_err)
}
2022-03-13 20:11:37 +01:00
fn get(&self, db: &DB<StateAdapter>, key: impl AsRef<[u8]>)
-> Result<Option<LMDBorrow<RoTransaction, Archived<State>>>, DBError>
{
let txn = self.env.begin_ro_txn().map_err(StateAdapter::from_db_err)?;
2022-03-13 20:11:37 +01:00
if let Some(state) = db.get(&txn, &key.as_ref())? {
let ptr = state.into();
Ok(Some(unsafe { LMDBorrow::new(ptr, txn) }))
} else {
Ok(None)
}
}
#[inline(always)]
2022-03-13 20:11:37 +01:00
pub fn get_input(&self, key: impl AsRef<[u8]>)
-> Result<Option<LMDBorrow<RoTransaction, Archived<State>>>, DBError>
{ self.get(&self.input, key) }
#[inline(always)]
2022-03-13 20:11:37 +01:00
pub fn get_output(&self, key: impl AsRef<[u8]>)
-> Result<Option<LMDBorrow<RoTransaction, Archived<State>>>, DBError>
{ self.get(&self.output, key) }
}
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;
use crate::resource::state::value::{OID_COLOUR, OID_POWERED, OID_INTENSITY};
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()
2021-10-18 11:27:42 +02:00
.add(OID_COLOUR.clone(), Box::new(Vec3u8 { a: 1, b: 2, c: 3}))
.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()
.add(OID_COLOUR.clone(), Box::new(Vec3u8 { a: 1, b: 2, c: 3}))
.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());
}
}