From 4a0b30499caab8628efcedb8be5643fead7cd17e Mon Sep 17 00:00:00 2001 From: Hallvard Furuseth Date: Thu, 12 Apr 2012 07:34:13 +0200 Subject: [PATCH] libmdb: Do not use the MDB_txbody.mtb_txnid field. Get txn->mt_txnid from the meta page instead. Otherwise it and txn->mt_toggle could become inconsistent, since read-only txns fetched both from MDB_txbody without mutex proteciton. --- libraries/libmdb/mdb.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/libraries/libmdb/mdb.c b/libraries/libmdb/mdb.c index ba6ded3..8280e22 100644 --- a/libraries/libmdb/mdb.c +++ b/libraries/libmdb/mdb.c @@ -511,11 +511,17 @@ typedef struct MDB_txbody { */ pthread_mutex_t mtb_mutex; #endif +#if MDB_VERSION == 1 /** The ID of the last transaction committed to the database. * This is recorded here only for convenience; the value can always * be determined by reading the main database meta pages. + * + * Value is unused, but maintained for backwards compatibility. + * Drop this or mtb_me_toggle when changing MDB_VERSION. + * (Reading both should have been done atomically.) */ txnid_t mtb_txnid; +#endif /** The number of slots that have been used in the reader table. * This always records the maximum count, it is not decremented * when readers release their slots. @@ -536,7 +542,9 @@ typedef struct MDB_txninfo { #define mti_version mt1.mtb.mtb_version #define mti_mutex mt1.mtb.mtb_mutex #define mti_rmname mt1.mtb.mtb_rmname +#if MDB_VERSION == 1 #define mti_txnid mt1.mtb.mtb_txnid +#endif #define mti_numreaders mt1.mtb.mtb_numreaders #define mti_me_toggle mt1.mtb.mtb_me_toggle char pad[(sizeof(MDB_txbody)+CACHELINE-1) & ~(CACHELINE-1)]; @@ -1565,18 +1573,19 @@ mdb_txn_renew0(MDB_txn *txn) pthread_setspecific(env->me_txkey, r); } txn->mt_toggle = env->me_txns->mti_me_toggle; - txn->mt_txnid = env->me_txns->mti_txnid; + txn->mt_txnid = r->mr_txnid = env->me_metas[txn->mt_toggle]->mm_txnid; + /* This happens if a different process was the * last writer to the DB. */ if (env->me_wtxnid < txn->mt_txnid) mt_dbflag = DB_STALE; - r->mr_txnid = txn->mt_txnid; txn->mt_u.reader = r; } else { LOCK_MUTEX_W(env); - txn->mt_txnid = env->me_txns->mti_txnid; + txn->mt_toggle = env->me_txns->mti_me_toggle; + txn->mt_txnid = env->me_metas[txn->mt_toggle]->mm_txnid; if (env->me_wtxnid < txn->mt_txnid) mt_dbflag = DB_STALE; txn->mt_txnid++; @@ -1584,7 +1593,6 @@ mdb_txn_renew0(MDB_txn *txn) if (txn->mt_txnid == mdb_debug_start) mdb_debug = 1; #endif - txn->mt_toggle = env->me_txns->mti_me_toggle; txn->mt_u.dirty_list = env->me_dirty_list; txn->mt_u.dirty_list[0].mid = 0; txn->mt_free_pgs = env->me_free_pgs;