add persy backend and make building optional

This commit is contained in:
Jonathan de Jong 2022-03-19 16:50:54 +01:00
parent 0e0a025c37
commit 805baa0705
6 changed files with 276 additions and 19 deletions

View file

@ -7,9 +7,16 @@ edition = "2018"
[dependencies]
itertools = "0.10.1"
sled = { version = "0.34.6", features = ["compression", "no_metrics"] }
rusqlite = { version = "0.25.3", features = ["bundled"] }
anyhow = "1.0.42"
heed = { git = "https://github.com/timokoesters/heed.git", rev = "f6f825da7fb2c758867e05ad973ef800a6fe1d5d" }
thiserror = "1.0.26"
rocksdb = { version = "0.17.0", features = ["multi-threaded-cf", "zstd"] }
anyhow = "1.0.42"
sled = { version = "0.34.6", features = ["compression", "no_metrics"], optional = true }
rusqlite = { version = "0.25.3", features = ["bundled"], optional = true }
heed = { git = "https://github.com/timokoesters/heed.git", rev = "f6f825da7fb2c758867e05ad973ef800a6fe1d5d", optional = true }
rocksdb = { version = "0.17.0", features = ["multi-threaded-cf", "zstd"], optional = true }
persy = { version = "1.2", optional = true }
[features]
default = ["sled", "persy", "heed", "sqlite", "rocksdb"]
sqlite = ["rusqlite"]

View file

@ -1,6 +1,12 @@
#[cfg(feature = "heed")]
pub mod heed;
#[cfg(feature = "persy")]
pub mod persy;
#[cfg(feature = "rocksdb")]
pub mod rocksdb;
#[cfg(feature = "sled")]
pub mod sled;
#[cfg(feature = "sqlite")]
pub mod sqlite;
use itertools::Itertools;

View file

@ -0,0 +1,98 @@
use super::{Database, KVIter, Segment, SegmentIter};
use persy::{ByteVec, Persy};
use std::path::Path;
pub fn new_db<P: AsRef<Path>>(path: P) -> anyhow::Result<PersyDB> {
let path = Path::new("./db.persy").join(path);
let persy = persy::OpenOptions::new()
.create(true)
.config(persy::Config::new())
.open(&path)?;
Ok(PersyDB { persy })
}
pub struct PersyDB {
persy: Persy,
}
impl Database for PersyDB {
fn names<'a>(&'a self) -> Vec<Vec<u8>> {
self.persy
.list_indexes()
.unwrap()
.iter()
.map(|(s, _)| s.as_bytes().to_vec())
.collect()
}
fn segment<'a>(&'a mut self, name: Vec<u8>) -> Option<Box<dyn Segment + 'a>> {
let string = String::from_utf8(name).unwrap();
if !self.persy.exists_index(&string).unwrap() {
use persy::ValueMode;
let mut tx = self.persy.begin().unwrap();
tx.create_index::<ByteVec, ByteVec>(&string, ValueMode::Replace)
.unwrap();
tx.prepare().unwrap().commit().unwrap();
}
Some(Box::new(PersySeg {
db: self,
name: string,
}))
}
fn flush(&mut self) {
// NOOP
}
}
pub struct PersySeg<'a> {
db: &'a mut PersyDB,
name: String,
}
impl<'r> Segment for PersySeg<'r> {
fn batch_insert<'a>(
&'a mut self,
batch: Box<dyn Iterator<Item = (Vec<u8>, Vec<u8>)> + 'a>,
) -> anyhow::Result<()> {
let mut tx = self.db.persy.begin()?;
for (key, value) in batch {
tx.put::<ByteVec, ByteVec>(
&self.name,
ByteVec::from(key.clone()),
ByteVec::from(value),
)?;
}
tx.prepare()?.commit()?;
Ok(())
}
fn get_iter<'a>(&'a mut self) -> Box<dyn SegmentIter + 'a> {
Box::new(PersySegIter(self, &self.name))
}
}
pub struct PersySegIter<'a>(&'a PersySeg<'a>, &'a str);
impl<'r> SegmentIter for PersySegIter<'r> {
fn iter<'a>(&'a mut self) -> KVIter<'a> {
Box::new(
self.0
.db
.persy
.range::<ByteVec, ByteVec, _>(self.1, ..)
.unwrap()
.filter_map(|(k, v)| {
v.into_iter()
.map(|val| ((*k).to_owned().into(), (*val).to_owned().into()))
.next()
}),
)
}
}