From 48dc782ea612f85e8356a50bfbafe22e5be121cf Mon Sep 17 00:00:00 2001 From: Howard Chu Date: Thu, 31 Jan 2013 20:05:48 -0800 Subject: [PATCH 1/4] ITS#7515 fix mdb_dbi_open/close If a DBI handle is opened by a txn that aborts, the DBI handle should no longer be valid. --- libraries/liblmdb/mdb.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/libraries/liblmdb/mdb.c b/libraries/liblmdb/mdb.c index cdd8ea104e..578e6b6979 100644 --- a/libraries/liblmdb/mdb.c +++ b/libraries/liblmdb/mdb.c @@ -1947,6 +1947,11 @@ static void mdb_txn_reset0(MDB_txn *txn) { MDB_env *env = txn->mt_env; + unsigned int i; + + /* If there were uncommitted dbi_opens, undo them now */ + for (i=env->me_numdbs; imt_numdbs; i++) + mdb_dbi_close(env, i); if (F_ISSET(txn->mt_flags, MDB_TXN_RDONLY)) { if (!(env->me_flags & MDB_ROFS)) @@ -1954,7 +1959,6 @@ mdb_txn_reset0(MDB_txn *txn) } else { MDB_oldpages *mop; MDB_page *dp; - unsigned int i; /* close(free) all cursors */ for (i=0; imt_numdbs; i++) { @@ -7047,7 +7051,6 @@ int mdb_dbi_open(MDB_txn *txn, const char *name, unsigned int flags, MDB_dbi *db mdb_default_cmp(txn, slot); if (!unused) { txn->mt_numdbs++; - txn->mt_env->me_numdbs++; } } @@ -7065,8 +7068,12 @@ int mdb_stat(MDB_txn *txn, MDB_dbi dbi, MDB_stat *arg) void mdb_dbi_close(MDB_env *env, MDB_dbi dbi) { char *ptr; - if (dbi <= MAIN_DBI || dbi >= env->me_numdbs) + if (dbi <= MAIN_DBI || dbi >= env->me_maxdbs) return; + /* If the dbi is greater than env->me_numdbs, no harm is done. + * And it may happen if we're closing a DB that was just opened, + * but the opening txn hadn't committed yet. + */ ptr = env->me_dbxs[dbi].md_name.mv_data; env->me_dbxs[dbi].md_name.mv_data = NULL; env->me_dbxs[dbi].md_name.mv_size = 0; From 744e31193913d117a68414fe163c9038a78edde2 Mon Sep 17 00:00:00 2001 From: Howard Chu Date: Fri, 1 Feb 2013 06:19:23 -0800 Subject: [PATCH 2/4] NULL key is allowed for MDB_CURRENT --- libraries/liblmdb/mdb.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/libraries/liblmdb/mdb.c b/libraries/liblmdb/mdb.c index 578e6b6979..36b02a3452 100644 --- a/libraries/liblmdb/mdb.c +++ b/libraries/liblmdb/mdb.c @@ -1095,6 +1095,10 @@ mdb_dkey(MDB_val *key, char *buf) char *ptr = buf; unsigned char *c = key->mv_data; unsigned int i; + + if (!key) + return ""; + if (key->mv_size > MDB_MAXKEYSIZE) return "MDB_MAXKEYSIZE"; /* may want to make this a dynamic check: if the key is mostly @@ -4823,7 +4827,7 @@ mdb_cursor_put(MDB_cursor *mc, MDB_val *key, MDB_val *data, if (F_ISSET(mc->mc_txn->mt_flags, MDB_TXN_RDONLY)) return EACCES; - if (key->mv_size == 0 || key->mv_size > MDB_MAXKEYSIZE) + if (flags != MDB_CURRENT && (key->mv_size == 0 || key->mv_size > MDB_MAXKEYSIZE)) return EINVAL; if (F_ISSET(mc->mc_db->md_flags, MDB_DUPSORT) && data->mv_size > MDB_MAXKEYSIZE) From e0eb495fb3c0909b341803c98ac2c78ac39f1f5b Mon Sep 17 00:00:00 2001 From: Howard Chu Date: Mon, 4 Feb 2013 10:53:17 -0800 Subject: [PATCH 3/4] Revert "ITS#7515 fix mdb_dbi_open/close" This reverts commit 48dc782ea612f85e8356a50bfbafe22e5be121cf. --- libraries/liblmdb/mdb.c | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/libraries/liblmdb/mdb.c b/libraries/liblmdb/mdb.c index 36b02a3452..1bd472f6d8 100644 --- a/libraries/liblmdb/mdb.c +++ b/libraries/liblmdb/mdb.c @@ -1951,11 +1951,6 @@ static void mdb_txn_reset0(MDB_txn *txn) { MDB_env *env = txn->mt_env; - unsigned int i; - - /* If there were uncommitted dbi_opens, undo them now */ - for (i=env->me_numdbs; imt_numdbs; i++) - mdb_dbi_close(env, i); if (F_ISSET(txn->mt_flags, MDB_TXN_RDONLY)) { if (!(env->me_flags & MDB_ROFS)) @@ -1963,6 +1958,7 @@ mdb_txn_reset0(MDB_txn *txn) } else { MDB_oldpages *mop; MDB_page *dp; + unsigned int i; /* close(free) all cursors */ for (i=0; imt_numdbs; i++) { @@ -7055,6 +7051,7 @@ int mdb_dbi_open(MDB_txn *txn, const char *name, unsigned int flags, MDB_dbi *db mdb_default_cmp(txn, slot); if (!unused) { txn->mt_numdbs++; + txn->mt_env->me_numdbs++; } } @@ -7072,12 +7069,8 @@ int mdb_stat(MDB_txn *txn, MDB_dbi dbi, MDB_stat *arg) void mdb_dbi_close(MDB_env *env, MDB_dbi dbi) { char *ptr; - if (dbi <= MAIN_DBI || dbi >= env->me_maxdbs) + if (dbi <= MAIN_DBI || dbi >= env->me_numdbs) return; - /* If the dbi is greater than env->me_numdbs, no harm is done. - * And it may happen if we're closing a DB that was just opened, - * but the opening txn hadn't committed yet. - */ ptr = env->me_dbxs[dbi].md_name.mv_data; env->me_dbxs[dbi].md_name.mv_data = NULL; env->me_dbxs[dbi].md_name.mv_size = 0; From 65c053a6e7f6973c1d09710aa1bd57b218206fcb Mon Sep 17 00:00:00 2001 From: Hallvard Furuseth Date: Thu, 7 Feb 2013 08:17:30 +0100 Subject: [PATCH 4/4] ITS#7512 Fix MDB page leak when malloc error. mdb_page_alloc(): Delay moving me_pgfirst,me_pglast until malloc(MDB_oldpages to hold the IDs) succeeds. --- libraries/liblmdb/mdb.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/libraries/liblmdb/mdb.c b/libraries/liblmdb/mdb.c index 1bd472f6d8..68f60832b4 100644 --- a/libraries/liblmdb/mdb.c +++ b/libraries/liblmdb/mdb.c @@ -1341,19 +1341,24 @@ again: if (!txn->mt_env->me_pgfirst) { mdb_node_read(txn, leaf, &data); } - txn->mt_env->me_pglast = last; - if (!txn->mt_env->me_pgfirst) - txn->mt_env->me_pgfirst = last; idl = (MDB_ID *) data.mv_data; /* We might have a zero-length IDL due to freelist growth * during a prior commit */ - if (!idl[0]) goto again; + if (!idl[0]) { + txn->mt_env->me_pglast = last; + if (!txn->mt_env->me_pgfirst) + txn->mt_env->me_pgfirst = last; + goto again; + } mop = malloc(sizeof(MDB_oldpages) + MDB_IDL_SIZEOF(idl) - sizeof(pgno_t)); if (!mop) return ENOMEM; mop->mo_next = txn->mt_env->me_pghead; mop->mo_txnid = last; + txn->mt_env->me_pglast = last; + if (!txn->mt_env->me_pgfirst) + txn->mt_env->me_pgfirst = last; txn->mt_env->me_pghead = mop; memcpy(mop->mo_pages, idl, MDB_IDL_SIZEOF(idl));