|
|
|
@ -1,17 +1,31 @@ |
|
|
|
|
use std::marker::PhantomData; |
|
|
|
|
use std::{fmt, mem, ptr, result, slice}; |
|
|
|
|
use std::{ |
|
|
|
|
fmt, |
|
|
|
|
mem, |
|
|
|
|
ptr, |
|
|
|
|
result, |
|
|
|
|
slice, |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
use libc::{EINVAL, c_void, size_t, c_uint}; |
|
|
|
|
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), |
|
|
|
@ -123,14 +150,18 @@ impl <'txn> Drop for 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, |
|
|
|
|
cursor, |
|
|
|
|
_marker: PhantomData, |
|
|
|
|
}) |
|
|
|
|
} |
|
|
|
@ -161,31 +192,40 @@ impl <'txn> Drop for 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, |
|
|
|
|
_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(), |
|
|
|
|
}, |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -243,10 +285,14 @@ pub enum 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, |
|
|
|
|
op, |
|
|
|
|
next_op, |
|
|
|
|
_marker: PhantomData, |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -257,14 +303,24 @@ impl <'txn> fmt::Debug 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) { |
|
|
|
@ -310,10 +366,13 @@ pub enum 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, |
|
|
|
|
op, |
|
|
|
|
_marker: PhantomData, |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -324,18 +383,25 @@ impl <'txn> fmt::Debug 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(); |
|
|
|
@ -561,29 +614,40 @@ mod test { |
|
|
|
|
|
|
|
|
|
let txn = env.begin_ro_txn().unwrap(); |
|
|
|
|
let mut cursor = txn.open_ro_cursor(db).unwrap(); |
|
|
|
|
assert_eq!(items, cursor.iter_dup().flat_map(|x| x).collect::<Result<Vec<_>>>().unwrap()); |
|
|
|
|
assert_eq!(items, cursor.iter_dup().flatten().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().flatten().collect::<Result<Vec<_>>>().unwrap() |
|
|
|
|
); |
|
|
|
|
|
|
|
|
|
assert_eq!(items, cursor.iter_dup_start().flatten().collect::<Result<Vec<(&[u8], &[u8])>>>().unwrap()); |
|
|
|
|
|
|
|
|
|
assert_eq!( |
|
|
|
|
items.clone().into_iter().skip(3).collect::<Vec<(&[u8], &[u8])>>(), |
|
|
|
|
cursor.iter_dup_from(b"b").flatten().collect::<Result<Vec<_>>>().unwrap() |
|
|
|
|
); |
|
|
|
|
|
|
|
|
|
assert_eq!( |
|
|
|
|
items.clone().into_iter().skip(3).collect::<Vec<(&[u8], &[u8])>>(), |
|
|
|
|
cursor.iter_dup_from(b"ab").flatten().collect::<Result<Vec<_>>>().unwrap() |
|
|
|
|
); |
|
|
|
|
|
|
|
|
|
assert_eq!( |
|
|
|
|
items.clone().into_iter().skip(9).collect::<Vec<(&[u8], &[u8])>>(), |
|
|
|
|
cursor.iter_dup_from(b"d").flatten().collect::<Result<Vec<_>>>().unwrap() |
|
|
|
|
); |
|
|
|
|
|
|
|
|
|
assert_eq!( |
|
|
|
|
vec!().into_iter().collect::<Vec<(&[u8], &[u8])>>(), |
|
|
|
|
cursor.iter_dup_from(b"f").flatten().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()); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|