summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Cahill <michael.cahill@mongodb.com>2016-09-23 14:46:33 +1000
committerAlex Gorrod <alexander.gorrod@mongodb.com>2016-09-23 14:46:33 +1000
commitd85e1890639ed51bd72841ef3143e696b32c1ba6 (patch)
treef2cc578179e547b582e661788e8a19a3524f6631
parente75ef579dd4c3a911ba4dc0d2619b9ba5c9b166a (diff)
downloadmongo-d85e1890639ed51bd72841ef3143e696b32c1ba6.tar.gz
WT-2924 Ensure we are doing eviction when threads are waiting for it. (#3056)
Fix a bug in scrub step down, where it could set the target below the eviction target leading to an unexpected eviction state.
-rw-r--r--src/evict/evict_lru.c13
-rw-r--r--src/include/cache.h2
-rw-r--r--src/include/cache.i94
-rw-r--r--src/txn/txn_ckpt.c3
4 files changed, 77 insertions, 35 deletions
diff --git a/src/evict/evict_lru.c b/src/evict/evict_lru.c
index 35c057c9767..fcea343c2a1 100644
--- a/src/evict/evict_lru.c
+++ b/src/evict/evict_lru.c
@@ -431,7 +431,6 @@ __evict_update_work(WT_SESSION_IMPL *session)
{
WT_CACHE *cache;
WT_CONNECTION_IMPL *conn;
- double dirty_trigger;
uint64_t bytes_inuse, bytes_max, dirty_inuse;
conn = S2C(session);
@@ -456,15 +455,13 @@ __evict_update_work(WT_SESSION_IMPL *session)
bytes_inuse = __wt_cache_bytes_inuse(cache);
if (bytes_inuse > (cache->eviction_target * bytes_max) / 100)
F_SET(cache, WT_CACHE_EVICT_CLEAN);
- if (bytes_inuse > (cache->eviction_trigger * bytes_max) / 100)
+ if (__wt_eviction_clean_needed(session, NULL))
F_SET(cache, WT_CACHE_EVICT_CLEAN_HARD);
dirty_inuse = __wt_cache_dirty_leaf_inuse(cache);
if (dirty_inuse > (cache->eviction_dirty_target * bytes_max) / 100)
F_SET(cache, WT_CACHE_EVICT_DIRTY);
- if ((dirty_trigger = cache->eviction_scrub_limit) < 1.0)
- dirty_trigger = (double)cache->eviction_dirty_trigger;
- if (dirty_inuse > (uint64_t)(dirty_trigger * bytes_max) / 100)
+ if (__wt_eviction_dirty_needed(session, NULL))
F_SET(cache, WT_CACHE_EVICT_DIRTY_HARD);
/*
@@ -497,6 +494,12 @@ __evict_update_work(WT_SESSION_IMPL *session)
F_CLR(cache, WT_CACHE_EVICT_CLEAN | WT_CACHE_EVICT_CLEAN_HARD);
}
+ /* If threads are blocked by eviction we should be looking for pages. */
+ WT_ASSERT(session, !F_ISSET(cache, WT_CACHE_EVICT_CLEAN_HARD) ||
+ F_ISSET(cache, WT_CACHE_EVICT_CLEAN));
+ WT_ASSERT(session, !F_ISSET(cache, WT_CACHE_EVICT_DIRTY_HARD) ||
+ F_ISSET(cache, WT_CACHE_EVICT_DIRTY));
+
WT_STAT_CONN_SET(session, cache_eviction_state,
F_MASK(cache, WT_CACHE_EVICT_MASK));
diff --git a/src/include/cache.h b/src/include/cache.h
index 515135f26ab..fceba6536c2 100644
--- a/src/include/cache.h
+++ b/src/include/cache.h
@@ -175,7 +175,7 @@ struct __wt_cache {
#define WT_CACHE_EVICT_CLEAN_HARD 0x002 /* Clean % blocking app threads */
#define WT_CACHE_EVICT_DIRTY 0x004 /* Evict dirty pages */
#define WT_CACHE_EVICT_DIRTY_HARD 0x008 /* Dirty % blocking app threads */
-#define WT_CACHE_EVICT_SCRUB 0x010 /* Scrub dirty pages pages */
+#define WT_CACHE_EVICT_SCRUB 0x010 /* Scrub dirty pages */
#define WT_CACHE_EVICT_URGENT 0x020 /* Pages are in the urgent queue */
#define WT_CACHE_EVICT_ALL (WT_CACHE_EVICT_CLEAN | WT_CACHE_EVICT_DIRTY)
#define WT_CACHE_EVICT_MASK 0x0FF
diff --git a/src/include/cache.i b/src/include/cache.i
index b5605769f1a..4255d04ec37 100644
--- a/src/include/cache.i
+++ b/src/include/cache.i
@@ -193,7 +193,7 @@ __wt_cache_bytes_other(WT_CACHE *cache)
* __wt_session_can_wait --
* Return if a session available for a potentially slow operation.
*/
-static inline int
+static inline bool
__wt_session_can_wait(WT_SESSION_IMPL *session)
{
/*
@@ -202,17 +202,71 @@ __wt_session_can_wait(WT_SESSION_IMPL *session)
* the system cache.
*/
if (!F_ISSET(session, WT_SESSION_CAN_WAIT))
- return (0);
+ return (false);
/*
* LSM sets the no-eviction flag when holding the LSM tree lock, in that
* case, or when holding the schema lock, we don't want to highjack the
* thread for eviction.
*/
- if (F_ISSET(session, WT_SESSION_NO_EVICTION | WT_SESSION_LOCKED_SCHEMA))
- return (0);
+ return (!F_ISSET(
+ session, WT_SESSION_NO_EVICTION | WT_SESSION_LOCKED_SCHEMA));
+}
+
+/*
+ * __wt_eviction_clean_needed --
+ * Return if an application thread should do eviction due to the total
+ * volume of dirty data in cache.
+ */
+static inline bool
+__wt_eviction_clean_needed(WT_SESSION_IMPL *session, u_int *pct_fullp)
+{
+ WT_CACHE *cache;
+ uint64_t bytes_inuse, bytes_max;
+
+ cache = S2C(session)->cache;
+
+ /*
+ * Avoid division by zero if the cache size has not yet been set in a
+ * shared cache.
+ */
+ bytes_max = S2C(session)->cache_size + 1;
+ bytes_inuse = __wt_cache_bytes_inuse(cache);
+
+ if (pct_fullp != NULL)
+ *pct_fullp = (u_int)((100 * bytes_inuse) / bytes_max);
+
+ return (bytes_inuse > (cache->eviction_trigger * bytes_max) / 100);
+}
+
+/*
+ * __wt_eviction_dirty_needed --
+ * Return if an application thread should do eviction due to the total
+ * volume of dirty data in cache.
+ */
+static inline bool
+__wt_eviction_dirty_needed(WT_SESSION_IMPL *session, u_int *pct_fullp)
+{
+ WT_CACHE *cache;
+ double dirty_trigger;
+ uint64_t dirty_inuse, bytes_max;
+
+ cache = S2C(session)->cache;
+
+ /*
+ * Avoid division by zero if the cache size has not yet been set in a
+ * shared cache.
+ */
+ bytes_max = S2C(session)->cache_size + 1;
+ dirty_inuse = __wt_cache_dirty_leaf_inuse(cache);
+
+ if (pct_fullp != NULL)
+ *pct_fullp = (u_int)((100 * dirty_inuse) / bytes_max);
+
+ if ((dirty_trigger = cache->eviction_scrub_limit) < 1.0)
+ dirty_trigger = (double)cache->eviction_dirty_trigger;
- return (1);
+ return (dirty_inuse > (uint64_t)(dirty_trigger * bytes_max) / 100);
}
/*
@@ -223,42 +277,30 @@ __wt_session_can_wait(WT_SESSION_IMPL *session)
static inline bool
__wt_eviction_needed(WT_SESSION_IMPL *session, bool busy, u_int *pct_fullp)
{
- WT_CONNECTION_IMPL *conn;
WT_CACHE *cache;
- double dirty_trigger;
- uint64_t bytes_inuse, bytes_max, dirty_inuse;
u_int pct_dirty, pct_full;
+ bool clean_needed, dirty_needed;
- conn = S2C(session);
- cache = conn->cache;
+ cache = S2C(session)->cache;
/*
* If the connection is closing we do not need eviction from an
* application thread. The eviction subsystem is already closed.
*/
- if (F_ISSET(conn, WT_CONN_CLOSING))
+ if (F_ISSET(S2C(session), WT_CONN_CLOSING))
return (false);
- /*
- * Avoid division by zero if the cache size has not yet been set in a
- * shared cache.
- */
- bytes_max = conn->cache_size + 1;
- bytes_inuse = __wt_cache_bytes_inuse(cache);
- dirty_inuse = __wt_cache_dirty_leaf_inuse(cache);
+ clean_needed = __wt_eviction_clean_needed(session, &pct_full);
+ dirty_needed = __wt_eviction_dirty_needed(session, &pct_dirty);
/*
* Calculate the cache full percentage; anything over the trigger means
* we involve the application thread.
*/
- if (pct_fullp != NULL) {
- pct_full = (u_int)((100 * bytes_inuse) / bytes_max);
- pct_dirty = (u_int)((100 * dirty_inuse) / bytes_max);
-
+ if (pct_fullp != NULL)
*pct_fullp = (u_int)WT_MAX(0, 100 - WT_MIN(
(int)cache->eviction_trigger - (int)pct_full,
(int)cache->eviction_dirty_trigger - (int)pct_dirty));
- }
/*
* Only check the dirty trigger when the session is not busy.
@@ -268,11 +310,7 @@ __wt_eviction_needed(WT_SESSION_IMPL *session, bool busy, u_int *pct_fullp)
* The next transaction in this session will not be able to start until
* the cache is under the limit.
*/
- if ((dirty_trigger = cache->eviction_scrub_limit) < 1.0)
- dirty_trigger = (double)cache->eviction_dirty_trigger;
- return (bytes_inuse > (cache->eviction_trigger * bytes_max) / 100 ||
- (!busy &&
- dirty_inuse > (uint64_t)(dirty_trigger * bytes_max) / 100));
+ return (clean_needed || (!busy && dirty_needed));
}
/*
diff --git a/src/txn/txn_ckpt.c b/src/txn/txn_ckpt.c
index 180a06a3aed..3aad95f5a9f 100644
--- a/src/txn/txn_ckpt.c
+++ b/src/txn/txn_ckpt.c
@@ -423,7 +423,8 @@ __checkpoint_reduce_dirty_cache(WT_SESSION_IMPL *session)
* level.
*/
__wt_sleep(0, 10 * stepdown_us);
- cache->eviction_scrub_limit = current_dirty - delta;
+ cache->eviction_scrub_limit =
+ WT_MAX(cache->eviction_dirty_target, current_dirty - delta);
WT_STAT_CONN_SET(session, txn_checkpoint_scrub_target,
cache->eviction_scrub_limit);
WT_RET(__wt_epoch(session, &last));