diff options
author | Michael Cahill <michael.cahill@wiredtiger.com> | 2015-01-27 11:15:13 +1100 |
---|---|---|
committer | Michael Cahill <michael.cahill@wiredtiger.com> | 2015-01-27 11:15:13 +1100 |
commit | eec40152e6780a69d24bb24be6480bfd1d9bcdf9 (patch) | |
tree | 2f8b6a6c9ab584d8c23687bf42a76b4d518280a2 | |
parent | 2063efb22c3c29b980f86f7fee77b6d03ba63ec1 (diff) | |
download | mongo-eec40152e6780a69d24bb24be6480bfd1d9bcdf9.tar.gz |
Reorg code so that fast paths stay inlined, shift the slow part of full cache handling into a separate function.
refs #1596
-rw-r--r-- | src/evict/evict_lru.c | 88 | ||||
-rw-r--r-- | src/include/cache.i | 91 | ||||
-rw-r--r-- | src/include/extern.h | 2 | ||||
-rw-r--r-- | src/include/txn.i | 29 | ||||
-rw-r--r-- | src/txn/txn.c | 29 |
5 files changed, 125 insertions, 114 deletions
diff --git a/src/evict/evict_lru.c b/src/evict/evict_lru.c index a7e666e31a2..ccabddcf539 100644 --- a/src/evict/evict_lru.c +++ b/src/evict/evict_lru.c @@ -1319,6 +1319,94 @@ __wt_evict_lru_page(WT_SESSION_IMPL *session, int is_server) return (ret); } +/* + * __wt_cache_wait -- + * Wait for space in the cache. + */ +int +__wt_cache_wait(WT_SESSION_IMPL *session, int full) +{ + WT_CACHE *cache; + WT_DECL_RET; + WT_TXN_GLOBAL *txn_global; + WT_TXN_STATE *txn_state; + int busy, count; + + cache = S2C(session)->cache; + + /* + * If the current transaction is keeping the oldest ID pinned, it is in + * the middle of an operation. This may prevent the oldest ID from + * moving forward, leading to deadlock, so only evict what we can. + * Otherwise, we are at a transaction boundary and we can work harder + * to make sure there is free space in the cache. + */ + txn_global = &S2C(session)->txn_global; + txn_state = &txn_global->states[session->id]; + busy = txn_state->id != WT_TXN_NONE || + session->nhazard > 0 || + (txn_state->snap_min != WT_TXN_NONE && + txn_global->current != txn_global->oldest_id); + if (busy && full < 100) + return (0); + count = busy ? 1 : 10; + + for (;;) { + /* + * A pathological case: if we're the oldest transaction in the + * system and the eviction server is stuck trying to find space, + * abort the transaction to give up all hazard pointers before + * trying again. + */ + if (F_ISSET(cache, WT_EVICT_STUCK) && + __wt_txn_am_oldest(session)) { + F_CLR(cache, WT_EVICT_STUCK); + WT_STAT_FAST_CONN_INCR(session, txn_fail_cache); + return (WT_ROLLBACK); + } + + switch (ret = __wt_evict_lru_page(session, 0)) { + case 0: + if (--count == 0) + return (0); + break; + case EBUSY: + continue; + case WT_NOTFOUND: + break; + default: + return (ret); + } + + WT_RET(__wt_eviction_check(session, &full, 0)); + if (full < 100) + return (0); + else if (ret == 0) + continue; + + /* + * The cache is still full and no pages were found in the queue + * to evict. If this transaction is the one holding back the + * oldest ID, we can't wait forever. We'll block next time we + * are not busy. + */ + if (busy) { + __wt_txn_update_oldest(session); + if (txn_state->id == txn_global->oldest_id || + txn_state->snap_min == txn_global->oldest_id) + return (0); + } + + /* Wait for the queue to re-populate before trying again. */ + WT_RET(__wt_cond_wait(session, + S2C(session)->cache->evict_waiter_cond, 100000)); + + /* Check if things have changed so that we are busy. */ + if (!busy && txn_state->snap_min != WT_TXN_NONE && + txn_global->current != txn_global->oldest_id) + busy = count = 1; + } +} #ifdef HAVE_DIAGNOSTIC /* * __wt_cache_dump -- diff --git a/src/include/cache.i b/src/include/cache.i index af6f1bf375d..c5bf8c4221f 100644 --- a/src/include/cache.i +++ b/src/include/cache.i @@ -136,13 +136,7 @@ static inline int __wt_cache_full_check(WT_SESSION_IMPL *session) { WT_BTREE *btree; - WT_CACHE *cache; - WT_DECL_RET; - WT_TXN_GLOBAL *txn_global; - WT_TXN_STATE *txn_state; - int busy, count, full; - - cache = S2C(session)->cache; + int full; /* * LSM sets the no-cache-check flag when holding the LSM tree lock, in @@ -165,86 +159,15 @@ __wt_cache_full_check(WT_SESSION_IMPL *session) * Only wake the eviction server the first time through here (if the * cache is too full). * - * If the cache is less than 95% full, no work to be done. + * If the cache is less than 95% full, no work to be done. If we are + * at the API boundary and the cache is more than 95% full, try to + * evict at least one page before we start an operation. This helps + * with some eviction-dominated workloads. */ WT_RET(__wt_eviction_check(session, &full, 1)); if (full < 95) return (0); - /* - * If we are at the API boundary and the cache is more than 95% full, - * try to evict at least one page before we start an operation. This - * helps with some eviction-dominated workloads. - * - * If the current transaction is keeping the oldest ID pinned, it is in - * the middle of an operation. This may prevent the oldest ID from - * moving forward, leading to deadlock, so only evict what we can. - * Otherwise, we are at a transaction boundary and we can work harder - * to make sure there is free space in the cache. - */ - txn_global = &S2C(session)->txn_global; - txn_state = &txn_global->states[session->id]; - busy = txn_state->id != WT_TXN_NONE || - session->nhazard > 0 || - (txn_state->snap_min != WT_TXN_NONE && - txn_global->current != txn_global->oldest_id); - if (busy && full < 100) - return (0); - count = busy ? 1 : 10; - - for (;;) { - /* - * A pathological case: if we're the oldest transaction in the - * system and the eviction server is stuck trying to find space, - * abort the transaction to give up all hazard pointers before - * trying again. - */ - if (F_ISSET(cache, WT_EVICT_STUCK) && - __wt_txn_am_oldest(session)) { - F_CLR(cache, WT_EVICT_STUCK); - WT_STAT_FAST_CONN_INCR(session, txn_fail_cache); - return (WT_ROLLBACK); - } - - switch (ret = __wt_evict_lru_page(session, 0)) { - case 0: - if (--count == 0) - return (0); - break; - case EBUSY: - continue; - case WT_NOTFOUND: - break; - default: - return (ret); - } - - WT_RET(__wt_eviction_check(session, &full, 0)); - if (full < 100) - return (0); - else if (ret == 0) - continue; - - /* - * The cache is still full and no pages were found in the queue - * to evict. If this transaction is the one holding back the - * oldest ID, we can't wait forever. We'll block next time we - * are not busy. - */ - if (busy) { - __wt_txn_update_oldest(session); - if (txn_state->id == txn_global->oldest_id || - txn_state->snap_min == txn_global->oldest_id) - return (0); - } - - /* Wait for the queue to re-populate before trying again. */ - WT_RET(__wt_cond_wait(session, - S2C(session)->cache->evict_waiter_cond, 100000)); - - /* Check if things have changed so that we are busy. */ - if (!busy && txn_state->snap_min != WT_TXN_NONE && - txn_global->current != txn_global->oldest_id) - busy = count = 1; - } + return (__wt_cache_wait(session, full)); } + diff --git a/src/include/extern.h b/src/include/extern.h index 1850aec75ce..a40f9fec368 100644 --- a/src/include/extern.h +++ b/src/include/extern.h @@ -299,6 +299,7 @@ extern int __wt_evict_page(WT_SESSION_IMPL *session, WT_REF *ref); extern int __wt_evict_file_exclusive_on(WT_SESSION_IMPL *session); extern void __wt_evict_file_exclusive_off(WT_SESSION_IMPL *session); extern int __wt_evict_lru_page(WT_SESSION_IMPL *session, int is_server); +extern int __wt_cache_wait(WT_SESSION_IMPL *session, int full); extern void __wt_cache_dump(WT_SESSION_IMPL *session); extern int __wt_evict(WT_SESSION_IMPL *session, WT_REF *ref, int exclusive); extern void __wt_rec_page_clean_update(WT_SESSION_IMPL *session, WT_REF *ref); @@ -633,7 +634,6 @@ extern void __wt_stat_init_connection_stats(WT_CONNECTION_STATS *stats); extern void __wt_stat_refresh_connection_stats(void *stats_arg); extern int __wt_txnid_cmp(const void *v1, const void *v2); extern void __wt_txn_release_snapshot(WT_SESSION_IMPL *session); -extern int __wt_txn_am_oldest(WT_SESSION_IMPL *session); extern void __wt_txn_update_oldest(WT_SESSION_IMPL *session); extern void __wt_txn_refresh(WT_SESSION_IMPL *session, int get_snapshot); extern int __wt_txn_begin(WT_SESSION_IMPL *session, const char *cfg[]); diff --git a/src/include/txn.i b/src/include/txn.i index be8af9ae77b..f5f9b662e6f 100644 --- a/src/include/txn.i +++ b/src/include/txn.i @@ -359,3 +359,32 @@ __wt_txn_cursor_op(WT_SESSION_IMPL *session) !F_ISSET(txn, TXN_HAS_SNAPSHOT)) __wt_txn_refresh(session, 1); } + +/* + * __wt_txn_am_oldest -- + * Am I the oldest transaction in the system? + */ +static inline int +__wt_txn_am_oldest(WT_SESSION_IMPL *session) +{ + WT_CONNECTION_IMPL *conn; + WT_TXN *txn; + WT_TXN_GLOBAL *txn_global; + WT_TXN_STATE *s; + uint64_t id; + uint32_t i, session_cnt; + + conn = S2C(session); + txn = &session->txn; + txn_global = &conn->txn_global; + + if (txn->id == WT_TXN_NONE) + return (0); + + WT_ORDERED_READ(session_cnt, conn->session_cnt); + for (i = 0, s = txn_global->states; i < session_cnt; i++, s++) + if ((id = s->id) != WT_TXN_NONE && TXNID_LT(id, txn->id)) + return (0); + + return (1); +} diff --git a/src/txn/txn.c b/src/txn/txn.c index 7eef7ad20ac..5b8f11a88a5 100644 --- a/src/txn/txn.c +++ b/src/txn/txn.c @@ -67,35 +67,6 @@ __wt_txn_release_snapshot(WT_SESSION_IMPL *session) } /* - * __wt_txn_am_oldest -- - * Am I the oldest transaction in the system? - */ -int -__wt_txn_am_oldest(WT_SESSION_IMPL *session) -{ - WT_CONNECTION_IMPL *conn; - WT_TXN *txn; - WT_TXN_GLOBAL *txn_global; - WT_TXN_STATE *s; - uint64_t id; - uint32_t i, session_cnt; - - conn = S2C(session); - txn = &session->txn; - txn_global = &conn->txn_global; - - if (txn->id == WT_TXN_NONE) - return (0); - - WT_ORDERED_READ(session_cnt, conn->session_cnt); - for (i = 0, s = txn_global->states; i < session_cnt; i++, s++) - if ((id = s->id) != WT_TXN_NONE && TXNID_LT(id, txn->id)) - return (0); - - return (1); -} - -/* * __wt_txn_update_oldest -- * Sweep the running transactions to update the oldest ID required. */ |