summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Cahill <mjc@wiredtiger.com>2013-03-13 16:46:24 -0700
committerMichael Cahill <mjc@wiredtiger.com>2013-03-13 16:46:24 -0700
commit37765b9501cbd10fa5a56fcc325cfffa408285b9 (patch)
tree7be1ef90c86f7260d3e7ea1a81b39ed6b2241d6d
parent500e907962eac0d7f5100727e2a4bf2f9df693f5 (diff)
parentee61b20abdadc48cfc689f54c55a644775ac0b22 (diff)
downloadmongo-37765b9501cbd10fa5a56fcc325cfffa408285b9.tar.gz
Merge pull request #478 from wiredtiger/txn-generation
Use generation numbers to avoid polling global transaction state if nothing has changed.
-rw-r--r--src/btree/bt_evict.c4
-rw-r--r--src/include/extern.h3
-rw-r--r--src/include/txn.h5
-rw-r--r--src/include/txn.i2
-rw-r--r--src/txn/txn.c68
5 files changed, 43 insertions, 39 deletions
diff --git a/src/btree/bt_evict.c b/src/btree/bt_evict.c
index 49cdbbfe768..e0f8521887d 100644
--- a/src/btree/bt_evict.c
+++ b/src/btree/bt_evict.c
@@ -726,8 +726,8 @@ __wt_sync_file(WT_SESSION_IMPL *session, int syncop)
/* Write dirty pages if nobody beat us to it. */
if (__wt_page_is_modified(page)) {
if (txn->isolation == TXN_ISO_READ_COMMITTED)
- __wt_txn_get_snapshot(
- session, WT_TXN_NONE, WT_TXN_NONE);
+ __wt_txn_get_snapshot(session,
+ WT_TXN_NONE, WT_TXN_NONE, 0);
ret = __wt_rec_write(session, page, NULL, 0);
if (txn->isolation == TXN_ISO_READ_COMMITTED)
__wt_txn_release_snapshot(session);
diff --git a/src/include/extern.h b/src/include/extern.h
index e0bc28ab6f4..f75a20ae987 100644
--- a/src/include/extern.h
+++ b/src/include/extern.h
@@ -1239,7 +1239,8 @@ extern void __wt_txn_release_snapshot(WT_SESSION_IMPL *session);
extern void __wt_txn_get_oldest(WT_SESSION_IMPL *session);
extern void __wt_txn_get_snapshot( WT_SESSION_IMPL *session,
wt_txnid_t my_id,
- wt_txnid_t max_id);
+ wt_txnid_t max_id,
+ int force);
extern void __wt_txn_get_evict_snapshot(WT_SESSION_IMPL *session);
extern int __wt_txn_begin(WT_SESSION_IMPL *session, const char *cfg[]);
extern void __wt_txn_release(WT_SESSION_IMPL *session);
diff --git a/src/include/txn.h b/src/include/txn.h
index 813ecfb793e..75a33f6924a 100644
--- a/src/include/txn.h
+++ b/src/include/txn.h
@@ -49,6 +49,7 @@ struct __wt_txn_state {
struct __wt_txn_global {
volatile wt_txnid_t current; /* Current transaction ID. */
+ volatile uint32_t gen; /* Completed transaction genertion */
WT_TXN_STATE *states; /* Per-session transaction states */
};
@@ -79,6 +80,10 @@ struct __wt_txn {
*/
wt_txnid_t oldest_snap_min;
+ /* Saved global state, to avoid scans. */
+ wt_txnid_t last_id;
+ uint32_t last_gen, last_oldest_gen;
+
/*
* Arrays of txn IDs in WT_UPDATE or WT_REF structures created or
* modified by this transaction.
diff --git a/src/include/txn.i b/src/include/txn.i
index cea149c4abf..b06a33fcdeb 100644
--- a/src/include/txn.i
+++ b/src/include/txn.i
@@ -276,7 +276,7 @@ __wt_txn_read_first(WT_SESSION_IMPL *session)
if (txn->isolation == TXN_ISO_READ_COMMITTED ||
(!F_ISSET(txn, TXN_RUNNING) &&
txn->isolation == TXN_ISO_SNAPSHOT))
- __wt_txn_get_snapshot(session, WT_TXN_NONE, WT_TXN_NONE);
+ __wt_txn_get_snapshot(session, WT_TXN_NONE, WT_TXN_NONE, 0);
else if (!F_ISSET(txn, TXN_RUNNING))
txn_state->snap_min = txn_global->current;
}
diff --git a/src/txn/txn.c b/src/txn/txn.c
index 7ee269525e3..2b0bef4f44f 100644
--- a/src/txn/txn.c
+++ b/src/txn/txn.c
@@ -51,13 +51,9 @@ __txn_sort_snapshot(WT_SESSION_IMPL *session,
void
__wt_txn_release_snapshot(WT_SESSION_IMPL *session)
{
- WT_TXN *txn;
WT_TXN_STATE *txn_state;
- txn = &session->txn;
txn_state = &S2C(session)->txn_global.states[session->id];
-
- txn->snapshot_count = 0;
txn_state->snap_min = WT_TXN_NONE;
}
@@ -79,6 +75,12 @@ __wt_txn_get_oldest(WT_SESSION_IMPL *session)
conn = S2C(session);
txn = &session->txn;
txn_global = &conn->txn_global;
+
+ /* If nothing has changed since last time, we're done. */
+ if (txn->last_oldest_gen == txn_global->gen)
+ return;
+ txn->last_oldest_gen = txn_global->gen;
+
oldest_snap_min =
(txn->id != WT_TXN_NONE) ? txn->id : txn_global->current;
@@ -100,7 +102,7 @@ __wt_txn_get_oldest(WT_SESSION_IMPL *session)
*/
void
__wt_txn_get_snapshot(
- WT_SESSION_IMPL *session, wt_txnid_t my_id, wt_txnid_t max_id)
+ WT_SESSION_IMPL *session, wt_txnid_t my_id, wt_txnid_t max_id, int force)
{
WT_CONNECTION_IMPL *conn;
WT_TXN *txn;
@@ -114,9 +116,18 @@ __wt_txn_get_snapshot(
txn_global = &conn->txn_global;
txn_state = &txn_global->states[session->id];
+ /* If nothing has changed since last time, we're done. */
+ if (!force && txn->last_id == txn_global->current &&
+ txn->last_gen == txn_global->gen) {
+ txn_state->snap_min = txn->snap_min;
+ return;
+ }
+
do {
/* Take a copy of the current session ID. */
- current_id = oldest_snap_min = txn_global->current;
+ txn->last_gen = txn->last_oldest_gen = txn_global->gen;
+ txn->last_id = oldest_snap_min = current_id =
+ txn_global->current;
/* Copy the array of concurrent transactions. */
WT_ORDERED_READ(session_cnt, conn->session_cnt);
@@ -153,39 +164,19 @@ __wt_txn_get_snapshot(
/*
* __wt_txn_get_evict_snapshot --
* Set up a snapshot in the current transaction for eviction.
- * No changes that are invisible to any active transaction can be evicted.
+ * Only changes that visible to all active transactions can be evicted.
*/
void
__wt_txn_get_evict_snapshot(WT_SESSION_IMPL *session)
{
- WT_CONNECTION_IMPL *conn;
- WT_TXN_GLOBAL *txn_global;
- WT_TXN_STATE *s;
- wt_txnid_t current_id, id, oldest_snap_min;
- uint32_t i, session_cnt;
-
- conn = S2C(session);
- txn_global = &conn->txn_global;
-
- do {
- /* Take a copy of the current session ID. */
- current_id = oldest_snap_min = txn_global->current;
+ WT_TXN *txn;
- /* Walk the array of concurrent transactions. */
- WT_ORDERED_READ(session_cnt, conn->session_cnt);
- for (i = 0, s = txn_global->states; i < session_cnt; i++, s++)
- if ((id = s->snap_min) != WT_TXN_NONE &&
- TXNID_LT(id, oldest_snap_min))
- oldest_snap_min = id;
+ txn = &session->txn;
- /*
- * Ensure the snapshot reads are scheduled before re-checking
- * the global current ID.
- */
- WT_READ_BARRIER();
- } while (current_id != txn_global->current);
+ __wt_txn_get_oldest(session);
+ __txn_sort_snapshot(
+ session, 0, txn->oldest_snap_min, txn->oldest_snap_min);
- __txn_sort_snapshot(session, 0, oldest_snap_min, oldest_snap_min);
/*
* Note that we carefully don't update the global table with this
* snap_min value: there is already a running transaction in this
@@ -249,7 +240,6 @@ __wt_txn_begin(WT_SESSION_IMPL *session, const char *cfg[])
txn->id = WT_ATOMIC_ADD(txn_global->current, 1);
} while (txn->id == WT_TXN_NONE || txn->id == WT_TXN_ABORTED);
WT_PUBLISH(txn_state->id, txn->id);
- oldest_snap_min = txn->id;
/*
* If we are starting a snapshot isolation transaction, get
@@ -260,6 +250,9 @@ __wt_txn_begin(WT_SESSION_IMPL *session, const char *cfg[])
* visible.
*/
if (txn->isolation == TXN_ISO_SNAPSHOT) {
+ txn->last_gen = txn->last_oldest_gen = txn_global->gen;
+ oldest_snap_min = txn->id;
+
/* Copy the array of concurrent transactions. */
WT_ORDERED_READ(session_cnt, conn->session_cnt);
for (i = n = 0, s = txn_global->states;
@@ -297,11 +290,13 @@ void
__wt_txn_release(WT_SESSION_IMPL *session)
{
WT_TXN *txn;
+ WT_TXN_GLOBAL *txn_global;
WT_TXN_STATE *txn_state;
txn = &session->txn;
txn->mod_count = txn->modref_count = 0;
- txn_state = &S2C(session)->txn_global.states[session->id];
+ txn_global = &S2C(session)->txn_global;
+ txn_state = &txn_global->states[session->id];
/* Clear the transaction's ID from the global table. */
WT_ASSERT(session, txn_state->id != WT_TXN_NONE &&
@@ -319,6 +314,9 @@ __wt_txn_release(WT_SESSION_IMPL *session)
__wt_txn_release_snapshot(session);
txn->isolation = session->isolation;
F_CLR(txn, TXN_ERROR | TXN_OLDEST | TXN_RUNNING);
+
+ /* Update the global generation number. */
+ ++txn_global->gen;
}
/*
@@ -347,7 +345,7 @@ __wt_txn_commit(WT_SESSION_IMPL *session, const char *cfg[])
* commit.
*/
if (session->ncursors > 0)
- __wt_txn_get_snapshot(session, txn->id, WT_TXN_NONE);
+ __wt_txn_get_snapshot(session, txn->id, WT_TXN_NONE, 1);
__wt_txn_release(session);
return (0);
}