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.
vmware
Hallvard Furuseth 13 years ago
parent d1738c3e6b
commit 4a0b30499c
  1. 16
      libraries/libmdb/mdb.c

@ -511,11 +511,17 @@ typedef struct MDB_txbody {
*/ */
pthread_mutex_t mtb_mutex; pthread_mutex_t mtb_mutex;
#endif #endif
#if MDB_VERSION == 1
/** The ID of the last transaction committed to the database. /** The ID of the last transaction committed to the database.
* This is recorded here only for convenience; the value can always * This is recorded here only for convenience; the value can always
* be determined by reading the main database meta pages. * 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; txnid_t mtb_txnid;
#endif
/** The number of slots that have been used in the reader table. /** The number of slots that have been used in the reader table.
* This always records the maximum count, it is not decremented * This always records the maximum count, it is not decremented
* when readers release their slots. * when readers release their slots.
@ -536,7 +542,9 @@ typedef struct MDB_txninfo {
#define mti_version mt1.mtb.mtb_version #define mti_version mt1.mtb.mtb_version
#define mti_mutex mt1.mtb.mtb_mutex #define mti_mutex mt1.mtb.mtb_mutex
#define mti_rmname mt1.mtb.mtb_rmname #define mti_rmname mt1.mtb.mtb_rmname
#if MDB_VERSION == 1
#define mti_txnid mt1.mtb.mtb_txnid #define mti_txnid mt1.mtb.mtb_txnid
#endif
#define mti_numreaders mt1.mtb.mtb_numreaders #define mti_numreaders mt1.mtb.mtb_numreaders
#define mti_me_toggle mt1.mtb.mtb_me_toggle #define mti_me_toggle mt1.mtb.mtb_me_toggle
char pad[(sizeof(MDB_txbody)+CACHELINE-1) & ~(CACHELINE-1)]; 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); pthread_setspecific(env->me_txkey, r);
} }
txn->mt_toggle = env->me_txns->mti_me_toggle; 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 /* This happens if a different process was the
* last writer to the DB. * last writer to the DB.
*/ */
if (env->me_wtxnid < txn->mt_txnid) if (env->me_wtxnid < txn->mt_txnid)
mt_dbflag = DB_STALE; mt_dbflag = DB_STALE;
r->mr_txnid = txn->mt_txnid;
txn->mt_u.reader = r; txn->mt_u.reader = r;
} else { } else {
LOCK_MUTEX_W(env); 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) if (env->me_wtxnid < txn->mt_txnid)
mt_dbflag = DB_STALE; mt_dbflag = DB_STALE;
txn->mt_txnid++; txn->mt_txnid++;
@ -1584,7 +1593,6 @@ mdb_txn_renew0(MDB_txn *txn)
if (txn->mt_txnid == mdb_debug_start) if (txn->mt_txnid == mdb_debug_start)
mdb_debug = 1; mdb_debug = 1;
#endif #endif
txn->mt_toggle = env->me_txns->mti_me_toggle;
txn->mt_u.dirty_list = env->me_dirty_list; txn->mt_u.dirty_list = env->me_dirty_list;
txn->mt_u.dirty_list[0].mid = 0; txn->mt_u.dirty_list[0].mid = 0;
txn->mt_free_pgs = env->me_free_pgs; txn->mt_free_pgs = env->me_free_pgs;

Loading…
Cancel
Save