summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAlex Gorrod <alexg@wiredtiger.com>2014-01-14 13:51:42 +1100
committerAlex Gorrod <alexg@wiredtiger.com>2014-01-14 13:51:42 +1100
commite9a7bd96d5ceff6c3bdfd4068455c126a7d5ac7c (patch)
tree79248fc2f9fd177e5d33d1d0e9a556fe92dc6892 /src
parentc408c9c8737d669d92240c9c3b2d98bb6c95acb8 (diff)
downloadmongo-e9a7bd96d5ceff6c3bdfd4068455c126a7d5ac7c.tar.gz
Add a new mode to eviction that only considers internal pages.
The mode is triggered when we are force evicting pages, and the cache is not yet full. If we don't merge internal pages while doing forced eviction we can end up with very deep chains of WT_REC_SPLIT pages.
Diffstat (limited to 'src')
-rw-r--r--src/btree/bt_evict.c56
-rw-r--r--src/include/btree.i7
-rw-r--r--src/include/cache.h11
3 files changed, 47 insertions, 27 deletions
diff --git a/src/btree/bt_evict.c b/src/btree/bt_evict.c
index fdb7b9162ba..a5b864a5fd7 100644
--- a/src/btree/bt_evict.c
+++ b/src/btree/bt_evict.c
@@ -9,10 +9,10 @@
static void __evict_init_candidate(
WT_SESSION_IMPL *, WT_EVICT_ENTRY *, WT_PAGE *);
-static int __evict_lru(WT_SESSION_IMPL *, int);
+static int __evict_lru(WT_SESSION_IMPL *, uint32_t);
static int __evict_lru_cmp(const void *, const void *);
-static int __evict_walk(WT_SESSION_IMPL *, uint32_t *, int);
-static int __evict_walk_file(WT_SESSION_IMPL *, u_int *, int);
+static int __evict_walk(WT_SESSION_IMPL *, uint32_t *, uint32_t);
+static int __evict_walk_file(WT_SESSION_IMPL *, u_int *, uint32_t);
static int __evict_worker(WT_SESSION_IMPL *);
/*
@@ -210,8 +210,9 @@ __evict_worker(WT_SESSION_IMPL *session)
{
WT_CACHE *cache;
WT_CONNECTION_IMPL *conn;
+ int loop;
uint64_t bytes_inuse, bytes_max, dirty_inuse;
- int clean, loop;
+ uint32_t flags;
conn = S2C(session);
cache = conn->cache;
@@ -225,25 +226,28 @@ __evict_worker(WT_SESSION_IMPL *session)
bytes_inuse = __wt_cache_bytes_inuse(cache);
dirty_inuse = cache->bytes_dirty;
bytes_max = conn->cache_size;
- if (bytes_inuse < (cache->eviction_target * bytes_max) / 100 &&
- dirty_inuse <
+
+ /* Check to see if the eviction server should run. */
+ if (bytes_inuse > (cache->eviction_target * bytes_max) / 100)
+ flags = WT_EVICT_PASS_ALL;
+ else if (dirty_inuse >
(cache->eviction_dirty_target * bytes_max) / 100)
+ /* Ignore clean pages unless the cache is too large */
+ flags = WT_EVICT_PASS_DIRTY;
+ else if (F_ISSET(cache, WT_EVICT_INTERNAL))
+ /* Only consider merging internal pages. */
+ flags = WT_EVICT_PASS_INTERNAL;
+ else
break;
+ F_CLR(cache, WT_EVICT_INTERNAL);
F_SET(cache, WT_EVICT_ACTIVE);
WT_VERBOSE_RET(session, evictserver,
"Eviction pass with: Max: %" PRIu64
- " In use: %" PRIu64 " Dirty: %" PRIu64,
- bytes_max, bytes_inuse, dirty_inuse);
+ " In use: %" PRIu64 " Dirty: %" PRIu64 " Internal: %s",
+ bytes_max, bytes_inuse, dirty_inuse,
+ F_ISSET(cache, WT_EVICT_INTERNAL) ? "yes" : "no");
- /*
- * Either the cache is too large or there are too many dirty
- * pages (or both). Ignore clean pages unless the cache is
- * too large.
- */
- clean = 0;
- if (bytes_inuse > (cache->eviction_target * bytes_max) / 100)
- clean = 1;
/*
* When the cache is full, track whether pages are being
@@ -255,7 +259,7 @@ __evict_worker(WT_SESSION_IMPL *session)
else
F_CLR(cache, WT_EVICT_NO_PROGRESS);
- WT_RET(__evict_lru(session, clean));
+ WT_RET(__evict_lru(session, flags));
/*
* If we're making progress, keep going; if we're not making
@@ -625,7 +629,7 @@ err: /* On error, clear any left-over tree walk. */
* Evict pages from the cache based on their read generation.
*/
static int
-__evict_lru(WT_SESSION_IMPL *session, int clean)
+__evict_lru(WT_SESSION_IMPL *session, uint32_t flags)
{
WT_CACHE *cache;
WT_DECL_RET;
@@ -636,7 +640,7 @@ __evict_lru(WT_SESSION_IMPL *session, int clean)
cache = S2C(session)->cache;
/* Get some more pages to consider for eviction. */
- WT_RET(__evict_walk(session, &entries, clean));
+ WT_RET(__evict_walk(session, &entries, flags));
/* Sort the list into LRU order and restart. */
__wt_spin_lock(session, &cache->evict_lock);
@@ -711,7 +715,7 @@ __evict_lru(WT_SESSION_IMPL *session, int clean)
* Fill in the array by walking the next set of pages.
*/
static int
-__evict_walk(WT_SESSION_IMPL *session, u_int *entriesp, int clean)
+__evict_walk(WT_SESSION_IMPL *session, u_int *entriesp, uint32_t flags)
{
WT_BTREE *btree;
WT_CACHE *cache;
@@ -777,7 +781,7 @@ retry: SLIST_FOREACH(dhandle, &conn->dhlh, l) {
*/
if (!F_ISSET(btree, WT_BTREE_NO_EVICTION))
WT_WITH_BTREE(session, btree,
- ret = __evict_walk_file(session, &slot, clean));
+ ret = __evict_walk_file(session, &slot, flags));
__wt_spin_unlock(session, &cache->evict_walk_lock);
@@ -833,7 +837,7 @@ __evict_init_candidate(
* Get a few page eviction candidates from a single underlying file.
*/
static int
-__evict_walk_file(WT_SESSION_IMPL *session, u_int *slotp, int clean)
+__evict_walk_file(WT_SESSION_IMPL *session, u_int *slotp, uint32_t flags)
{
WT_BTREE *btree;
WT_CACHE *cache;
@@ -841,6 +845,7 @@ __evict_walk_file(WT_SESSION_IMPL *session, u_int *slotp, int clean)
WT_EVICT_ENTRY *end, *evict, *start;
WT_PAGE *page;
int modified, restarts, levels;
+ uint32_t walk_flags;
btree = S2BT(session);
cache = S2C(session)->cache;
@@ -853,12 +858,15 @@ __evict_walk_file(WT_SESSION_IMPL *session, u_int *slotp, int clean)
WT_PAGE_IS_ROOT(btree->evict_page) ||
btree->evict_page->ref->state == WT_REF_EVICT_WALK);
+ walk_flags = WT_TREE_EVICT;
+ if (F_ISSET(cache, WT_EVICT_INTERNAL))
+ walk_flags |= WT_TREE_SKIP_LEAF;
/*
* Get some more eviction candidate pages.
*/
for (evict = start, restarts = 0;
evict < end && (ret == 0 || ret == WT_NOTFOUND);
- ret = __wt_tree_walk(session, &btree->evict_page, WT_TREE_EVICT)) {
+ ret = __wt_tree_walk(session, &btree->evict_page, walk_flags)) {
if ((page = btree->evict_page) == NULL) {
ret = 0;
/*
@@ -946,7 +954,7 @@ __evict_walk_file(WT_SESSION_IMPL *session, u_int *slotp, int clean)
continue;
/* Optionally ignore clean pages. */
- if (!modified && !clean)
+ if (!modified && LF_ISSET(WT_EVICT_PASS_DIRTY))
continue;
/*
diff --git a/src/include/btree.i b/src/include/btree.i
index 42b6663f7c5..09e8a916ff8 100644
--- a/src/include/btree.i
+++ b/src/include/btree.i
@@ -716,6 +716,13 @@ __wt_eviction_force(WT_SESSION_IMPL *session, WT_PAGE *page)
__wt_txn_visible_all(session, page->modify->update_txn)) {
page->read_gen = WT_READ_GEN_OLDEST;
WT_RET(__wt_page_release(session, page));
+ /*
+ * Forced eviction can create chains of internal pages before
+ * the cache is full. Setup the eviction server to look for
+ * internal page merges after we successfully force evict.
+ */
+ F_SET(S2C(session)->cache, WT_EVICT_INTERNAL);
+ WT_RET(__wt_evict_server_wake(session));
} else {
WT_RET(__wt_page_release(session, page));
__wt_sleep(0, 10000);
diff --git a/src/include/cache.h b/src/include/cache.h
index 82f6bbf9dd1..055041b7e6c 100644
--- a/src/include/cache.h
+++ b/src/include/cache.h
@@ -16,6 +16,10 @@
#define WT_EVICT_WALK_BASE 300 /* Pages tracked across file visits */
#define WT_EVICT_WALK_INCR 100 /* Pages added each walk */
+#define WT_EVICT_PASS_ALL 0x01
+#define WT_EVICT_PASS_DIRTY 0x02
+#define WT_EVICT_PASS_INTERNAL 0x04
+
/*
* WT_EVICT_ENTRY --
* Encapsulation of an eviction candidate.
@@ -90,9 +94,10 @@ struct __wt_cache {
/*
* Flags.
*/
-#define WT_EVICT_NO_PROGRESS 0x01 /* Check if pages are being evicted */
-#define WT_EVICT_STUCK 0x02 /* Eviction server is stuck */
-#define WT_EVICT_ACTIVE 0x04 /* Eviction server is active */
+#define WT_EVICT_ACTIVE 0x01 /* Eviction server is active */
+#define WT_EVICT_INTERNAL 0x02 /* Check for deep internal trees */
+#define WT_EVICT_NO_PROGRESS 0x04 /* Check if pages are being evicted */
+#define WT_EVICT_STUCK 0x08 /* Eviction server is stuck */
uint32_t flags;
};