summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Cahill <michael.cahill@wiredtiger.com>2015-01-27 11:15:13 +1100
committerMichael Cahill <michael.cahill@wiredtiger.com>2015-01-27 11:15:13 +1100
commiteec40152e6780a69d24bb24be6480bfd1d9bcdf9 (patch)
tree2f8b6a6c9ab584d8c23687bf42a76b4d518280a2
parent2063efb22c3c29b980f86f7fee77b6d03ba63ec1 (diff)
downloadmongo-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.c88
-rw-r--r--src/include/cache.i91
-rw-r--r--src/include/extern.h2
-rw-r--r--src/include/txn.i29
-rw-r--r--src/txn/txn.c29
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.
*/