On 03/01/17 22:04, lazarev.michael@gmail.com wrote:
After a number of mdb_put calls, mdb_cursor_get with MDB_LAST operation positions the cursor incorrectly. Test code is submitted here: ftp://ftp.openldap.org/incoming/mdb_put_test.c
The C_EOF flag is doubly broken here, and maybe ill-defined:
Previous mdb_cursor_last() set C_EOF as a "cursor is on the last page" hint, cursor_put() did not clear it in this cursor when putting through another cursor, and then next cursor_last() uses the hint in "if (!(mc->mc_flags & C_EOF))" when the cursor is no longer at the end.
However, elsewhere the flag is seen as "cursor is beyond last item": mdb_cursor_next(), MDB_GET_MULTIPLE, mdb_cursor_count(). It is set that way after mdb_cursor_sibling(<right>) fails. But it's not used consistently that way either: At least MDB_GET_CURRENT, MDB_PREV, put(MDB_CURRENT) succeed with C_EOF set. (And they don't move the cursor to the last item first.)
As for the "cursor is on last page" hint, page_search() & co could at least avoid some page_get()s without using C_EOF: If C_INITIALIZED is set, then while mc_pg[] and mc_ki[] are correct it can just walk down the cursor without doing page_get(). If a _pg or _ki needs to change, it can switch to the regular page_seaarch() code. Helps write-txns and MDB_VL32, but not read-only txns.