lmdb_util.h (3278B)
1 2 // Define callback function type 3 typedef bool (*lmdb_callback_t)(const MDB_val*, const MDB_val*); 4 5 6 int lmdb_foreach(MDB_txn *txn, MDB_dbi dbi, MDB_val *start, MDB_val *start_dup, callback_t cb, bool reverse) { 7 int success = 0; 8 MDB_cursor *cursor; 9 10 // Open a cursor on the provided transaction and database 11 int rc = mdb_cursor_open(txn, dbi, &cursor); 12 13 if (rc != 0) 14 return 0; 15 16 MDB_val k = *start, v = *start_dup; 17 MDB_cursor_op op = reverse ? MDB_PREV : MDB_NEXT; 18 19 // If we're scanning in reverse... 20 if (reverse) { 21 // Try to position the cursor at the first key-value pair where 22 // both the key and the value are greater than or equal to our 23 // starting point. 24 rc = mdb_cursor_get(cursor, &k, &v, MDB_GET_BOTH_RANGE); 25 if (rc == 0) { 26 if (v.mv_size != start_dup->mv_size || 27 memcmp(v.mv_data, start_dup->mv_data, v.mv_size) != 0) { 28 // If the value doesn't match our starting 29 // point, step back to the previous record. 30 if (mdb_cursor_get(cursor, &k, &v, MDB_PREV) != 0) 31 goto cleanup; 32 } 33 } else { 34 // If we couldn't find a record that matches both our 35 // starting key and value, try to find a record that 36 // matches just our starting key. 37 if (mdb_cursor_get(cursor, &k, &v, MDB_SET) == 0) { 38 // If we find a match, move to the last value 39 // for this key, since we're scanning in 40 // reverse. 41 if (mdb_cursor_get(cursor, &k, &v, MDB_LAST_DUP) != 0) 42 goto cleanup; 43 } else { 44 // If we can't find a record with our starting 45 // key, try to find the first record with a key 46 // greater than our starting key. 47 if (mdb_cursor_get(cursor, &k, &v, MDB_SET_RANGE) == 0) { 48 // If we find such a record, step back 49 // to the previous record. 50 if (mdb_cursor_get(cursor, &k, &v, MDB_PREV) != 0) 51 goto cleanup; 52 } else { 53 // If we can't even find a record with 54 // a key greater than our starting key, 55 // fall back to starting from the last 56 // record in the database. 57 if (mdb_cursor_get(cursor, &k, &v, MDB_LAST) != 0) 58 goto cleanup; 59 } 60 } 61 } 62 // If we're not scanning in reverse... 63 else { 64 // Try to position the cursor at the first key-value 65 // pair where both the key and the value are greater 66 // than or equal to our starting point. 67 if (mdb_cursor_get(cursor, &k, &v, MDB_SET) != 0) { 68 // If we couldn't find a record that matches 69 // both our starting key and value, try to find 70 // a record that matches just our starting key. 71 if (mdb_cursor_get(cursor, &k, &v, MDB_SET_RANGE) != 0) 72 goto cleanup; 73 74 // If we can't find a record with our starting 75 // key, try to find the first record with a key 76 // greater than our starting key. 77 if (mdb_cursor_get(cursor, &k, &v, MDB_FIRST_DUP) != 0) 78 goto cleanup; 79 } 80 } 81 } 82 83 // Whether we're scanning forward or backward, start the actual 84 // iteration, moving one step at a time in the appropriate direction 85 // and calling the provided callback for each record. 86 do { 87 if (!cb(&k, &v)) 88 goto cleanup; 89 } while (mdb_cursor_get(cursor, &k, &v, op) == 0); 90 91 // If we make it through the entire iteration without the callback 92 // returning false, return true to signal success. 93 success = 1; 94 95 cleanup: 96 mdb_cursor_close(cursor); 97 return success; 98 } 99 100