Fork of https://github.com/oxigraph/oxigraph.git for the purpose of NextGraph project
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
174 lines
4.7 KiB
174 lines
4.7 KiB
use std::collections::btree_map::Entry;
|
|
use std::collections::BTreeMap;
|
|
use std::io::Result;
|
|
use std::sync::{Arc, Mutex, RwLock};
|
|
|
|
#[derive(Clone)]
|
|
pub struct Db {
|
|
trees: Arc<Mutex<BTreeMap<&'static str, Tree>>>,
|
|
default: Tree,
|
|
}
|
|
|
|
impl Db {
|
|
pub fn new() -> Result<Self> {
|
|
Ok(Self {
|
|
trees: Arc::default(),
|
|
default: Tree::new(),
|
|
})
|
|
}
|
|
|
|
pub fn open_tree(&self, name: &'static str) -> Result<Tree> {
|
|
Ok(self
|
|
.trees
|
|
.lock()
|
|
.unwrap()
|
|
.entry(name)
|
|
.or_insert_with(Tree::new)
|
|
.clone())
|
|
}
|
|
|
|
pub fn flush(&self) -> Result<()> {
|
|
Ok(())
|
|
}
|
|
|
|
pub fn get(&self, key: &[u8]) -> Result<Option<Vec<u8>>> {
|
|
self.default.get(key)
|
|
}
|
|
|
|
pub fn insert(&self, key: &[u8], value: impl Into<Vec<u8>>) -> Result<bool> {
|
|
self.default.insert(key.into(), value)
|
|
}
|
|
}
|
|
#[derive(Clone)]
|
|
pub struct Tree {
|
|
tree: Arc<RwLock<BTreeMap<Vec<u8>, Vec<u8>>>>,
|
|
merge_operator: Arc<dyn Fn(&[u8], Option<&[u8]>, &[u8]) -> Option<Vec<u8>> + 'static>,
|
|
}
|
|
|
|
impl Tree {
|
|
fn new() -> Self {
|
|
Self {
|
|
tree: Arc::default(),
|
|
merge_operator: Arc::new(|_, _, v| Some(v.into())),
|
|
}
|
|
}
|
|
pub fn get(&self, key: &[u8]) -> Result<Option<Vec<u8>>> {
|
|
Ok(
|
|
self.tree.read().unwrap().get(key).map(|v| v.clone()), //TODO: avoid clone
|
|
)
|
|
}
|
|
|
|
pub fn contains_key(&self, key: &[u8]) -> Result<bool> {
|
|
Ok(self.tree.read().unwrap().contains_key(key.as_ref()))
|
|
}
|
|
|
|
pub fn insert(&self, key: &[u8], value: impl Into<Vec<u8>>) -> Result<bool> {
|
|
Ok(self
|
|
.tree
|
|
.write()
|
|
.unwrap()
|
|
.insert(key.into(), value.into())
|
|
.is_none())
|
|
}
|
|
|
|
pub fn insert_empty(&self, key: &[u8]) -> Result<bool> {
|
|
self.insert(key, [])
|
|
}
|
|
|
|
pub fn merge(&self, key: &[u8], value: &[u8]) -> Result<()> {
|
|
match self.tree.write().unwrap().entry(key.into()) {
|
|
Entry::Occupied(e) => match (self.merge_operator)(key.as_ref(), Some(e.get()), value) {
|
|
Some(v) => {
|
|
*e.into_mut() = v;
|
|
}
|
|
None => {
|
|
e.remove();
|
|
}
|
|
},
|
|
Entry::Vacant(e) => {
|
|
if let Some(v) = (self.merge_operator)(key.as_ref(), None, value) {
|
|
e.insert(v);
|
|
}
|
|
}
|
|
}
|
|
Ok(())
|
|
}
|
|
|
|
pub fn remove(&self, key: &[u8]) -> Result<bool> {
|
|
Ok(self.tree.write().unwrap().remove(key.as_ref()).is_some())
|
|
}
|
|
|
|
pub fn update_and_fetch<V: Into<Vec<u8>>>(
|
|
&self,
|
|
key: &[u8],
|
|
mut f: impl FnMut(Option<&[u8]>) -> Option<V>,
|
|
) -> Result<Option<Vec<u8>>> {
|
|
Ok(match self.tree.write().unwrap().entry(key.into()) {
|
|
Entry::Occupied(e) => match f(Some(e.get())) {
|
|
Some(v) => {
|
|
let v = v.into();
|
|
let e_mut = e.into_mut();
|
|
e_mut.clear();
|
|
e_mut.extend_from_slice(&v);
|
|
Some(v)
|
|
}
|
|
None => {
|
|
e.remove();
|
|
None
|
|
}
|
|
},
|
|
Entry::Vacant(e) => match f(None) {
|
|
Some(v) => {
|
|
let v = v.into();
|
|
e.insert(v.clone());
|
|
Some(v)
|
|
}
|
|
None => None,
|
|
},
|
|
})
|
|
}
|
|
|
|
pub fn clear(&self) -> Result<()> {
|
|
Ok(self.tree.write().unwrap().clear())
|
|
}
|
|
|
|
pub fn iter(&self) -> Iter {
|
|
self.scan_prefix(&[])
|
|
}
|
|
|
|
pub fn scan_prefix(&self, prefix: &[u8]) -> Iter {
|
|
let tree = self.tree.read().unwrap();
|
|
let data: Vec<_> = if prefix.is_empty() {
|
|
tree.iter()
|
|
.map(|(k, v)| Ok((k.clone(), v.clone())))
|
|
.collect()
|
|
} else {
|
|
tree.range(prefix.to_vec()..)
|
|
.take_while(|(k, _)| k.starts_with(prefix))
|
|
.map(|(k, v)| Ok((k.clone(), v.clone())))
|
|
.collect()
|
|
};
|
|
data.into_iter()
|
|
}
|
|
|
|
pub fn len(&self) -> usize {
|
|
self.tree.read().unwrap().len()
|
|
}
|
|
|
|
pub fn is_empty(&self) -> bool {
|
|
self.tree.read().unwrap().is_empty()
|
|
}
|
|
|
|
pub fn flush(&self) -> Result<()> {
|
|
Ok(())
|
|
}
|
|
|
|
pub fn set_merge_operator(
|
|
&mut self,
|
|
merge_operator: impl Fn(&[u8], Option<&[u8]>, &[u8]) -> Option<Vec<u8>> + 'static,
|
|
) {
|
|
self.merge_operator = Arc::new(merge_operator)
|
|
}
|
|
}
|
|
|
|
pub type Iter = std::vec::IntoIter<Result<(Vec<u8>, Vec<u8>)>>;
|
|
|