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
12pub trait Cursor<'txn> {
14
15 fn cursor(&self) -> *mut ffi::MDB_cursor;
20
21 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 fn iter(&mut self) -> Iter<'txn> {
43 Iter::new(self.cursor(), ffi::MDB_NEXT, ffi::MDB_NEXT)
44 }
45
46 fn iter_start(&mut self) -> Iter<'txn> {
52 Iter::new(self.cursor(), ffi::MDB_FIRST, ffi::MDB_NEXT)
53 }
54
55 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 fn iter_dup(&mut self) -> IterDup<'txn> {
72 IterDup::new(self.cursor(), ffi::MDB_NEXT)
73 }
74
75 fn iter_dup_start(&mut self) -> IterDup<'txn> {
78 IterDup::new(self.cursor(), ffi::MDB_FIRST)
79 }
80
81 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 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
101pub 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 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
139pub 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 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 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 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
217pub enum Iter<'txn> {
219 Err(Error),
225
226 Ok {
231 cursor: *mut ffi::MDB_cursor,
233
234 op: c_uint,
236
237 next_op: c_uint,
239
240 _marker: PhantomData<fn(&'txn ())>,
242 },
243}
244
245impl <'txn> Iter<'txn> {
246
247 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 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
284pub enum IterDup<'txn> {
289 Err(Error),
295
296 Ok {
301 cursor: *mut ffi::MDB_cursor,
303
304 op: c_uint,
306
307 _marker: PhantomData<fn(&'txn ())>,
309 },
310}
311
312impl <'txn> IterDup<'txn> {
313
314 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 assert_eq!(items, cursor.iter().collect::<Result<Vec<_>>>().unwrap());
489
490 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 #[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 #[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 #[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}