1
- use libc:: { c_void, size_t, c_uint} ;
2
- use std:: { fmt, ptr, result, slice} ;
3
1
use std:: marker:: PhantomData ;
2
+ use std:: { fmt, mem, ptr, result, slice} ;
3
+
4
+ use libc:: { EINVAL , c_void, size_t, c_uint} ;
4
5
5
6
use database:: Database ;
6
7
use error:: { Error , Result , lmdb_result} ;
@@ -19,11 +20,7 @@ pub trait Cursor<'txn> {
19
20
20
21
/// Retrieves a key/data pair from the cursor. Depending on the cursor op,
21
22
/// the current key may be returned.
22
- fn get ( & self ,
23
- key : Option < & [ u8 ] > ,
24
- data : Option < & [ u8 ] > ,
25
- op : c_uint )
26
- -> Result < ( Option < & ' txn [ u8 ] > , & ' txn [ u8 ] ) > {
23
+ fn get ( & self , key : Option < & [ u8 ] > , data : Option < & [ u8 ] > , op : c_uint ) -> Result < ( Option < & ' txn [ u8 ] > , & ' txn [ u8 ] ) > {
27
24
unsafe {
28
25
let mut key_val = slice_to_val ( key) ;
29
26
let mut data_val = slice_to_val ( data) ;
@@ -52,14 +49,7 @@ pub trait Cursor<'txn> {
52
49
/// duplicate data items of each key will be returned before moving on to
53
50
/// the next key.
54
51
fn iter_start ( & mut self ) -> Iter < ' txn > {
55
- // When the db is empty, this returns NotFound, which means the iterator should not even
56
- // try to proceed or it too will error with code 22
57
- let complete = self . get ( None , None , ffi:: MDB_FIRST )
58
- . map ( |_| false )
59
- . unwrap_or ( true ) ;
60
- let mut iter = Iter :: new ( self . cursor ( ) , ffi:: MDB_GET_CURRENT , ffi:: MDB_NEXT ) ;
61
- iter. complete = complete;
62
- iter
52
+ Iter :: new ( self . cursor ( ) , ffi:: MDB_FIRST , ffi:: MDB_NEXT )
63
53
}
64
54
65
55
/// Iterate over database items starting from the given key.
@@ -69,10 +59,9 @@ pub trait Cursor<'txn> {
69
59
/// the next key.
70
60
fn iter_from < K > ( & mut self , key : K ) -> Iter < ' txn > where K : AsRef < [ u8 ] > {
71
61
match self . get ( Some ( key. as_ref ( ) ) , None , ffi:: MDB_SET_RANGE ) {
72
- Err ( Error :: NotFound ) => Ok ( ( ) ) ,
73
- Err ( error) => Err ( error) ,
74
- Ok ( _) => Ok ( ( ) ) ,
75
- } . unwrap ( ) ;
62
+ Ok ( _) | Err ( Error :: NotFound ) => ( ) ,
63
+ Err ( error) => panic ! ( "mdb_cursor_get returned an unexpected error: {}" , error) ,
64
+ } ;
76
65
Iter :: new ( self . cursor ( ) , ffi:: MDB_GET_CURRENT , ffi:: MDB_NEXT )
77
66
}
78
67
@@ -86,27 +75,26 @@ pub trait Cursor<'txn> {
86
75
/// Iterate over duplicate database items starting from the beginning of the
87
76
/// database. Each item will be returned as an iterator of its duplicates.
88
77
fn iter_dup_start ( & mut self ) -> IterDup < ' txn > {
89
- self . get ( None , None , ffi:: MDB_FIRST ) . unwrap ( ) ;
90
- IterDup :: new ( self . cursor ( ) , ffi:: MDB_GET_CURRENT )
78
+ IterDup :: new ( self . cursor ( ) , ffi:: MDB_FIRST )
91
79
}
92
80
93
81
/// Iterate over duplicate items in the database starting from the given
94
82
/// key. Each item will be returned as an iterator of its duplicates.
95
83
fn iter_dup_from < K > ( & mut self , key : & K ) -> IterDup < ' txn > where K : AsRef < [ u8 ] > {
96
84
match self . get ( Some ( key. as_ref ( ) ) , None , ffi:: MDB_SET_RANGE ) {
97
- Err ( Error :: NotFound ) => Ok ( ( ) ) ,
98
- Err ( error) => Err ( error) ,
99
- Ok ( _) => Ok ( ( ) ) ,
100
- } . unwrap ( ) ;
85
+ Ok ( _) | Err ( Error :: NotFound ) => ( ) ,
86
+ Err ( error) => panic ! ( "mdb_cursor_get returned an unexpected error: {}" , error) ,
87
+ } ;
101
88
IterDup :: new ( self . cursor ( ) , ffi:: MDB_GET_CURRENT )
102
89
}
103
90
104
- /// Iterate over the duplicates of the item in the database with the given
105
- /// key.
106
- fn iter_dup_of < K > ( & mut self , key : & K ) -> Result < Iter < ' txn > > where K :
107
- AsRef < [ u8 ] > {
108
- self . get ( Some ( key. as_ref ( ) ) , None , ffi:: MDB_SET ) ?;
109
- Ok ( Iter :: new ( self . cursor ( ) , ffi:: MDB_GET_CURRENT , ffi:: MDB_NEXT_DUP ) )
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) => panic ! ( "mdb_cursor_get returned an unexpected error: {}" , error) ,
96
+ } ;
97
+ Iter :: new ( self . cursor ( ) , ffi:: MDB_GET_CURRENT , ffi:: MDB_NEXT_DUP )
110
98
}
111
99
}
112
100
@@ -231,15 +219,14 @@ pub struct Iter<'txn> {
231
219
cursor : * mut ffi:: MDB_cursor ,
232
220
op : c_uint ,
233
221
next_op : c_uint ,
234
- complete : bool ,
235
222
_marker : PhantomData < fn ( & ' txn ( ) ) > ,
236
223
}
237
224
238
225
impl < ' txn > Iter < ' txn > {
239
226
240
227
/// Creates a new iterator backed by the given cursor.
241
228
fn new < ' t > ( cursor : * mut ffi:: MDB_cursor , op : c_uint , next_op : c_uint ) -> Iter < ' t > {
242
- Iter { cursor : cursor, op : op, next_op : next_op, complete : false , _marker : PhantomData }
229
+ Iter { cursor : cursor, op : op, next_op : next_op, _marker : PhantomData }
243
230
}
244
231
}
245
232
@@ -254,26 +241,16 @@ impl <'txn> Iterator for Iter<'txn> {
254
241
type Item = ( & ' txn [ u8 ] , & ' txn [ u8 ] ) ;
255
242
256
243
fn next ( & mut self ) -> Option < ( & ' txn [ u8 ] , & ' txn [ u8 ] ) > {
257
- if self . complete {
258
- return None
259
- }
260
244
let mut key = ffi:: MDB_val { mv_size : 0 , mv_data : ptr:: null_mut ( ) } ;
261
245
let mut data = ffi:: MDB_val { mv_size : 0 , mv_data : ptr:: null_mut ( ) } ;
262
-
246
+ let op = mem :: replace ( & mut self . op , self . next_op ) ;
263
247
unsafe {
264
- let err_code = ffi:: mdb_cursor_get ( self . cursor , & mut key, & mut data, self . op ) ;
265
- // Set the operation for the next get
266
- self . op = self . next_op ;
267
- if err_code == ffi:: MDB_SUCCESS {
268
- Some ( ( val_to_slice ( key) , val_to_slice ( data) ) )
269
- } else {
270
- // The documentation for mdb_cursor_get specifies that it may fail with MDB_NOTFOUND
271
- // and MDB_EINVAL (and we shouldn't be passing in invalid parameters).
272
- // TODO: validate that these are the only failures possible.
273
- debug_assert ! ( err_code == ffi:: MDB_NOTFOUND ,
274
- "Unexpected LMDB error {:?}." , Error :: from_err_code( err_code) ) ;
275
- self . complete = true ;
276
- None
248
+ match ffi:: mdb_cursor_get ( self . cursor , & mut key, & mut data, op) {
249
+ ffi:: MDB_SUCCESS => Some ( ( val_to_slice ( key) , val_to_slice ( data) ) ) ,
250
+ // EINVAL can occur when the cursor was previously seeked to a non-existent value,
251
+ // e.g. iter_from with a key greater than all values in the database.
252
+ ffi:: MDB_NOTFOUND | EINVAL => None ,
253
+ error => panic ! ( "mdb_cursor_get returned an unexpected error: {}" , error) ,
277
254
}
278
255
}
279
256
}
@@ -310,12 +287,12 @@ impl <'txn> Iterator for IterDup<'txn> {
310
287
fn next ( & mut self ) -> Option < Iter < ' txn > > {
311
288
let mut key = ffi:: MDB_val { mv_size : 0 , mv_data : ptr:: null_mut ( ) } ;
312
289
let mut data = ffi:: MDB_val { mv_size : 0 , mv_data : ptr:: null_mut ( ) } ;
290
+ let op = mem:: replace ( & mut self . op , ffi:: MDB_NEXT_NODUP ) ;
313
291
let err_code = unsafe {
314
- ffi:: mdb_cursor_get ( self . cursor , & mut key, & mut data, self . op )
292
+ ffi:: mdb_cursor_get ( self . cursor , & mut key, & mut data, op)
315
293
} ;
316
294
317
295
if err_code == ffi:: MDB_SUCCESS {
318
- self . op = ffi:: MDB_NEXT ;
319
296
Some ( Iter :: new ( self . cursor , ffi:: MDB_GET_CURRENT , ffi:: MDB_NEXT_DUP ) )
320
297
} else {
321
298
None
@@ -475,25 +452,33 @@ mod test {
475
452
}
476
453
477
454
#[ test]
478
- fn test_iter_start_empty ( ) {
455
+ fn test_iter_empty_database ( ) {
479
456
let dir = TempDir :: new ( "test" ) . unwrap ( ) ;
480
457
let env = Environment :: new ( ) . open ( dir. path ( ) ) . unwrap ( ) ;
481
458
let db = env. open_db ( None ) . unwrap ( ) ;
482
459
let txn = env. begin_ro_txn ( ) . unwrap ( ) ;
483
460
let mut cursor = txn. open_ro_cursor ( db) . unwrap ( ) ;
484
461
462
+ assert_eq ! ( 0 , cursor. iter( ) . count( ) ) ;
485
463
assert_eq ! ( 0 , cursor. iter_start( ) . count( ) ) ;
464
+ assert_eq ! ( 0 , cursor. iter_from( b"foo" ) . count( ) ) ;
486
465
}
487
466
488
467
#[ test]
489
- fn test_iter_empty ( ) {
468
+ fn test_iter_empty_dup_database ( ) {
490
469
let dir = TempDir :: new ( "test" ) . unwrap ( ) ;
491
470
let env = Environment :: new ( ) . open ( dir. path ( ) ) . unwrap ( ) ;
492
- let db = env. open_db ( None ) . unwrap ( ) ;
471
+ let db = env. create_db ( None , DatabaseFlags :: DUP_SORT ) . unwrap ( ) ;
493
472
let txn = env. begin_ro_txn ( ) . unwrap ( ) ;
494
473
let mut cursor = txn. open_ro_cursor ( db) . unwrap ( ) ;
495
474
496
475
assert_eq ! ( 0 , cursor. iter( ) . count( ) ) ;
476
+ assert_eq ! ( 0 , cursor. iter_start( ) . count( ) ) ;
477
+ assert_eq ! ( 0 , cursor. iter_from( b"foo" ) . count( ) ) ;
478
+ assert_eq ! ( 0 , cursor. iter_dup( ) . count( ) ) ;
479
+ assert_eq ! ( 0 , cursor. iter_dup_start( ) . count( ) ) ;
480
+ assert_eq ! ( 0 , cursor. iter_dup_from( b"foo" ) . count( ) ) ;
481
+ assert_eq ! ( 0 , cursor. iter_dup_of( b"foo" ) . count( ) ) ;
497
482
}
498
483
499
484
#[ test]
@@ -547,9 +532,9 @@ mod test {
547
532
cursor. iter_dup_from( b"f" ) . flat_map( |x| x) . collect:: <Vec <_>>( ) ) ;
548
533
549
534
assert_eq ! ( items. clone( ) . into_iter( ) . skip( 3 ) . take( 3 ) . collect:: <Vec <( & [ u8 ] , & [ u8 ] ) >>( ) ,
550
- cursor. iter_dup_of( b"b" ) . unwrap ( ) . collect:: <Vec <_>>( ) ) ;
535
+ cursor. iter_dup_of( b"b" ) . collect:: <Vec <_>>( ) ) ;
551
536
552
- assert ! ( cursor. iter_dup_of( b"foo" ) . is_err ( ) ) ;
537
+ assert_eq ! ( 0 , cursor. iter_dup_of( b"foo" ) . count ( ) ) ;
553
538
}
554
539
555
540
#[ test]
0 commit comments