diff options
author | Michael Cahill <michael.cahill@wiredtiger.com> | 2013-01-09 16:13:28 +1100 |
---|---|---|
committer | Michael Cahill <michael.cahill@wiredtiger.com> | 2013-01-09 16:13:28 +1100 |
commit | b23b5454d9814d6ab55e113f865ceb62adf6336c (patch) | |
tree | debbc940afa5144543487140c1fd1f8f366c54a8 | |
parent | a1a8624bd9950cd87eb24f665e1fdbe25a86e828 (diff) | |
download | mongo-b23b5454d9814d6ab55e113f865ceb62adf6336c.tar.gz |
Fix some races in forced eviction:
* only try to force eviction of ordinary pages in memory
* lock the page before trying to queue it for forced eviction
* protect the cache flags with evict_lock in the eviction server
-rw-r--r-- | src/btree/bt_evict.c | 56 |
1 files changed, 36 insertions, 20 deletions
diff --git a/src/btree/bt_evict.c b/src/btree/bt_evict.c index 48d7c7a8b32..fc4ee95f923 100644 --- a/src/btree/bt_evict.c +++ b/src/btree/bt_evict.c @@ -127,7 +127,6 @@ __wt_evict_list_clr_page(WT_SESSION_IMPL *session, WT_PAGE *page) WT_ASSERT(session, WT_PAGE_IS_ROOT(page) || page->ref->page != page || - page->ref->state == WT_REF_EVICT_FORCE || page->ref->state == WT_REF_EVICT_WALK || page->ref->state == WT_REF_LOCKED); @@ -171,6 +170,17 @@ __wt_evict_forced_page(WT_SESSION_IMPL *session, WT_PAGE *page) if (!__wt_eviction_page_force_check(btree, page)) return (0); + /* + * Try to lock the page. If this succeeds, we're going to queue + * it for forced eviction. We don't go right to the EVICT_FORCED + * state, because that is cleared by __wt_evict_list_clr_page. + */ + if (!WT_ATOMIC_CAS(page->ref->state, WT_REF_MEM, WT_REF_LOCKED)) + return (EBUSY); + + /* If the page is already queued for ordinary eviction, clear it. */ + __wt_evict_list_clr_page(session, page); + __wt_spin_lock(session, &cache->evict_lock); /* @@ -198,15 +208,20 @@ __wt_evict_forced_page(WT_SESSION_IMPL *session, WT_PAGE *page) * page - which makes it more likely that the next pass of the eviction * server will successfully evict the page. */ - if (!WT_ATOMIC_CAS(page->ref->state, WT_REF_MEM, WT_REF_EVICT_FORCE)) - goto err; + if (!WT_ATOMIC_CAS(page->ref->state, WT_REF_LOCKED, WT_REF_EVICT_FORCE)) + WT_ERR(EBUSY); err: __wt_spin_unlock(session, &cache->evict_lock); - /* Only wake the server if the page was added and locked. */ - if (ret == 0 && page->ref->state == WT_REF_EVICT_FORCE) { + + /* + * Only wake the server if the page was successfully queued. + * Otherwise, unlock it. + */ + if (ret == 0) { F_SET(S2C(session)->cache, WT_EVICT_FORCE_PASS); __wt_evict_server_wake(session); - } + } else + page->ref->state = WT_REF_MEM; return (ret); } @@ -324,7 +339,7 @@ __evict_worker(WT_SESSION_IMPL *session) WT_CONNECTION_IMPL *conn; WT_DECL_RET; uint64_t bytes_inuse, bytes_max, dirty_inuse; - int clean, loop; + int clean, force, loop; conn = S2C(session); cache = conn->cache; @@ -340,22 +355,23 @@ __evict_worker(WT_SESSION_IMPL *session) while (ret == 0 && cache->sync_complete != cache->sync_request) ret = __evict_file_request_walk(session); + /* Check for forced eviction while we hold the lock. */ + force = F_ISSET(cache, WT_EVICT_FORCE_PASS) ? 1 : 0; + F_CLR(cache, WT_EVICT_FORCE_PASS); + __wt_spin_unlock(session, &cache->evict_lock); WT_RET(ret); - if (F_ISSET(cache, WT_EVICT_FORCE_PASS)) { - ret = __wt_evict_lru_page(session, 0); - /* - * Sometimes the page won't be available for eviction - * because there is a reader still holding a hazard - * reference. Give up in that case, the application - * thread can add it again. - */ - if (ret == EBUSY) - ret = 0; - WT_RET(ret); - F_CLR(cache, WT_EVICT_FORCE_PASS); - } + /* + * If we've been awoken for forced eviction, just try to evict + * the first page in the queue: don't do a walk and sort first. + * Sometimes the page won't be available for eviction because + * there is a reader still holding a hazard reference. Give up + * in that case, the application thread can add it again. + */ + if (force) + (void)__wt_evict_lru_page(session, 0); + /* * Keep evicting until we hit the target cache usage and the * target dirty percentage. |