summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Cahill <michael.cahill@mongodb.com>2015-08-14 16:20:41 +1000
committerMichael Cahill <michael.cahill@mongodb.com>2015-08-14 17:22:40 +1000
commitd71de5fff7596af4c991654c716b6e40ca86e630 (patch)
tree3bd46a27bdb1e9cbb39147a2e1620659b3dd5dbf
parent95eba9dbd0dbdb549485c61c0c385ce0e911f892 (diff)
downloadmongo-d71de5fff7596af4c991654c716b6e40ca86e630.tar.gz
WT-2038 Immediately discard temporary handles from session caches.
This should mean that checkpoint locks don't accumulate waiting for a sweep. (cherry picked from commit 9309a888c136521e3e415ca8df5c42f63f1c2ebd)
-rw-r--r--src/conn/conn_sweep.c43
-rw-r--r--src/include/dhandle.h6
-rw-r--r--src/session/session_dhandle.c122
3 files changed, 103 insertions, 68 deletions
diff --git a/src/conn/conn_sweep.c b/src/conn/conn_sweep.c
index f45477196bd..061d70221c7 100644
--- a/src/conn/conn_sweep.c
+++ b/src/conn/conn_sweep.c
@@ -8,6 +8,10 @@
#include "wt_internal.h"
+#define WT_DHANDLE_CAN_DISCARD(dhandle) \
+ (!F_ISSET(dhandle, WT_DHANDLE_EXCLUSIVE | WT_DHANDLE_OPEN) && \
+ dhandle->session_inuse == 0 && dhandle->session_ref == 0)
+
/*
* __sweep_mark --
* Mark idle handles with a time of death, and note if we see dead
@@ -34,8 +38,12 @@ __sweep_mark(WT_SESSION_IMPL *session, time_t now)
if (dhandle->session_inuse > 1)
dhandle->timeofdeath = 0;
- if (F_ISSET(dhandle, WT_DHANDLE_DEAD) ||
- dhandle->session_inuse != 0 ||
+ /*
+ * If the handle is open exclusive or currently in use, or the
+ * time of death is already set, move on.
+ */
+ if (F_ISSET(dhandle, WT_DHANDLE_EXCLUSIVE) ||
+ dhandle->session_inuse > 0 ||
dhandle->timeofdeath != 0)
continue;
@@ -125,7 +133,7 @@ __sweep_expire(WT_SESSION_IMPL *session, time_t now)
break;
if (WT_IS_METADATA(dhandle) ||
- F_ISSET(dhandle, WT_DHANDLE_DEAD) ||
+ !F_ISSET(dhandle, WT_DHANDLE_OPEN) ||
dhandle->session_inuse != 0 ||
dhandle->timeofdeath == 0 ||
now <= dhandle->timeofdeath + conn->sweep_idle_time)
@@ -145,8 +153,7 @@ __sweep_expire(WT_SESSION_IMPL *session, time_t now)
* Discard pages from dead trees.
*/
static int
-__sweep_discard_trees(
- WT_SESSION_IMPL *session, time_t now, u_int *dead_handlesp)
+__sweep_discard_trees(WT_SESSION_IMPL *session, u_int *dead_handlesp)
{
WT_CONNECTION_IMPL *conn;
WT_DATA_HANDLE *dhandle;
@@ -157,9 +164,7 @@ __sweep_discard_trees(
*dead_handlesp = 0;
TAILQ_FOREACH(dhandle, &conn->dhqh, q) {
- if (!F_ISSET(dhandle, WT_DHANDLE_OPEN | WT_DHANDLE_EXCLUSIVE) &&
- (dhandle->timeofdiscard == 0 ||
- now <= dhandle->timeofdiscard + conn->sweep_idle_time))
+ if (WT_DHANDLE_CAN_DISCARD(dhandle))
++*dead_handlesp;
if (!F_ISSET(dhandle, WT_DHANDLE_OPEN) ||
@@ -199,8 +204,7 @@ __sweep_remove_one(WT_SESSION_IMPL *session, WT_DATA_HANDLE *dhandle)
* If there are no longer any references to the handle in any
* sessions, attempt to discard it.
*/
- if (F_ISSET(dhandle, WT_DHANDLE_EXCLUSIVE | WT_DHANDLE_OPEN) ||
- dhandle->session_inuse != 0 || dhandle->session_ref != 0)
+ if (!WT_DHANDLE_CAN_DISCARD(dhandle))
WT_ERR(EBUSY);
WT_WITH_DHANDLE(session, dhandle,
@@ -222,7 +226,7 @@ err: WT_TRET(__wt_writeunlock(session, dhandle->rwlock));
* Remove closed handles from the connection list.
*/
static int
-__sweep_remove_handles(WT_SESSION_IMPL *session, time_t now)
+__sweep_remove_handles(WT_SESSION_IMPL *session)
{
WT_CONNECTION_IMPL *conn;
WT_DATA_HANDLE *dhandle, *dhandle_next;
@@ -236,22 +240,15 @@ __sweep_remove_handles(WT_SESSION_IMPL *session, time_t now)
dhandle_next = TAILQ_NEXT(dhandle, q);
if (WT_IS_METADATA(dhandle))
continue;
- if (F_ISSET(dhandle, WT_DHANDLE_EXCLUSIVE | WT_DHANDLE_OPEN) ||
- dhandle->session_inuse != 0 || dhandle->session_ref != 0)
- continue;
- if (dhandle->timeofdiscard != 0 &&
- now <= dhandle->timeofdiscard + conn->sweep_idle_time)
+ if (!WT_DHANDLE_CAN_DISCARD(dhandle))
continue;
WT_WITH_DHANDLE_LOCK(session,
ret = __sweep_remove_one(session, dhandle));
if (ret == 0)
- WT_STAT_FAST_CONN_INCR(
- session, dh_sweep_remove);
- else {
+ WT_STAT_FAST_CONN_INCR(session, dh_sweep_remove);
+ else
WT_STAT_FAST_CONN_INCR(session, dh_sweep_ref);
- dhandle->timeofdiscard = now;
- }
WT_RET_BUSY_OK(ret);
}
@@ -302,10 +299,10 @@ __sweep_server(void *arg)
conn->open_btree_count >= conn->sweep_handles_min)
WT_ERR(__sweep_expire(session, now));
- WT_ERR(__sweep_discard_trees(session, now, &dead_handles));
+ WT_ERR(__sweep_discard_trees(session, &dead_handles));
if (dead_handles > 0)
- WT_ERR(__sweep_remove_handles(session, now));
+ WT_ERR(__sweep_remove_handles(session));
}
if (0) {
diff --git a/src/include/dhandle.h b/src/include/dhandle.h
index e7231616c12..82797be0d58 100644
--- a/src/include/dhandle.h
+++ b/src/include/dhandle.h
@@ -28,6 +28,11 @@
*/
#define WT_SAVE_DHANDLE(s, e) WT_WITH_DHANDLE(s, (s)->dhandle, e)
+/* Check if a handle is inactive. */
+#define WT_DHANDLE_INACTIVE(dhandle) \
+ (F_ISSET(dhandle, WT_DHANDLE_DEAD) || \
+ !F_ISSET(dhandle, WT_DHANDLE_EXCLUSIVE | WT_DHANDLE_OPEN))
+
/*
* WT_DATA_HANDLE --
* A handle for a generic named data source.
@@ -45,7 +50,6 @@ struct __wt_data_handle {
uint32_t session_ref; /* Sessions referencing this handle */
int32_t session_inuse; /* Sessions using this handle */
time_t timeofdeath; /* Use count went to 0 */
- time_t timeofdiscard; /* Time of last failed discard */
uint64_t name_hash; /* Hash of name */
const char *name; /* Object name as a URI */
diff --git a/src/session/session_dhandle.c b/src/session/session_dhandle.c
index 731e54884db..7488d9115f0 100644
--- a/src/session/session_dhandle.c
+++ b/src/session/session_dhandle.c
@@ -38,6 +38,61 @@ __session_add_dhandle(
}
/*
+ * __session_discard_dhandle --
+ * Remove a data handle from the session cache.
+ */
+static void
+__session_discard_dhandle(
+ WT_SESSION_IMPL *session, WT_DATA_HANDLE_CACHE *dhandle_cache)
+{
+ uint64_t bucket;
+
+ bucket = dhandle_cache->dhandle->name_hash % WT_HASH_ARRAY_SIZE;
+ TAILQ_REMOVE(&session->dhandles, dhandle_cache, q);
+ TAILQ_REMOVE(&session->dhhash[bucket], dhandle_cache, hashq);
+
+ (void)WT_ATOMIC_SUB4(dhandle_cache->dhandle->session_ref, 1);
+
+ __wt_overwrite_and_free(session, dhandle_cache);
+}
+
+/*
+ * __session_find_dhandle --
+ * Search for a data handle in the session cache.
+ */
+static void
+__session_find_dhandle(WT_SESSION_IMPL *session,
+ const char *uri, const char *checkpoint,
+ WT_DATA_HANDLE_CACHE **dhandle_cachep)
+{
+ WT_DATA_HANDLE *dhandle;
+ WT_DATA_HANDLE_CACHE *dhandle_cache;
+ uint64_t bucket;
+
+ dhandle = NULL;
+
+ bucket = __wt_hash_city64(uri, strlen(uri)) % WT_HASH_ARRAY_SIZE;
+retry: TAILQ_FOREACH(dhandle_cache, &session->dhhash[bucket], hashq) {
+ dhandle = dhandle_cache->dhandle;
+ if (WT_DHANDLE_INACTIVE(dhandle) && !WT_IS_METADATA(dhandle)) {
+ __session_discard_dhandle(session, dhandle_cache);
+ /* We deleted our entry, retry from the start. */
+ goto retry;
+ }
+
+ if (strcmp(uri, dhandle->name) != 0)
+ continue;
+ if (checkpoint == NULL && dhandle->checkpoint == NULL)
+ break;
+ if (checkpoint != NULL && dhandle->checkpoint != NULL &&
+ strcmp(checkpoint, dhandle->checkpoint) == 0)
+ break;
+ }
+
+ *dhandle_cachep = dhandle_cache;
+}
+
+/*
* __wt_session_lock_dhandle --
* Try to lock a handle that is cached in this session. This is the fast
* path that tries to lock a handle without the need for the schema lock.
@@ -134,6 +189,7 @@ __wt_session_release_btree(WT_SESSION_IMPL *session)
enum { NOLOCK, READLOCK, WRITELOCK } locked;
WT_BTREE *btree;
WT_DATA_HANDLE *dhandle;
+ WT_DATA_HANDLE_CACHE *dhandle_cache;
WT_DECL_RET;
btree = S2BT(session);
@@ -144,6 +200,13 @@ __wt_session_release_btree(WT_SESSION_IMPL *session)
* If we had special flags set, close the handle so that future access
* can get a handle without special flags.
*/
+ if (F_ISSET(dhandle, WT_DHANDLE_DISCARD | WT_DHANDLE_DISCARD_FORCE)) {
+ __session_find_dhandle(session,
+ dhandle->name, dhandle->checkpoint, &dhandle_cache);
+ if (dhandle_cache != NULL)
+ __session_discard_dhandle(session, dhandle_cache);
+ }
+
if (F_ISSET(dhandle, WT_DHANDLE_DISCARD_FORCE)) {
WT_WITH_DHANDLE_LOCK(session,
ret = __wt_conn_btree_sync_and_close(session, 0, 1));
@@ -232,25 +295,6 @@ retry: WT_RET(__wt_meta_checkpoint_last_name(
}
/*
- * __session_discard_btree --
- * Discard our reference to the btree.
- */
-static void
-__session_discard_btree(
- WT_SESSION_IMPL *session, WT_DATA_HANDLE_CACHE *dhandle_cache)
-{
- uint64_t bucket;
-
- bucket = dhandle_cache->dhandle->name_hash % WT_HASH_ARRAY_SIZE;
- TAILQ_REMOVE(&session->dhandles, dhandle_cache, q);
- TAILQ_REMOVE(&session->dhhash[bucket], dhandle_cache, hashq);
-
- (void)WT_ATOMIC_SUB4(dhandle_cache->dhandle->session_ref, 1);
-
- __wt_overwrite_and_free(session, dhandle_cache);
-}
-
-/*
* __wt_session_close_cache --
* Close any cached handles in a session.
*/
@@ -260,7 +304,7 @@ __wt_session_close_cache(WT_SESSION_IMPL *session)
WT_DATA_HANDLE_CACHE *dhandle_cache;
while ((dhandle_cache = TAILQ_FIRST(&session->dhandles)) != NULL)
- __session_discard_btree(session, dhandle_cache);
+ __session_discard_dhandle(session, dhandle_cache);
}
/*
@@ -294,10 +338,12 @@ __session_dhandle_sweep(WT_SESSION_IMPL *session)
dhandle = dhandle_cache->dhandle;
if (dhandle != session->dhandle &&
dhandle->session_inuse == 0 &&
- (F_ISSET(dhandle, WT_DHANDLE_DEAD) ||
- now - dhandle->timeofdeath > conn->sweep_idle_time)) {
+ (WT_DHANDLE_INACTIVE(dhandle) ||
+ (dhandle->timeofdeath != 0 &&
+ now - dhandle->timeofdeath > conn->sweep_idle_time))) {
WT_STAT_FAST_CONN_INCR(session, dh_session_handles);
- __session_discard_btree(session, dhandle_cache);
+ WT_ASSERT(session, !WT_IS_METADATA(dhandle));
+ __session_discard_dhandle(session, dhandle_cache);
}
dhandle_cache = dhandle_cache_next;
}
@@ -305,18 +351,19 @@ __session_dhandle_sweep(WT_SESSION_IMPL *session)
}
/*
- * __session_dhandle_find --
+ * __session_find_shared_dhandle --
* Search for a data handle in the connection and add it to a session's
* cache. Since the data handle isn't locked, this must be called holding
* the handle list lock, and we must increment the handle's reference
* count before releasing it.
*/
static int
-__session_dhandle_find(WT_SESSION_IMPL *session,
+__session_find_shared_dhandle(WT_SESSION_IMPL *session,
const char *uri, const char *checkpoint, uint32_t flags)
{
WT_RET(__wt_conn_dhandle_find(session, uri, checkpoint, flags));
- return (__session_add_dhandle(session, NULL));
+ (void)WT_ATOMIC_ADD4(session->dhandle->session_ref, 1);
+ return (0);
}
/*
@@ -330,35 +377,22 @@ __wt_session_get_btree(WT_SESSION_IMPL *session,
WT_DATA_HANDLE *dhandle;
WT_DATA_HANDLE_CACHE *dhandle_cache;
WT_DECL_RET;
- uint64_t bucket;
int is_dead;
WT_ASSERT(session, !F_ISSET(session, WT_SESSION_NO_DATA_HANDLES));
WT_ASSERT(session, !LF_ISSET(WT_DHANDLE_HAVE_REF));
- dhandle = NULL;
-
- bucket = __wt_hash_city64(uri, strlen(uri)) % WT_HASH_ARRAY_SIZE;
- TAILQ_FOREACH(dhandle_cache, &session->dhhash[bucket], hashq) {
- dhandle = dhandle_cache->dhandle;
- if (strcmp(uri, dhandle->name) != 0)
- continue;
- if (checkpoint == NULL && dhandle->checkpoint == NULL)
- break;
- if (checkpoint != NULL && dhandle->checkpoint != NULL &&
- strcmp(checkpoint, dhandle->checkpoint) == 0)
- break;
- }
+ __session_find_dhandle(session, uri, checkpoint, &dhandle_cache);
if (dhandle_cache != NULL)
- session->dhandle = dhandle;
+ session->dhandle = dhandle = dhandle_cache->dhandle;
else {
/*
* We didn't find a match in the session cache, now search the
* shared handle list and cache any handle we find.
*/
WT_WITH_DHANDLE_LOCK(session, ret =
- __session_dhandle_find(session, uri, checkpoint, flags));
+ __session_find_shared_dhandle(session, uri, checkpoint, flags));
dhandle = (ret == 0) ? session->dhandle : NULL;
WT_RET_NOTFOUND_OK(ret);
}
@@ -386,7 +420,7 @@ __wt_session_get_btree(WT_SESSION_IMPL *session,
/* If we found the handle and it isn't dead, reopen it. */
if (is_dead) {
- __session_discard_btree(session, dhandle_cache);
+ __session_discard_dhandle(session, dhandle_cache);
dhandle_cache = NULL;
session->dhandle = dhandle = NULL;
} else
@@ -413,7 +447,7 @@ retry: is_dead = 0;
if (is_dead) {
if (dhandle_cache != NULL)
- __session_discard_btree(session, dhandle_cache);
+ __session_discard_dhandle(session, dhandle_cache);
dhandle_cache = NULL;
session->dhandle = dhandle = NULL;
LF_CLR(WT_DHANDLE_HAVE_REF);