diff options
Diffstat (limited to 'src/third_party/wiredtiger/src/conn/conn_dhandle.c')
-rw-r--r-- | src/third_party/wiredtiger/src/conn/conn_dhandle.c | 107 |
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); } |