diff options
Diffstat (limited to 'src/evict/evict_page.c')
-rw-r--r-- | src/evict/evict_page.c | 87 |
1 files changed, 43 insertions, 44 deletions
diff --git a/src/evict/evict_page.c b/src/evict/evict_page.c index b15e1c1f26c..5b17a78a4dd 100644 --- a/src/evict/evict_page.c +++ b/src/evict/evict_page.c @@ -37,7 +37,7 @@ __evict_exclusive(WT_SESSION_IMPL *session, WT_REF *ref) * Check for a hazard pointer indicating another thread is using the * page, meaning the page cannot be evicted. */ - if (__wt_page_hazard_check(session, ref->page) == NULL) + if (__wt_hazard_check(session, ref) == NULL) return (0); WT_STAT_DATA_INCR(session, cache_eviction_hazard); @@ -66,7 +66,7 @@ __wt_page_release_evict(WT_SESSION_IMPL *session, WT_REF *ref) * between. */ locked = __wt_atomic_casv32(&ref->state, WT_REF_MEM, WT_REF_LOCKED); - if ((ret = __wt_hazard_clear(session, page)) != 0 || !locked) { + if ((ret = __wt_hazard_clear(session, ref)) != 0 || !locked) { if (locked) ref->state = WT_REF_MEM; return (ret == 0 ? EBUSY : ret); @@ -163,19 +163,8 @@ __wt_evict(WT_SESSION_IMPL *session, WT_REF *ref, bool closing) */ WT_ERR(__evict_page_clean_update( session, ref, tree_dead || closing)); - else { - /* - * The page is not being completely evicted: instead it is - * being split or replaced. In that case, don't increment the - * count of pages evicted, which we use to decide whether - * eviction is making progress. Repeatedly rewriting the same - * page isn't progress. - */ - F_SET(session, WT_SESSION_IN_SPLIT); - ret = __evict_page_dirty_update(session, ref, closing); - F_CLR(session, WT_SESSION_IN_SPLIT); - WT_ERR(ret); - } + else + WT_ERR(__evict_page_dirty_update(session, ref, closing)); if (clean_page) { WT_STAT_CONN_INCR(session, cache_eviction_clean); @@ -407,7 +396,7 @@ __evict_review( WT_DECL_RET; WT_PAGE *page; uint32_t flags; - bool modified; + bool lookaside_retry, modified; flags = WT_EVICTING; *flagsp = flags; @@ -506,27 +495,29 @@ __evict_review( * If we have an exclusive lock (we're discarding the tree), assert * there are no updates we cannot read. * - * Don't set any other flags for internal pages: they don't have update - * lists to be saved and restored, nor can we re-create them in memory. + * Don't set any other flags for internal pages: there are no update + * lists to be saved and restored, changes can't be written into the + * lookaside table, nor can we re-create internal pages in memory. * * For leaf pages: * - * If an in-memory configuration or the page is being forcibly evicted, - * set the update-restore flag, so reconciliation will write blocks it + * In-memory pages are a known configuration. + * + * Set the update/restore flag, so reconciliation will write blocks it * can write and create a list of skipped updates for blocks it cannot - * write, along with disk images. This is how eviction of active, huge + * write, along with disk images. This is how eviction of active, huge * pages works: we take a big page and reconcile it into blocks, some of * which we write and discard, the rest of which we re-create as smaller * in-memory pages, (restoring the updates that stopped us from writing - * the block), and inserting the whole mess into the page's parent. + * the block), and inserting the whole mess into the page's parent. Set + * the flag in all cases because the incremental cost of update/restore + * in reconciliation is minimal, eviction shouldn't have picked a page + * where update/restore is necessary, absent some cache pressure. It's + * possible updates occurred after we selected this page for eviction, + * but it's unlikely and we don't try and manage that risk. * - * Otherwise, if eviction is getting pressed, configure reconciliation - * to write not-yet-globally-visible updates to the lookaside table, - * allowing the eviction of pages we'd otherwise have to retain in cache - * to support older readers. - * - * Finally, if we don't need to do eviction at the moment, create disk - * images of split pages in order to re-instantiate them. + * Additionally, if we aren't trying to free space in the cache, scrub + * the page and keep it in memory. */ cache = S2C(session)->cache; if (closing) @@ -535,25 +526,33 @@ __evict_review( if (F_ISSET(S2C(session), WT_CONN_IN_MEMORY)) LF_SET(WT_EVICT_IN_MEMORY | WT_EVICT_SCRUB | WT_EVICT_UPDATE_RESTORE); - else if (__wt_cache_stuck(session)) - LF_SET(WT_EVICT_LOOKASIDE); - else if (!__wt_txn_visible_all( - session, page->modify->update_txn) || - page->read_gen == WT_READGEN_OLDEST || - page->memory_footprint >= S2BT(session)->splitmempage) + else { LF_SET(WT_EVICT_UPDATE_RESTORE); - /* - * If we aren't trying to free space in the cache, scrub the - * page and keep it around. - */ - if (!LF_ISSET(WT_EVICT_LOOKASIDE) && - F_ISSET(cache, WT_CACHE_EVICT_SCRUB)) - LF_SET(WT_EVICT_SCRUB); + if (F_ISSET(cache, WT_CACHE_EVICT_SCRUB)) + LF_SET(WT_EVICT_SCRUB); + } } - *flagsp = flags; - WT_RET(__wt_reconcile(session, ref, NULL, flags)); + /* Reconcile the page. */ + ret = __wt_reconcile(session, ref, NULL, flags, &lookaside_retry); + + /* + * If reconciliation fails, eviction is stuck and reconciliation reports + * it might succeed if we use the lookaside table (the page didn't have + * uncommitted updates, it was not-yet-globally visible updates causing + * the problem), configure reconciliation to write those updates to the + * lookaside table, allowing the eviction of pages we'd otherwise have + * to retain in cache to support older readers. + */ + if (ret == EBUSY && __wt_cache_stuck(session) && lookaside_retry) { + LF_CLR(WT_EVICT_SCRUB | WT_EVICT_UPDATE_RESTORE); + LF_SET(WT_EVICT_LOOKASIDE); + ret = __wt_reconcile(session, ref, NULL, flags, NULL); + } + + *flagsp = flags; + WT_RET(ret); /* * Success: assert the page is clean or reconciliation was configured |