h.b.furuseth@usit.uio.no wrote:
Full_Name: Hallvard B Furuseth Version: mdb.master 0cdd9dffddf66c730a35f48db2bb02d8bb3e5731 OS: Linux x86_64 URL: Submission from: (NULL) (193.69.163.163) Submitted by: hallvard
If a cursor is at a clean subDB page, and its current item is deleted by another cursor, then MDB_GET_CURRENT returns the deleted item.
Fixed now in mdb.master. The subcursor on the clean page will be invalidated when the page is touched.
Test program below, run with no args, the "m2/del" output line.
If the page was dirty, I instead got (key = old, data = size 0). I don't know if it should give MDB_NOTFOUND instead. That's the test program run with one arg. I did not check what happens if the other cursor rearranged the pages, e.g. split the item off to another page.
#include "lmdb.h" #include <assert.h> #include <stdio.h> #include <stdlib.h>
int main(int argc, char **argv) { char *fname = "test.mdb"; MDB_env *env; MDB_txn *txn; MDB_dbi dbi; MDB_cursor *mc, *m2; MDB_val key, data; int rc; # define STR2VAL(s) (&(MDB_val){sizeof(s), s}) /* includes final \0 */ # define SHOW(name) printf("%s:\t%s[%zd] -> %s[%zd]\n", name, \ (char*)key.mv_data, key.mv_size, (char*)data.mv_data, data.mv_size) # define E(e) { rc = (e); if (rc) { fprintf(stderr, "%s:%d: %s: %s\n",\ __FILE__, __LINE__, #e, mdb_strerror(rc)); abort(); } }
remove(fname); E(mdb_env_create(&env)); E(mdb_env_open(env, fname, MDB_NOSUBDIR, 0666)); E(mdb_txn_begin(env, NULL, 0, &txn)); E(mdb_dbi_open(txn, NULL, MDB_DUPSORT, &dbi)); E(mdb_cursor_open(txn, dbi, &mc)); E(mdb_cursor_put(mc, STR2VAL("a"), STR2VAL("x"), 0)); E(mdb_cursor_put(mc, STR2VAL("a"), STR2VAL("y"), 0)); if (argc < 2) { E(mdb_txn_commit(txn)); E(mdb_txn_begin(env, NULL, 0, &txn)); E(mdb_cursor_open(txn, dbi, &mc)); puts("With clean page:"); } E(mdb_cursor_open(txn, dbi, &m2)); E(mdb_cursor_get(mc, &key, &data, MDB_FIRST)); E(mdb_cursor_get(m2, &key, &data, MDB_FIRST)); SHOW("Name:\tKey -> Data (mv_data[mv_len]):\n" "m2"); E(mdb_cursor_del(mc, 0)); E(mdb_cursor_get(m2, &key, &data, MDB_GET_CURRENT)); SHOW("m2/del"); /* Should output the same as... */ E(mdb_cursor_get(mc, &key, &data, MDB_GET_CURRENT)); SHOW("mc/del"); /* ...this: "a[2] -> [0]". */ mdb_txn_abort(txn); mdb_env_close(env); return 0;
}