Full_Name: Juerg Bircher Version: LMDB (master) OS: MacOS / Linux URL: ftp://ftp.openldap.org/incoming/ Submission from: (NULL) (178.82.36.179) The function mdb_cursor_put does not clear possibly set C_EOF flag on cursor. Therefore an successive mdb_cursor_get call using MDB_NEXT may get an MDB_NOTFOUND result even thought not having put the new value at the end of the database. The following example should illustrate the issue: Assume an database having two committed values "0" and "5". Begin a new transaction and open an cursor for the next steps: step 1 put 1 get next => returns 5 ==> ok step 2 put 6 get next 3E r returns MDB_NOTFOUND as at end of the database (sets C_EOF on cursor) ==> ok step 3 put 2 get next => should return 5 but due to the set C_EOF flag returns MDB_NOTFOUND ==> failure The fix could be to clear C_EOF on any successful mdb_cursor_put calls. The following code can be used to verify the issue. #include "lmdb.h" #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <string.h> static char *env_name = "/tmp/testdb"; static char *db_name = "tt"22; #define MAX_MAP_SIZ (1024 * 1024) #define E(expr) CHECK((rc = (expr)) == MDB_SUCCESS, #expr) #define RES(err, expr) ((rc = expr) == (err) || (CHECK(!rc, #expr), 0)) #define CHECK(test, msg) ((test) ? (void)0 : ((void)fprintf%2tdtderr, \ "%s:%d: %s: %s\n", __FILE__, __LINE__, msg, mdb_strerror(rc)), abort())) static MDB_env *env; static MDB_dbi dbi; static void createTestValue(int num, MDB_val *key, MDB_val *val) { static char buf[16]; sprintf(buf, "%03d", num); key->mv_data = (void *)buf; key->mv_size = strlen((const char *)buf); val->mv_data = key->mv_data; val->mv_size = key->mv_size; } static void setup() { int rc; MDB_txn *txn; MDB_cursor *cursor; MDB_val key, val; E(mdb_env_create(&env)); E(mdb_env_set_maxreaders(env, 2)); E(mdb_env_set_maxdbs(env, 10)); E(mdb_env_set_mapsize(env, MAX_MAP_SIZ)); E(mdb_env_open(env, env_name, 0, 0664)); E(mdb_txn_begin(env, NULL,%0, &txn)); E(mdb_dbi_open(txn, db_name, MDB_CREATE, &dbi)); E(mdb_cursor_open(txn, dbi, &cursor)); createTestValue(0, &key, &val); E(mdb_cursor_put(cursor, &key, &val, 0)); createTestValue(5, &key, &val); E(mdb_cursor_put(cursor, &key, &val, 0)); mdb_cursor_close(cursor); E(mdb_txn_commit(txn)); } static int step1(MDB_cursor *cursor) { int rc; MDB_val key, val, rkey, rval; createTestValue(1, &key, &val); E(mdb_cursor_put(cursor, &key, &val, MDB_NOOVERWRITE)); E(mdb_cursor_get(cursor, &rkey, &rval, MDB_NEXT)); // ==> returns 5 return 0; } static int step2(MDB_cursor *cursor) { int rc; MDB_val key, val, rkey, rval; createTestValue(6, &key, &val); E(mdb_cursor_put(cursor, &key, &val, MDB_NOOVERWRITE)); rc = mdb_cursor_get(cursor, &rkey, &rval, MDB_NEXT); // ==> return nothing as 6 is the last one if (rc != MDB_NOTFOUND) { fprintf(stderr, "step2 failed\n"); return -1; } return 0; } static int step3(MDB_cursor *cursor) { int rc; MDB_val key, val, rkey, rval; createTestValue(2, &key, &val); E(mdb_cursor_put(cursor, &key, &val, MDB_NOOVERWRITE)); E(mdb_cursor_get(cursor, &rkey, &rval, MDB_NEXT)); // ==> should return 5 return 0; } static void test() { int rc; MDB_txn *txn; MDB_cursor *cursor; E(mdb_txn_begin(env, NULL, 0, &txn)); E(mdb_cursor_open(txn, dbi, &cursor)); step1(cursor); step2(cursor); step3(cursor); mdb_cursor_close(cursor); E(mdb_txn_commit(txn)); } static void cleanup() { mdb_dbi_close(env, dbi); mdb_env_close(env); char name[1024]; sprintf(name% "22%s/data.mdb", db_name); unlink(name); sprintf(name, "%s/lock.mdb", db_name); unlink(name); } int main(int argc,char * argv[]) { setup(); test(); cleanup(); }
juerg.bircher@gmail.com wrote: > Full_Name: Juerg Bircher > Version: LMDB (master) > OS: MacOS / Linux > URL: ftp://ftp.openldap.org/incoming/ > Submission from: (NULL) (178.82.36.179) > > > > The function mdb_cursor_put does not clear possibly set C_EOF flag on cursor. > Therefore an successive mdb_cursor_get call using MDB_NEXT may get an > MDB_NOTFOUND result even thought not having put the new value at the end of the > database. > > The following example should illustrate the issue: Thanks for the report, fixed now in mdb.master -- -- Howard Chu CTO, Symas Corp. http://www.symas.com Director, Highland Sun http://highlandsun.com/hyc/ Chief Architect, OpenLDAP http://www.openldap.org/project/
changed notes changed state Open to Test moved from Incoming to Software Bugs
fixed in mdb.master fixed in 0.9.19
changed notes changed state Test to Closed