Close cursors when commit(writer). Factor out code.

Close remaining cursors when committing a write txn. The doc says this
happens, and it avoids cursor tracking when updating mainDB + freeDB.

Rename mdb_cursor_merge() -> mdb_cursors_close() for code reuse,
and add a merge option.  Simplify its loop a bit.

Factor out cleanup of DBIs.
vmware
Hallvard Furuseth 12 years ago
parent dca0cef678
commit 17ffe9c992
  1. 98
      libraries/liblmdb/mdb.c

@ -1742,30 +1742,34 @@ mdb_cursor_shadow(MDB_txn *src, MDB_txn *dst)
return MDB_SUCCESS; return MDB_SUCCESS;
} }
/** Merge shadow cursors back into parent's */ /** Close this write txn's cursors, after optionally merging its shadow
* cursors back into parent's.
* @param[in] txn the transaction handle.
* @param[in] merge 0 to not merge cursors, C_SHADOW to merge.
* @return 0 on success, non-zero on failure.
*/
static void static void
mdb_cursor_merge(MDB_txn *txn) mdb_cursors_close(MDB_txn *txn, unsigned merge)
{ {
MDB_dbi i; MDB_cursor **cursors = txn->mt_cursors, *mc, *next;
for (i=0; i<txn->mt_numdbs; i++) { int i, j;
if (txn->mt_cursors[i]) {
MDB_cursor *mc; for (i = txn->mt_numdbs; --i >= 0; ) {
while ((mc = txn->mt_cursors[i])) { for (mc = cursors[i]; mc; mc = next) {
txn->mt_cursors[i] = mc->mc_next; next = mc->mc_next;
if (mc->mc_flags & C_SHADOW) { if (mc->mc_flags & merge) {
MDB_cursor *m2 = mc->mc_orig; MDB_cursor *m2 = mc->mc_orig;
unsigned int j;
m2->mc_snum = mc->mc_snum; m2->mc_snum = mc->mc_snum;
m2->mc_top = mc->mc_top; m2->mc_top = mc->mc_top;
for (j=0; j<mc->mc_snum; j++) { for (j = mc->mc_snum; --j >= 0; ) {
m2->mc_pg[j] = mc->mc_pg[j]; m2->mc_pg[j] = mc->mc_pg[j];
m2->mc_ki[j] = mc->mc_ki[j]; m2->mc_ki[j] = mc->mc_ki[j];
} }
} }
if (mc->mc_flags & C_ALLOCD) if (mc->mc_flags & C_ALLOCD)
free(mc); free(mc);
}
} }
cursors[i] = NULL;
} }
} }
@ -1991,6 +1995,32 @@ mdb_txn_begin(MDB_env *env, MDB_txn *parent, unsigned int flags, MDB_txn **ret)
return rc; return rc;
} }
/** Export or close DBI handles opened in this txn. */
static void
mdb_dbis_update(MDB_txn *txn, int keep)
{
int i;
MDB_dbi n = txn->mt_numdbs;
MDB_env *env = txn->mt_env;
unsigned char *tdbflags = txn->mt_dbflags;
for (i = n; --i >= 2;) {
if (tdbflags[i] & DB_NEW) {
if (keep) {
env->me_dbflags[i] = txn->mt_dbs[i].md_flags | MDB_VALID;
} else {
char *ptr = env->me_dbxs[i].md_name.mv_data;
env->me_dbxs[i].md_name.mv_data = NULL;
env->me_dbxs[i].md_name.mv_size = 0;
env->me_dbflags[i] = 0;
free(ptr);
}
}
}
if (keep && env->me_numdbs < n)
env->me_numdbs = n;
}
/** Common code for #mdb_txn_reset() and #mdb_txn_abort(). /** Common code for #mdb_txn_reset() and #mdb_txn_abort().
* May be called twice for readonly txns: First reset it, then abort. * May be called twice for readonly txns: First reset it, then abort.
* @param[in] txn the transaction handle to reset * @param[in] txn the transaction handle to reset
@ -2002,15 +2032,7 @@ mdb_txn_reset0(MDB_txn *txn)
unsigned int i; unsigned int i;
/* Close any DBI handles opened in this txn */ /* Close any DBI handles opened in this txn */
for (i=2; i<txn->mt_numdbs; i++) { mdb_dbis_update(txn, 0);
if (txn->mt_dbflags[i] & DB_NEW) {
char *ptr = env->me_dbxs[i].md_name.mv_data;
env->me_dbxs[i].md_name.mv_data = NULL;
env->me_dbxs[i].md_name.mv_size = 0;
env->me_dbflags[i] = 0;
free(ptr);
}
}
if (F_ISSET(txn->mt_flags, MDB_TXN_RDONLY)) { if (F_ISSET(txn->mt_flags, MDB_TXN_RDONLY)) {
if (txn->mt_u.reader) { if (txn->mt_u.reader) {
@ -2023,17 +2045,7 @@ mdb_txn_reset0(MDB_txn *txn)
} else { } else {
MDB_page *dp; MDB_page *dp;
/* close(free) all cursors */ mdb_cursors_close(txn, 0);
for (i=0; i<txn->mt_numdbs; i++) {
if (txn->mt_cursors[i]) {
MDB_cursor *mc;
while ((mc = txn->mt_cursors[i])) {
txn->mt_cursors[i] = mc->mc_next;
if (mc->mc_flags & C_ALLOCD)
free(mc);
}
}
}
if (!(env->me_flags & MDB_WRITEMAP)) { if (!(env->me_flags & MDB_WRITEMAP)) {
/* return all dirty pages to dpage list */ /* return all dirty pages to dpage list */
@ -2133,13 +2145,7 @@ mdb_txn_commit(MDB_txn *txn)
env = txn->mt_env; env = txn->mt_env;
if (F_ISSET(txn->mt_flags, MDB_TXN_RDONLY)) { if (F_ISSET(txn->mt_flags, MDB_TXN_RDONLY)) {
/* update the DB flags */ mdb_dbis_update(txn, 1);
for (i = 2; i<txn->mt_numdbs; i++) {
if (txn->mt_dbflags[i] & DB_NEW)
env->me_dbflags[i] = txn->mt_dbs[i].md_flags | MDB_VALID;
}
if (txn->mt_numdbs > env->me_numdbs)
env->me_numdbs = txn->mt_numdbs;
txn->mt_numdbs = 2; /* so txn_abort() doesn't close any new handles */ txn->mt_numdbs = 2; /* so txn_abort() doesn't close any new handles */
mdb_txn_abort(txn); mdb_txn_abort(txn);
return MDB_SUCCESS; return MDB_SUCCESS;
@ -2168,8 +2174,8 @@ mdb_txn_commit(MDB_txn *txn)
parent->mt_next_pgno = txn->mt_next_pgno; parent->mt_next_pgno = txn->mt_next_pgno;
parent->mt_flags = txn->mt_flags; parent->mt_flags = txn->mt_flags;
/* Merge (and close) our cursors with parent's */ /* Merge our cursors into parent's and close them */
mdb_cursor_merge(txn); mdb_cursors_close(txn, C_SHADOW);
/* Update parent's DB table. */ /* Update parent's DB table. */
memcpy(parent->mt_dbs, txn->mt_dbs, txn->mt_numdbs * sizeof(MDB_db)); memcpy(parent->mt_dbs, txn->mt_dbs, txn->mt_numdbs * sizeof(MDB_db));
@ -2228,6 +2234,8 @@ mdb_txn_commit(MDB_txn *txn)
return EINVAL; return EINVAL;
} }
mdb_cursors_close(txn, 0);
if (!txn->mt_u.dirty_list[0].mid && !(txn->mt_flags & MDB_TXN_DIRTY)) if (!txn->mt_u.dirty_list[0].mid && !(txn->mt_flags & MDB_TXN_DIRTY))
goto done; goto done;
@ -2523,13 +2531,7 @@ sync:
done: done:
env->me_pglast = 0; env->me_pglast = 0;
env->me_txn = NULL; env->me_txn = NULL;
/* update the DB flags */ mdb_dbis_update(txn, 1);
for (i = 2; i<txn->mt_numdbs; i++) {
if (txn->mt_dbflags[i] & DB_NEW)
env->me_dbflags[i] = txn->mt_dbs[i].md_flags | MDB_VALID;
}
if (txn->mt_numdbs > env->me_numdbs)
env->me_numdbs = txn->mt_numdbs;
UNLOCK_MUTEX_W(env); UNLOCK_MUTEX_W(env);
free(txn); free(txn);

Loading…
Cancel
Save