Full_Name: Hallvard B Furuseth Version: mdb.master 48dc782ea612f85e8356a50bfbafe22e5be121cf OS: Linux x86_64 URL: Submission from: (NULL) (193.69.163.163) Submitted by: hallvard
If a thread modifies a named MDB database and closes it before committing, the changes are lost. The mdb_dbi_close() doc only says we must not close DBs which _other_ theads will reference.
I expect mdb_dbi_close() could check if the env has an active write txn where the DB is dirty, and mdb_put() it first. And in any parent txns which have it open, dunno if that's doable.
If not, in this case maybe _close() could stash away the DB info so mdb_txn_commit()/mdb_txn_reset0() can save the updates.
Note that another mdb_dbi_open() can reuse the closed DBI, so carelessness could e.g. save the changes with the wrong DB name.
Test case (no nested txns):
#include <lmdb.h> #include <stdio.h> #include <stdlib.h>
int main(void) { char *dbname = "test.mdb"; MDB_env *env; MDB_txn *txn; MDB_dbi dbi; int rdonly, rc; MDB_val key = {3, "foo"}, data = {3, "abc"}, rdata;
# define E(e) { rc = (e); if (rc) { fprintf(stderr, "%s:%d: %s: %s\n", \ __FILE__, __LINE__, #e, mdb_strerror(rc)); abort(); } }
remove(dbname); for (rdonly = 0; rdonly <= MDB_RDONLY; rdonly += MDB_RDONLY) { E(mdb_env_create(&env)); E(mdb_env_set_maxdbs(env, 1)); E(mdb_env_open(env, dbname, MDB_NOSYNC|MDB_NOSUBDIR, 0666)); E(mdb_txn_begin(env, NULL, rdonly, &txn)); E(mdb_dbi_open(txn, NULL, rdonly ? 0 : MDB_CREATE, &dbi)); if (!rdonly) { E(mdb_put(txn, dbi, &key, &data, 0)); mdb_dbi_close(env, dbi); } else { E(mdb_get(txn, dbi, &key, &rdata)); } E(mdb_txn_commit(txn)); mdb_env_close(env); } return 0; }