nostrdb

an unfairly fast embedded nostr database backed by lmdb
git clone git://jb55.com/nostrdb
Log | Files | Refs | Submodules | README | LICENSE

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