2021-10-07 16:44:01 +02:00
|
|
|
use std::{
|
2021-10-13 04:57:40 +02:00
|
|
|
sync::Arc,
|
2021-10-07 16:44:01 +02:00
|
|
|
path::Path,
|
|
|
|
};
|
2021-10-06 13:53:14 +02:00
|
|
|
|
2021-10-13 04:57:40 +02:00
|
|
|
use rkyv::Archived;
|
2021-10-07 16:44:01 +02:00
|
|
|
|
2021-10-13 04:57:40 +02:00
|
|
|
use super::{
|
2021-10-07 16:44:01 +02:00
|
|
|
DB,
|
|
|
|
Environment,
|
|
|
|
|
|
|
|
EnvironmentFlags,
|
|
|
|
DatabaseFlags,
|
|
|
|
WriteFlags,
|
|
|
|
|
|
|
|
Adapter,
|
2021-10-13 04:57:40 +02:00
|
|
|
AllocAdapter,
|
|
|
|
DBError,
|
2021-10-07 16:44:01 +02:00
|
|
|
|
|
|
|
Transaction,
|
2021-10-13 04:57:40 +02:00
|
|
|
RoTransaction,
|
2021-10-07 16:44:01 +02:00
|
|
|
RwTransaction,
|
2021-10-06 13:53:14 +02:00
|
|
|
|
2021-10-13 04:57:40 +02:00
|
|
|
LMDBorrow,
|
|
|
|
};
|
2021-10-07 16:44:01 +02:00
|
|
|
|
2021-10-13 04:57:40 +02:00
|
|
|
use crate::state::State;
|
2021-10-06 13:53:14 +02:00
|
|
|
|
2021-10-13 04:57:40 +02:00
|
|
|
type StateAdapter = AllocAdapter<State>;
|
2021-10-06 13:53:14 +02:00
|
|
|
|
2021-10-07 16:44:01 +02:00
|
|
|
/// State Database containing the currently set state
|
2021-10-13 04:57:40 +02:00
|
|
|
#[derive(Clone, Debug)]
|
2021-10-07 16:44:01 +02:00
|
|
|
pub struct StateDB {
|
|
|
|
/// The environment for all the databases below
|
2021-10-13 04:57:40 +02:00
|
|
|
env: Arc<Environment>,
|
2021-10-06 13:53:14 +02:00
|
|
|
|
2021-10-07 16:44:01 +02:00
|
|
|
input: DB<StateAdapter>,
|
|
|
|
output: DB<StateAdapter>,
|
2021-10-06 13:53:14 +02:00
|
|
|
|
2021-10-07 16:44:01 +02:00
|
|
|
// TODO: Index resource name/id/uuid -> u64
|
2021-10-06 13:53:14 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
impl StateDB {
|
2021-10-13 04:57:40 +02:00
|
|
|
fn open_env<P: AsRef<Path>>(path: P) -> lmdb::Result<Environment> {
|
2021-10-07 16:44:01 +02:00
|
|
|
Environment::new()
|
|
|
|
.set_flags( EnvironmentFlags::WRITE_MAP
|
|
|
|
| EnvironmentFlags::NO_SUB_DIR
|
|
|
|
| EnvironmentFlags::NO_TLS
|
|
|
|
| EnvironmentFlags::NO_READAHEAD)
|
|
|
|
.set_max_dbs(2)
|
|
|
|
.open(path.as_ref())
|
2021-10-06 13:53:14 +02:00
|
|
|
}
|
|
|
|
|
2021-10-07 16:44:01 +02:00
|
|
|
fn new(env: Environment, input: DB<StateAdapter>, output: DB<StateAdapter>) -> Self {
|
2021-10-13 04:57:40 +02:00
|
|
|
Self { env: Arc::new(env), input, output }
|
2021-10-06 13:53:14 +02:00
|
|
|
}
|
|
|
|
|
2021-10-13 04:57:40 +02:00
|
|
|
pub fn init<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::create(&env, Some("input"), DatabaseFlags::INTEGER_KEY)?
|
|
|
|
};
|
|
|
|
let output = unsafe {
|
|
|
|
DB::create(&env, Some("output"), DatabaseFlags::INTEGER_KEY)?
|
|
|
|
};
|
2021-10-06 13:53:14 +02:00
|
|
|
|
2021-10-07 16:44:01 +02:00
|
|
|
Ok(Self::new(env, input, output))
|
|
|
|
}
|
2021-10-06 13:53:14 +02:00
|
|
|
|
2021-10-13 04:57:40 +02:00
|
|
|
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-06 13:53:14 +02:00
|
|
|
|
2021-10-07 16:44:01 +02:00
|
|
|
Ok(Self::new(env, input, output))
|
|
|
|
}
|
2021-10-06 13:53:14 +02:00
|
|
|
|
2021-10-07 16:44:01 +02:00
|
|
|
fn update_txn(&self, txn: &mut RwTransaction, key: u64, input: &State, output: &State)
|
2021-10-13 04:57:40 +02:00
|
|
|
-> Result<(), DBError>
|
2021-10-07 16:44:01 +02:00
|
|
|
{
|
|
|
|
let flags = WriteFlags::empty();
|
|
|
|
let k = key.to_ne_bytes();
|
|
|
|
self.input.put(txn, &k, input, flags)?;
|
|
|
|
self.output.put(txn, &k, output, flags)?;
|
2021-10-06 13:53:14 +02:00
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2021-10-13 04:57:40 +02:00
|
|
|
pub fn update(&self, key: u64, input: &State, output: &State)
|
|
|
|
-> Result<(), DBError>
|
2021-10-06 13:53:14 +02:00
|
|
|
{
|
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-06 13:53:14 +02:00
|
|
|
|
2021-10-07 16:44:01 +02:00
|
|
|
txn.commit().map_err(StateAdapter::from_db_err)
|
2021-10-06 13:53:14 +02:00
|
|
|
}
|
2021-10-13 04:57:40 +02:00
|
|
|
|
|
|
|
fn get(&self, db: &DB<StateAdapter>, key: u64)
|
|
|
|
-> Result<Option<LMDBorrow<RoTransaction, Archived<State>>>, DBError>
|
|
|
|
{
|
|
|
|
let txn = self.env.begin_ro_txn().map_err(StateAdapter::from_db_err)?;
|
|
|
|
if let Some(state) = db.get(&txn, &key.to_ne_bytes())? {
|
|
|
|
let ptr = state.into();
|
|
|
|
Ok(Some(unsafe { LMDBorrow::new(ptr, txn) }))
|
|
|
|
} else {
|
|
|
|
Ok(None)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[inline(always)]
|
|
|
|
pub fn get_input(&self, key: u64)
|
|
|
|
-> Result<Option<LMDBorrow<RoTransaction, Archived<State>>>, DBError>
|
|
|
|
{ self.get(&self.input, key) }
|
|
|
|
|
|
|
|
#[inline(always)]
|
|
|
|
pub fn get_output(&self, key: u64)
|
|
|
|
-> Result<Option<LMDBorrow<RoTransaction, Archived<State>>>, DBError>
|
|
|
|
{ self.get(&self.output, key) }
|
|
|
|
|
|
|
|
pub fn accessor(&self, key: u64) -> StateAccessor {
|
|
|
|
StateAccessor::new(key, self.clone())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Debug)]
|
|
|
|
pub struct StateAccessor {
|
|
|
|
key: u64,
|
|
|
|
db: StateDB
|
|
|
|
}
|
|
|
|
|
|
|
|
impl StateAccessor {
|
|
|
|
pub fn new(key: u64, db: StateDB) -> Self {
|
|
|
|
Self { key, db }
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn get_input(&self)
|
|
|
|
-> Result<Option<LMDBorrow<RoTransaction, Archived<State>>>, DBError>
|
|
|
|
{
|
|
|
|
self.db.get_input(self.key)
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn get_output(&self)
|
|
|
|
-> Result<Option<LMDBorrow<RoTransaction, Archived<State>>>, DBError>
|
|
|
|
{
|
|
|
|
self.db.get_output(self.key)
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn set(&self, input: &State, output: &State) -> Result<(), DBError> {
|
|
|
|
self.db.update(self.key, input, output)
|
|
|
|
}
|
2021-10-06 13:53:14 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
mod tests {
|
|
|
|
use super::*;
|
|
|
|
|
|
|
|
use crate::db::tests::open_test_env;
|
|
|
|
use lmdb::{
|
|
|
|
EnvironmentFlags as EF,
|
|
|
|
DatabaseFlags as DF,
|
|
|
|
WriteFlags as WF,
|
|
|
|
};
|
|
|
|
|
|
|
|
use rkyv::Infallible;
|
|
|
|
use rkyv::ser::serializers::AllocSerializer;
|
|
|
|
use rkyv::archived_root;
|
|
|
|
use rkyv::util::archived_value;
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn construct_state() {
|
|
|
|
let b = State::build()
|
|
|
|
.add("Colour".to_string(), Vec3u8 { a: 1, b: 2, c: 3})
|
|
|
|
.add("Powered".to_string(), Bool(true))
|
|
|
|
.add("Intensity".to_string(), UInt32(4242))
|
|
|
|
.finish();
|
|
|
|
|
|
|
|
println!("({}) {:?}", b.hash(), b);
|
|
|
|
|
|
|
|
let mut serializer = AllocSerializer::<256>::default();
|
|
|
|
let pos = serializer.serialize_value(&b).unwrap();
|
|
|
|
let buf = serializer.into_serializer().into_inner();
|
|
|
|
|
|
|
|
println!("Encsize: {}", buf.len());
|
|
|
|
|
|
|
|
let archived_state = unsafe {
|
|
|
|
archived_value::<State>(buf.as_ref(), pos)
|
|
|
|
};
|
|
|
|
let s: State = archived_state.deserialize(&mut Infallible).unwrap();
|
|
|
|
|
|
|
|
println!("({}) {:?}", pos, s);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn function_name_test() {
|
|
|
|
let te = open_text_env();
|
|
|
|
let ildb = e.create_db(Some("input"), DF::empty()).expect("Failed to create db file");
|
|
|
|
let oldb = e.create_db(Some("output"), DF::empty()).expect("Failed to create db file");
|
|
|
|
|
|
|
|
let idb = DB::new(e.env.clone(), ildb);
|
|
|
|
let odb = DB::new(e.env.clone(), oldb);
|
|
|
|
let db = StateDB::new(idb, odb);
|
|
|
|
}
|
|
|
|
}
|