diff options
author | Michael Cahill <michael.cahill@mongodb.com> | 2015-08-14 16:20:41 +1000 |
---|---|---|
committer | Michael Cahill <michael.cahill@mongodb.com> | 2015-08-14 17:22:40 +1000 |
commit | d71de5fff7596af4c991654c716b6e40ca86e630 (patch) | |
tree | 3bd46a27bdb1e9cbb39147a2e1620659b3dd5dbf | |
parent | 95eba9dbd0dbdb549485c61c0c385ce0e911f892 (diff) | |
download | mongo-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.c | 43 | ||||
-rw-r--r-- | src/include/dhandle.h | 6 | ||||
-rw-r--r-- | src/session/session_dhandle.c | 122 |
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); |