Drop copy and clone traits requirement on backend databases

Signed-off-by: Victor Porof <victor.porof@gmail.com>
without.crypto
Victor Porof 5 years ago
parent a4d76eb250
commit 2bb1436375
  1. 4
      examples/iterator.rs
  2. 8
      examples/simple-store.rs
  3. 2
      src/backend/impl_lmdb/database.rs
  4. 14
      src/backend/impl_lmdb/transaction.rs
  5. 16
      src/backend/traits.rs
  6. 14
      src/env.rs
  7. 18
      src/readwrite.rs
  8. 29
      src/store/multi.rs
  9. 25
      src/store/single.rs
  10. 14
      tests/test_txn.rs

@ -35,7 +35,7 @@ fn main() {
let k = created_arc.read().unwrap();
let store = k.open_single("store", StoreOptions::create()).unwrap();
populate_store(&k, store).unwrap();
populate_store(&k, &store).unwrap();
let reader = k.read().unwrap();
@ -64,7 +64,7 @@ fn main() {
}
}
fn populate_store(k: &Rkv<LmdbEnvironment>, store: SingleStore<LmdbDatabase>) -> Result<(), StoreError> {
fn populate_store(k: &Rkv<LmdbEnvironment>, store: &SingleStore<LmdbDatabase>) -> Result<(), StoreError> {
let mut writer = k.write()?;
for (country, city) in vec![
("Canada", Value::Str("Ottawa")),

@ -27,7 +27,7 @@ use rkv::{
type MultiStore = rkv::MultiStore<LmdbDatabase>;
type Writer<'env> = rkv::Writer<LmdbRwTransaction<'env>>;
fn getput<'env, 's>(store: MultiStore, writer: &'env mut Writer, ids: &'s mut Vec<String>) {
fn getput<'env, 's>(store: &MultiStore, writer: &'env mut Writer, ids: &'s mut Vec<String>) {
let keys = vec!["str1", "str2", "str3"];
// we convert the writer into a cursor so that we can safely read
for k in keys.iter() {
@ -46,7 +46,7 @@ fn getput<'env, 's>(store: MultiStore, writer: &'env mut Writer, ids: &'s mut Ve
}
}
fn delete(store: MultiStore, writer: &mut Writer) {
fn delete(store: &MultiStore, writer: &mut Writer) {
let keys = vec!["str1", "str2", "str3"];
let vals = vec!["string uno", "string quatro", "string siete"];
// we convert the writer into a cursor so that we can safely read
@ -96,10 +96,10 @@ fn main() {
multistore.put(&mut writer, "str3", &Value::Str("string siete")).unwrap();
multistore.put(&mut writer, "str3", &Value::Str("string ocho")).unwrap();
multistore.put(&mut writer, "str3", &Value::Str("string nueve")).unwrap();
getput(multistore, &mut writer, &mut ids);
getput(&multistore, &mut writer, &mut ids);
writer.commit().unwrap();
let mut writer = k.write().unwrap();
delete(multistore, &mut writer);
delete(&multistore, &mut writer);
writer.commit().unwrap();
}

@ -10,7 +10,7 @@
use crate::backend::traits::BackendDatabase;
#[derive(Debug, Eq, PartialEq, Copy, Clone)]
#[derive(Debug, Eq, PartialEq)]
pub struct DatabaseImpl(pub(crate) lmdb::Database);
impl BackendDatabase for DatabaseImpl {}

@ -31,7 +31,7 @@ impl<'env> BackendRoTransaction for RoTransactionImpl<'env> {
type Database = DatabaseImpl;
type Flags = WriteFlagsImpl;
fn get(&self, db: Self::Database, key: &[u8]) -> Result<&[u8], Self::Error> {
fn get(&self, db: &Self::Database, key: &[u8]) -> Result<&[u8], Self::Error> {
self.0.get(db.0, &key).map_err(ErrorImpl)
}
@ -43,7 +43,7 @@ impl<'env> BackendRoTransaction for RoTransactionImpl<'env> {
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> {
fn open_ro_cursor(&'env self, db: &Self::Database) -> Result<Self::RoCursor, Self::Error> {
self.0.open_ro_cursor(db.0).map(RoCursorImpl).map_err(ErrorImpl)
}
}
@ -56,19 +56,19 @@ impl<'env> BackendRwTransaction for RwTransactionImpl<'env> {
type Database = DatabaseImpl;
type Flags = WriteFlagsImpl;
fn get(&self, db: Self::Database, key: &[u8]) -> Result<&[u8], Self::Error> {
fn get(&self, db: &Self::Database, key: &[u8]) -> Result<&[u8], Self::Error> {
self.0.get(db.0, &key).map_err(ErrorImpl)
}
fn put(&mut self, db: Self::Database, key: &[u8], value: &[u8], flags: Self::Flags) -> Result<(), Self::Error> {
fn put(&mut self, db: &Self::Database, key: &[u8], value: &[u8], flags: Self::Flags) -> Result<(), Self::Error> {
self.0.put(db.0, &key, &value, flags.0).map_err(ErrorImpl)
}
fn del(&mut self, db: Self::Database, key: &[u8], value: Option<&[u8]>) -> Result<(), Self::Error> {
fn del(&mut self, db: &Self::Database, key: &[u8], value: Option<&[u8]>) -> Result<(), Self::Error> {
self.0.del(db.0, &key, value).map_err(ErrorImpl)
}
fn clear_db(&mut self, db: Self::Database) -> Result<(), Self::Error> {
fn clear_db(&mut self, db: &Self::Database) -> Result<(), Self::Error> {
self.0.clear_db(db.0).map_err(ErrorImpl)
}
@ -84,7 +84,7 @@ impl<'env> BackendRwTransaction for RwTransactionImpl<'env> {
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> {
fn open_ro_cursor(&'env self, db: &Self::Database) -> Result<Self::RoCursor, Self::Error> {
self.0.open_ro_cursor(db.0).map(RoCursorImpl).map_err(ErrorImpl)
}
}

@ -23,7 +23,7 @@ use crate::error::StoreError;
pub trait BackendError: Debug + Display + Into<StoreError> {}
pub trait BackendDatabase: Debug + Eq + PartialEq + Copy + Clone {}
pub trait BackendDatabase: Debug + Eq + PartialEq {}
pub trait BackendFlags: Debug + Eq + PartialEq + Copy + Clone + Default {
fn empty() -> Self;
@ -120,7 +120,7 @@ pub trait BackendRoTransaction: Debug {
type Database: BackendDatabase;
type Flags: BackendWriteFlags;
fn get(&self, db: Self::Database, key: &[u8]) -> Result<&[u8], Self::Error>;
fn get(&self, db: &Self::Database, key: &[u8]) -> Result<&[u8], Self::Error>;
fn abort(self);
}
@ -130,13 +130,13 @@ pub trait BackendRwTransaction: Debug {
type Database: BackendDatabase;
type Flags: BackendWriteFlags;
fn get(&self, db: Self::Database, key: &[u8]) -> Result<&[u8], Self::Error>;
fn get(&self, db: &Self::Database, key: &[u8]) -> Result<&[u8], Self::Error>;
fn put(&mut self, db: Self::Database, key: &[u8], value: &[u8], flags: Self::Flags) -> Result<(), Self::Error>;
fn put(&mut self, db: &Self::Database, key: &[u8], value: &[u8], flags: Self::Flags) -> Result<(), Self::Error>;
fn del(&mut self, db: Self::Database, key: &[u8], value: Option<&[u8]>) -> Result<(), Self::Error>;
fn del(&mut self, db: &Self::Database, key: &[u8], value: Option<&[u8]>) -> Result<(), Self::Error>;
fn clear_db(&mut self, db: Self::Database) -> Result<(), Self::Error>;
fn clear_db(&mut self, db: &Self::Database) -> Result<(), Self::Error>;
fn commit(self) -> Result<(), Self::Error>;
@ -146,13 +146,13 @@ pub trait BackendRwTransaction: Debug {
pub trait BackendRoCursorTransaction<'env>: BackendRoTransaction {
type RoCursor: BackendRoCursor<'env>;
fn open_ro_cursor(&'env self, db: Self::Database) -> Result<Self::RoCursor, Self::Error>;
fn open_ro_cursor(&'env self, db: &Self::Database) -> Result<Self::RoCursor, Self::Error>;
}
pub trait BackendRwCursorTransaction<'env>: BackendRwTransaction {
type RoCursor: BackendRoCursor<'env>;
fn open_ro_cursor(&'env self, db: Self::Database) -> Result<Self::RoCursor, Self::Error>;
fn open_ro_cursor(&'env self, db: &Self::Database) -> Result<Self::RoCursor, Self::Error>;
}
pub trait BackendRoCursor<'env>: Debug {

@ -734,7 +734,7 @@ mod tests {
// as the Value::I64 borrows an immutable reference to the Writer.
// So we extract and copy its primitive value.
fn get_existing_foo(store: SingleStore<LmdbDatabase>, writer: &Writer<LmdbRwTransaction>) -> Option<i64> {
fn get_existing_foo(store: &SingleStore<LmdbDatabase>, writer: &Writer<LmdbRwTransaction>) -> Option<i64> {
match store.get(writer, "foo").expect("read") {
Some(Value::I64(val)) => Some(val),
_ => None,
@ -742,11 +742,11 @@ mod tests {
}
let mut writer = k.write().expect("writer");
let mut existing = get_existing_foo(sk, &writer).unwrap_or(99);
let mut existing = get_existing_foo(&sk, &writer).unwrap_or(99);
existing += 1;
sk.put(&mut writer, "foo", &Value::I64(existing)).expect("success");
let updated = get_existing_foo(sk, &writer).unwrap_or(99);
let updated = get_existing_foo(&sk, &writer).unwrap_or(99);
assert_eq!(updated, 100);
writer.commit().expect("commit");
}
@ -1246,7 +1246,7 @@ mod tests {
let root = Builder::new().prefix("test_multiple_thread").tempdir().expect("tempdir");
fs::create_dir_all(root.path()).expect("dir created");
let rkv_arc = Arc::new(RwLock::new(Rkv::new::<backend::Lmdb>(root.path()).expect("new succeeded")));
let store = rkv_arc.read().unwrap().open_single("test", StoreOptions::create()).expect("opened");
let store_arc = Arc::new(rkv_arc.read().unwrap().open_single("test", StoreOptions::create()).expect("opened"));
let num_threads = 10;
let mut write_handles = Vec::with_capacity(num_threads as usize);
@ -1260,10 +1260,11 @@ mod tests {
// For each KV pair, spawn a thread that writes it to the store.
for i in 0..num_threads {
let rkv_arc = rkv_arc.clone();
let store_arc = store_arc.clone();
write_handles.push(thread::spawn(move || {
let rkv = rkv_arc.write().expect("rkv");
let mut writer = rkv.write().expect("writer");
store.put(&mut writer, i.to_string(), &Value::U64(i)).expect("written");
store_arc.put(&mut writer, i.to_string(), &Value::U64(i)).expect("written");
writer.commit().unwrap();
}));
}
@ -1275,10 +1276,11 @@ mod tests {
// and returns its value.
for i in 0..num_threads {
let rkv_arc = rkv_arc.clone();
let store_arc = store_arc.clone();
read_handles.push(thread::spawn(move || {
let rkv = rkv_arc.read().expect("rkv");
let reader = rkv.read().expect("reader");
let value = match store.get(&reader, i.to_string()) {
let value = match store_arc.get(&reader, i.to_string()) {
Ok(Some(Value::U64(value))) => value,
Ok(Some(_)) => panic!("value type unexpected"),
Ok(None) => panic!("value not found"),

@ -27,11 +27,11 @@ pub trait Readable<'env> {
type Database: BackendDatabase;
type RoCursor: BackendRoCursor<'env>;
fn get<K>(&'env self, db: Self::Database, k: &K) -> Result<Option<Value<'env>>, StoreError>
fn get<K>(&'env self, db: &Self::Database, k: &K) -> Result<Option<Value<'env>>, StoreError>
where
K: AsRef<[u8]>;
fn open_ro_cursor(&'env self, db: Self::Database) -> Result<Self::RoCursor, StoreError>;
fn open_ro_cursor(&'env self, db: &Self::Database) -> Result<Self::RoCursor, StoreError>;
}
impl<'env, T> Readable<'env> for Reader<T>
@ -41,7 +41,7 @@ where
type Database = T::Database;
type RoCursor = T::RoCursor;
fn get<K>(&'env self, db: T::Database, k: &K) -> Result<Option<Value<'env>>, StoreError>
fn get<K>(&'env self, db: &T::Database, k: &K) -> Result<Option<Value<'env>>, StoreError>
where
K: AsRef<[u8]>,
{
@ -49,7 +49,7 @@ where
read_transform(bytes)
}
fn open_ro_cursor(&'env self, db: T::Database) -> Result<T::RoCursor, StoreError> {
fn open_ro_cursor(&'env self, db: &T::Database) -> Result<T::RoCursor, StoreError> {
self.0.open_ro_cursor(db).map_err(|e| e.into())
}
}
@ -76,7 +76,7 @@ where
type Database = T::Database;
type RoCursor = T::RoCursor;
fn get<K>(&'env self, db: T::Database, k: &K) -> Result<Option<Value<'env>>, StoreError>
fn get<K>(&'env self, db: &T::Database, k: &K) -> Result<Option<Value<'env>>, StoreError>
where
K: AsRef<[u8]>,
{
@ -84,7 +84,7 @@ where
read_transform(bytes)
}
fn open_ro_cursor(&'env self, db: T::Database) -> Result<T::RoCursor, StoreError> {
fn open_ro_cursor(&'env self, db: &T::Database) -> Result<T::RoCursor, StoreError> {
self.0.open_ro_cursor(db).map_err(|e| e.into())
}
}
@ -107,7 +107,7 @@ where
self.0.abort();
}
pub(crate) fn put<K>(&mut self, db: T::Database, k: &K, v: &Value, flags: T::Flags) -> Result<(), StoreError>
pub(crate) fn put<K>(&mut self, db: &T::Database, k: &K, v: &Value, flags: T::Flags) -> Result<(), StoreError>
where
K: AsRef<[u8]>,
{
@ -115,14 +115,14 @@ where
self.0.put(db, k.as_ref(), &v.to_bytes()?, flags).map_err(|e| e.into())
}
pub(crate) fn delete<K>(&mut self, db: T::Database, k: &K, v: Option<&[u8]>) -> Result<(), StoreError>
pub(crate) fn delete<K>(&mut self, db: &T::Database, k: &K, v: Option<&[u8]>) -> Result<(), StoreError>
where
K: AsRef<[u8]>,
{
self.0.del(db, k.as_ref(), v).map_err(|e| e.into())
}
pub(crate) fn clear(&mut self, db: T::Database) -> Result<(), StoreError> {
pub(crate) fn clear(&mut self, db: &T::Database) -> Result<(), StoreError> {
self.0.clear_db(db).map_err(|e| e.into())
}
}

@ -27,7 +27,6 @@ use crate::value::Value;
type EmptyResult = Result<(), StoreError>;
#[derive(Copy, Clone)]
pub struct MultiStore<D> {
db: D,
}
@ -49,14 +48,14 @@ where
}
/// Provides a cursor to all of the values for the duplicate entries that match this key
pub fn get<'env, R, I, C, K>(self, reader: &'env R, k: K) -> Result<Iter<'env, I, C>, StoreError>
pub fn get<'env, R, I, C, K>(&self, reader: &'env R, k: K) -> Result<Iter<'env, I, C>, StoreError>
where
R: Readable<'env, Database = D, RoCursor = C>,
I: BackendIter<'env>,
C: BackendRoCursor<'env, Iter = I>,
K: AsRef<[u8]>,
{
let mut cursor = reader.open_ro_cursor(self.db)?;
let mut cursor = reader.open_ro_cursor(&self.db)?;
let iter = cursor.iter_dup_of(k);
Ok(Iter {
@ -67,54 +66,54 @@ where
}
/// Provides the first value that matches this key
pub fn get_first<'env, R, K>(self, reader: &'env R, k: K) -> Result<Option<Value<'env>>, StoreError>
pub fn get_first<'env, R, K>(&self, reader: &'env R, k: K) -> Result<Option<Value<'env>>, StoreError>
where
R: Readable<'env, Database = D>,
K: AsRef<[u8]>,
{
reader.get(self.db, &k)
reader.get(&self.db, &k)
}
/// Insert a value at the specified key.
/// This put will allow duplicate entries. If you wish to have duplicate entries
/// rejected, use the `put_with_flags` function and specify NO_DUP_DATA
pub fn put<T, K>(self, writer: &mut Writer<T>, k: K, v: &Value) -> EmptyResult
pub fn put<T, K>(&self, writer: &mut Writer<T>, k: K, v: &Value) -> EmptyResult
where
T: BackendRwTransaction<Database = D>,
K: AsRef<[u8]>,
{
writer.put(self.db, &k, v, T::Flags::empty())
writer.put(&self.db, &k, v, T::Flags::empty())
}
pub fn put_with_flags<T, K>(self, writer: &mut Writer<T>, k: K, v: &Value, flags: T::Flags) -> EmptyResult
pub fn put_with_flags<T, K>(&self, writer: &mut Writer<T>, k: K, v: &Value, flags: T::Flags) -> EmptyResult
where
T: BackendRwTransaction<Database = D>,
K: AsRef<[u8]>,
{
writer.put(self.db, &k, v, flags)
writer.put(&self.db, &k, v, flags)
}
pub fn delete_all<T, K>(self, writer: &mut Writer<T>, k: K) -> EmptyResult
pub fn delete_all<T, K>(&self, writer: &mut Writer<T>, k: K) -> EmptyResult
where
T: BackendRwTransaction<Database = D>,
K: AsRef<[u8]>,
{
writer.delete(self.db, &k, None)
writer.delete(&self.db, &k, None)
}
pub fn delete<T, K>(self, writer: &mut Writer<T>, k: K, v: &Value) -> EmptyResult
pub fn delete<T, K>(&self, writer: &mut Writer<T>, k: K, v: &Value) -> EmptyResult
where
T: BackendRwTransaction<Database = D>,
K: AsRef<[u8]>,
{
writer.delete(self.db, &k, Some(&v.to_bytes()?))
writer.delete(&self.db, &k, Some(&v.to_bytes()?))
}
pub fn clear<T>(self, writer: &mut Writer<T>) -> EmptyResult
pub fn clear<T>(&self, writer: &mut Writer<T>) -> EmptyResult
where
T: BackendRwTransaction<Database = D>,
{
writer.clear(self.db)
writer.clear(&self.db)
}
}

@ -27,7 +27,6 @@ use crate::value::Value;
type EmptyResult = Result<(), StoreError>;
#[derive(Copy, Clone)]
pub struct SingleStore<D> {
db: D,
}
@ -48,38 +47,38 @@ where
}
}
pub fn get<'env, R, K>(self, reader: &'env R, k: K) -> Result<Option<Value<'env>>, StoreError>
pub fn get<'env, R, K>(&self, reader: &'env R, k: K) -> Result<Option<Value<'env>>, StoreError>
where
R: Readable<'env, Database = D>,
K: AsRef<[u8]>,
{
reader.get(self.db, &k)
reader.get(&self.db, &k)
}
// TODO: flags
pub fn put<T, K>(self, writer: &mut Writer<T>, k: K, v: &Value) -> EmptyResult
pub fn put<T, K>(&self, writer: &mut Writer<T>, k: K, v: &Value) -> EmptyResult
where
T: BackendRwTransaction<Database = D>,
K: AsRef<[u8]>,
{
writer.put(self.db, &k, v, T::Flags::empty())
writer.put(&self.db, &k, v, T::Flags::empty())
}
pub fn delete<T, K>(self, writer: &mut Writer<T>, k: K) -> EmptyResult
pub fn delete<T, K>(&self, writer: &mut Writer<T>, k: K) -> EmptyResult
where
T: BackendRwTransaction<Database = D>,
K: AsRef<[u8]>,
{
writer.delete(self.db, &k, None)
writer.delete(&self.db, &k, None)
}
pub fn iter_start<'env, R, I, C>(self, reader: &'env R) -> Result<Iter<'env, I, C>, StoreError>
pub fn iter_start<'env, R, I, C>(&self, reader: &'env R) -> Result<Iter<'env, I, C>, StoreError>
where
R: Readable<'env, Database = D, RoCursor = C>,
I: BackendIter<'env>,
C: BackendRoCursor<'env, Iter = I>,
{
let mut cursor = reader.open_ro_cursor(self.db)?;
let mut cursor = reader.open_ro_cursor(&self.db)?;
// We call Cursor.iter() instead of Cursor.iter_start() because
// the latter panics at "called `Result::unwrap()` on an `Err` value:
@ -98,14 +97,14 @@ where
})
}
pub fn iter_from<'env, R, I, C, K>(self, reader: &'env R, k: K) -> Result<Iter<'env, I, C>, StoreError>
pub fn iter_from<'env, R, I, C, K>(&self, reader: &'env R, k: K) -> Result<Iter<'env, I, C>, StoreError>
where
R: Readable<'env, Database = D, RoCursor = C>,
I: BackendIter<'env>,
C: BackendRoCursor<'env, Iter = I>,
K: AsRef<[u8]>,
{
let mut cursor = reader.open_ro_cursor(self.db)?;
let mut cursor = reader.open_ro_cursor(&self.db)?;
let iter = cursor.iter_from(k);
Ok(Iter {
@ -115,12 +114,12 @@ where
})
}
pub fn clear<T>(self, writer: &mut Writer<T>) -> EmptyResult
pub fn clear<T>(&self, writer: &mut Writer<T>) -> EmptyResult
where
D: BackendDatabase,
T: BackendRwTransaction<Database = D>,
{
writer.clear(self.db)
writer.clear(&self.db)
}
}

@ -48,9 +48,9 @@ fn read_many() {
let root = Builder::new().prefix("test_txns").tempdir().expect("tempdir");
fs::create_dir_all(root.path()).expect("dir created");
let k = Rkv::new::<Lmdb>(root.path()).expect("new succeeded");
let samplestore = k.open_single("s", StoreOptions::create()).expect("open");
let datestore = k.open_multi("m", StoreOptions::create()).expect("open");
let valuestore = k.open_multi("m", StoreOptions::create()).expect("open");
let samplestore = &k.open_single("s", StoreOptions::create()).expect("open");
let datestore = &k.open_multi("m", StoreOptions::create()).expect("open");
let valuestore = &k.open_multi("m", StoreOptions::create()).expect("open");
{
let mut writer = k.write().expect("env write lock");
@ -89,7 +89,7 @@ fn read_many() {
}
}
fn get_ids_by_field<'env, T>(txn: &'env T, store: MultiStore, field: &str) -> Vec<u64>
fn get_ids_by_field<'env, T>(txn: &'env T, store: &MultiStore, field: &str) -> Vec<u64>
where
T: Readable<'env, Database = LmdbDatabase, RoCursor = LmdbRoCursor<'env>>,
{
@ -103,7 +103,7 @@ where
.collect::<Vec<u64>>()
}
fn get_samples<'env, T>(txn: &'env T, samplestore: SingleStore, ids: &[u64]) -> Vec<String>
fn get_samples<'env, T>(txn: &'env T, samplestore: &SingleStore, ids: &[u64]) -> Vec<String>
where
T: Readable<'env, Database = LmdbDatabase, RoCursor = LmdbRoCursor<'env>>,
{
@ -119,11 +119,11 @@ where
.collect::<Vec<String>>()
}
fn put_sample(txn: &mut Writer<LmdbRwTransaction>, samplestore: SingleStore, id: u64, value: &str) {
fn put_sample(txn: &mut Writer<LmdbRwTransaction>, samplestore: &SingleStore, id: u64, value: &str) {
let idbytes = id.to_be_bytes();
samplestore.put(txn, &idbytes, &Value::Str(value)).expect("put id");
}
fn put_id_field(txn: &mut Writer<LmdbRwTransaction>, store: MultiStore, field: &str, id: u64) {
fn put_id_field(txn: &mut Writer<LmdbRwTransaction>, store: &MultiStore, field: &str, id: u64) {
store.put(txn, field, &Value::U64(id)).expect("put id");
}

Loading…
Cancel
Save