2022-06-02 17:46:26 +02:00
|
|
|
use thiserror::Error;
|
|
|
|
|
2022-03-16 18:10:59 +01:00
|
|
|
use crate::db;
|
2022-05-05 15:50:44 +02:00
|
|
|
use crate::db::{AlignedAdapter, ArchivedValue, RawDB, DB};
|
|
|
|
use lmdb::{DatabaseFlags, Environment, EnvironmentFlags, Transaction, WriteFlags};
|
2022-06-02 17:46:26 +02:00
|
|
|
use miette::{Diagnostic, LabeledSpan, Severity, SourceCode};
|
|
|
|
use std::any::TypeId;
|
|
|
|
use std::error::Error;
|
|
|
|
use std::fmt::{Debug, Display, Formatter};
|
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;
|
2021-10-06 13:53:14 +02:00
|
|
|
|
2022-03-16 18:10:59 +01:00
|
|
|
#[derive(Debug, Clone)]
|
2021-10-07 16:44:01 +02:00
|
|
|
pub struct StateDB {
|
2021-10-13 04:57:40 +02:00
|
|
|
env: Arc<Environment>,
|
2022-03-16 18:10:59 +01:00
|
|
|
db: DB<AlignedAdapter<State>>,
|
2021-10-06 13:53:14 +02:00
|
|
|
}
|
|
|
|
|
2022-12-25 11:54:36 +01:00
|
|
|
#[derive(Clone, Debug, PartialEq, Eq, Error, Diagnostic)]
|
2022-06-02 17:46:26 +02:00
|
|
|
pub enum StateDBError {
|
|
|
|
#[error("opening the state db environment failed")]
|
|
|
|
#[diagnostic(
|
|
|
|
code(bffh::db::state::open_env),
|
|
|
|
help("does the parent directory for state_db exist?")
|
|
|
|
)]
|
|
|
|
OpenEnv(#[source] db::Error),
|
|
|
|
#[error("opening the state db failed")]
|
|
|
|
#[diagnostic(code(bffh::db::state::open))]
|
|
|
|
Open(#[source] db::Error),
|
|
|
|
#[error("creating the state db failed")]
|
|
|
|
#[diagnostic(code(bffh::db::state::create))]
|
|
|
|
Create(#[source] db::Error),
|
|
|
|
}
|
|
|
|
|
2021-10-06 13:53:14 +02:00
|
|
|
impl StateDB {
|
2022-06-02 17:46:26 +02:00
|
|
|
pub fn open_env<P: AsRef<Path>>(path: P) -> Result<Arc<Environment>, StateDBError> {
|
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-06-02 17:46:26 +02:00
|
|
|
.map_err(|e| StateDBError::OpenEnv(e.into()))
|
2021-10-06 13:53:14 +02:00
|
|
|
}
|
|
|
|
|
2022-03-16 18:10:59 +01:00
|
|
|
fn new(env: Arc<Environment>, db: RawDB) -> Self {
|
|
|
|
let db = DB::new(db);
|
|
|
|
Self { env, db }
|
|
|
|
}
|
|
|
|
|
2022-06-02 17:46:26 +02:00
|
|
|
pub fn open_with_env(env: Arc<Environment>) -> Result<Self, StateDBError> {
|
|
|
|
let db = unsafe { RawDB::open(&env, Some("state")) };
|
|
|
|
let db = db.map_err(|e| StateDBError::Open(e.into()))?;
|
2022-03-16 18:10:59 +01:00
|
|
|
Ok(Self::new(env, db))
|
2021-10-06 13:53:14 +02:00
|
|
|
}
|
|
|
|
|
2022-06-02 17:46:26 +02:00
|
|
|
pub fn open<P: AsRef<Path>>(path: P) -> Result<Self, StateDBError> {
|
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
|
|
|
}
|
2021-10-06 13:53:14 +02:00
|
|
|
|
2022-06-02 17:46:26 +02:00
|
|
|
pub fn create_with_env(env: Arc<Environment>) -> Result<Self, StateDBError> {
|
2021-10-20 18:37:50 +02:00
|
|
|
let flags = DatabaseFlags::empty();
|
2022-06-02 17:46:26 +02:00
|
|
|
let db = unsafe { RawDB::create(&env, Some("state"), flags) };
|
|
|
|
let db = db.map_err(|e| StateDBError::Create(e.into()))?;
|
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-06-02 17:46:26 +02:00
|
|
|
pub fn create<P: AsRef<Path>>(path: P) -> Result<Self, StateDBError> {
|
2022-03-13 22:50:37 +01:00
|
|
|
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> {
|
2022-06-02 17:46:26 +02:00
|
|
|
self.env.begin_ro_txn().map_err(db::Error::from)
|
2021-10-06 13:53:14 +02:00
|
|
|
}
|
|
|
|
|
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())
|
2021-10-06 13:53:14 +02:00
|
|
|
}
|
2021-10-13 04:57:40 +02:00
|
|
|
|
2022-03-16 18:10:59 +01:00
|
|
|
pub fn get_all<'txn, T: Transaction>(
|
|
|
|
&self,
|
|
|
|
txn: &'txn T,
|
2022-05-05 15:50:44 +02:00
|
|
|
) -> Result<impl IntoIterator<Item = (&'txn [u8], ArchivedValue<State>)>, db::Error> {
|
2022-03-16 18:10:59 +01:00
|
|
|
self.db.get_all(txn)
|
2021-10-13 04:57:40 +02:00
|
|
|
}
|
|
|
|
|
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)?;
|
2022-06-02 17:46:26 +02:00
|
|
|
Ok(txn.commit()?)
|
2022-03-16 18:10:59 +01:00
|
|
|
}
|
2021-10-06 13:53:14 +02:00
|
|
|
}
|
|
|
|
|
2021-10-18 11:27:42 +02:00
|
|
|
#[cfg(test)]
|
2021-10-06 13:53:14 +02:00
|
|
|
mod tests {
|
|
|
|
use super::*;
|
|
|
|
|
2021-10-18 11:27:42 +02:00
|
|
|
use std::ops::Deref;
|
2021-10-06 13:53:14 +02:00
|
|
|
}
|