diff options
author | Michael Cahill <mjc@wiredtiger.com> | 2013-03-13 16:46:24 -0700 |
---|---|---|
committer | Michael Cahill <mjc@wiredtiger.com> | 2013-03-13 16:46:24 -0700 |
commit | 37765b9501cbd10fa5a56fcc325cfffa408285b9 (patch) | |
tree | 7be1ef90c86f7260d3e7ea1a81b39ed6b2241d6d | |
parent | 500e907962eac0d7f5100727e2a4bf2f9df693f5 (diff) | |
parent | ee61b20abdadc48cfc689f54c55a644775ac0b22 (diff) | |
download | mongo-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.c | 4 | ||||
-rw-r--r-- | src/include/extern.h | 3 | ||||
-rw-r--r-- | src/include/txn.h | 5 | ||||
-rw-r--r-- | src/include/txn.i | 2 | ||||
-rw-r--r-- | src/txn/txn.c | 68 |
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); } |