mirror of https://github.com/nextgraph-org/rkv.git
Signed-off-by: Victor Porof <victor.porof@gmail.com>without.crypto
parent
1d9c11f9f4
commit
4a955a70a0
@ -0,0 +1,42 @@ |
||||
// Copyright 2018-2019 Mozilla
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use
|
||||
// this file except in compliance with the License. You may obtain a copy of the
|
||||
// License at http://www.apache.org/licenses/LICENSE-2.0
|
||||
// Unless required by applicable law or agreed to in writing, software distributed
|
||||
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations under the License.
|
||||
|
||||
mod cursor; |
||||
mod database; |
||||
mod environment; |
||||
mod error; |
||||
mod flags; |
||||
mod info; |
||||
mod iter; |
||||
mod stat; |
||||
mod transaction; |
||||
|
||||
pub use cursor::{ |
||||
RoCursorImpl, |
||||
RwCursorImpl, |
||||
}; |
||||
pub use database::DatabaseImpl; |
||||
pub use environment::{ |
||||
EnvironmentBuilderImpl, |
||||
EnvironmentImpl, |
||||
}; |
||||
pub use error::ErrorImpl; |
||||
pub use flags::{ |
||||
DatabaseFlagsImpl, |
||||
EnvironmentFlagsImpl, |
||||
WriteFlagsImpl, |
||||
}; |
||||
pub use info::InfoImpl; |
||||
pub use iter::IterImpl; |
||||
pub use stat::StatImpl; |
||||
pub use transaction::{ |
||||
RoTransactionImpl, |
||||
RwTransactionImpl, |
||||
}; |
@ -0,0 +1,69 @@ |
||||
// Copyright 2018-2019 Mozilla
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use
|
||||
// this file except in compliance with the License. You may obtain a copy of the
|
||||
// License at http://www.apache.org/licenses/LICENSE-2.0
|
||||
// Unless required by applicable law or agreed to in writing, software distributed
|
||||
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations under the License.
|
||||
|
||||
use super::{ |
||||
database::Snapshot, |
||||
IterImpl, |
||||
}; |
||||
use crate::backend::traits::BackendRoCursor; |
||||
|
||||
#[derive(Debug)] |
||||
pub struct RoCursorImpl<'env>(pub(crate) &'env Snapshot); |
||||
|
||||
impl<'env> BackendRoCursor<'env> for RoCursorImpl<'env> { |
||||
type Iter = IterImpl<'env>; |
||||
|
||||
fn iter(&mut self) -> Self::Iter { |
||||
IterImpl(Box::new(self.0.iter())) |
||||
} |
||||
|
||||
fn iter_from<K>(&mut self, key: K) -> Self::Iter |
||||
where |
||||
K: AsRef<[u8]>, |
||||
{ |
||||
// FIXME: Don't allocate.
|
||||
let key = key.as_ref().to_vec(); |
||||
IterImpl(Box::new(self.0.iter().skip_while(move |&(k, _)| k != &key[..]))) |
||||
} |
||||
|
||||
fn iter_dup_of<K>(&mut self, key: K) -> Self::Iter |
||||
where |
||||
K: AsRef<[u8]>, |
||||
{ |
||||
// FIXME: Don't allocate.
|
||||
let key = key.as_ref().to_vec(); |
||||
IterImpl(Box::new(self.0.iter().filter(move |&(k, _)| k == &key[..]))) |
||||
} |
||||
} |
||||
|
||||
#[derive(Debug)] |
||||
pub struct RwCursorImpl<'env>(&'env mut Snapshot); |
||||
|
||||
impl<'env> BackendRoCursor<'env> for RwCursorImpl<'env> { |
||||
type Iter = IterImpl<'env>; |
||||
|
||||
fn iter(&mut self) -> Self::Iter { |
||||
unimplemented!() |
||||
} |
||||
|
||||
fn iter_from<K>(&mut self, _key: K) -> Self::Iter |
||||
where |
||||
K: AsRef<[u8]>, |
||||
{ |
||||
unimplemented!() |
||||
} |
||||
|
||||
fn iter_dup_of<K>(&mut self, _key: K) -> Self::Iter |
||||
where |
||||
K: AsRef<[u8]>, |
||||
{ |
||||
unimplemented!() |
||||
} |
||||
} |
@ -0,0 +1,116 @@ |
||||
// Copyright 2018-2019 Mozilla
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use
|
||||
// this file except in compliance with the License. You may obtain a copy of the
|
||||
// License at http://www.apache.org/licenses/LICENSE-2.0
|
||||
// Unless required by applicable law or agreed to in writing, software distributed
|
||||
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations under the License.
|
||||
|
||||
use std::collections::{ |
||||
BTreeSet, |
||||
HashMap, |
||||
}; |
||||
use std::sync::{ |
||||
Arc, |
||||
RwLock, |
||||
}; |
||||
|
||||
use serde_derive::{ |
||||
Deserialize, |
||||
Serialize, |
||||
}; |
||||
use uuid::Uuid; |
||||
|
||||
use super::{ |
||||
DatabaseFlagsImpl, |
||||
ErrorImpl, |
||||
}; |
||||
use crate::backend::traits::BackendDatabase; |
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)] |
||||
pub struct DatabaseImpl { |
||||
id: Uuid, |
||||
flags: DatabaseFlagsImpl, |
||||
snapshot: Arc<RwLock<Snapshot>>, |
||||
} |
||||
|
||||
impl DatabaseImpl { |
||||
pub(crate) fn new(flags: Option<DatabaseFlagsImpl>, snapshot: Option<Snapshot>) -> DatabaseImpl { |
||||
DatabaseImpl { |
||||
id: Uuid::new_v4(), |
||||
flags: flags.unwrap_or_else(DatabaseFlagsImpl::default), |
||||
snapshot: Arc::new(RwLock::new(snapshot.unwrap_or_else(Snapshot::new))), |
||||
} |
||||
} |
||||
|
||||
pub(crate) fn id(&self) -> &Uuid { |
||||
&self.id |
||||
} |
||||
|
||||
pub(crate) fn flags(&self) -> &DatabaseFlagsImpl { |
||||
&self.flags |
||||
} |
||||
|
||||
pub(crate) fn snapshot(&self) -> Result<Snapshot, ErrorImpl> { |
||||
let snapshot = self.snapshot.read().map_err(|_| ErrorImpl::TxnPoisonError)?; |
||||
Ok(snapshot.clone()) |
||||
} |
||||
|
||||
pub(crate) fn replace(&mut self, value: Snapshot) -> Result<Snapshot, ErrorImpl> { |
||||
let mut snapshot = self.snapshot.write().map_err(|_| ErrorImpl::TxnPoisonError)?; |
||||
Ok(std::mem::replace(&mut snapshot, value)) |
||||
} |
||||
} |
||||
|
||||
impl BackendDatabase for DatabaseImpl {} |
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)] |
||||
pub struct Snapshot { |
||||
map: HashMap<Box<[u8]>, BTreeSet<Box<[u8]>>>, |
||||
} |
||||
|
||||
impl Snapshot { |
||||
pub(crate) fn new() -> Snapshot { |
||||
Snapshot { |
||||
map: HashMap::new(), |
||||
} |
||||
} |
||||
|
||||
pub(crate) fn get(&self, key: &[u8]) -> Option<&[u8]> { |
||||
self.map.get(key).and_then(|v| v.iter().next()).map(|v| v.as_ref()) |
||||
} |
||||
|
||||
pub(crate) fn put_one(&mut self, key: &[u8], value: &[u8]) { |
||||
let values = self.map.entry(Box::from(key)).or_insert_with(BTreeSet::new); |
||||
values.clear(); |
||||
values.insert(Box::from(value)); |
||||
} |
||||
|
||||
pub(crate) fn put_dup(&mut self, key: &[u8], value: &[u8]) { |
||||
let values = self.map.entry(Box::from(key)).or_insert_with(BTreeSet::new); |
||||
values.insert(Box::from(value)); |
||||
} |
||||
|
||||
pub(crate) fn del_exact(&mut self, key: &[u8], value: &[u8]) -> Option<()> { |
||||
let values = self.map.entry(Box::from(key)).or_insert_with(BTreeSet::new); |
||||
let was_removed = values.remove(value); |
||||
Some(()).filter(|_| was_removed) |
||||
} |
||||
|
||||
pub(crate) fn del_all(&mut self, key: &[u8]) -> Option<()> { |
||||
let values = self.map.entry(Box::from(key)).or_insert_with(BTreeSet::new); |
||||
let was_empty = values.is_empty(); |
||||
values.clear(); |
||||
Some(()).filter(|_| !was_empty) |
||||
} |
||||
|
||||
pub(crate) fn clear(&mut self) { |
||||
self.map.clear(); |
||||
} |
||||
|
||||
pub(crate) fn iter(&self) -> impl Iterator<Item = (&[u8], &[u8])> { |
||||
self.map.iter().flat_map(|(key, values)| values.iter().map(move |value| (key.as_ref(), value.as_ref()))) |
||||
} |
||||
} |
@ -0,0 +1,186 @@ |
||||
// Copyright 2018-2019 Mozilla
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use
|
||||
// this file except in compliance with the License. You may obtain a copy of the
|
||||
// License at http://www.apache.org/licenses/LICENSE-2.0
|
||||
// Unless required by applicable law or agreed to in writing, software distributed
|
||||
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations under the License.
|
||||
|
||||
use std::borrow::Cow; |
||||
use std::collections::HashMap; |
||||
use std::fs; |
||||
use std::path::{ |
||||
Path, |
||||
PathBuf, |
||||
}; |
||||
use std::sync::{ |
||||
RwLock, |
||||
RwLockReadGuard, |
||||
RwLockWriteGuard, |
||||
}; |
||||
|
||||
use log::warn; |
||||
|
||||
use super::{ |
||||
DatabaseFlagsImpl, |
||||
DatabaseImpl, |
||||
EnvironmentFlagsImpl, |
||||
ErrorImpl, |
||||
InfoImpl, |
||||
RoTransactionImpl, |
||||
RwTransactionImpl, |
||||
StatImpl, |
||||
}; |
||||
use crate::backend::traits::{ |
||||
BackendEnvironment, |
||||
BackendEnvironmentBuilder, |
||||
}; |
||||
|
||||
const DEFAULT_DB_FILENAME: &str = "data.safe.bin"; |
||||
|
||||
#[derive(Debug, PartialEq, Eq, Copy, Clone)] |
||||
pub struct EnvironmentBuilderImpl { |
||||
flags: EnvironmentFlagsImpl, |
||||
} |
||||
|
||||
impl<'env> BackendEnvironmentBuilder<'env> for EnvironmentBuilderImpl { |
||||
type Error = ErrorImpl; |
||||
type Environment = EnvironmentImpl; |
||||
type Flags = EnvironmentFlagsImpl; |
||||
|
||||
fn new() -> EnvironmentBuilderImpl { |
||||
EnvironmentBuilderImpl { |
||||
flags: EnvironmentFlagsImpl::empty(), |
||||
} |
||||
} |
||||
|
||||
fn set_flags<T>(&mut self, flags: T) -> &mut Self |
||||
where |
||||
T: Into<Self::Flags>, |
||||
{ |
||||
self.flags = flags.into(); |
||||
self |
||||
} |
||||
|
||||
fn set_max_readers(&mut self, max_readers: u32) -> &mut Self { |
||||
warn!("Ignoring `set_max_readers({})`", max_readers); |
||||
self |
||||
} |
||||
|
||||
fn set_max_dbs(&mut self, max_dbs: u32) -> &mut Self { |
||||
warn!("Ignoring `set_max_dbs({})`", max_dbs); |
||||
self |
||||
} |
||||
|
||||
fn set_map_size(&mut self, size: usize) -> &mut Self { |
||||
warn!("Ignoring `set_map_size({})`", size); |
||||
self |
||||
} |
||||
|
||||
fn open(&self, path: &Path) -> Result<Self::Environment, Self::Error> { |
||||
let mut env = EnvironmentImpl::new(path, self.flags)?; |
||||
env.read_from_disk()?; |
||||
Ok(env) |
||||
} |
||||
} |
||||
|
||||
#[derive(Debug)] |
||||
pub struct EnvironmentImpl { |
||||
path: PathBuf, |
||||
dbs: RwLock<HashMap<Option<String>, DatabaseImpl>>, |
||||
} |
||||
|
||||
impl EnvironmentImpl { |
||||
pub(crate) fn new(path: &Path, _flags: EnvironmentFlagsImpl) -> Result<EnvironmentImpl, ErrorImpl> { |
||||
Ok(EnvironmentImpl { |
||||
path: path.to_path_buf(), |
||||
dbs: RwLock::new(HashMap::new()), |
||||
}) |
||||
} |
||||
|
||||
pub(crate) fn read_from_disk(&mut self) -> Result<(), ErrorImpl> { |
||||
let mut path = Cow::from(&self.path); |
||||
if fs::metadata(&path)?.is_dir() { |
||||
path.to_mut().push(DEFAULT_DB_FILENAME); |
||||
}; |
||||
if fs::metadata(&path).is_err() { |
||||
fs::write(&path, bincode::serialize(&self.dbs)?)?; |
||||
}; |
||||
let serialized = fs::read(&path)?; |
||||
self.dbs = bincode::deserialize(&serialized)?; |
||||
Ok(()) |
||||
} |
||||
|
||||
pub(crate) fn write_to_disk(&self) -> Result<(), ErrorImpl> { |
||||
let mut path = Cow::from(&self.path); |
||||
if fs::metadata(&path)?.is_dir() { |
||||
path.to_mut().push(DEFAULT_DB_FILENAME); |
||||
}; |
||||
fs::write(&path, bincode::serialize(&self.dbs)?)?; |
||||
Ok(()) |
||||
} |
||||
|
||||
pub(crate) fn dbs(&self) -> Result<RwLockReadGuard<HashMap<Option<String>, DatabaseImpl>>, ErrorImpl> { |
||||
self.dbs.read().map_err(|_| ErrorImpl::DbPoisonError) |
||||
} |
||||
|
||||
pub(crate) fn dbs_mut(&self) -> Result<RwLockWriteGuard<HashMap<Option<String>, DatabaseImpl>>, ErrorImpl> { |
||||
self.dbs.write().map_err(|_| ErrorImpl::DbPoisonError) |
||||
} |
||||
} |
||||
|
||||
impl<'env> BackendEnvironment<'env> for EnvironmentImpl { |
||||
type Error = ErrorImpl; |
||||
type Database = DatabaseImpl; |
||||
type Flags = DatabaseFlagsImpl; |
||||
type Stat = StatImpl; |
||||
type Info = InfoImpl; |
||||
type RoTransaction = RoTransactionImpl<'env>; |
||||
type RwTransaction = RwTransactionImpl<'env>; |
||||
|
||||
fn open_db(&self, name: Option<&str>) -> Result<Self::Database, Self::Error> { |
||||
// TOOD: don't reallocate `name`.
|
||||
let dbs = self.dbs.read().map_err(|_| ErrorImpl::DbPoisonError)?; |
||||
let db = dbs.get(&name.map(String::from)).ok_or(ErrorImpl::DbNotFoundError)?.clone(); |
||||
Ok(db) |
||||
} |
||||
|
||||
fn create_db(&self, name: Option<&str>, flags: Self::Flags) -> Result<Self::Database, Self::Error> { |
||||
// TOOD: don't reallocate `name`.
|
||||
let mut dbs = self.dbs.write().map_err(|_| ErrorImpl::DbPoisonError)?; |
||||
let db = dbs.entry(name.map(String::from)).or_insert_with(|| DatabaseImpl::new(Some(flags), None)).clone(); |
||||
Ok(db) |
||||
} |
||||
|
||||
fn begin_ro_txn(&'env self) -> Result<Self::RoTransaction, Self::Error> { |
||||
RoTransactionImpl::new(self) |
||||
} |
||||
|
||||
fn begin_rw_txn(&'env self) -> Result<Self::RwTransaction, Self::Error> { |
||||
RwTransactionImpl::new(self) |
||||
} |
||||
|
||||
fn sync(&self, force: bool) -> Result<(), Self::Error> { |
||||
warn!("Ignoring `force={}`", force); |
||||
self.write_to_disk() |
||||
} |
||||
|
||||
fn stat(&self) -> Result<Self::Stat, Self::Error> { |
||||
Ok(StatImpl) |
||||
} |
||||
|
||||
fn info(&self) -> Result<Self::Info, Self::Error> { |
||||
Ok(InfoImpl) |
||||
} |
||||
|
||||
fn freelist(&self) -> Result<usize, Self::Error> { |
||||
unimplemented!() |
||||
} |
||||
|
||||
fn set_map_size(&self, size: usize) -> Result<(), Self::Error> { |
||||
warn!("Ignoring `set_map_size({})`", size); |
||||
Ok(()) |
||||
} |
||||
} |
@ -0,0 +1,65 @@ |
||||
// Copyright 2018-2019 Mozilla
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use
|
||||
// this file except in compliance with the License. You may obtain a copy of the
|
||||
// License at http://www.apache.org/licenses/LICENSE-2.0
|
||||
// Unless required by applicable law or agreed to in writing, software distributed
|
||||
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations under the License.
|
||||
|
||||
use std::fmt; |
||||
use std::io; |
||||
|
||||
use bincode::Error as BincodeError; |
||||
|
||||
use crate::backend::traits::BackendError; |
||||
use crate::error::StoreError; |
||||
|
||||
#[derive(Debug)] |
||||
pub enum ErrorImpl { |
||||
KeyValuePairNotFound, |
||||
DbPoisonError, |
||||
DbNotFoundError, |
||||
DbIsForeignError, |
||||
TxnPoisonError, |
||||
IoError(io::Error), |
||||
BincodeError(BincodeError), |
||||
} |
||||
|
||||
impl BackendError for ErrorImpl {} |
||||
|
||||
impl fmt::Display for ErrorImpl { |
||||
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { |
||||
match self { |
||||
ErrorImpl::KeyValuePairNotFound => write!(fmt, "KeyValuePairNotFound (safe mode)"), |
||||
ErrorImpl::DbPoisonError => write!(fmt, "DbPoisonError (safe mode)"), |
||||
ErrorImpl::DbNotFoundError => write!(fmt, "DbNotFoundError (safe mode)"), |
||||
ErrorImpl::DbIsForeignError => write!(fmt, "DbIsForeignError (safe mode)"), |
||||
ErrorImpl::TxnPoisonError => write!(fmt, "TxnPoisonError (safe mode)"), |
||||
ErrorImpl::IoError(e) => e.fmt(fmt), |
||||
ErrorImpl::BincodeError(e) => e.fmt(fmt), |
||||
} |
||||
} |
||||
} |
||||
|
||||
impl Into<StoreError> for ErrorImpl { |
||||
fn into(self) -> StoreError { |
||||
match self { |
||||
ErrorImpl::KeyValuePairNotFound => StoreError::KeyValuePairNotFound, |
||||
_ => StoreError::SafeModeError(self), |
||||
} |
||||
} |
||||
} |
||||
|
||||
impl From<io::Error> for ErrorImpl { |
||||
fn from(e: io::Error) -> ErrorImpl { |
||||
ErrorImpl::IoError(e) |
||||
} |
||||
} |
||||
|
||||
impl From<BincodeError> for ErrorImpl { |
||||
fn from(e: BincodeError) -> ErrorImpl { |
||||
ErrorImpl::BincodeError(e) |
||||
} |
||||
} |
@ -0,0 +1,128 @@ |
||||
// Copyright 2018-2019 Mozilla
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use
|
||||
// this file except in compliance with the License. You may obtain a copy of the
|
||||
// License at http://www.apache.org/licenses/LICENSE-2.0
|
||||
// Unless required by applicable law or agreed to in writing, software distributed
|
||||
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations under the License.
|
||||
|
||||
use bitflags::bitflags; |
||||
use serde_derive::{ |
||||
Deserialize, |
||||
Serialize, |
||||
}; |
||||
|
||||
use crate::backend::common::{ |
||||
DatabaseFlags, |
||||
EnvironmentFlags, |
||||
WriteFlags, |
||||
}; |
||||
use crate::backend::traits::{ |
||||
BackendDatabaseFlags, |
||||
BackendEnvironmentFlags, |
||||
BackendFlags, |
||||
BackendWriteFlags, |
||||
}; |
||||
|
||||
bitflags! { |
||||
#[derive(Default, Serialize, Deserialize)] |
||||
pub struct EnvironmentFlagsImpl: u32 { |
||||
const NIL = 0b0000_0000; |
||||
} |
||||
} |
||||
|
||||
impl BackendFlags for EnvironmentFlagsImpl { |
||||
fn empty() -> EnvironmentFlagsImpl { |
||||
EnvironmentFlagsImpl::empty() |
||||
} |
||||
} |
||||
|
||||
impl BackendEnvironmentFlags for EnvironmentFlagsImpl { |
||||
fn set(&mut self, flag: EnvironmentFlags, value: bool) { |
||||
self.set(flag.into(), value) |
||||
} |
||||
} |
||||
|
||||
impl Into<EnvironmentFlagsImpl> for EnvironmentFlags { |
||||
fn into(self) -> EnvironmentFlagsImpl { |
||||
match self { |
||||
EnvironmentFlags::FIXED_MAP => unimplemented!(), |
||||
EnvironmentFlags::NO_SUB_DIR => unimplemented!(), |
||||
EnvironmentFlags::WRITE_MAP => unimplemented!(), |
||||
EnvironmentFlags::READ_ONLY => unimplemented!(), |
||||
EnvironmentFlags::NO_META_SYNC => unimplemented!(), |
||||
EnvironmentFlags::NO_SYNC => unimplemented!(), |
||||
EnvironmentFlags::MAP_ASYNC => unimplemented!(), |
||||
EnvironmentFlags::NO_TLS => unimplemented!(), |
||||
EnvironmentFlags::NO_LOCK => unimplemented!(), |
||||
EnvironmentFlags::NO_READAHEAD => unimplemented!(), |
||||
EnvironmentFlags::NO_MEM_INIT => unimplemented!(), |
||||
} |
||||
} |
||||
} |
||||
|
||||
bitflags! { |
||||
#[derive(Default, Serialize, Deserialize)] |
||||
pub struct DatabaseFlagsImpl: u32 { |
||||
const DUP_SORT = 0b0000_0001; |
||||
const INTEGER_KEY = 0b0000_0010; |
||||
} |
||||
} |
||||
|
||||
impl BackendFlags for DatabaseFlagsImpl { |
||||
fn empty() -> DatabaseFlagsImpl { |
||||
DatabaseFlagsImpl::empty() |
||||
} |
||||
} |
||||
|
||||
impl BackendDatabaseFlags for DatabaseFlagsImpl { |
||||
fn set(&mut self, flag: DatabaseFlags, value: bool) { |
||||
self.set(flag.into(), value) |
||||
} |
||||
} |
||||
|
||||
impl Into<DatabaseFlagsImpl> for DatabaseFlags { |
||||
fn into(self) -> DatabaseFlagsImpl { |
||||
match self { |
||||
DatabaseFlags::REVERSE_KEY => unimplemented!(), |
||||
DatabaseFlags::DUP_SORT => DatabaseFlagsImpl::DUP_SORT, |
||||
DatabaseFlags::INTEGER_KEY => DatabaseFlagsImpl::INTEGER_KEY, |
||||
DatabaseFlags::DUP_FIXED => unimplemented!(), |
||||
DatabaseFlags::INTEGER_DUP => unimplemented!(), |
||||
DatabaseFlags::REVERSE_DUP => unimplemented!(), |
||||
} |
||||
} |
||||
} |
||||
|
||||
bitflags! { |
||||
#[derive(Default, Serialize, Deserialize)] |
||||
pub struct WriteFlagsImpl: u32 { |
||||
const NIL = 0b0000_0000; |
||||
} |
||||
} |
||||
|
||||
impl BackendFlags for WriteFlagsImpl { |
||||
fn empty() -> WriteFlagsImpl { |
||||
WriteFlagsImpl::empty() |
||||
} |
||||
} |
||||
|
||||
impl BackendWriteFlags for WriteFlagsImpl { |
||||
fn set(&mut self, flag: WriteFlags, value: bool) { |
||||
self.set(flag.into(), value) |
||||
} |
||||
} |
||||
|
||||
impl Into<WriteFlagsImpl> for WriteFlags { |
||||
fn into(self) -> WriteFlagsImpl { |
||||
match self { |
||||
WriteFlags::NO_OVERWRITE => unimplemented!(), |
||||
WriteFlags::NO_DUP_DATA => unimplemented!(), |
||||
WriteFlags::CURRENT => unimplemented!(), |
||||
WriteFlags::APPEND => unimplemented!(), |
||||
WriteFlags::APPEND_DUP => unimplemented!(), |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,35 @@ |
||||
// Copyright 2018-2019 Mozilla
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use
|
||||
// this file except in compliance with the License. You may obtain a copy of the
|
||||
// License at http://www.apache.org/licenses/LICENSE-2.0
|
||||
// Unless required by applicable law or agreed to in writing, software distributed
|
||||
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations under the License.
|
||||
|
||||
use crate::backend::traits::BackendInfo; |
||||
|
||||
pub struct InfoImpl; |
||||
|
||||
impl BackendInfo for InfoImpl { |
||||
fn map_size(&self) -> usize { |
||||
unimplemented!() |
||||
} |
||||
|
||||
fn last_pgno(&self) -> usize { |
||||
unimplemented!() |
||||
} |
||||
|
||||
fn last_txnid(&self) -> usize { |
||||
unimplemented!() |
||||
} |
||||
|
||||
fn max_readers(&self) -> usize { |
||||
unimplemented!() |
||||
} |
||||
|
||||
fn num_readers(&self) -> usize { |
||||
unimplemented!() |
||||
} |
||||
} |
@ -0,0 +1,24 @@ |
||||
// Copyright 2018-2019 Mozilla
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use
|
||||
// this file except in compliance with the License. You may obtain a copy of the
|
||||
// License at http://www.apache.org/licenses/LICENSE-2.0
|
||||
// Unless required by applicable law or agreed to in writing, software distributed
|
||||
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations under the License.
|
||||
|
||||
use super::ErrorImpl; |
||||
use crate::backend::traits::BackendIter; |
||||
|
||||
// FIXME: Use generics instead.
|
||||
pub struct IterImpl<'env>(pub(crate) Box<dyn Iterator<Item = (&'env [u8], &'env [u8])> + 'env>); |
||||
|
||||
impl<'env> BackendIter<'env> for IterImpl<'env> { |
||||
type Error = ErrorImpl; |
||||
|
||||
#[allow(clippy::type_complexity)] |
||||
fn next(&mut self) -> Option<Result<(&'env [u8], &'env [u8]), Self::Error>> { |
||||
self.0.next().map(Ok) |
||||
} |
||||
} |
@ -0,0 +1,39 @@ |
||||
// Copyright 2018-2019 Mozilla
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use
|
||||
// this file except in compliance with the License. You may obtain a copy of the
|
||||
// License at http://www.apache.org/licenses/LICENSE-2.0
|
||||
// Unless required by applicable law or agreed to in writing, software distributed
|
||||
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations under the License.
|
||||
|
||||
use crate::backend::traits::BackendStat; |
||||
|
||||
pub struct StatImpl; |
||||
|
||||
impl BackendStat for StatImpl { |
||||
fn page_size(&self) -> usize { |
||||
unimplemented!() |
||||
} |
||||
|
||||
fn depth(&self) -> usize { |
||||
unimplemented!() |
||||
} |
||||
|
||||
fn branch_pages(&self) -> usize { |
||||
unimplemented!() |
||||
} |
||||
|
||||
fn leaf_pages(&self) -> usize { |
||||
unimplemented!() |
||||
} |
||||
|
||||
fn overflow_pages(&self) -> usize { |
||||
unimplemented!() |
||||
} |
||||
|
||||
fn entries(&self) -> usize { |
||||
unimplemented!() |
||||
} |
||||
} |
@ -0,0 +1,159 @@ |
||||
// Copyright 2018-2019 Mozilla
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use
|
||||
// this file except in compliance with the License. You may obtain a copy of the
|
||||
// License at http://www.apache.org/licenses/LICENSE-2.0
|
||||
// Unless required by applicable law or agreed to in writing, software distributed
|
||||
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations under the License.
|
||||
|
||||
use std::collections::HashMap; |
||||
|
||||
use uuid::Uuid; |
||||
|
||||
use super::{ |
||||
database::Snapshot, |
||||
DatabaseFlagsImpl, |
||||
DatabaseImpl, |
||||
EnvironmentImpl, |
||||
ErrorImpl, |
||||
RoCursorImpl, |
||||
WriteFlagsImpl, |
||||
}; |
||||
use crate::backend::traits::{ |
||||
BackendRoCursorTransaction, |
||||
BackendRoTransaction, |
||||
BackendRwCursorTransaction, |
||||
BackendRwTransaction, |
||||
}; |
||||
|
||||
#[derive(Debug)] |
||||
pub struct RoTransactionImpl<'env> { |
||||
env: &'env EnvironmentImpl, |
||||
snapshots: HashMap<Uuid, Result<Snapshot, ErrorImpl>>, |
||||
} |
||||
|
||||
impl<'env> RoTransactionImpl<'env> { |
||||
pub(crate) fn new(env: &'env EnvironmentImpl) -> Result<RoTransactionImpl<'env>, ErrorImpl> { |
||||
let snapshots = env.dbs()?.iter().map(|(_, db)| (*db.id(), db.snapshot())).collect(); |
||||
Ok(RoTransactionImpl { |
||||
env, |
||||
snapshots, |
||||
}) |
||||
} |
||||
} |
||||
|
||||
impl<'env> BackendRoTransaction for RoTransactionImpl<'env> { |
||||
type Error = ErrorImpl; |
||||
type Database = DatabaseImpl; |
||||
type Flags = WriteFlagsImpl; |
||||
|
||||
fn get(&self, db: &Self::Database, key: &[u8]) -> Result<&[u8], Self::Error> { |
||||
let snapshot = self.snapshots.get(db.id()).ok_or_else(|| ErrorImpl::DbIsForeignError)?; |
||||
let data = snapshot.as_ref().map_err(|_| ErrorImpl::TxnPoisonError)?; |
||||
data.get(key).ok_or_else(|| ErrorImpl::KeyValuePairNotFound) |
||||
} |
||||
|
||||
fn abort(self) { |
||||
// noop
|
||||
} |
||||
} |
||||
|
||||
impl<'env> BackendRoCursorTransaction<'env> for RoTransactionImpl<'env> { |
||||
type RoCursor = RoCursorImpl<'env>; |
||||
|
||||
fn open_ro_cursor(&'env self, db: &Self::Database) -> Result<Self::RoCursor, Self::Error> { |
||||
let snapshot = self.snapshots.get(db.id()).ok_or_else(|| ErrorImpl::DbIsForeignError)?; |
||||
let data = snapshot.as_ref().map_err(|_| ErrorImpl::TxnPoisonError)?; |
||||
Ok(RoCursorImpl(data)) |
||||
} |
||||
} |
||||
|
||||
#[derive(Debug)] |
||||
pub struct RwTransactionImpl<'env> { |
||||
env: &'env EnvironmentImpl, |
||||
snapshots: HashMap<Uuid, Result<Snapshot, ErrorImpl>>, |
||||
} |
||||
|
||||
impl<'env> RwTransactionImpl<'env> { |
||||
pub(crate) fn new(env: &'env EnvironmentImpl) -> Result<RwTransactionImpl<'env>, ErrorImpl> { |
||||
let snapshots = env.dbs()?.iter().map(|(_, db)| (*db.id(), db.snapshot())).collect(); |
||||
Ok(RwTransactionImpl { |
||||
env, |
||||
snapshots, |
||||
}) |
||||
} |
||||
} |
||||
|
||||
impl<'env> BackendRwTransaction for RwTransactionImpl<'env> { |
||||
type Error = ErrorImpl; |
||||
type Database = DatabaseImpl; |
||||
type Flags = WriteFlagsImpl; |
||||
|
||||
fn get(&self, db: &Self::Database, key: &[u8]) -> Result<&[u8], Self::Error> { |
||||
let snapshot = self.snapshots.get(db.id()).ok_or_else(|| ErrorImpl::DbIsForeignError)?; |
||||
let data = snapshot.as_ref().map_err(|_| ErrorImpl::TxnPoisonError)?; |
||||
data.get(key).ok_or_else(|| ErrorImpl::KeyValuePairNotFound) |
||||
} |
||||
|
||||
fn put(&mut self, db: &Self::Database, key: &[u8], value: &[u8], _flags: Self::Flags) -> Result<(), Self::Error> { |
||||
let snapshot = self.snapshots.get_mut(db.id()).ok_or_else(|| ErrorImpl::DbIsForeignError)?; |
||||
let data = snapshot.as_mut().map_err(|_| ErrorImpl::TxnPoisonError)?; |
||||
if db.flags().contains(DatabaseFlagsImpl::DUP_SORT) { |
||||
data.put_dup(key, value); |
||||
} else { |
||||
data.put_one(key, value); |
||||
} |
||||
Ok(()) |
||||
} |
||||
|
||||
fn del(&mut self, db: &Self::Database, key: &[u8], value: Option<&[u8]>) -> Result<(), Self::Error> { |
||||
let snapshot = self.snapshots.get_mut(db.id()).ok_or_else(|| ErrorImpl::DbIsForeignError)?; |
||||
let data = snapshot.as_mut().map_err(|_| ErrorImpl::TxnPoisonError)?; |
||||
let deleted = match (value, db.flags()) { |
||||
(Some(value), flags) if flags.contains(DatabaseFlagsImpl::DUP_SORT) => data.del_exact(key, value), |
||||
_ => data.del_all(key), |
||||
}; |
||||
Ok(deleted.ok_or_else(|| ErrorImpl::KeyValuePairNotFound)?) |
||||
} |
||||
|
||||
fn clear_db(&mut self, db: &Self::Database) -> Result<(), Self::Error> { |
||||
let snapshot = self.snapshots.get_mut(db.id()).ok_or_else(|| ErrorImpl::DbIsForeignError)?; |
||||
let data = snapshot.as_mut().map_err(|_| ErrorImpl::TxnPoisonError)?; |
||||
data.clear(); |
||||
Ok(()) |
||||
} |
||||
|
||||
fn commit(self) -> Result<(), Self::Error> { |
||||
let mut dbs = self.env.dbs_mut()?; |
||||
|
||||
for (id, snapshot) in self.snapshots { |
||||
match dbs.iter_mut().find(|(_, db)| db.id() == &id) { |
||||
Some((_, db)) => { |
||||
db.replace(snapshot?)?; |
||||
}, |
||||
None => { |
||||
unreachable!(); |
||||
}, |
||||
} |
||||
} |
||||
|
||||
drop(dbs); |
||||
self.env.write_to_disk() |
||||
} |
||||
|
||||
fn abort(self) { |
||||
// noop
|
||||
} |
||||
} |
||||
|
||||
impl<'env> BackendRwCursorTransaction<'env> for RwTransactionImpl<'env> { |
||||
type RoCursor = RoCursorImpl<'env>; |
||||
|
||||
fn open_ro_cursor(&'env self, db: &Self::Database) -> Result<Self::RoCursor, Self::Error> { |
||||
let snapshot = self.snapshots.get(db.id()).ok_or_else(|| ErrorImpl::DbIsForeignError)?; |
||||
let data = snapshot.as_ref().map_err(|_| ErrorImpl::TxnPoisonError)?; |
||||
Ok(RoCursorImpl(data)) |
||||
} |
||||
} |
Loading…
Reference in new issue