Rustfmt pass (cargo +nightly fmt --all)

Signed-off-by: Victor Porof <victor.porof@gmail.com>
without.crypto
Victor Porof 5 years ago
parent ea60c303fe
commit 2acd21c529
  1. 24
      benches/cursor.rs
  2. 36
      benches/transaction.rs
  3. 6
      benches/utils.rs
  4. 360
      src/cursor.rs
  5. 21
      src/database.rs
  6. 136
      src/environment.rs
  7. 13
      src/error.rs
  8. 39
      src/lib.rs
  9. 266
      src/transaction.rs

@ -7,9 +7,17 @@ extern crate test;
mod utils;
use ffi::*;
use lmdb::{Cursor, Result, RoCursor, Transaction};
use lmdb::{
Cursor,
Result,
RoCursor,
Transaction,
};
use std::ptr;
use test::{Bencher, black_box};
use test::{
black_box,
Bencher,
};
use utils::*;
/// Benchmark of iterator sequential read performance.
@ -85,8 +93,14 @@ fn bench_get_seq_raw(b: &mut Bencher) {
let _txn = env.begin_ro_txn().unwrap();
let txn = _txn.txn();
let mut key = MDB_val { mv_size: 0, mv_data: ptr::null_mut() };
let mut data = MDB_val { mv_size: 0, mv_data: ptr::null_mut() };
let mut key = MDB_val {
mv_size: 0,
mv_data: ptr::null_mut(),
};
let mut data = MDB_val {
mv_size: 0,
mv_data: ptr::null_mut(),
};
let mut cursor: *mut MDB_cursor = ptr::null_mut();
b.iter(|| unsafe {
@ -97,7 +111,7 @@ fn bench_get_seq_raw(b: &mut Bencher) {
while mdb_cursor_get(cursor, &mut key, &mut data, MDB_NEXT) == 0 {
i += key.mv_size + data.mv_size;
count += 1;
};
}
black_box(i);
assert_eq!(count, n);

@ -10,10 +10,19 @@ mod utils;
use ffi::*;
use libc::size_t;
use lmdb::{Transaction, WriteFlags};
use rand::{Rng, XorShiftRng};
use lmdb::{
Transaction,
WriteFlags,
};
use rand::{
Rng,
XorShiftRng,
};
use std::ptr;
use test::{Bencher, black_box};
use test::{
black_box,
Bencher,
};
use utils::*;
#[bench]
@ -48,8 +57,14 @@ fn bench_get_rand_raw(b: &mut Bencher) {
let dbi = db.dbi();
let txn = _txn.txn();
let mut key_val: MDB_val = MDB_val { mv_size: 0, mv_data: ptr::null_mut() };
let mut data_val: MDB_val = MDB_val { mv_size: 0, mv_data: ptr::null_mut() };
let mut key_val: MDB_val = MDB_val {
mv_size: 0,
mv_data: ptr::null_mut(),
};
let mut data_val: MDB_val = MDB_val {
mv_size: 0,
mv_data: ptr::null_mut(),
};
b.iter(|| unsafe {
let mut i: size_t = 0;
@ -95,8 +110,14 @@ fn bench_put_rand_raw(b: &mut Bencher) {
let dbi = db.dbi();
let env = _env.env();
let mut key_val: MDB_val = MDB_val { mv_size: 0, mv_data: ptr::null_mut() };
let mut data_val: MDB_val = MDB_val { mv_size: 0, mv_data: ptr::null_mut() };
let mut key_val: MDB_val = MDB_val {
mv_size: 0,
mv_data: ptr::null_mut(),
};
let mut data_val: MDB_val = MDB_val {
mv_size: 0,
mv_data: ptr::null_mut(),
};
b.iter(|| unsafe {
let mut txn: *mut MDB_txn = ptr::null_mut();
@ -104,7 +125,6 @@ fn bench_put_rand_raw(b: &mut Bencher) {
let mut i: ::libc::c_int = 0;
for &(ref key, ref data) in items.iter() {
key_val.mv_size = key.len() as size_t;
key_val.mv_data = key.as_bytes().as_ptr() as *mut _;
data_val.mv_size = data.len() as size_t;

@ -1,8 +1,12 @@
extern crate lmdb;
extern crate tempdir;
use lmdb::{Environment, Transaction, WriteFlags};
use self::tempdir::TempDir;
use lmdb::{
Environment,
Transaction,
WriteFlags,
};
pub fn get_key(n: u32) -> String {
format!("key{}", n)

@ -1,17 +1,31 @@
use std::marker::PhantomData;
use std::{fmt, mem, ptr, result, slice};
use libc::{EINVAL, c_void, size_t, c_uint};
use std::{
fmt,
mem,
ptr,
result,
slice,
};
use libc::{
c_uint,
c_void,
size_t,
EINVAL,
};
use database::Database;
use error::{Error, Result, lmdb_result};
use error::{
lmdb_result,
Error,
Result,
};
use ffi;
use flags::WriteFlags;
use transaction::Transaction;
/// An LMDB cursor.
pub trait Cursor<'txn> {
/// Returns a raw pointer to the underlying LMDB cursor.
///
/// The caller **must** ensure that the pointer is not used after the
@ -26,7 +40,11 @@ pub trait Cursor<'txn> {
let mut data_val = slice_to_val(data);
let key_ptr = key_val.mv_data;
lmdb_result(ffi::mdb_cursor_get(self.cursor(), &mut key_val, &mut data_val, op))?;
let key_out = if key_ptr != key_val.mv_data { Some(val_to_slice(key_val)) } else { None };
let key_out = if key_ptr != key_val.mv_data {
Some(val_to_slice(key_val))
} else {
None
};
let data_out = val_to_slice(data_val);
Ok((key_out, data_out))
}
@ -57,7 +75,10 @@ pub trait Cursor<'txn> {
/// For databases with duplicate data items (`DatabaseFlags::DUP_SORT`), the
/// duplicate data items of each key will be returned before moving on to
/// the next key.
fn iter_from<K>(&mut self, key: K) -> Iter<'txn> where K: AsRef<[u8]> {
fn iter_from<K>(&mut self, key: K) -> Iter<'txn>
where
K: AsRef<[u8]>,
{
match self.get(Some(key.as_ref()), None, ffi::MDB_SET_RANGE) {
Ok(_) | Err(Error::NotFound) => (),
Err(error) => return Iter::Err(error),
@ -80,7 +101,10 @@ pub trait Cursor<'txn> {
/// Iterate over duplicate items in the database starting from the given
/// key. Each item will be returned as an iterator of its duplicates.
fn iter_dup_from<K>(&mut self, key: K) -> IterDup<'txn> where K: AsRef<[u8]> {
fn iter_dup_from<K>(&mut self, key: K) -> IterDup<'txn>
where
K: AsRef<[u8]>,
{
match self.get(Some(key.as_ref()), None, ffi::MDB_SET_RANGE) {
Ok(_) | Err(Error::NotFound) => (),
Err(error) => return IterDup::Err(error),
@ -89,7 +113,10 @@ pub trait Cursor<'txn> {
}
/// Iterate over the duplicates of the item in the database with the given key.
fn iter_dup_of<K>(&mut self, key: K) -> Iter<'txn> where K: AsRef<[u8]> {
fn iter_dup_of<K>(&mut self, key: K) -> Iter<'txn>
where
K: AsRef<[u8]>,
{
match self.get(Some(key.as_ref()), None, ffi::MDB_SET) {
Ok(_) | Err(Error::NotFound) => (),
Err(error) => return Iter::Err(error),
@ -104,31 +131,35 @@ pub struct RoCursor<'txn> {
_marker: PhantomData<fn() -> &'txn ()>,
}
impl <'txn> Cursor<'txn> for RoCursor<'txn> {
impl<'txn> Cursor<'txn> for RoCursor<'txn> {
fn cursor(&self) -> *mut ffi::MDB_cursor {
self.cursor
}
}
impl <'txn> fmt::Debug for RoCursor<'txn> {
impl<'txn> fmt::Debug for RoCursor<'txn> {
fn fmt(&self, f: &mut fmt::Formatter) -> result::Result<(), fmt::Error> {
f.debug_struct("RoCursor").finish()
}
}
impl <'txn> Drop for RoCursor<'txn> {
impl<'txn> Drop for RoCursor<'txn> {
fn drop(&mut self) {
unsafe { ffi::mdb_cursor_close(self.cursor) }
}
}
impl <'txn> RoCursor<'txn> {
impl<'txn> RoCursor<'txn> {
/// Creates a new read-only cursor in the given database and transaction.
/// Prefer using `Transaction::open_cursor`.
pub(crate) fn new<T>(txn: &'txn T, db: Database) -> Result<RoCursor<'txn>> where T: Transaction {
pub(crate) fn new<T>(txn: &'txn T, db: Database) -> Result<RoCursor<'txn>>
where
T: Transaction,
{
let mut cursor: *mut ffi::MDB_cursor = ptr::null_mut();
unsafe { lmdb_result(ffi::mdb_cursor_open(txn.txn(), db.dbi(), &mut cursor))?; }
unsafe {
lmdb_result(ffi::mdb_cursor_open(txn.txn(), db.dbi(), &mut cursor))?;
}
Ok(RoCursor {
cursor: cursor,
_marker: PhantomData,
@ -142,50 +173,59 @@ pub struct RwCursor<'txn> {
_marker: PhantomData<fn() -> &'txn ()>,
}
impl <'txn> Cursor<'txn> for RwCursor<'txn> {
impl<'txn> Cursor<'txn> for RwCursor<'txn> {
fn cursor(&self) -> *mut ffi::MDB_cursor {
self.cursor
}
}
impl <'txn> fmt::Debug for RwCursor<'txn> {
impl<'txn> fmt::Debug for RwCursor<'txn> {
fn fmt(&self, f: &mut fmt::Formatter) -> result::Result<(), fmt::Error> {
f.debug_struct("RwCursor").finish()
}
}
impl <'txn> Drop for RwCursor<'txn> {
impl<'txn> Drop for RwCursor<'txn> {
fn drop(&mut self) {
unsafe { ffi::mdb_cursor_close(self.cursor) }
}
}
impl <'txn> RwCursor<'txn> {
impl<'txn> RwCursor<'txn> {
/// Creates a new read-only cursor in the given database and transaction.
/// Prefer using `RwTransaction::open_rw_cursor`.
pub(crate) fn new<T>(txn: &'txn T, db: Database) -> Result<RwCursor<'txn>> where T: Transaction {
pub(crate) fn new<T>(txn: &'txn T, db: Database) -> Result<RwCursor<'txn>>
where
T: Transaction,
{
let mut cursor: *mut ffi::MDB_cursor = ptr::null_mut();
unsafe { lmdb_result(ffi::mdb_cursor_open(txn.txn(), db.dbi(), &mut cursor))?; }
Ok(RwCursor { cursor: cursor, _marker: PhantomData })
unsafe {
lmdb_result(ffi::mdb_cursor_open(txn.txn(), db.dbi(), &mut cursor))?;
}
Ok(RwCursor {
cursor: cursor,
_marker: PhantomData,
})
}
/// Puts a key/data pair into the database. The cursor will be positioned at
/// the new data item, or on failure usually near it.
pub fn put<K, D>(&mut self, key: &K, data: &D, flags: WriteFlags) -> Result<()>
where K: AsRef<[u8]>, D: AsRef<[u8]> {
where
K: AsRef<[u8]>,
D: AsRef<[u8]>,
{
let key = key.as_ref();
let data = data.as_ref();
let mut key_val: ffi::MDB_val = ffi::MDB_val { mv_size: key.len() as size_t,
mv_data: key.as_ptr() as *mut c_void };
let mut data_val: ffi::MDB_val = ffi::MDB_val { mv_size: data.len() as size_t,
mv_data: data.as_ptr() as *mut c_void };
unsafe {
lmdb_result(ffi::mdb_cursor_put(self.cursor(),
&mut key_val,
&mut data_val,
flags.bits()))
}
let mut key_val: ffi::MDB_val = ffi::MDB_val {
mv_size: key.len() as size_t,
mv_data: key.as_ptr() as *mut c_void,
};
let mut data_val: ffi::MDB_val = ffi::MDB_val {
mv_size: data.len() as size_t,
mv_data: data.as_ptr() as *mut c_void,
};
unsafe { lmdb_result(ffi::mdb_cursor_put(self.cursor(), &mut key_val, &mut data_val, flags.bits())) }
}
/// Deletes the current key/data pair.
@ -201,12 +241,14 @@ impl <'txn> RwCursor<'txn> {
unsafe fn slice_to_val(slice: Option<&[u8]>) -> ffi::MDB_val {
match slice {
Some(slice) =>
ffi::MDB_val { mv_size: slice.len() as size_t,
mv_data: slice.as_ptr() as *mut c_void },
None =>
ffi::MDB_val { mv_size: 0,
mv_data: ptr::null_mut() },
Some(slice) => ffi::MDB_val {
mv_size: slice.len() as size_t,
mv_data: slice.as_ptr() as *mut c_void,
},
None => ffi::MDB_val {
mv_size: 0,
mv_data: ptr::null_mut(),
},
}
}
@ -242,29 +284,43 @@ pub enum Iter<'txn> {
},
}
impl <'txn> Iter<'txn> {
impl<'txn> Iter<'txn> {
/// Creates a new iterator backed by the given cursor.
fn new<'t>(cursor: *mut ffi::MDB_cursor, op: c_uint, next_op: c_uint) -> Iter<'t> {
Iter::Ok { cursor: cursor, op: op, next_op: next_op, _marker: PhantomData }
Iter::Ok {
cursor: cursor,
op: op,
next_op: next_op,
_marker: PhantomData,
}
}
}
impl <'txn> fmt::Debug for Iter<'txn> {
impl<'txn> fmt::Debug for Iter<'txn> {
fn fmt(&self, f: &mut fmt::Formatter) -> result::Result<(), fmt::Error> {
f.debug_struct("Iter").finish()
}
}
impl <'txn> Iterator for Iter<'txn> {
impl<'txn> Iterator for Iter<'txn> {
type Item = Result<(&'txn [u8], &'txn [u8])>;
fn next(&mut self) -> Option<Result<(&'txn [u8], &'txn [u8])>> {
match self {
&mut Iter::Ok { cursor, ref mut op, next_op, _marker } => {
let mut key = ffi::MDB_val { mv_size: 0, mv_data: ptr::null_mut() };
let mut data = ffi::MDB_val { mv_size: 0, mv_data: ptr::null_mut() };
&mut Iter::Ok {
cursor,
ref mut op,
next_op,
_marker,
} => {
let mut key = ffi::MDB_val {
mv_size: 0,
mv_data: ptr::null_mut(),
};
let mut data = ffi::MDB_val {
mv_size: 0,
mv_data: ptr::null_mut(),
};
let op = mem::replace(op, next_op);
unsafe {
match ffi::mdb_cursor_get(cursor, &mut key, &mut data, op) {
@ -309,33 +365,43 @@ pub enum IterDup<'txn> {
},
}
impl <'txn> IterDup<'txn> {
impl<'txn> IterDup<'txn> {
/// Creates a new iterator backed by the given cursor.
fn new<'t>(cursor: *mut ffi::MDB_cursor, op: c_uint) -> IterDup<'t> {
IterDup::Ok { cursor: cursor, op: op, _marker: PhantomData }
IterDup::Ok {
cursor: cursor,
op: op,
_marker: PhantomData,
}
}
}
impl <'txn> fmt::Debug for IterDup<'txn> {
impl<'txn> fmt::Debug for IterDup<'txn> {
fn fmt(&self, f: &mut fmt::Formatter) -> result::Result<(), fmt::Error> {
f.debug_struct("IterDup").finish()
}
}
impl <'txn> Iterator for IterDup<'txn> {
impl<'txn> Iterator for IterDup<'txn> {
type Item = Iter<'txn>;
fn next(&mut self) -> Option<Iter<'txn>> {
match self {
&mut IterDup::Ok { cursor, ref mut op, _marker } => {
let mut key = ffi::MDB_val { mv_size: 0, mv_data: ptr::null_mut() };
let mut data = ffi::MDB_val { mv_size: 0, mv_data: ptr::null_mut() };
let op = mem::replace(op, ffi::MDB_NEXT_NODUP);
let err_code = unsafe {
ffi::mdb_cursor_get(cursor, &mut key, &mut data, op)
&mut IterDup::Ok {
cursor,
ref mut op,
_marker,
} => {
let mut key = ffi::MDB_val {
mv_size: 0,
mv_data: ptr::null_mut(),
};
let mut data = ffi::MDB_val {
mv_size: 0,
mv_data: ptr::null_mut(),
};
let op = mem::replace(op, ffi::MDB_NEXT_NODUP);
let err_code = unsafe { ffi::mdb_cursor_get(cursor, &mut key, &mut data, op) };
if err_code == ffi::MDB_SUCCESS {
Some(Iter::new(cursor, ffi::MDB_GET_CURRENT, ffi::MDB_NEXT_DUP))
@ -352,10 +418,10 @@ impl <'txn> Iterator for IterDup<'txn> {
mod test {
use tempdir::TempDir;
use super::*;
use environment::*;
use ffi::*;
use flags::*;
use super::*;
#[test]
fn test_get() {
@ -369,22 +435,14 @@ mod test {
txn.put(db, b"key3", b"val3", WriteFlags::empty()).unwrap();
let cursor = txn.open_ro_cursor(db).unwrap();
assert_eq!((Some(&b"key1"[..]), &b"val1"[..]),
cursor.get(None, None, MDB_FIRST).unwrap());
assert_eq!((Some(&b"key1"[..]), &b"val1"[..]),
cursor.get(None, None, MDB_GET_CURRENT).unwrap());
assert_eq!((Some(&b"key2"[..]), &b"val2"[..]),
cursor.get(None, None, MDB_NEXT).unwrap());
assert_eq!((Some(&b"key1"[..]), &b"val1"[..]),
cursor.get(None, None, MDB_PREV).unwrap());
assert_eq!((Some(&b"key3"[..]), &b"val3"[..]),
cursor.get(None, None, MDB_LAST).unwrap());
assert_eq!((None, &b"val2"[..]),
cursor.get(Some(b"key2"), None, MDB_SET).unwrap());
assert_eq!((Some(&b"key3"[..]), &b"val3"[..]),
cursor.get(Some(&b"key3"[..]), None, MDB_SET_KEY).unwrap());
assert_eq!((Some(&b"key3"[..]), &b"val3"[..]),
cursor.get(Some(&b"key2\0"[..]), None, MDB_SET_RANGE).unwrap());
assert_eq!((Some(&b"key1"[..]), &b"val1"[..]), cursor.get(None, None, MDB_FIRST).unwrap());
assert_eq!((Some(&b"key1"[..]), &b"val1"[..]), cursor.get(None, None, MDB_GET_CURRENT).unwrap());
assert_eq!((Some(&b"key2"[..]), &b"val2"[..]), cursor.get(None, None, MDB_NEXT).unwrap());
assert_eq!((Some(&b"key1"[..]), &b"val1"[..]), cursor.get(None, None, MDB_PREV).unwrap());
assert_eq!((Some(&b"key3"[..]), &b"val3"[..]), cursor.get(None, None, MDB_LAST).unwrap());
assert_eq!((None, &b"val2"[..]), cursor.get(Some(b"key2"), None, MDB_SET).unwrap());
assert_eq!((Some(&b"key3"[..]), &b"val3"[..]), cursor.get(Some(&b"key3"[..]), None, MDB_SET_KEY).unwrap());
assert_eq!((Some(&b"key3"[..]), &b"val3"[..]), cursor.get(Some(&b"key2\0"[..]), None, MDB_SET_RANGE).unwrap());
}
#[test]
@ -402,35 +460,24 @@ mod test {
txn.put(db, b"key2", b"val3", WriteFlags::empty()).unwrap();
let cursor = txn.open_ro_cursor(db).unwrap();
assert_eq!((Some(&b"key1"[..]), &b"val1"[..]),
cursor.get(None, None, MDB_FIRST).unwrap());
assert_eq!((None, &b"val1"[..]),
cursor.get(None, None, MDB_FIRST_DUP).unwrap());
assert_eq!((Some(&b"key1"[..]), &b"val1"[..]),
cursor.get(None, None, MDB_GET_CURRENT).unwrap());
assert_eq!((Some(&b"key2"[..]), &b"val1"[..]),
cursor.get(None, None, MDB_NEXT_NODUP).unwrap());
assert_eq!((Some(&b"key2"[..]), &b"val2"[..]),
cursor.get(None, None, MDB_NEXT_DUP).unwrap());
assert_eq!((Some(&b"key2"[..]), &b"val3"[..]),
cursor.get(None, None, MDB_NEXT_DUP).unwrap());
assert_eq!((Some(&b"key1"[..]), &b"val1"[..]), cursor.get(None, None, MDB_FIRST).unwrap());
assert_eq!((None, &b"val1"[..]), cursor.get(None, None, MDB_FIRST_DUP).unwrap());
assert_eq!((Some(&b"key1"[..]), &b"val1"[..]), cursor.get(None, None, MDB_GET_CURRENT).unwrap());
assert_eq!((Some(&b"key2"[..]), &b"val1"[..]), cursor.get(None, None, MDB_NEXT_NODUP).unwrap());
assert_eq!((Some(&b"key2"[..]), &b"val2"[..]), cursor.get(None, None, MDB_NEXT_DUP).unwrap());
assert_eq!((Some(&b"key2"[..]), &b"val3"[..]), cursor.get(None, None, MDB_NEXT_DUP).unwrap());
assert!(cursor.get(None, None, MDB_NEXT_DUP).is_err());
assert_eq!((Some(&b"key2"[..]), &b"val2"[..]),
cursor.get(None, None, MDB_PREV_DUP).unwrap());
assert_eq!((None, &b"val3"[..]),
cursor.get(None, None, MDB_LAST_DUP).unwrap());
assert_eq!((Some(&b"key1"[..]), &b"val3"[..]),
cursor.get(None, None, MDB_PREV_NODUP).unwrap());
assert_eq!((None, &b"val1"[..]),
cursor.get(Some(&b"key1"[..]), None, MDB_SET).unwrap());
assert_eq!((Some(&b"key2"[..]), &b"val1"[..]),
cursor.get(Some(&b"key2"[..]), None, MDB_SET_KEY).unwrap());
assert_eq!((Some(&b"key2"[..]), &b"val1"[..]),
cursor.get(Some(&b"key1\0"[..]), None, MDB_SET_RANGE).unwrap());
assert_eq!((None, &b"val3"[..]),
cursor.get(Some(&b"key1"[..]), Some(&b"val3"[..]), MDB_GET_BOTH).unwrap());
assert_eq!((None, &b"val1"[..]),
cursor.get(Some(&b"key2"[..]), Some(&b"val"[..]), MDB_GET_BOTH_RANGE).unwrap());
assert_eq!((Some(&b"key2"[..]), &b"val2"[..]), cursor.get(None, None, MDB_PREV_DUP).unwrap());
assert_eq!((None, &b"val3"[..]), cursor.get(None, None, MDB_LAST_DUP).unwrap());
assert_eq!((Some(&b"key1"[..]), &b"val3"[..]), cursor.get(None, None, MDB_PREV_NODUP).unwrap());
assert_eq!((None, &b"val1"[..]), cursor.get(Some(&b"key1"[..]), None, MDB_SET).unwrap());
assert_eq!((Some(&b"key2"[..]), &b"val1"[..]), cursor.get(Some(&b"key2"[..]), None, MDB_SET_KEY).unwrap());
assert_eq!((Some(&b"key2"[..]), &b"val1"[..]), cursor.get(Some(&b"key1\0"[..]), None, MDB_SET_RANGE).unwrap());
assert_eq!((None, &b"val3"[..]), cursor.get(Some(&b"key1"[..]), Some(&b"val3"[..]), MDB_GET_BOTH).unwrap());
assert_eq!(
(None, &b"val1"[..]),
cursor.get(Some(&b"key2"[..]), Some(&b"val"[..]), MDB_GET_BOTH_RANGE).unwrap()
);
}
#[test]
@ -448,10 +495,8 @@ mod test {
txn.put(db, b"key2", b"val6", WriteFlags::empty()).unwrap();
let cursor = txn.open_ro_cursor(db).unwrap();
assert_eq!((Some(&b"key1"[..]), &b"val1"[..]),
cursor.get(None, None, MDB_FIRST).unwrap());
assert_eq!((None, &b"val1val2val3"[..]),
cursor.get(None, None, MDB_GET_MULTIPLE).unwrap());
assert_eq!((Some(&b"key1"[..]), &b"val1"[..]), cursor.get(None, None, MDB_FIRST).unwrap());
assert_eq!((None, &b"val1val2val3"[..]), cursor.get(None, None, MDB_GET_MULTIPLE).unwrap());
assert!(cursor.get(None, None, MDB_NEXT_MULTIPLE).is_err());
}
@ -461,10 +506,8 @@ mod test {
let env = Environment::new().open(dir.path()).unwrap();
let db = env.open_db(None).unwrap();
let items: Vec<(&[u8], &[u8])> = vec!((b"key1", b"val1"),
(b"key2", b"val2"),
(b"key3", b"val3"),
(b"key5", b"val5"));
let items: Vec<(&[u8], &[u8])> =
vec![(b"key1", b"val1"), (b"key2", b"val2"), (b"key3", b"val3"), (b"key5", b"val5")];
{
let mut txn = env.begin_rw_txn().unwrap();
@ -487,19 +530,27 @@ mod test {
assert_eq!(items, retr.unwrap());
cursor.get(Some(b"key2"), None, MDB_SET).unwrap();
assert_eq!(items.clone().into_iter().skip(2).collect::<Vec<_>>(),
cursor.iter().collect::<Result<Vec<_>>>().unwrap());
assert_eq!(
items.clone().into_iter().skip(2).collect::<Vec<_>>(),
cursor.iter().collect::<Result<Vec<_>>>().unwrap()
);
assert_eq!(items, cursor.iter_start().collect::<Result<Vec<_>>>().unwrap());
assert_eq!(items.clone().into_iter().skip(1).collect::<Vec<_>>(),
cursor.iter_from(b"key2").collect::<Result<Vec<_>>>().unwrap());
assert_eq!(
items.clone().into_iter().skip(1).collect::<Vec<_>>(),
cursor.iter_from(b"key2").collect::<Result<Vec<_>>>().unwrap()
);
assert_eq!(items.clone().into_iter().skip(3).collect::<Vec<_>>(),
cursor.iter_from(b"key4").collect::<Result<Vec<_>>>().unwrap());
assert_eq!(
items.clone().into_iter().skip(3).collect::<Vec<_>>(),
cursor.iter_from(b"key4").collect::<Result<Vec<_>>>().unwrap()
);
assert_eq!(vec!().into_iter().collect::<Vec<(&[u8], &[u8])>>(),
cursor.iter_from(b"key6").collect::<Result<Vec<_>>>().unwrap());
assert_eq!(
vec!().into_iter().collect::<Vec<(&[u8], &[u8])>>(),
cursor.iter_from(b"key6").collect::<Result<Vec<_>>>().unwrap()
);
}
#[test]
@ -538,7 +589,8 @@ mod test {
let env = Environment::new().open(dir.path()).unwrap();
let db = env.create_db(None, DatabaseFlags::DUP_SORT).unwrap();
let items: Vec<(&[u8], &[u8])> = vec!((b"a", b"1"),
let items: Vec<(&[u8], &[u8])> = vec![
(b"a", b"1"),
(b"a", b"2"),
(b"a", b"3"),
(b"b", b"1"),
@ -549,7 +601,8 @@ mod test {
(b"c", b"3"),
(b"e", b"1"),
(b"e", b"2"),
(b"e", b"3"));
(b"e", b"3"),
];
{
let mut txn = env.begin_rw_txn().unwrap();
@ -564,26 +617,37 @@ mod test {
assert_eq!(items, cursor.iter_dup().flat_map(|x| x).collect::<Result<Vec<_>>>().unwrap());
cursor.get(Some(b"b"), None, MDB_SET).unwrap();
assert_eq!(items.clone().into_iter().skip(4).collect::<Vec<(&[u8], &[u8])>>(),
cursor.iter_dup().flat_map(|x| x).collect::<Result<Vec<_>>>().unwrap());
assert_eq!(items,
cursor.iter_dup_start().flat_map(|x| x).collect::<Result<Vec<(&[u8], &[u8])>>>().unwrap());
assert_eq!(items.clone().into_iter().skip(3).collect::<Vec<(&[u8], &[u8])>>(),
cursor.iter_dup_from(b"b").flat_map(|x| x).collect::<Result<Vec<_>>>().unwrap());
assert_eq!(items.clone().into_iter().skip(3).collect::<Vec<(&[u8], &[u8])>>(),
cursor.iter_dup_from(b"ab").flat_map(|x| x).collect::<Result<Vec<_>>>().unwrap());
assert_eq!(items.clone().into_iter().skip(9).collect::<Vec<(&[u8], &[u8])>>(),
cursor.iter_dup_from(b"d").flat_map(|x| x).collect::<Result<Vec<_>>>().unwrap());
assert_eq!(vec!().into_iter().collect::<Vec<(&[u8], &[u8])>>(),
cursor.iter_dup_from(b"f").flat_map(|x| x).collect::<Result<Vec<_>>>().unwrap());
assert_eq!(items.clone().into_iter().skip(3).take(3).collect::<Vec<(&[u8], &[u8])>>(),
cursor.iter_dup_of(b"b").collect::<Result<Vec<_>>>().unwrap());
assert_eq!(
items.clone().into_iter().skip(4).collect::<Vec<(&[u8], &[u8])>>(),
cursor.iter_dup().flat_map(|x| x).collect::<Result<Vec<_>>>().unwrap()
);
assert_eq!(items, cursor.iter_dup_start().flat_map(|x| x).collect::<Result<Vec<(&[u8], &[u8])>>>().unwrap());
assert_eq!(
items.clone().into_iter().skip(3).collect::<Vec<(&[u8], &[u8])>>(),
cursor.iter_dup_from(b"b").flat_map(|x| x).collect::<Result<Vec<_>>>().unwrap()
);
assert_eq!(
items.clone().into_iter().skip(3).collect::<Vec<(&[u8], &[u8])>>(),
cursor.iter_dup_from(b"ab").flat_map(|x| x).collect::<Result<Vec<_>>>().unwrap()
);
assert_eq!(
items.clone().into_iter().skip(9).collect::<Vec<(&[u8], &[u8])>>(),
cursor.iter_dup_from(b"d").flat_map(|x| x).collect::<Result<Vec<_>>>().unwrap()
);
assert_eq!(
vec!().into_iter().collect::<Vec<(&[u8], &[u8])>>(),
cursor.iter_dup_from(b"f").flat_map(|x| x).collect::<Result<Vec<_>>>().unwrap()
);
assert_eq!(
items.clone().into_iter().skip(3).take(3).collect::<Vec<(&[u8], &[u8])>>(),
cursor.iter_dup_of(b"b").collect::<Result<Vec<_>>>().unwrap()
);
assert_eq!(0, cursor.iter_dup_of(b"foo").count());
}
@ -601,11 +665,9 @@ mod test {
cursor.put(b"key2", b"val2", WriteFlags::empty()).unwrap();
cursor.put(b"key3", b"val3", WriteFlags::empty()).unwrap();
assert_eq!((Some(&b"key3"[..]), &b"val3"[..]),
cursor.get(None, None, MDB_GET_CURRENT).unwrap());
assert_eq!((Some(&b"key3"[..]), &b"val3"[..]), cursor.get(None, None, MDB_GET_CURRENT).unwrap());
cursor.del(WriteFlags::empty()).unwrap();
assert_eq!((Some(&b"key2"[..]), &b"val2"[..]),
cursor.get(None, None, MDB_LAST).unwrap());
assert_eq!((Some(&b"key2"[..]), &b"val2"[..]), cursor.get(None, None, MDB_LAST).unwrap());
}
}

@ -4,7 +4,10 @@ use std::ptr;
use ffi;
use error::{Result, lmdb_result};
use error::{
lmdb_result,
Result,
};
/// A handle to an individual database in an environment.
///
@ -15,20 +18,22 @@ pub struct Database {
}
impl Database {
/// Opens a new database handle in the given transaction.
///
/// Prefer using `Environment::open_db`, `Environment::create_db`, `TransactionExt::open_db`,
/// or `RwTransaction::create_db`.
pub(crate) unsafe fn new(txn: *mut ffi::MDB_txn,
name: Option<&str>,
flags: c_uint)
-> Result<Database> {
pub(crate) unsafe fn new(txn: *mut ffi::MDB_txn, name: Option<&str>, flags: c_uint) -> Result<Database> {
let c_name = name.map(|n| CString::new(n).unwrap());
let name_ptr = if let Some(ref c_name) = c_name { c_name.as_ptr() } else { ptr::null() };
let name_ptr = if let Some(ref c_name) = c_name {
c_name.as_ptr()
} else {
ptr::null()
};
let mut dbi: ffi::MDB_dbi = 0;
lmdb_result(ffi::mdb_dbi_open(txn, name_ptr, flags, &mut dbi))?;
Ok(Database { dbi: dbi })
Ok(Database {
dbi: dbi,
})
}
pub(crate) fn freelist_db() -> Database {

@ -1,22 +1,44 @@
use libc::{c_uint, size_t};
use std::{fmt, ptr, result, mem};
use libc::{
c_uint,
size_t,
};
use std::ffi::CString;
#[cfg(unix)]
use std::os::unix::ffi::OsStrExt;
#[cfg(windows)]
use std::ffi::OsStr;
#[cfg(unix)]
use std::os::unix::ffi::OsStrExt;
use std::path::Path;
use std::sync::Mutex;
use std::{
fmt,
mem,
ptr,
result,
};
use ffi;
use byteorder::{ByteOrder, NativeEndian};
use byteorder::{
ByteOrder,
NativeEndian,
};
use cursor::Cursor;
use error::{Error, Result, lmdb_result};
use database::Database;
use transaction::{RoTransaction, RwTransaction, Transaction};
use flags::{DatabaseFlags, EnvironmentFlags};
use error::{
lmdb_result,
Error,
Result,
};
use flags::{
DatabaseFlags,
EnvironmentFlags,
};
use transaction::{
RoTransaction,
RwTransaction,
Transaction,
};
#[cfg(windows)]
/// Adding a 'missing' trait from windows OsStrExt
@ -39,14 +61,13 @@ pub struct Environment {
}
impl Environment {
/// Creates a new builder for specifying options for opening an LMDB environment.
pub fn new() -> EnvironmentBuilder {
EnvironmentBuilder {
flags: EnvironmentFlags::empty(),
max_readers: None,
max_dbs: None,
map_size: None
map_size: None,
}
}
@ -95,10 +116,7 @@ impl Environment {
///
/// This function will fail with `Error::BadRslot` if called by a thread with an open
/// transaction.
pub fn create_db<'env>(&'env self,
name: Option<&str>,
flags: DatabaseFlags)
-> Result<Database> {
pub fn create_db<'env>(&'env self, name: Option<&str>, flags: DatabaseFlags) -> Result<Database> {
let mutex = self.dbi_open_mutex.lock();
let txn = self.begin_rw_txn()?;
let db = unsafe { txn.create_db(name, flags)? };
@ -137,7 +155,14 @@ impl Environment {
/// the environment was opened with `MDB_NOSYNC` or in part `MDB_NOMETASYNC`.
pub fn sync(&self, force: bool) -> Result<()> {
unsafe {
lmdb_result(ffi::mdb_env_sync(self.env(), if force { 1 } else { 0 }))
lmdb_result(ffi::mdb_env_sync(
self.env(),
if force {
1
} else {
0
},
))
}
}
@ -239,9 +264,7 @@ impl Environment {
/// with size 0 to update the environment. Otherwise, new transaction creation
/// will fail with `Error::MapResized`.
pub fn set_map_size(&self, size: size_t) -> Result<()> {
unsafe {
lmdb_result(ffi::mdb_env_set_mapsize(self.env(), size))
}
unsafe { lmdb_result(ffi::mdb_env_set_mapsize(self.env(), size)) }
}
}
@ -253,9 +276,7 @@ pub struct Stat(ffi::MDB_stat);
impl Stat {
/// Create a new Stat with zero'd inner struct `ffi::MDB_stat`.
pub(crate) fn new() -> Stat {
unsafe {
Stat(mem::zeroed())
}
unsafe { Stat(mem::zeroed()) }
}
/// Returns a mut pointer to `ffi::MDB_stat`.
@ -368,7 +389,6 @@ pub struct EnvironmentBuilder {
}
impl EnvironmentBuilder {
/// Open an environment.
///
/// On UNIX, the database files will be opened with 644 permissions.
@ -390,26 +410,27 @@ impl EnvironmentBuilder {
unsafe {
lmdb_try!(ffi::mdb_env_create(&mut env));
if let Some(max_readers) = self.max_readers {
lmdb_try_with_cleanup!(ffi::mdb_env_set_maxreaders(env, max_readers),
ffi::mdb_env_close(env))
lmdb_try_with_cleanup!(ffi::mdb_env_set_maxreaders(env, max_readers), ffi::mdb_env_close(env))
}
if let Some(max_dbs) = self.max_dbs {
lmdb_try_with_cleanup!(ffi::mdb_env_set_maxdbs(env, max_dbs),
ffi::mdb_env_close(env))
lmdb_try_with_cleanup!(ffi::mdb_env_set_maxdbs(env, max_dbs), ffi::mdb_env_close(env))
}
if let Some(map_size) = self.map_size {
lmdb_try_with_cleanup!(ffi::mdb_env_set_mapsize(env, map_size),
ffi::mdb_env_close(env))
lmdb_try_with_cleanup!(ffi::mdb_env_set_mapsize(env, map_size), ffi::mdb_env_close(env))
}
let path = match CString::new(path.as_os_str().as_bytes()) {
Ok(path) => path,
Err(..) => return Err(::Error::Invalid),
};
lmdb_try_with_cleanup!(ffi::mdb_env_open(env, path.as_ptr(), self.flags.bits(), mode),
ffi::mdb_env_close(env));
lmdb_try_with_cleanup!(
ffi::mdb_env_open(env, path.as_ptr(), self.flags.bits(), mode),
ffi::mdb_env_close(env)
);
}
Ok(Environment { env: env, dbi_open_mutex: Mutex::new(()) })
Ok(Environment {
env: env,
dbi_open_mutex: Mutex::new(()),
})
}
/// Sets the provided options in the environment.
@ -465,8 +486,11 @@ mod test {
extern crate byteorder;
use self::byteorder::{
ByteOrder,
LittleEndian,
};
use tempdir::TempDir;
use self::byteorder::{ByteOrder, LittleEndian};
use flags::*;
@ -477,34 +501,30 @@ mod test {
let dir = TempDir::new("test").unwrap();
// opening non-existent env with read-only should fail
assert!(Environment::new().set_flags(EnvironmentFlags::READ_ONLY)
.open(dir.path())
.is_err());
assert!(Environment::new().set_flags(EnvironmentFlags::READ_ONLY).open(dir.path()).is_err());
// opening non-existent env should succeed
assert!(Environment::new().open(dir.path()).is_ok());
// opening env with read-only should succeed
assert!(Environment::new().set_flags(EnvironmentFlags::READ_ONLY)
.open(dir.path())
.is_ok());
assert!(Environment::new().set_flags(EnvironmentFlags::READ_ONLY).open(dir.path()).is_ok());
}
#[test]
fn test_begin_txn() {
let dir = TempDir::new("test").unwrap();
{ // writable environment
{
// writable environment
let env = Environment::new().open(dir.path()).unwrap();
assert!(env.begin_rw_txn().is_ok());
assert!(env.begin_ro_txn().is_ok());
}
{ // read-only environment
let env = Environment::new().set_flags(EnvironmentFlags::READ_ONLY)
.open(dir.path())
.unwrap();
{
// read-only environment
let env = Environment::new().set_flags(EnvironmentFlags::READ_ONLY).open(dir.path()).unwrap();
assert!(env.begin_rw_txn().is_err());
assert!(env.begin_ro_txn().is_ok());
@ -514,9 +534,7 @@ mod test {
#[test]
fn test_open_db() {
let dir = TempDir::new("test").unwrap();
let env = Environment::new().set_max_dbs(1)
.open(dir.path())
.unwrap();
let env = Environment::new().set_max_dbs(1).open(dir.path()).unwrap();
assert!(env.open_db(None).is_ok());
assert!(env.open_db(Some("testdb")).is_err());
@ -525,9 +543,7 @@ mod test {
#[test]
fn test_create_db() {
let dir = TempDir::new("test").unwrap();
let env = Environment::new().set_max_dbs(11)
.open(dir.path())
.unwrap();
let env = Environment::new().set_max_dbs(11).open(dir.path()).unwrap();
assert!(env.open_db(Some("testdb")).is_err());
assert!(env.create_db(Some("testdb"), DatabaseFlags::empty()).is_ok());
assert!(env.open_db(Some("testdb")).is_ok())
@ -536,12 +552,12 @@ mod test {
#[test]
fn test_close_database() {
let dir = TempDir::new("test").unwrap();
let mut env = Environment::new().set_max_dbs(10)
.open(dir.path())
.unwrap();
let mut env = Environment::new().set_max_dbs(10).open(dir.path()).unwrap();
let db = env.create_db(Some("db"), DatabaseFlags::empty()).unwrap();
unsafe { env.close_db(db); }
unsafe {
env.close_db(db);
}
assert!(env.open_db(Some("db")).is_ok());
}
@ -551,10 +567,9 @@ mod test {
{
let env = Environment::new().open(dir.path()).unwrap();
assert!(env.sync(true).is_ok());
} {
let env = Environment::new().set_flags(EnvironmentFlags::READ_ONLY)
.open(dir.path())
.unwrap();
}
{
let env = Environment::new().set_flags(EnvironmentFlags::READ_ONLY).open(dir.path()).unwrap();
assert!(env.sync(true).is_err());
}
}
@ -598,10 +613,7 @@ mod test {
fn test_info() {
let map_size = 1024 * 1024;
let dir = TempDir::new("test").unwrap();
let env = Environment::new()
.set_map_size(map_size)
.open(dir.path())
.unwrap();
let env = Environment::new().set_map_size(map_size).open(dir.path()).unwrap();
let info = env.info().unwrap();
assert_eq!(info.map_size(), map_size);

@ -2,7 +2,11 @@ use libc::c_int;
use std::error::Error as StdError;
use std::ffi::CStr;
use std::os::raw::c_char;
use std::{fmt, result, str};
use std::{
fmt,
result,
str,
};
use ffi;
@ -54,7 +58,6 @@ pub enum Error {
}
impl Error {
/// Converts a raw error code to an `Error`.
pub fn from_err_code(err_code: c_int) -> Error {
match err_code {
@ -146,9 +149,7 @@ mod test {
#[test]
fn test_description() {
assert_eq!("Permission denied",
Error::from_err_code(13).description());
assert_eq!("MDB_NOTFOUND: No matching key/data pair found",
Error::NotFound.description());
assert_eq!("Permission denied", Error::from_err_code(13).description());
assert_eq!("MDB_NOTFOUND: No matching key/data pair found", Error::NotFound.description());
}
}

@ -4,19 +4,21 @@
#![deny(missing_docs)]
#![doc(html_root_url = "https://docs.rs/lmdb-rkv/0.12.0")]
extern crate byteorder;
extern crate libc;
extern crate lmdb_rkv_sys as ffi;
extern crate byteorder;
#[cfg(test)] extern crate tempdir;
#[macro_use] extern crate bitflags;
#[cfg(test)]
extern crate tempdir;
#[macro_use]
extern crate bitflags;
pub use cursor::{
Cursor,
RoCursor,
RwCursor,
Iter,
IterDup,
RoCursor,
RwCursor,
};
pub use database::Database;
pub use environment::{
@ -25,7 +27,10 @@ pub use environment::{
Info,
Stat,
};
pub use error::{Error, Result};
pub use error::{
Error,
Result,
};
pub use flags::*;
pub use transaction::{
InactiveTransaction,
@ -35,37 +40,40 @@ pub use transaction::{
};
macro_rules! lmdb_try {
($expr:expr) => ({
($expr:expr) => {{
match $expr {
::ffi::MDB_SUCCESS => (),
err_code => return Err(::Error::from_err_code(err_code)),
}
})
}};
}
macro_rules! lmdb_try_with_cleanup {
($expr:expr, $cleanup:expr) => ({
($expr:expr, $cleanup:expr) => {{
match $expr {
::ffi::MDB_SUCCESS => (),
err_code => {
let _ = $cleanup;
return Err(::Error::from_err_code(err_code))
return Err(::Error::from_err_code(err_code));
},
}
})
}};
}
mod flags;
mod cursor;
mod database;
mod environment;
mod error;
mod flags;
mod transaction;
#[cfg(test)]
mod test_utils {
use byteorder::{ByteOrder, LittleEndian};
use byteorder::{
ByteOrder,
LittleEndian,
};
use tempdir::TempDir;
use super::*;
@ -91,10 +99,7 @@ mod test_utils {
let mut value = [0u8; 8];
LittleEndian::write_u64(&mut value, height);
let mut tx = env.begin_rw_txn().expect("begin_rw_txn");
tx.put(index,
&HEIGHT_KEY,
&value,
WriteFlags::empty()).expect("tx.put");
tx.put(index, &HEIGHT_KEY, &value, WriteFlags::empty()).expect("tx.put");
tx.commit().expect("tx.commit")
}
}

@ -1,20 +1,43 @@
use libc::{c_uint, c_void, size_t};
use std::{fmt, mem, ptr, result, slice};
use std::marker::PhantomData ;
use libc::{
c_uint,
c_void,
size_t,
};
use std::marker::PhantomData;
use std::{
fmt,
mem,
ptr,
result,
slice,
};
use ffi;
use cursor::{RoCursor, RwCursor};
use environment::{Environment, Stat};
use cursor::{
RoCursor,
RwCursor,
};
use database::Database;
use error::{Error, Result, lmdb_result};
use flags::{DatabaseFlags, EnvironmentFlags, WriteFlags};
use environment::{
Environment,
Stat,
};
use error::{
lmdb_result,
Error,
Result,
};
use flags::{
DatabaseFlags,
EnvironmentFlags,
WriteFlags,
};
/// An LMDB transaction.
///
/// All database operations require a transaction.
pub trait Transaction : Sized {
pub trait Transaction: Sized {
/// Returns a raw pointer to the underlying LMDB transaction.
///
/// The caller **must** ensure that the pointer is not used after the
@ -68,22 +91,22 @@ pub trait Transaction : Sized {
/// returned. Retrieval of other items requires the use of
/// `Transaction::cursor_get`. If the item is not in the database, then
/// `Error::NotFound` will be returned.
fn get<'txn, K>(&'txn self,
database: Database,
key: &K)
-> Result<&'txn [u8]>
where K: AsRef<[u8]> {
fn get<'txn, K>(&'txn self, database: Database, key: &K) -> Result<&'txn [u8]>
where
K: AsRef<[u8]>,
{
let key = key.as_ref();
let mut key_val: ffi::MDB_val = ffi::MDB_val { mv_size: key.len() as size_t,
mv_data: key.as_ptr() as *mut c_void };
let mut data_val: ffi::MDB_val = ffi::MDB_val { mv_size: 0,
mv_data: ptr::null_mut() };
let mut key_val: ffi::MDB_val = ffi::MDB_val {
mv_size: key.len() as size_t,
mv_data: key.as_ptr() as *mut c_void,
};
let mut data_val: ffi::MDB_val = ffi::MDB_val {
mv_size: 0,
mv_data: ptr::null_mut(),
};
unsafe {
match ffi::mdb_get(self.txn(), database.dbi(), &mut key_val, &mut data_val) {
ffi::MDB_SUCCESS => {
Ok(slice::from_raw_parts(data_val.mv_data as *const u8,
data_val.mv_size as usize))
},
ffi::MDB_SUCCESS => Ok(slice::from_raw_parts(data_val.mv_data as *const u8, data_val.mv_size as usize)),
err_code => Err(Error::from_err_code(err_code)),
}
}
@ -119,27 +142,29 @@ pub struct RoTransaction<'env> {
_marker: PhantomData<&'env ()>,
}
impl <'env> fmt::Debug for RoTransaction<'env> {
impl<'env> fmt::Debug for RoTransaction<'env> {
fn fmt(&self, f: &mut fmt::Formatter) -> result::Result<(), fmt::Error> {
f.debug_struct("RoTransaction").finish()
}
}
impl <'env> Drop for RoTransaction<'env> {
impl<'env> Drop for RoTransaction<'env> {
fn drop(&mut self) {
unsafe { ffi::mdb_txn_abort(self.txn) }
}
}
impl <'env> RoTransaction<'env> {
impl<'env> RoTransaction<'env> {
/// Creates a new read-only transaction in the given environment. Prefer
/// using `Environment::begin_ro_txn`.
pub(crate) fn new(env: &'env Environment) -> Result<RoTransaction<'env>> {
let mut txn: *mut ffi::MDB_txn = ptr::null_mut();
unsafe {
lmdb_result(ffi::mdb_txn_begin(env.env(), ptr::null_mut(), ffi::MDB_RDONLY, &mut txn))?;
Ok(RoTransaction { txn: txn, _marker: PhantomData })
Ok(RoTransaction {
txn: txn,
_marker: PhantomData,
})
}
}
@ -161,11 +186,14 @@ impl <'env> RoTransaction<'env> {
mem::forget(self);
ffi::mdb_txn_reset(txn)
};
InactiveTransaction { txn: txn, _marker: PhantomData }
InactiveTransaction {
txn: txn,
_marker: PhantomData,
}
}
}
impl <'env> Transaction for RoTransaction<'env> {
impl<'env> Transaction for RoTransaction<'env> {
fn txn(&self) -> *mut ffi::MDB_txn {
self.txn
}
@ -177,20 +205,19 @@ pub struct InactiveTransaction<'env> {
_marker: PhantomData<&'env ()>,
}
impl <'env> fmt::Debug for InactiveTransaction<'env> {
impl<'env> fmt::Debug for InactiveTransaction<'env> {
fn fmt(&self, f: &mut fmt::Formatter) -> result::Result<(), fmt::Error> {
f.debug_struct("InactiveTransaction").finish()
}
}
impl <'env> Drop for InactiveTransaction<'env> {
impl<'env> Drop for InactiveTransaction<'env> {
fn drop(&mut self) {
unsafe { ffi::mdb_txn_abort(self.txn) }
}
}
impl <'env> InactiveTransaction<'env> {
impl<'env> InactiveTransaction<'env> {
/// Renews the inactive transaction, returning an active read-only
/// transaction.
///
@ -202,7 +229,10 @@ impl <'env> InactiveTransaction<'env> {
mem::forget(self);
lmdb_result(ffi::mdb_txn_renew(txn))?
};
Ok(RoTransaction { txn: txn, _marker: PhantomData })
Ok(RoTransaction {
txn: txn,
_marker: PhantomData,
})
}
}
@ -212,30 +242,29 @@ pub struct RwTransaction<'env> {
_marker: PhantomData<&'env ()>,
}
impl <'env> fmt::Debug for RwTransaction<'env> {
impl<'env> fmt::Debug for RwTransaction<'env> {
fn fmt(&self, f: &mut fmt::Formatter) -> result::Result<(), fmt::Error> {
f.debug_struct("RwTransaction").finish()
}
}
impl <'env> Drop for RwTransaction<'env> {
impl<'env> Drop for RwTransaction<'env> {
fn drop(&mut self) {
unsafe { ffi::mdb_txn_abort(self.txn) }
}
}
impl <'env> RwTransaction<'env> {
impl<'env> RwTransaction<'env> {
/// Creates a new read-write transaction in the given environment. Prefer
/// using `Environment::begin_ro_txn`.
pub(crate) fn new(env: &'env Environment) -> Result<RwTransaction<'env>> {
let mut txn: *mut ffi::MDB_txn = ptr::null_mut();
unsafe {
lmdb_result(ffi::mdb_txn_begin(env.env(),
ptr::null_mut(),
EnvironmentFlags::empty().bits(),
&mut txn))?;
Ok(RwTransaction { txn: txn, _marker: PhantomData })
lmdb_result(ffi::mdb_txn_begin(env.env(), ptr::null_mut(), EnvironmentFlags::empty().bits(), &mut txn))?;
Ok(RwTransaction {
txn: txn,
_marker: PhantomData,
})
}
}
@ -271,51 +300,55 @@ impl <'env> RwTransaction<'env> {
/// behavior is to enter the new key/data pair, replacing any previously
/// existing key if duplicates are disallowed, or adding a duplicate data
/// item if duplicates are allowed (`DatabaseFlags::DUP_SORT`).
pub fn put<K, D>(&mut self,
database: Database,
key: &K,
data: &D,
flags: WriteFlags)
-> Result<()>
where K: AsRef<[u8]>, D: AsRef<[u8]> {
pub fn put<K, D>(&mut self, database: Database, key: &K, data: &D, flags: WriteFlags) -> Result<()>
where
K: AsRef<[u8]>,
D: AsRef<[u8]>,
{
let key = key.as_ref();
let data = data.as_ref();
let mut key_val: ffi::MDB_val = ffi::MDB_val { mv_size: key.len() as size_t,
mv_data: key.as_ptr() as *mut c_void };
let mut data_val: ffi::MDB_val = ffi::MDB_val { mv_size: data.len() as size_t,
mv_data: data.as_ptr() as *mut c_void };
unsafe {
lmdb_result(ffi::mdb_put(self.txn(),
database.dbi(),
&mut key_val,
&mut data_val,
flags.bits()))
}
let mut key_val: ffi::MDB_val = ffi::MDB_val {
mv_size: key.len() as size_t,
mv_data: key.as_ptr() as *mut c_void,
};
let mut data_val: ffi::MDB_val = ffi::MDB_val {
mv_size: data.len() as size_t,
mv_data: data.as_ptr() as *mut c_void,
};
unsafe { lmdb_result(ffi::mdb_put(self.txn(), database.dbi(), &mut key_val, &mut data_val, flags.bits())) }
}
/// Returns a buffer which can be used to write a value into the item at the
/// given key and with the given length. The buffer must be completely
/// filled by the caller.
pub fn reserve<'txn, K>(&'txn mut self,
pub fn reserve<'txn, K>(
&'txn mut self,
database: Database,
key: &K,
len: size_t,
flags: WriteFlags)
-> Result<&'txn mut [u8]>
where K: AsRef<[u8]> {
flags: WriteFlags,
) -> Result<&'txn mut [u8]>
where
K: AsRef<[u8]>,
{
let key = key.as_ref();
let mut key_val: ffi::MDB_val = ffi::MDB_val { mv_size: key.len() as size_t,
mv_data: key.as_ptr() as *mut c_void };
let mut data_val: ffi::MDB_val = ffi::MDB_val { mv_size: len,
mv_data: ptr::null_mut::<c_void>() };
let mut key_val: ffi::MDB_val = ffi::MDB_val {
mv_size: key.len() as size_t,
mv_data: key.as_ptr() as *mut c_void,
};
let mut data_val: ffi::MDB_val = ffi::MDB_val {
mv_size: len,
mv_data: ptr::null_mut::<c_void>(),
};
unsafe {
lmdb_result(ffi::mdb_put(self.txn(),
lmdb_result(ffi::mdb_put(
self.txn(),
database.dbi(),
&mut key_val,
&mut data_val,
flags.bits() | ffi::MDB_RESERVE))?;
Ok(slice::from_raw_parts_mut(data_val.mv_data as *mut u8,
data_val.mv_size as usize))
flags.bits() | ffi::MDB_RESERVE,
))?;
Ok(slice::from_raw_parts_mut(data_val.mv_data as *mut u8, data_val.mv_size as usize))
}
}
@ -329,34 +362,24 @@ impl <'env> RwTransaction<'env> {
/// `Some` only the matching data item will be deleted. This function will
/// return `Error::NotFound` if the specified key/data pair is not in the
/// database.
pub fn del<K>(&mut self,
database: Database,
key: &K,
data: Option<&[u8]>)
-> Result<()>
where K: AsRef<[u8]> {
pub fn del<K>(&mut self, database: Database, key: &K, data: Option<&[u8]>) -> Result<()>
where
K: AsRef<[u8]>,
{
let key = key.as_ref();
let mut key_val: ffi::MDB_val = ffi::MDB_val { mv_size: key.len() as size_t,
mv_data: key.as_ptr() as *mut c_void };
let data_val: Option<ffi::MDB_val> =
data.map(|data| ffi::MDB_val { mv_size: data.len() as size_t,
mv_data: data.as_ptr() as *mut c_void });
let mut key_val: ffi::MDB_val = ffi::MDB_val {
mv_size: key.len() as size_t,
mv_data: key.as_ptr() as *mut c_void,
};
let data_val: Option<ffi::MDB_val> = data.map(|data| ffi::MDB_val {
mv_size: data.len() as size_t,
mv_data: data.as_ptr() as *mut c_void,
});
if let Some(mut d) = data_val {
unsafe {
lmdb_result(ffi::mdb_del(self.txn(),
database.dbi(),
&mut key_val,
&mut d))
}
unsafe { lmdb_result(ffi::mdb_del(self.txn(), database.dbi(), &mut key_val, &mut d)) }
} else {
unsafe {
lmdb_result(ffi::mdb_del(self.txn(),
database.dbi(),
&mut key_val,
ptr::null_mut()))
}
unsafe { lmdb_result(ffi::mdb_del(self.txn(), database.dbi(), &mut key_val, ptr::null_mut())) }
}
}
@ -382,11 +405,14 @@ impl <'env> RwTransaction<'env> {
let env: *mut ffi::MDB_env = ffi::mdb_txn_env(self.txn());
ffi::mdb_txn_begin(env, self.txn(), 0, &mut nested);
}
Ok(RwTransaction { txn: nested, _marker: PhantomData })
Ok(RwTransaction {
txn: nested,
_marker: PhantomData,
})
}
}
impl <'env> Transaction for RwTransaction<'env> {
impl<'env> Transaction for RwTransaction<'env> {
fn txn(&self) -> *mut ffi::MDB_txn {
self.txn
}
@ -396,16 +422,21 @@ impl <'env> Transaction for RwTransaction<'env> {
mod test {
use std::io::Write;
use std::sync::{Arc, Barrier};
use std::thread::{self, JoinHandle};
use std::sync::{
Arc,
Barrier,
};
use std::thread::{
self,
JoinHandle,
};
use tempdir::TempDir;
use environment::*;
use error::*;
use flags::*;
use super::*;
use cursor::Cursor;
use error::*;
use flags::*;
#[test]
fn test_put_get_del() {
@ -451,9 +482,8 @@ mod test {
{
let mut cur = txn.open_ro_cursor(db).unwrap();
let iter = cur.iter_dup_of(b"key1");
let vals = iter.map(|x| x.unwrap()).map(|(_,x)| x).collect::<Vec<_>>();
let vals = iter.map(|x| x.unwrap()).map(|(_, x)| x).collect::<Vec<_>>();
assert_eq!(vals, vec![b"val1", b"val2", b"val3"]);
}
txn.commit().unwrap();
@ -466,7 +496,7 @@ mod test {
{
let mut cur = txn.open_ro_cursor(db).unwrap();
let iter = cur.iter_dup_of(b"key1");
let vals = iter.map(|x| x.unwrap()).map(|(_,x)| x).collect::<Vec<_>>();
let vals = iter.map(|x| x.unwrap()).map(|(_, x)| x).collect::<Vec<_>>();
assert_eq!(vals, vec![b"val1", b"val3"]);
let iter = cur.iter_dup_of(b"key2");
@ -475,7 +505,6 @@ mod test {
txn.commit().unwrap();
}
#[test]
fn test_reserve() {
let dir = TempDir::new("test").unwrap();
@ -557,12 +586,10 @@ mod test {
assert_eq!(txn.get(db, b"key"), Err(Error::NotFound));
}
#[test]
fn test_drop_db() {
let dir = TempDir::new("test").unwrap();
let env = Environment::new().set_max_dbs(2)
.open(dir.path()).unwrap();
let env = Environment::new().set_max_dbs(2).open(dir.path()).unwrap();
let db = env.create_db(Some("test"), DatabaseFlags::empty()).unwrap();
{
@ -572,7 +599,9 @@ mod test {
}
{
let mut txn = env.begin_rw_txn().unwrap();
unsafe { txn.drop_db(db).unwrap(); }
unsafe {
txn.drop_db(db).unwrap();
}
txn.commit().unwrap();
}
@ -595,7 +624,7 @@ mod test {
let reader_env = env.clone();
let reader_barrier = barrier.clone();
threads.push(thread::spawn(move|| {
threads.push(thread::spawn(move || {
let db = reader_env.open_db(None).unwrap();
{
let txn = reader_env.begin_ro_txn().unwrap();
@ -635,14 +664,10 @@ mod test {
for i in 0..n {
let writer_env = env.clone();
threads.push(thread::spawn(move|| {
threads.push(thread::spawn(move || {
let db = writer_env.open_db(None).unwrap();
let mut txn = writer_env.begin_rw_txn().unwrap();
txn.put(db,
&format!("{}{}", key, i),
&format!("{}{}", val, i),
WriteFlags::empty())
.unwrap();
txn.put(db, &format!("{}{}", key, i), &format!("{}{}", val, i), WriteFlags::empty()).unwrap();
txn.commit().is_ok()
}));
}
@ -652,8 +677,7 @@ mod test {
let txn = env.begin_ro_txn().unwrap();
for i in 0..n {
assert_eq!(format!("{}{}", val, i).as_bytes(),
txn.get(db, &format!("{}{}", key, i)).unwrap());
assert_eq!(format!("{}{}", val, i).as_bytes(), txn.get(db, &format!("{}{}", key, i)).unwrap());
}
}

Loading…
Cancel
Save