summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlex Gorrod <alexg@wiredtiger.com>2013-01-08 19:37:09 +1100
committerAlex Gorrod <alexg@wiredtiger.com>2013-01-08 19:37:09 +1100
commita3237122ec0f32cb1082292a052419dc85925afb (patch)
tree57112e270dc98961b6a55e4bc174d05a6bd31a3b
parenta2188ebb823f491786f6116ddb588eb81ea95184 (diff)
downloadmongo-a3237122ec0f32cb1082292a052419dc85925afb.tar.gz
Add a forced eviction mode that uses a new page state, instead
of re-using the locked state and tracking other information in the eviction server.
-rw-r--r--src/btree/bt_debug.c3
-rw-r--r--src/btree/bt_evict.c44
-rw-r--r--src/btree/bt_page.c1
-rw-r--r--src/btree/bt_walk.c5
-rw-r--r--src/btree/rec_evict.c4
-rw-r--r--src/btree/rec_write.c1
-rw-r--r--src/include/btmem.h7
7 files changed, 39 insertions, 26 deletions
diff --git a/src/btree/bt_debug.c b/src/btree/bt_debug.c
index 20a5f74632c..d740a6550a0 100644
--- a/src/btree/bt_debug.c
+++ b/src/btree/bt_debug.c
@@ -781,6 +781,9 @@ __debug_ref(WT_DBG *ds, WT_REF *ref, WT_PAGE *page)
case WT_REF_DELETED:
__dmsg(ds, "deleted");
break;
+ case WT_REF_EVICT_FORCE:
+ __dmsg(ds, "evict-force %p", ref->page);
+ break;
case WT_REF_EVICT_WALK:
__dmsg(ds, "evict-walk %p", ref->page);
break;
diff --git a/src/btree/bt_evict.c b/src/btree/bt_evict.c
index 558ed786055..204f08d7d01 100644
--- a/src/btree/bt_evict.c
+++ b/src/btree/bt_evict.c
@@ -36,19 +36,22 @@ static int __evict_worker(WT_SESSION_IMPL *);
static inline uint64_t
__evict_read_gen(const WT_EVICT_ENTRY *entry)
{
+ WT_PAGE *page;
uint64_t read_gen;
+ page = entry->page;
+
/* Never prioritize empty slots. */
- if (entry->page == NULL)
+ if (page == NULL)
return (UINT64_MAX);
/* Always prioritize pages selected by force. */
- if (F_ISSET_ATOMIC(entry->page, WT_PAGE_EVICT_LOCKED))
+ if (page->ref->state == WT_REF_EVICT_FORCE)
return (0);
- read_gen = entry->page->read_gen + entry->btree->evict_priority;
- if (entry->page->type == WT_PAGE_ROW_INT ||
- entry->page->type == WT_PAGE_COL_INT)
+ read_gen = page->read_gen + entry->btree->evict_priority;
+ if (page->type == WT_PAGE_ROW_INT ||
+ page->type == WT_PAGE_COL_INT)
read_gen += WT_EVICT_INT_SKEW;
return (read_gen);
@@ -76,8 +79,6 @@ __evict_lru_cmp(const void *a, const void *b)
static inline void
__evict_list_clr(WT_SESSION_IMPL *session, WT_EVICT_ENTRY *e)
{
- WT_REF *ref;
-
if (e->page != NULL) {
WT_ASSERT(session, F_ISSET_ATOMIC(e->page, WT_PAGE_EVICT_LRU));
F_CLR_ATOMIC(e->page, WT_PAGE_EVICT_LRU);
@@ -86,13 +87,8 @@ __evict_list_clr(WT_SESSION_IMPL *session, WT_EVICT_ENTRY *e)
* clear the locked state when removing it from the eviction
* queue.
*/
- if (F_ISSET_ATOMIC(e->page, WT_PAGE_EVICT_LOCKED)) {
- ref = e->page->ref;
- WT_ASSERT(session, ref->state == WT_REF_LOCKED);
- (void)WT_ATOMIC_CAS(
- ref->state, WT_REF_LOCKED, WT_REF_MEM);
- F_CLR_ATOMIC(e->page, WT_PAGE_EVICT_LOCKED);
- }
+ (void)WT_ATOMIC_CAS(e->page->ref->state,
+ WT_REF_EVICT_FORCE, WT_REF_MEM);
}
e->page = NULL;
e->btree = WT_DEBUG_POINT;
@@ -131,6 +127,7 @@ __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);
@@ -201,14 +198,12 @@ __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_LOCKED))
+ if (!WT_ATOMIC_CAS(page->ref->state, WT_REF_MEM, WT_REF_EVICT_FORCE))
goto err;
- /* Tell eviction that we already have the page locked. */
- F_SET_ATOMIC(page, WT_PAGE_EVICT_LOCKED);
err: __wt_spin_unlock(session, &cache->evict_lock);
/* Only wake the server if the page was added and locked. */
- if (ret == 0 && F_ISSET_ATOMIC(page, WT_PAGE_EVICT_LOCKED)) {
+ if (ret == 0 && page->ref->state == WT_REF_EVICT_FORCE) {
F_SET(S2C(session)->cache, WT_EVICT_FORCE_PASS);
__wt_evict_server_wake(session);
}
@@ -1085,10 +1080,15 @@ __evict_get_page(
ref = evict->page->ref;
WT_ASSERT(session, evict->page == ref->page);
- /* Explicitly requested pages are already locked. */
- if (F_ISSET_ATOMIC(ref->page, WT_PAGE_EVICT_LOCKED))
- F_CLR_ATOMIC(ref->page, WT_PAGE_EVICT_LOCKED);
- else if (!WT_ATOMIC_CAS(ref->state, WT_REF_MEM, WT_REF_LOCKED))
+ /*
+ * Switch pages from the evict force state to locked - the
+ * logic for forced and regular eviction is identical from here
+ * on, and having reconciliation be able to use a single
+ * locked state simplifies that code.
+ */
+ if (!WT_ATOMIC_CAS(
+ ref->state, WT_REF_EVICT_FORCE, WT_REF_LOCKED) &&
+ !WT_ATOMIC_CAS(ref->state, WT_REF_MEM, WT_REF_LOCKED))
continue;
/*
diff --git a/src/btree/bt_page.c b/src/btree/bt_page.c
index 0f63b11b7a2..712417f8889 100644
--- a/src/btree/bt_page.c
+++ b/src/btree/bt_page.c
@@ -42,6 +42,7 @@ __wt_page_in_func(
WT_RET(__wt_cache_full_check(session));
WT_RET(__wt_cache_read(session, parent, ref));
continue;
+ case WT_REF_EVICT_FORCE:
case WT_REF_LOCKED:
case WT_REF_READING:
/*
diff --git a/src/btree/bt_walk.c b/src/btree/bt_walk.c
index 1b4a1d7c2fa..7c5b2f2ca79 100644
--- a/src/btree/bt_walk.c
+++ b/src/btree/bt_walk.c
@@ -284,8 +284,9 @@ retry: if (!WT_ATOMIC_CAS(ref->state,
* that the page will be read back in to cache.
*/
while (LF_ISSET(WT_TREE_WAIT) &&
- (ref->state == WT_REF_LOCKED ||
- ref->state == WT_REF_READING))
+ (ref->state == WT_REF_EVICT_FORCE ||
+ ref->state == WT_REF_LOCKED ||
+ ref->state == WT_REF_READING))
__wt_yield();
if (ref->state == WT_REF_DELETED ||
ref->state == WT_REF_DISK)
diff --git a/src/btree/rec_evict.c b/src/btree/rec_evict.c
index b739e644099..c158a20325c 100644
--- a/src/btree/rec_evict.c
+++ b/src/btree/rec_evict.c
@@ -273,6 +273,7 @@ __rec_review(WT_SESSION_IMPL *session,
session, ref, ref->page, exclusive, 0));
break;
case WT_REF_EVICT_WALK: /* Walk point */
+ case WT_REF_EVICT_FORCE: /* Forced evict */
case WT_REF_LOCKED: /* Being evicted */
case WT_REF_READING: /* Being read */
return (EBUSY);
@@ -462,7 +463,8 @@ __rec_excl_clear(WT_SESSION_IMPL *session)
if ((ref = session->excl[i]) == NULL)
break;
WT_ASSERT(session,
- ref->state == WT_REF_LOCKED && ref->page != NULL);
+ (ref->state == WT_REF_LOCKED ||
+ ref->state == WT_REF_EVICT_FORCE) && ref->page != NULL);
ref->state = WT_REF_MEM;
}
}
diff --git a/src/btree/rec_write.c b/src/btree/rec_write.c
index 34908d5a79f..61fbf030596 100644
--- a/src/btree/rec_write.c
+++ b/src/btree/rec_write.c
@@ -323,6 +323,7 @@ __rec_child_modify(WT_SESSION_IMPL *session,
WT_HAVE_DIAGNOSTIC_YIELD;
return (ret);
+ case WT_REF_EVICT_FORCE:
case WT_REF_LOCKED:
/*
* If being called by the eviction server, the page was
diff --git a/src/include/btmem.h b/src/include/btmem.h
index 16572e433be..9fc0225e296 100644
--- a/src/include/btmem.h
+++ b/src/include/btmem.h
@@ -308,7 +308,6 @@ struct __wt_page {
#define WT_PAGE_BUILD_KEYS 0x01 /* Keys have been built in memory */
#define WT_PAGE_EVICT_LRU 0x02 /* Page is on the LRU queue */
-#define WT_PAGE_EVICT_LOCKED 0x04 /* Page was locked when queued */
uint8_t flags_atomic; /* Atomic flags, use F_*_ATOMIC */
};
@@ -338,6 +337,11 @@ struct __wt_page {
* row-store leaf pages without reading them if they don't reference overflow
* items.
*
+ * WT_REF_EVICT_FORCE:
+ * An application thread has selected this page for eviction. No other
+ * hazard references should be granted. If eviction fails, the eviction server
+ * should set the state back to WT_REF_MEM.
+ *
* WT_REF_EVICT_WALK:
* The next page to be walked for LRU eviction. This page is available for
* reads but not eviction.
@@ -375,6 +379,7 @@ struct __wt_page {
enum __wt_page_state {
WT_REF_DISK=0, /* Page is on disk */
WT_REF_DELETED, /* Page is on disk, but deleted */
+ WT_REF_EVICT_FORCE, /* Page is ready for forced eviction */
WT_REF_EVICT_WALK, /* Next page for LRU eviction */
WT_REF_LOCKED, /* Page being evicted */
WT_REF_MEM, /* Page is in cache and valid */