summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/evict/evict_lru.c54
-rw-r--r--src/include/btmem.h3
-rw-r--r--src/include/btree.i19
-rw-r--r--src/reconcile/rec_write.c6
4 files changed, 62 insertions, 20 deletions
diff --git a/src/evict/evict_lru.c b/src/evict/evict_lru.c
index dd2f58c43fa..0207798bdb9 100644
--- a/src/evict/evict_lru.c
+++ b/src/evict/evict_lru.c
@@ -1196,26 +1196,44 @@ fast: /* If the page can't be evicted, give up. */
continue;
/*
- * If the oldest transaction hasn't changed since the last time
- * this page was written, it's unlikely we can make progress (an
- * heuristic to avoid repeated attempts to evict the same page).
- * Similarly, if the most recent update on the page is not yet
- * committed, eviction will fail.
+ * Additional tests if eviction is likely to succeed.
*
- * If eviction is stuck, or we are helping with forced eviction,
- * try anyway: maybe a transaction that was running last time we
- * wrote the page has since rolled back, or we can help get the
- * checkpoint completed sooner.
- *
- * Note: take care with ordering: if we detected that the page
- * is modified above, we expect mod != NULL.
+ * If eviction is stuck or we are helping with forced eviction,
+ * try anyway: maybe a transaction that was running last time
+ * we wrote the page has since rolled back, or we can help the
+ * checkpoint complete sooner. Additionally, being stuck will
+ * configure lookaside file writes in reconciliation, allowing
+ * us to evict pages we can't usually evict.
*/
- mod = page->modify;
- if (modified && !FLD_ISSET(cache->state,
- WT_EVICT_PASS_AGGRESSIVE | WT_EVICT_PASS_WOULD_BLOCK) &&
- (!__wt_txn_committed(session, mod->update_txn) ||
- mod->disk_snap_min == conn->txn_global.oldest_id))
- continue;
+ if (!FLD_ISSET(cache->state,
+ WT_EVICT_PASS_AGGRESSIVE | WT_EVICT_PASS_WOULD_BLOCK)) {
+ /*
+ * Note: take care with ordering: if we detected that
+ * the page is modified above, we expect mod != NULL.
+ */
+ mod = page->modify;
+
+ /*
+ * If the page is clean but has modifications that
+ * appear too new to evict, skip it.
+ */
+ if (!modified && mod != NULL &&
+ !__wt_txn_visible_all(session, mod->rec_max_txn))
+ continue;
+
+ /*
+ * If the oldest transaction hasn't changed since the
+ * last time this page was written, it's unlikely we
+ * can make progress. Similarly, if the most recent
+ * update on the page is not yet globally visible,
+ * eviction will fail. These heuristics attempt to
+ * avoid repeated attempts to evict the same page.
+ */
+ if (modified &&
+ (mod->disk_snap_min == conn->txn_global.oldest_id ||
+ !__wt_txn_visible_all(session, mod->update_txn)))
+ continue;
+ }
WT_ASSERT(session, evict->ref == NULL);
__evict_init_candidate(session, evict, ref);
diff --git a/src/include/btmem.h b/src/include/btmem.h
index 5f713877373..a813dce48a0 100644
--- a/src/include/btmem.h
+++ b/src/include/btmem.h
@@ -209,6 +209,9 @@ struct __wt_page_modify {
/* Avoid checking for obsolete updates during checkpoints. */
uint64_t obsolete_check_txn;
+ /* The largest transaction ID seen on the page by reconciliation. */
+ uint64_t rec_max_txn;
+
/* The largest update transaction ID (approximate). */
uint64_t update_txn;
diff --git a/src/include/btree.i b/src/include/btree.i
index 58a66738aa2..40858175ca4 100644
--- a/src/include/btree.i
+++ b/src/include/btree.i
@@ -975,6 +975,7 @@ __wt_page_can_evict(WT_SESSION_IMPL *session,
WT_BTREE *btree;
WT_PAGE_MODIFY *mod;
WT_TXN_GLOBAL *txn_global;
+ uint64_t txnid;
if (inmem_splitp != NULL)
*inmem_splitp = 0;
@@ -1044,9 +1045,23 @@ __wt_page_can_evict(WT_SESSION_IMPL *session,
* for existing hazard pointers, the checkpoint thread reconciling an
* internal page acquires hazard pointers on child pages it reads, and
* is blocked by the exclusive lock.
- *
- * KEITH: this comment should move to somewhere else.
*/
+ if (page->read_gen != WT_READGEN_OLDEST) {
+ /*
+ * If eviction is stuck, we'll use the lookaside file and so
+ * only care if all changes on the page are committed.
+ */
+ if (__wt_eviction_aggressive(session)) {
+ if (__wt_page_is_modified(page) &&
+ !__wt_txn_committed(session, mod->update_txn))
+ return (0);
+ } else {
+ if (!__wt_txn_visible_all(session,
+ __wt_page_is_modified(page) ?
+ mod->update_txn : mod->rec_max_txn))
+ return (0);
+ }
+ }
/*
* If the page was recently split in-memory, don't force it out: we
diff --git a/src/reconcile/rec_write.c b/src/reconcile/rec_write.c
index 2ccbe1a1ab1..81cd2e673e9 100644
--- a/src/reconcile/rec_write.c
+++ b/src/reconcile/rec_write.c
@@ -5506,6 +5506,12 @@ err: __wt_scr_free(session, &tkey);
return (EBUSY);
} else {
/*
+ * Track the page's maximum transaction ID (used to decide if
+ * we're likely to be able to evict this page in the future).
+ */
+ mod->rec_max_txn = r->max_txn;
+
+ /*
* Track the tree's maximum transaction ID (used to decide if
* it's safe to discard the tree). Reconciliation for eviction
* is multi-threaded, only update the tree's maximum transaction