[Date Prev][Date Next]
[Chronological]
[Thread]
[Top]
Re: (ITS#7515) Nested liblmdb transaction bugs
MDB can act on P_DIRTY without checking whether the page is
dirty in this txn's dirty_list, or only some ancestor txn's:
* mdb_cursor_put() line 5094, overwriting an F_BIGDATA node:
Let a nested txn replace a big item whose page is dirty
only in an ancestor txn. The parent will see the new
value if the old page had room for it, even if the child
aborted. Test program enclosed.
Proposed fix: No need to search dirty_list, mdb_page_get()
just did. Make it return where the page was found instead
of an error code: <0 not found, 0 in map, >0 txn nesting
level of the dirty_list with the page. Branch mdb/its7515
in <http://folk.uio.no/hbf/OpenLDAP/openldap.git>, except
the commit message may need tweaks.
* mdb_xcursor_init1(): Sets DB_DIRTY if mc_top has P_DIRTY.
Seems to cancel some MDB_PS_MODIFY activity. Is that OK?
#include <lmdb.h>
#include <stdio.h>
int main(void)
{
static char pTxt[9999] = "parent", cTxt[9999] = "child";
MDB_val key = {1,""}, pVal = {9999,pTxt}, cVal = {9999,cTxt}, val;
MDB_env *env;
MDB_txn *txn, *ctxn;
MDB_dbi dbi;
mdb_env_create(&env);
mdb_env_open(env, "test.mdb", MDB_NOSUBDIR, 0666);
mdb_txn_begin(env, 0, 0, &txn);
mdb_dbi_open(txn, 0, 0, &dbi);
mdb_put(txn, dbi, &key, &pVal, 0); /* put "parent" */
mdb_txn_begin(env, txn, 0, &ctxn);
mdb_put(ctxn, dbi, &key, &cVal, 0); /* overwrite with "child" */
mdb_txn_abort(ctxn);
mdb_get(txn, dbi, &key, &val); /* should get "parent" */
puts(val.mv_data); /* ...but got "child" */
mdb_txn_commit(txn);
mdb_env_close(env);
return 0;
}
--
Hallvard