summaryrefslogtreecommitdiff
path: root/src/third_party/wiredtiger/src/conn/conn_dhandle.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/third_party/wiredtiger/src/conn/conn_dhandle.c')
-rw-r--r--src/third_party/wiredtiger/src/conn/conn_dhandle.c107
1 files changed, 81 insertions, 26 deletions
diff --git a/src/third_party/wiredtiger/src/conn/conn_dhandle.c b/src/third_party/wiredtiger/src/conn/conn_dhandle.c
index 63180d64019..60e7c41f76d 100644
--- a/src/third_party/wiredtiger/src/conn/conn_dhandle.c
+++ b/src/third_party/wiredtiger/src/conn/conn_dhandle.c
@@ -74,16 +74,19 @@ __conn_dhandle_open_lock(
*
* Wait for a read lock if we want exclusive access and failed
* to get it: the sweep server may be closing this handle, and
- * we need to wait for it to complete. If we want exclusive
- * access and find the handle open once we get the read lock,
- * give up: some other thread has it locked for real.
+ * we need to wait for it to release its lock. If we want
+ * exclusive access and find the handle open once we get the
+ * read lock, give up: some other thread has it locked for real.
*/
if (F_ISSET(dhandle, WT_DHANDLE_OPEN) &&
(!want_exclusive || lock_busy)) {
WT_RET(__wt_readlock(session, dhandle->rwlock));
is_open = F_ISSET(dhandle, WT_DHANDLE_OPEN) ? 1 : 0;
- if (is_open && !want_exclusive)
+ if (is_open && !want_exclusive) {
+ WT_ASSERT(session,
+ !F_ISSET(dhandle, WT_DHANDLE_DEAD));
return (0);
+ }
WT_RET(__wt_readunlock(session, dhandle->rwlock));
} else
is_open = 0;
@@ -109,6 +112,7 @@ __conn_dhandle_open_lock(
/* We have an exclusive lock, we're done. */
F_SET(dhandle, WT_DHANDLE_EXCLUSIVE);
+ WT_ASSERT(session, !F_ISSET(dhandle, WT_DHANDLE_DEAD));
return (0);
} else if (ret != EBUSY || (is_open && want_exclusive))
return (ret);
@@ -132,22 +136,36 @@ __wt_conn_dhandle_find(WT_SESSION_IMPL *session,
WT_DATA_HANDLE *dhandle;
uint64_t bucket;
- WT_UNUSED(flags); /* Only used in diagnostic builds */
conn = S2C(session);
- /* We must be holding the handle list lock at a higher level. */
+ /*
+ * We must be holding the handle list lock at a higher level, and not
+ * have a reference.
+ */
WT_ASSERT(session, F_ISSET(session, WT_SESSION_HANDLE_LIST_LOCKED) &&
!LF_ISSET(WT_DHANDLE_HAVE_REF));
- /* Increment the reference count if we already have the btree open. */
bucket = __wt_hash_city64(name, strlen(name)) % WT_HASH_ARRAY_SIZE;
- SLIST_FOREACH(dhandle, &conn->dhhash[bucket], hashl)
- if (strcmp(name, dhandle->name) == 0 &&
- ((ckpt == NULL && dhandle->checkpoint == NULL) ||
- (ckpt != NULL && dhandle->checkpoint != NULL &&
- strcmp(ckpt, dhandle->checkpoint) == 0))) {
- session->dhandle = dhandle;
- return (0);
+ if (ckpt == NULL) {
+ SLIST_FOREACH(dhandle, &conn->dhhash[bucket], hashl) {
+ if (F_ISSET(dhandle, WT_DHANDLE_DEAD))
+ continue;
+ if (dhandle->checkpoint == NULL &&
+ strcmp(name, dhandle->name) == 0) {
+ session->dhandle = dhandle;
+ return (0);
+ }
+ }
+ } else
+ SLIST_FOREACH(dhandle, &conn->dhhash[bucket], hashl) {
+ if (F_ISSET(dhandle, WT_DHANDLE_DEAD))
+ continue;
+ if (dhandle->checkpoint != NULL &&
+ strcmp(name, dhandle->name) == 0 &&
+ strcmp(ckpt, dhandle->checkpoint) == 0) {
+ session->dhandle = dhandle;
+ return (0);
+ }
}
return (WT_NOTFOUND);
@@ -230,6 +248,30 @@ err: WT_TRET(__wt_rwlock_destroy(session, &dhandle->rwlock));
}
/*
+ * __conn_dhandle_mark_dead --
+ * Mark a data handle dead.
+ */
+static int
+__conn_dhandle_mark_dead(WT_SESSION_IMPL *session)
+{
+ int evict_reset;
+
+ WT_ASSERT(session, F_ISSET(session, WT_SESSION_HANDLE_LIST_LOCKED));
+
+ /*
+ * Handle forced discard (e.g., when dropping a file).
+ *
+ * We need exclusive access to the file -- disable ordinary
+ * eviction and drain any blocks already queued.
+ */
+ WT_RET(__wt_evict_file_exclusive_on(session, &evict_reset));
+ F_SET(session->dhandle, WT_DHANDLE_DEAD);
+ if (evict_reset)
+ __wt_evict_file_exclusive_off(session);
+ return (0);
+}
+
+/*
* __wt_conn_btree_sync_and_close --
* Sync and close the underlying btree handle.
*/
@@ -270,16 +312,25 @@ __wt_conn_btree_sync_and_close(WT_SESSION_IMPL *session, int final, int force)
/*
* The close can fail if an update cannot be written, return the EBUSY
* error to our caller for eventual retry.
+ *
+ * If we are forcing the close, just mark the handle dead and the tree
+ * will be discarded later. Don't do this for memory-mapped trees: we
+ * have to close the file handle to allow the file to be removed, but
+ * memory mapped trees contain pointers into memory that will become
+ * invalid if the mapping is closed.
*/
if (!F_ISSET(btree,
WT_BTREE_SALVAGE | WT_BTREE_UPGRADE | WT_BTREE_VERIFY))
- WT_ERR(__wt_checkpoint_close(session, final, force));
-
- if (dhandle->checkpoint == NULL)
- --S2C(session)->open_btree_count;
+ WT_ERR(force && (btree->bm == NULL || btree->bm->map == NULL) ?
+ __conn_dhandle_mark_dead(session) :
+ __wt_checkpoint_close(session, final));
WT_TRET(__wt_btree_close(session));
- F_CLR(dhandle, WT_DHANDLE_OPEN);
+ if (!force || final) {
+ F_CLR(dhandle, WT_DHANDLE_OPEN);
+ if (dhandle->checkpoint == NULL)
+ --S2C(session)->open_btree_count;
+ }
F_CLR(btree, WT_BTREE_SPECIAL_FLAGS);
err: __wt_spin_unlock(session, &dhandle->close_lock);
@@ -521,6 +572,7 @@ __wt_conn_btree_apply(WT_SESSION_IMPL *session,
__wt_hash_city64(uri, strlen(uri)) % WT_HASH_ARRAY_SIZE;
SLIST_FOREACH(dhandle, &conn->dhhash[bucket], hashl)
if (F_ISSET(dhandle, WT_DHANDLE_OPEN) &&
+ !F_ISSET(dhandle, WT_DHANDLE_DEAD) &&
strcmp(uri, dhandle->name) == 0 &&
(apply_checkpoints || dhandle->checkpoint == NULL))
WT_RET(__conn_btree_apply_internal(
@@ -528,6 +580,7 @@ __wt_conn_btree_apply(WT_SESSION_IMPL *session,
} else {
SLIST_FOREACH(dhandle, &conn->dhlh, l)
if (F_ISSET(dhandle, WT_DHANDLE_OPEN) &&
+ !F_ISSET(dhandle, WT_DHANDLE_DEAD) &&
(apply_checkpoints ||
dhandle->checkpoint == NULL) &&
WT_PREFIX_MATCH(dhandle->name, "file:") &&
@@ -649,8 +702,9 @@ __wt_conn_dhandle_close_all(
WT_ASSERT(session, session->dhandle == NULL);
bucket = __wt_hash_city64(name, strlen(name)) % WT_HASH_ARRAY_SIZE;
- SLIST_FOREACH(dhandle, &conn->dhhash[bucket], l) {
- if (strcmp(dhandle->name, name) != 0)
+ SLIST_FOREACH(dhandle, &conn->dhhash[bucket], hashl) {
+ if (strcmp(dhandle->name, name) != 0 ||
+ F_ISSET(dhandle, WT_DHANDLE_DEAD))
continue;
session->dhandle = dhandle;
@@ -722,7 +776,7 @@ __conn_dhandle_remove(WT_SESSION_IMPL *session, int final)
* Close/discard a single data handle.
*/
int
-__wt_conn_dhandle_discard_single(WT_SESSION_IMPL *session, int final)
+__wt_conn_dhandle_discard_single(WT_SESSION_IMPL *session, int final, int force)
{
WT_DATA_HANDLE *dhandle;
WT_DECL_RET;
@@ -730,8 +784,9 @@ __wt_conn_dhandle_discard_single(WT_SESSION_IMPL *session, int final)
dhandle = session->dhandle;
- if (F_ISSET(dhandle, WT_DHANDLE_OPEN)) {
- tret = __wt_conn_btree_sync_and_close(session, final, 0);
+ if (F_ISSET(dhandle, WT_DHANDLE_OPEN) ||
+ (final && F_ISSET(dhandle, WT_DHANDLE_DEAD))) {
+ tret = __wt_conn_btree_sync_and_close(session, final, force);
if (final && tret != 0) {
__wt_err(session, tret,
"Final close of %s failed", dhandle->name);
@@ -795,7 +850,7 @@ restart:
continue;
WT_WITH_DHANDLE(session, dhandle,
- WT_TRET(__wt_conn_dhandle_discard_single(session, 1)));
+ WT_TRET(__wt_conn_dhandle_discard_single(session, 1, 0)));
goto restart;
}
@@ -811,7 +866,7 @@ restart:
/* Close the metadata file handle. */
while ((dhandle = SLIST_FIRST(&conn->dhlh)) != NULL)
WT_WITH_DHANDLE(session, dhandle,
- WT_TRET(__wt_conn_dhandle_discard_single(session, 1)));
+ WT_TRET(__wt_conn_dhandle_discard_single(session, 1, 0)));
return (ret);
}