lmdb/
cursor.rs

1use std::marker::PhantomData;
2use std::{fmt, mem, ptr, result, slice};
3
4use libc::{EINVAL, c_void, size_t, c_uint};
5
6use database::Database;
7use error::{Error, Result, lmdb_result};
8use ffi;
9use flags::WriteFlags;
10use transaction::Transaction;
11
12/// An LMDB cursor.
13pub trait Cursor<'txn> {
14
15    /// Returns a raw pointer to the underlying LMDB cursor.
16    ///
17    /// The caller **must** ensure that the pointer is not used after the
18    /// lifetime of the cursor.
19    fn cursor(&self) -> *mut ffi::MDB_cursor;
20
21    /// Retrieves a key/data pair from the cursor. Depending on the cursor op,
22    /// the current key may be returned.
23    fn get(&self, key: Option<&[u8]>, data: Option<&[u8]>, op: c_uint) -> Result<(Option<&'txn [u8]>, &'txn [u8])> {
24        unsafe {
25            let mut key_val = slice_to_val(key);
26            let mut data_val = slice_to_val(data);
27            let key_ptr = key_val.mv_data;
28            lmdb_result(ffi::mdb_cursor_get(self.cursor(), &mut key_val, &mut data_val, op))?;
29            let key_out = if key_ptr != key_val.mv_data { Some(val_to_slice(key_val)) } else { None };
30            let data_out = val_to_slice(data_val);
31            Ok((key_out, data_out))
32        }
33    }
34
35    /// Iterate over database items. The iterator will begin with item next
36    /// after the cursor, and continue until the end of the database. For new
37    /// cursors, the iterator will begin with the first item in the database.
38    ///
39    /// For databases with duplicate data items (`DatabaseFlags::DUP_SORT`), the
40    /// duplicate data items of each key will be returned before moving on to
41    /// the next key.
42    fn iter(&mut self) -> Iter<'txn> {
43        Iter::new(self.cursor(), ffi::MDB_NEXT, ffi::MDB_NEXT)
44    }
45
46    /// Iterate over database items starting from the beginning of the database.
47    ///
48    /// For databases with duplicate data items (`DatabaseFlags::DUP_SORT`), the
49    /// duplicate data items of each key will be returned before moving on to
50    /// the next key.
51    fn iter_start(&mut self) -> Iter<'txn> {
52        Iter::new(self.cursor(), ffi::MDB_FIRST, ffi::MDB_NEXT)
53    }
54
55    /// Iterate over database items starting from the given key.
56    ///
57    /// For databases with duplicate data items (`DatabaseFlags::DUP_SORT`), the
58    /// duplicate data items of each key will be returned before moving on to
59    /// the next key.
60    fn iter_from<K>(&mut self, key: K) -> Iter<'txn> where K: AsRef<[u8]> {
61        match self.get(Some(key.as_ref()), None, ffi::MDB_SET_RANGE) {
62            Ok(_) | Err(Error::NotFound) => (),
63            Err(error) => return Iter::Err(error),
64        };
65        Iter::new(self.cursor(), ffi::MDB_GET_CURRENT, ffi::MDB_NEXT)
66    }
67
68    /// Iterate over duplicate database items. The iterator will begin with the
69    /// item next after the cursor, and continue until the end of the database.
70    /// Each item will be returned as an iterator of its duplicates.
71    fn iter_dup(&mut self) -> IterDup<'txn> {
72        IterDup::new(self.cursor(), ffi::MDB_NEXT)
73    }
74
75    /// Iterate over duplicate database items starting from the beginning of the
76    /// database. Each item will be returned as an iterator of its duplicates.
77    fn iter_dup_start(&mut self) -> IterDup<'txn> {
78        IterDup::new(self.cursor(), ffi::MDB_FIRST)
79    }
80
81    /// Iterate over duplicate items in the database starting from the given
82    /// key. Each item will be returned as an iterator of its duplicates.
83    fn iter_dup_from<K>(&mut self, key: K) -> IterDup<'txn> where K: AsRef<[u8]> {
84        match self.get(Some(key.as_ref()), None, ffi::MDB_SET_RANGE) {
85            Ok(_) | Err(Error::NotFound) => (),
86            Err(error) => return IterDup::Err(error),
87        };
88        IterDup::new(self.cursor(), ffi::MDB_GET_CURRENT)
89    }
90
91    /// Iterate over the duplicates of the item in the database with the given key.
92    fn iter_dup_of<K>(&mut self, key: K) -> Iter<'txn> where K: AsRef<[u8]> {
93        match self.get(Some(key.as_ref()), None, ffi::MDB_SET) {
94            Ok(_) | Err(Error::NotFound) => (),
95            Err(error) => return Iter::Err(error),
96        };
97        Iter::new(self.cursor(), ffi::MDB_GET_CURRENT, ffi::MDB_NEXT_DUP)
98    }
99}
100
101/// A read-only cursor for navigating the items within a database.
102pub struct RoCursor<'txn> {
103    cursor: *mut ffi::MDB_cursor,
104    _marker: PhantomData<fn() -> &'txn ()>,
105}
106
107impl <'txn> Cursor<'txn> for RoCursor<'txn> {
108    fn cursor(&self) -> *mut ffi::MDB_cursor {
109        self.cursor
110    }
111}
112
113impl <'txn> fmt::Debug for RoCursor<'txn> {
114    fn fmt(&self, f: &mut fmt::Formatter) -> result::Result<(), fmt::Error> {
115        f.debug_struct("RoCursor").finish()
116    }
117}
118
119impl <'txn> Drop for RoCursor<'txn> {
120    fn drop(&mut self) {
121        unsafe { ffi::mdb_cursor_close(self.cursor) }
122    }
123}
124
125impl <'txn> RoCursor<'txn> {
126
127    /// Creates a new read-only cursor in the given database and transaction.
128    /// Prefer using `Transaction::open_cursor`.
129    pub(crate) fn new<T>(txn: &'txn T, db: Database) -> Result<RoCursor<'txn>> where T: Transaction {
130        let mut cursor: *mut ffi::MDB_cursor = ptr::null_mut();
131        unsafe { lmdb_result(ffi::mdb_cursor_open(txn.txn(), db.dbi(), &mut cursor))?; }
132        Ok(RoCursor {
133            cursor: cursor,
134            _marker: PhantomData,
135        })
136    }
137}
138
139/// A read-write cursor for navigating items within a database.
140pub struct RwCursor<'txn> {
141    cursor: *mut ffi::MDB_cursor,
142    _marker: PhantomData<fn() -> &'txn ()>,
143}
144
145impl <'txn> Cursor<'txn> for RwCursor<'txn> {
146    fn cursor(&self) -> *mut ffi::MDB_cursor {
147        self.cursor
148    }
149}
150
151impl <'txn> fmt::Debug for RwCursor<'txn> {
152    fn fmt(&self, f: &mut fmt::Formatter) -> result::Result<(), fmt::Error> {
153        f.debug_struct("RwCursor").finish()
154    }
155}
156
157impl <'txn> Drop for RwCursor<'txn> {
158    fn drop(&mut self) {
159        unsafe { ffi::mdb_cursor_close(self.cursor) }
160    }
161}
162
163impl <'txn> RwCursor<'txn> {
164
165    /// Creates a new read-only cursor in the given database and transaction.
166    /// Prefer using `RwTransaction::open_rw_cursor`.
167    pub(crate) fn new<T>(txn: &'txn T, db: Database) -> Result<RwCursor<'txn>> where T: Transaction {
168        let mut cursor: *mut ffi::MDB_cursor = ptr::null_mut();
169        unsafe { lmdb_result(ffi::mdb_cursor_open(txn.txn(), db.dbi(), &mut cursor))?; }
170        Ok(RwCursor { cursor: cursor, _marker: PhantomData })
171    }
172
173    /// Puts a key/data pair into the database. The cursor will be positioned at
174    /// the new data item, or on failure usually near it.
175    pub fn put<K, D>(&mut self, key: &K, data: &D, flags: WriteFlags) -> Result<()>
176    where K: AsRef<[u8]>, D: AsRef<[u8]> {
177        let key = key.as_ref();
178        let data = data.as_ref();
179        let mut key_val: ffi::MDB_val = ffi::MDB_val { mv_size: key.len() as size_t,
180                                                       mv_data: key.as_ptr() as *mut c_void };
181        let mut data_val: ffi::MDB_val = ffi::MDB_val { mv_size: data.len() as size_t,
182                                                        mv_data: data.as_ptr() as *mut c_void };
183        unsafe {
184            lmdb_result(ffi::mdb_cursor_put(self.cursor(),
185                                            &mut key_val,
186                                            &mut data_val,
187                                            flags.bits()))
188        }
189    }
190
191    /// Deletes the current key/data pair.
192    ///
193    /// ### Flags
194    ///
195    /// `WriteFlags::NO_DUP_DATA` may be used to delete all data items for the
196    /// current key, if the database was opened with `DatabaseFlags::DUP_SORT`.
197    pub fn del(&mut self, flags: WriteFlags) -> Result<()> {
198        unsafe { lmdb_result(ffi::mdb_cursor_del(self.cursor(), flags.bits())) }
199    }
200}
201
202unsafe fn slice_to_val(slice: Option<&[u8]>) -> ffi::MDB_val {
203    match slice {
204        Some(slice) =>
205            ffi::MDB_val { mv_size: slice.len() as size_t,
206                           mv_data: slice.as_ptr() as *mut c_void },
207        None =>
208            ffi::MDB_val { mv_size: 0,
209                           mv_data: ptr::null_mut() },
210    }
211}
212
213unsafe fn val_to_slice<'a>(val: ffi::MDB_val) -> &'a [u8] {
214    slice::from_raw_parts(val.mv_data as *const u8, val.mv_size as usize)
215}
216
217/// An iterator over the key/value pairs in an LMDB database.
218pub enum Iter<'txn> {
219    /// An iterator that returns an error on every call to Iter.next().
220    /// Cursor.iter*() creates an Iter of this type when LMDB returns an error
221    /// on retrieval of a cursor.  Using this variant instead of returning
222    /// an error makes Cursor.iter()* methods infallible, so consumers only
223    /// need to check the result of Iter.next().
224    Err(Error),
225
226    /// An iterator that returns an Item on calls to Iter.next().
227    /// The Item is a Result<(&'txn [u8], &'txn [u8])>, so this variant
228    /// might still return an error, if retrieval of the key/value pair
229    /// fails for some reason.
230    Ok {
231        /// The LMDB cursor with which to iterate.
232        cursor: *mut ffi::MDB_cursor,
233
234        /// The first operation to perform when the consumer calls Iter.next().
235        op: c_uint,
236
237        /// The next and subsequent operations to perform.
238        next_op: c_uint,
239
240        /// A marker to ensure the iterator doesn't outlive the transaction.
241        _marker: PhantomData<fn(&'txn ())>,
242    },
243}
244
245impl <'txn> Iter<'txn> {
246
247    /// Creates a new iterator backed by the given cursor.
248    fn new<'t>(cursor: *mut ffi::MDB_cursor, op: c_uint, next_op: c_uint) -> Iter<'t> {
249        Iter::Ok { cursor: cursor, op: op, next_op: next_op, _marker: PhantomData }
250    }
251}
252
253impl <'txn> fmt::Debug for Iter<'txn> {
254    fn fmt(&self, f: &mut fmt::Formatter) -> result::Result<(), fmt::Error> {
255        f.debug_struct("Iter").finish()
256    }
257}
258
259impl <'txn> Iterator for Iter<'txn> {
260
261    type Item = Result<(&'txn [u8], &'txn [u8])>;
262
263    fn next(&mut self) -> Option<Result<(&'txn [u8], &'txn [u8])>> {
264        match self {
265            &mut Iter::Ok { cursor, ref mut op, next_op, _marker } => {
266                let mut key = ffi::MDB_val { mv_size: 0, mv_data: ptr::null_mut() };
267                let mut data = ffi::MDB_val { mv_size: 0, mv_data: ptr::null_mut() };
268                let op = mem::replace(op, next_op);
269                unsafe {
270                    match ffi::mdb_cursor_get(cursor, &mut key, &mut data, op) {
271                        ffi::MDB_SUCCESS => Some(Ok((val_to_slice(key), val_to_slice(data)))),
272                        // EINVAL can occur when the cursor was previously seeked to a non-existent value,
273                        // e.g. iter_from with a key greater than all values in the database.
274                        ffi::MDB_NOTFOUND | EINVAL => None,
275                        error => Some(Err(Error::from_err_code(error))),
276                    }
277                }
278            },
279            &mut Iter::Err(err) => Some(Err(err)),
280        }
281    }
282}
283
284/// An iterator over the keys and duplicate values in an LMDB database.
285///
286/// The yielded items of the iterator are themselves iterators over the duplicate values for a
287/// specific key.
288pub enum IterDup<'txn> {
289    /// An iterator that returns an error on every call to Iter.next().
290    /// Cursor.iter*() creates an Iter of this type when LMDB returns an error
291    /// on retrieval of a cursor.  Using this variant instead of returning
292    /// an error makes Cursor.iter()* methods infallible, so consumers only
293    /// need to check the result of Iter.next().
294    Err(Error),
295
296    /// An iterator that returns an Item on calls to Iter.next().
297    /// The Item is a Result<(&'txn [u8], &'txn [u8])>, so this variant
298    /// might still return an error, if retrieval of the key/value pair
299    /// fails for some reason.
300    Ok {
301        /// The LMDB cursor with which to iterate.
302        cursor: *mut ffi::MDB_cursor,
303
304        /// The first operation to perform when the consumer calls Iter.next().
305        op: c_uint,
306
307        /// A marker to ensure the iterator doesn't outlive the transaction.
308        _marker: PhantomData<fn(&'txn ())>,
309    },
310}
311
312impl <'txn> IterDup<'txn> {
313
314    /// Creates a new iterator backed by the given cursor.
315    fn new<'t>(cursor: *mut ffi::MDB_cursor, op: c_uint) -> IterDup<'t> {
316        IterDup::Ok { cursor: cursor, op: op, _marker: PhantomData }
317    }
318}
319
320impl <'txn> fmt::Debug for IterDup<'txn> {
321    fn fmt(&self, f: &mut fmt::Formatter) -> result::Result<(), fmt::Error> {
322        f.debug_struct("IterDup").finish()
323    }
324}
325
326impl <'txn> Iterator for IterDup<'txn> {
327
328    type Item = Iter<'txn>;
329
330    fn next(&mut self) -> Option<Iter<'txn>> {
331        match self {
332            &mut IterDup::Ok { cursor, ref mut op, _marker } => {
333                let mut key = ffi::MDB_val { mv_size: 0, mv_data: ptr::null_mut() };
334                let mut data = ffi::MDB_val { mv_size: 0, mv_data: ptr::null_mut() };
335                let op = mem::replace(op, ffi::MDB_NEXT_NODUP);
336                let err_code = unsafe {
337                    ffi::mdb_cursor_get(cursor, &mut key, &mut data, op)
338                };
339
340                if err_code == ffi::MDB_SUCCESS {
341                    Some(Iter::new(cursor, ffi::MDB_GET_CURRENT, ffi::MDB_NEXT_DUP))
342                } else {
343                    None
344                }
345            },
346            &mut IterDup::Err(err) => Some(Iter::Err(err)),
347        }
348    }
349}
350
351#[cfg(test)]
352mod test {
353
354    use std::ptr;
355    use test::{Bencher, black_box};
356
357    use tempdir::TempDir;
358
359    use environment::*;
360    use ffi::*;
361    use flags::*;
362    use super::*;
363    use test_utils::*;
364
365    #[test]
366    fn test_get() {
367        let dir = TempDir::new("test").unwrap();
368        let env = Environment::new().open(dir.path()).unwrap();
369        let db = env.open_db(None).unwrap();
370
371        let mut txn = env.begin_rw_txn().unwrap();
372        txn.put(db, b"key1", b"val1", WriteFlags::empty()).unwrap();
373        txn.put(db, b"key2", b"val2", WriteFlags::empty()).unwrap();
374        txn.put(db, b"key3", b"val3", WriteFlags::empty()).unwrap();
375
376        let cursor = txn.open_ro_cursor(db).unwrap();
377        assert_eq!((Some(&b"key1"[..]), &b"val1"[..]),
378                   cursor.get(None, None, MDB_FIRST).unwrap());
379        assert_eq!((Some(&b"key1"[..]), &b"val1"[..]),
380                   cursor.get(None, None, MDB_GET_CURRENT).unwrap());
381        assert_eq!((Some(&b"key2"[..]), &b"val2"[..]),
382                   cursor.get(None, None, MDB_NEXT).unwrap());
383        assert_eq!((Some(&b"key1"[..]), &b"val1"[..]),
384                   cursor.get(None, None, MDB_PREV).unwrap());
385        assert_eq!((Some(&b"key3"[..]), &b"val3"[..]),
386                   cursor.get(None, None, MDB_LAST).unwrap());
387        assert_eq!((None, &b"val2"[..]),
388                   cursor.get(Some(b"key2"), None, MDB_SET).unwrap());
389        assert_eq!((Some(&b"key3"[..]), &b"val3"[..]),
390                   cursor.get(Some(&b"key3"[..]), None, MDB_SET_KEY).unwrap());
391        assert_eq!((Some(&b"key3"[..]), &b"val3"[..]),
392                   cursor.get(Some(&b"key2\0"[..]), None, MDB_SET_RANGE).unwrap());
393    }
394
395    #[test]
396    fn test_get_dup() {
397        let dir = TempDir::new("test").unwrap();
398        let env = Environment::new().open(dir.path()).unwrap();
399        let db = env.create_db(None, DatabaseFlags::DUP_SORT).unwrap();
400
401        let mut txn = env.begin_rw_txn().unwrap();
402        txn.put(db, b"key1", b"val1", WriteFlags::empty()).unwrap();
403        txn.put(db, b"key1", b"val2", WriteFlags::empty()).unwrap();
404        txn.put(db, b"key1", b"val3", WriteFlags::empty()).unwrap();
405        txn.put(db, b"key2", b"val1", WriteFlags::empty()).unwrap();
406        txn.put(db, b"key2", b"val2", WriteFlags::empty()).unwrap();
407        txn.put(db, b"key2", b"val3", WriteFlags::empty()).unwrap();
408
409        let cursor = txn.open_ro_cursor(db).unwrap();
410        assert_eq!((Some(&b"key1"[..]), &b"val1"[..]),
411                   cursor.get(None, None, MDB_FIRST).unwrap());
412        assert_eq!((None, &b"val1"[..]),
413                   cursor.get(None, None, MDB_FIRST_DUP).unwrap());
414        assert_eq!((Some(&b"key1"[..]), &b"val1"[..]),
415                   cursor.get(None, None, MDB_GET_CURRENT).unwrap());
416        assert_eq!((Some(&b"key2"[..]), &b"val1"[..]),
417                   cursor.get(None, None, MDB_NEXT_NODUP).unwrap());
418        assert_eq!((Some(&b"key2"[..]), &b"val2"[..]),
419                   cursor.get(None, None, MDB_NEXT_DUP).unwrap());
420        assert_eq!((Some(&b"key2"[..]), &b"val3"[..]),
421                   cursor.get(None, None, MDB_NEXT_DUP).unwrap());
422        assert!(cursor.get(None, None, MDB_NEXT_DUP).is_err());
423        assert_eq!((Some(&b"key2"[..]), &b"val2"[..]),
424                   cursor.get(None, None, MDB_PREV_DUP).unwrap());
425        assert_eq!((None, &b"val3"[..]),
426                   cursor.get(None, None, MDB_LAST_DUP).unwrap());
427        assert_eq!((Some(&b"key1"[..]), &b"val3"[..]),
428                   cursor.get(None, None, MDB_PREV_NODUP).unwrap());
429        assert_eq!((None, &b"val1"[..]),
430                   cursor.get(Some(&b"key1"[..]), None, MDB_SET).unwrap());
431        assert_eq!((Some(&b"key2"[..]), &b"val1"[..]),
432                   cursor.get(Some(&b"key2"[..]), None, MDB_SET_KEY).unwrap());
433        assert_eq!((Some(&b"key2"[..]), &b"val1"[..]),
434                   cursor.get(Some(&b"key1\0"[..]), None, MDB_SET_RANGE).unwrap());
435        assert_eq!((None, &b"val3"[..]),
436                   cursor.get(Some(&b"key1"[..]), Some(&b"val3"[..]), MDB_GET_BOTH).unwrap());
437        assert_eq!((None, &b"val1"[..]),
438                   cursor.get(Some(&b"key2"[..]), Some(&b"val"[..]), MDB_GET_BOTH_RANGE).unwrap());
439    }
440
441    #[test]
442    fn test_get_dupfixed() {
443        let dir = TempDir::new("test").unwrap();
444        let env = Environment::new().open(dir.path()).unwrap();
445        let db = env.create_db(None, DatabaseFlags::DUP_SORT | DatabaseFlags::DUP_FIXED).unwrap();
446
447        let mut txn = env.begin_rw_txn().unwrap();
448        txn.put(db, b"key1", b"val1", WriteFlags::empty()).unwrap();
449        txn.put(db, b"key1", b"val2", WriteFlags::empty()).unwrap();
450        txn.put(db, b"key1", b"val3", WriteFlags::empty()).unwrap();
451        txn.put(db, b"key2", b"val4", WriteFlags::empty()).unwrap();
452        txn.put(db, b"key2", b"val5", WriteFlags::empty()).unwrap();
453        txn.put(db, b"key2", b"val6", WriteFlags::empty()).unwrap();
454
455        let cursor = txn.open_ro_cursor(db).unwrap();
456        assert_eq!((Some(&b"key1"[..]), &b"val1"[..]),
457                   cursor.get(None, None, MDB_FIRST).unwrap());
458        assert_eq!((None, &b"val1val2val3"[..]),
459                   cursor.get(None, None, MDB_GET_MULTIPLE).unwrap());
460        assert!(cursor.get(None, None, MDB_NEXT_MULTIPLE).is_err());
461    }
462
463    #[test]
464    fn test_iter() {
465        let dir = TempDir::new("test").unwrap();
466        let env = Environment::new().open(dir.path()).unwrap();
467        let db = env.open_db(None).unwrap();
468
469        let items: Vec<(&[u8], &[u8])> = vec!((b"key1", b"val1"),
470                                              (b"key2", b"val2"),
471                                              (b"key3", b"val3"),
472                                              (b"key5", b"val5"));
473
474        {
475            let mut txn = env.begin_rw_txn().unwrap();
476            for &(ref key, ref data) in &items {
477                txn.put(db, key, data, WriteFlags::empty()).unwrap();
478            }
479            txn.commit().unwrap();
480        }
481
482        let txn = env.begin_ro_txn().unwrap();
483        let mut cursor = txn.open_ro_cursor(db).unwrap();
484
485        // Because Result implements FromIterator, we can collect the iterator
486        // of items of type Result<_, E> into a Result<Vec<_, E>> by specifying
487        // the collection type via the turbofish syntax.
488        assert_eq!(items, cursor.iter().collect::<Result<Vec<_>>>().unwrap());
489
490        // Alternately, we can collect it into an appropriately typed variable.
491        let retr: Result<Vec<_>> = cursor.iter_start().collect();
492        assert_eq!(items, retr.unwrap());
493
494        cursor.get(Some(b"key2"), None, MDB_SET).unwrap();
495        assert_eq!(items.clone().into_iter().skip(2).collect::<Vec<_>>(),
496                   cursor.iter().collect::<Result<Vec<_>>>().unwrap());
497
498        assert_eq!(items, cursor.iter_start().collect::<Result<Vec<_>>>().unwrap());
499
500        assert_eq!(items.clone().into_iter().skip(1).collect::<Vec<_>>(),
501                   cursor.iter_from(b"key2").collect::<Result<Vec<_>>>().unwrap());
502
503        assert_eq!(items.clone().into_iter().skip(3).collect::<Vec<_>>(),
504                   cursor.iter_from(b"key4").collect::<Result<Vec<_>>>().unwrap());
505
506        assert_eq!(vec!().into_iter().collect::<Vec<(&[u8], &[u8])>>(),
507                   cursor.iter_from(b"key6").collect::<Result<Vec<_>>>().unwrap());
508    }
509
510    #[test]
511    fn test_iter_empty_database() {
512        let dir = TempDir::new("test").unwrap();
513        let env = Environment::new().open(dir.path()).unwrap();
514        let db = env.open_db(None).unwrap();
515        let txn = env.begin_ro_txn().unwrap();
516        let mut cursor = txn.open_ro_cursor(db).unwrap();
517
518        assert_eq!(0, cursor.iter().count());
519        assert_eq!(0, cursor.iter_start().count());
520        assert_eq!(0, cursor.iter_from(b"foo").count());
521    }
522
523    #[test]
524    fn test_iter_empty_dup_database() {
525        let dir = TempDir::new("test").unwrap();
526        let env = Environment::new().open(dir.path()).unwrap();
527        let db = env.create_db(None, DatabaseFlags::DUP_SORT).unwrap();
528        let txn = env.begin_ro_txn().unwrap();
529        let mut cursor = txn.open_ro_cursor(db).unwrap();
530
531        assert_eq!(0, cursor.iter().count());
532        assert_eq!(0, cursor.iter_start().count());
533        assert_eq!(0, cursor.iter_from(b"foo").count());
534        assert_eq!(0, cursor.iter_dup().count());
535        assert_eq!(0, cursor.iter_dup_start().count());
536        assert_eq!(0, cursor.iter_dup_from(b"foo").count());
537        assert_eq!(0, cursor.iter_dup_of(b"foo").count());
538    }
539
540    #[test]
541    fn test_iter_dup() {
542        let dir = TempDir::new("test").unwrap();
543        let env = Environment::new().open(dir.path()).unwrap();
544        let db = env.create_db(None, DatabaseFlags::DUP_SORT).unwrap();
545
546        let items: Vec<(&[u8], &[u8])> = vec!((b"a", b"1"),
547                                              (b"a", b"2"),
548                                              (b"a", b"3"),
549                                              (b"b", b"1"),
550                                              (b"b", b"2"),
551                                              (b"b", b"3"),
552                                              (b"c", b"1"),
553                                              (b"c", b"2"),
554                                              (b"c", b"3"),
555                                              (b"e", b"1"),
556                                              (b"e", b"2"),
557                                              (b"e", b"3"));
558
559        {
560            let mut txn = env.begin_rw_txn().unwrap();
561            for &(ref key, ref data) in &items {
562                txn.put(db, key, data, WriteFlags::empty()).unwrap();
563            }
564            txn.commit().unwrap();
565        }
566
567        let txn = env.begin_ro_txn().unwrap();
568        let mut cursor = txn.open_ro_cursor(db).unwrap();
569        assert_eq!(items, cursor.iter_dup().flat_map(|x| x).collect::<Result<Vec<_>>>().unwrap());
570
571        cursor.get(Some(b"b"), None, MDB_SET).unwrap();
572        assert_eq!(items.clone().into_iter().skip(4).collect::<Vec<(&[u8], &[u8])>>(),
573                   cursor.iter_dup().flat_map(|x| x).collect::<Result<Vec<_>>>().unwrap());
574
575        assert_eq!(items,
576                   cursor.iter_dup_start().flat_map(|x| x).collect::<Result<Vec<(&[u8], &[u8])>>>().unwrap());
577
578        assert_eq!(items.clone().into_iter().skip(3).collect::<Vec<(&[u8], &[u8])>>(),
579                   cursor.iter_dup_from(b"b").flat_map(|x| x).collect::<Result<Vec<_>>>().unwrap());
580
581        assert_eq!(items.clone().into_iter().skip(3).collect::<Vec<(&[u8], &[u8])>>(),
582                   cursor.iter_dup_from(b"ab").flat_map(|x| x).collect::<Result<Vec<_>>>().unwrap());
583
584        assert_eq!(items.clone().into_iter().skip(9).collect::<Vec<(&[u8], &[u8])>>(),
585                   cursor.iter_dup_from(b"d").flat_map(|x| x).collect::<Result<Vec<_>>>().unwrap());
586
587        assert_eq!(vec!().into_iter().collect::<Vec<(&[u8], &[u8])>>(),
588                   cursor.iter_dup_from(b"f").flat_map(|x| x).collect::<Result<Vec<_>>>().unwrap());
589
590        assert_eq!(items.clone().into_iter().skip(3).take(3).collect::<Vec<(&[u8], &[u8])>>(),
591                   cursor.iter_dup_of(b"b").collect::<Result<Vec<_>>>().unwrap());
592
593        assert_eq!(0, cursor.iter_dup_of(b"foo").count());
594    }
595
596    #[test]
597    fn test_put_del() {
598        let dir = TempDir::new("test").unwrap();
599        let env = Environment::new().open(dir.path()).unwrap();
600        let db = env.open_db(None).unwrap();
601
602        let mut txn = env.begin_rw_txn().unwrap();
603        let mut cursor = txn.open_rw_cursor(db).unwrap();
604
605        cursor.put(b"key1", b"val1", WriteFlags::empty()).unwrap();
606        cursor.put(b"key2", b"val2", WriteFlags::empty()).unwrap();
607        cursor.put(b"key3", b"val3", WriteFlags::empty()).unwrap();
608
609        assert_eq!((Some(&b"key3"[..]), &b"val3"[..]),
610                   cursor.get(None, None, MDB_GET_CURRENT).unwrap());
611
612        cursor.del(WriteFlags::empty()).unwrap();
613        assert_eq!((Some(&b"key2"[..]), &b"val2"[..]),
614                   cursor.get(None, None, MDB_LAST).unwrap());
615    }
616
617    /// Benchmark of iterator sequential read performance.
618    #[bench]
619    fn bench_get_seq_iter(b: &mut Bencher) {
620        let n = 100;
621        let (_dir, env) = setup_bench_db(n);
622        let db = env.open_db(None).unwrap();
623        let txn = env.begin_ro_txn().unwrap();
624
625        b.iter(|| {
626            let mut cursor = txn.open_ro_cursor(db).unwrap();
627            let mut i = 0;
628            let mut count = 0u32;
629
630            for (key, data) in cursor.iter().map(Result::unwrap) {
631                i = i + key.len() + data.len();
632                count = count + 1;
633            }
634            for (key, data) in cursor.iter().filter_map(Result::ok) {
635                i = i + key.len() + data.len();
636                count = count + 1;
637            }
638
639            fn iterate<'a>(cursor: &mut RoCursor) -> Result<()> {
640                let mut i = 0;
641                let mut count = 0u32;
642                for result in cursor.iter() {
643                    let (key, data) = result?;
644                    i = i + key.len() + data.len();
645                    count = count + 1;
646                }
647                Ok(())
648            }
649            iterate(&mut cursor).unwrap();
650
651            black_box(i);
652            assert_eq!(count, n);
653        });
654    }
655
656    /// Benchmark of cursor sequential read performance.
657    #[bench]
658    fn bench_get_seq_cursor(b: &mut Bencher) {
659        let n = 100;
660        let (_dir, env) = setup_bench_db(n);
661        let db = env.open_db(None).unwrap();
662        let txn = env.begin_ro_txn().unwrap();
663
664        b.iter(|| {
665            let cursor = txn.open_ro_cursor(db).unwrap();
666            let mut i = 0;
667            let mut count = 0u32;
668
669            while let Ok((key_opt, val)) = cursor.get(None, None, MDB_NEXT) {
670                i += key_opt.map(|key| key.len()).unwrap_or(0) + val.len();
671                count += 1;
672            }
673
674            black_box(i);
675            assert_eq!(count, n);
676        });
677    }
678
679    /// Benchmark of raw LMDB sequential read performance (control).
680    #[bench]
681    fn bench_get_seq_raw(b: &mut Bencher) {
682        let n = 100;
683        let (_dir, env) = setup_bench_db(n);
684        let db = env.open_db(None).unwrap();
685
686        let dbi: MDB_dbi = db.dbi();
687        let _txn = env.begin_ro_txn().unwrap();
688        let txn = _txn.txn();
689
690        let mut key = MDB_val { mv_size: 0, mv_data: ptr::null_mut() };
691        let mut data = MDB_val { mv_size: 0, mv_data: ptr::null_mut() };
692        let mut cursor: *mut MDB_cursor = ptr::null_mut();
693
694        b.iter(|| unsafe {
695            mdb_cursor_open(txn, dbi, &mut cursor);
696            let mut i = 0;
697            let mut count = 0u32;
698
699            while mdb_cursor_get(cursor, &mut key, &mut data, MDB_NEXT) == 0 {
700                i += key.mv_size + data.mv_size;
701                count += 1;
702            };
703
704            black_box(i);
705            assert_eq!(count, n);
706            mdb_cursor_close(cursor);
707        });
708    }
709}