Full_Name: Hallvard B Furuseth Version: mdb.master, 4c8f57615c5ca7b014c038e59c1045182e74f5ad OS: Linux x86_64 URL: ftp://ftp.openldap.org/incoming/Hallvard-Furuseth-131222.c Submission from: (NULL) (2001:700:100:556::233) Submitted by: hallvard mdb_cursor_put() doc bug in lmdb.h: "If the function fails for any reason, the state of the cursor will be unchanged." That's quite untrue. To do that, the function must backup the cursor before moving it. (What is a "failure" anyway - are MDB_KEYEXIST and MDB_NOTFOUND failures?) Cursor tracking issues with MDB_DUPSORT: Cursor tracking sometimes ignores xcursors referring to sub-pages, yet code which uses an xcursor does not always fix that first. The enclosed program has several crashes. I.e. lots more code needs something like if ((leaf->mn_flags & (F_DUPDATA|F_SUBDATA)) == F_DUPDATA) m2->mc_xcursor->mx_cursor.mc_pg[0] = NODEDATA(leaf); before using an xcursor. I tried that everywhere before using xcursors: That helped, but it was not enough. E.g. after mdb_cursor_del() calls mdb_node_shrink(), it tracks cursors in the same sub-page but not nearby sub-pages. Also the fix suggested above means readers do more work that writers did not. Maybe instead all code which modified a database, should fix or invalidate that DB's cursors before returning (even at failure).
Another problem when an xcursor's mc_pg[0] refers to a sub-page but has not been kept updated: The comparison 'mc_pg[i] == mp' below fails and mc_ki[i] does not get modified: if (m3->mc_pg[i] == mp && m3->mc_ki[i] >= mc->mc_ki[i]) { m3->mc_ki[i]++; } Then it's too late to fixup the sub-page pointer later, the xcursor refers to the wrong node in the sub-page. The above code is from mdb_cursor_put(), but there are other similar cases elsewhere. -- Hallvard
changed notes changed state Open to Test moved from Incoming to Software Bugs
changed state Test to Closed
changed notes changed state Closed to Partial
On 22/12/13 23:09, h.b.furuseth@usit.uio.no wrote: > I.e. lots more code needs something like > if ((leaf->mn_flags & (F_DUPDATA|F_SUBDATA)) == F_DUPDATA) > m2->mc_xcursor->mx_cursor.mc_pg[0] = NODEDATA(leaf); > before using an xcursor. I tried that everywhere before > using xcursors: That helped, but it was not enough. E.g. > after mdb_cursor_del() calls mdb_node_shrink(), it tracks > cursors in the same sub-page but not nearby sub-pages. Such fixups do heal this ITS's test program with current mdb.master, though. That is, perl -i -pe ' s/\b(\w+)->mc_xcursor->mx_cursor\./mdb_subcursor($1)->/gx; s/\&(\w+)->mc_xcursor->mx_cursor/mdb_subcursor($1)/gx;' mdb.c plus this function: static MDB_cursor * mdb_subcursor(MDB_cursor *mc) { MDB_xcursor *mx = mc->mc_xcursor; MDB_cursor *subc = NULL; MDB_page *mp = mc->mc_pg[mc->mc_top]; if (mx) { subc = &mx->mx_cursor; if (((mc->mc_flags | subc->mc_flags) & C_INITIALIZED) && mp && !(mp->mp_flags & (P_BRANCH|P_LEAF2|P_SUBP))) { MDB_node *leaf = NODEPTR(mp, mc->mc_ki[mc->mc_top]); if ((leaf->mn_flags & (F_SUBDATA|F_DUPDATA)) == F_DUPDATA) subc->mc_pg[0] = NODEDATA(leaf); } } return subc; }
changed notes changed state Partial to Test
I wrote: > mdb_subcursor(MDB_cursor *mc) > (...) > if (((mc->mc_flags | subc->mc_flags) & C_INITIALIZED) && Oops. For reference, the '|' should be '&'. mdb.master has now been fixed to work without this function, though. -- Hallvard
Partial fix in mdb.master and mdb.RE Remainder fixed in mdb.master
changed notes changed state Test to Closed