summaryrefslogtreecommitdiff
path: root/src/lsm
diff options
context:
space:
mode:
Diffstat (limited to 'src/lsm')
-rw-r--r--src/lsm/lsm_cursor.c116
-rw-r--r--src/lsm/lsm_manager.c66
-rw-r--r--src/lsm/lsm_merge.c4
-rw-r--r--src/lsm/lsm_meta.c2
-rw-r--r--src/lsm/lsm_stat.c12
-rw-r--r--src/lsm/lsm_tree.c73
-rw-r--r--src/lsm/lsm_work_unit.c62
-rw-r--r--src/lsm/lsm_worker.c25
8 files changed, 199 insertions, 161 deletions
diff --git a/src/lsm/lsm_cursor.c b/src/lsm/lsm_cursor.c
index 839648b97d7..52265f02e62 100644
--- a/src/lsm/lsm_cursor.c
+++ b/src/lsm/lsm_cursor.c
@@ -10,10 +10,10 @@
#define WT_FORALL_CURSORS(clsm, c, i) \
for ((i) = (clsm)->nchunks; (i) > 0;) \
- if (((c) = (clsm)->chunks[--i]->cursor) != NULL)
+ if (((c) = (clsm)->chunks[--(i)]->cursor) != NULL)
#define WT_LSM_CURCMP(s, lsm_tree, c1, c2, cmp) \
- __wt_compare(s, (lsm_tree)->collator, &(c1)->key, &(c2)->key, &cmp)
+ __wt_compare(s, (lsm_tree)->collator, &(c1)->key, &(c2)->key, &(cmp))
static int __clsm_lookup(WT_CURSOR_LSM *, WT_ITEM *);
static int __clsm_open_cursors(WT_CURSOR_LSM *, bool, u_int, uint32_t);
@@ -178,20 +178,12 @@ __clsm_enter(WT_CURSOR_LSM *clsm, bool reset, bool update)
if (reset) {
WT_ASSERT(session, !F_ISSET(&clsm->iface,
- WT_CURSTD_KEY_INT | WT_CURSTD_VALUE_INT));
+ WT_CURSTD_KEY_INT | WT_CURSTD_VALUE_INT));
WT_RET(__clsm_reset_cursors(clsm, NULL));
}
for (;;) {
- /*
- * If the cursor looks up-to-date, check if the cache is full.
- * In case this call blocks, the check will be repeated before
- * proceeding.
- */
- if (clsm->dsk_gen != lsm_tree->dsk_gen &&
- lsm_tree->nchunks != 0)
- goto open;
-
+ /* Check if the cursor looks up-to-date. */
if (clsm->dsk_gen != lsm_tree->dsk_gen &&
lsm_tree->nchunks != 0)
goto open;
@@ -304,7 +296,7 @@ __clsm_leave(WT_CURSOR_LSM *clsm)
* byte, if the application uses two leading DC4 byte for some reason, we'll do
* a wasted data copy each time a new value is inserted into the object.
*/
-static const WT_ITEM __tombstone = { "\x14\x14", 2, 0, NULL, 0 };
+static const WT_ITEM __tombstone = { "\x14\x14", 2, NULL, 0, 0 };
/*
* __clsm_deleted --
@@ -666,7 +658,7 @@ retry: if (F_ISSET(clsm, WT_CLSM_MERGE)) {
*/
if (i != nchunks - 1)
clsm->chunks[i]->cursor->insert =
- __wt_curfile_update_check;
+ __wt_curfile_insert_check;
if (!F_ISSET(clsm, WT_CLSM_MERGE) &&
F_ISSET(chunk, WT_LSM_CHUNK_BLOOM))
@@ -688,19 +680,29 @@ retry: if (F_ISSET(clsm, WT_CLSM_MERGE)) {
if (chunk != NULL &&
!F_ISSET(chunk, WT_LSM_CHUNK_ONDISK) &&
chunk->switch_txn == WT_TXN_NONE) {
- clsm->primary_chunk = chunk;
primary = clsm->chunks[clsm->nchunks - 1]->cursor;
+ btree = ((WT_CURSOR_BTREE *)primary)->btree;
+
/*
- * Disable eviction for the in-memory chunk. Also clear the
- * bulk load flag here, otherwise eviction will be enabled by
- * the first update.
+ * If the primary is not yet set as the primary, do that now.
+ * Note that eviction was configured off when the underlying
+ * object was created, which is what we want, leave it alone.
+ *
+ * We don't have to worry about races here: every thread that
+ * modifies the tree will have to come through here, at worse
+ * we set the flag repeatedly. We don't use a WT_BTREE handle
+ * flag, however, we could race doing the read-modify-write of
+ * the flags field.
+ *
+ * If something caused the chunk to be closed and reopened
+ * since it was created, we can no longer use it as a primary
+ * chunk and we need to force a switch. We detect the tree was
+ * created when it was opened by checking the "original" flag.
*/
- btree = ((WT_CURSOR_BTREE *)(primary))->btree;
- if (btree->bulk_load_ok) {
- btree->bulk_load_ok = false;
- WT_WITH_BTREE(session, btree,
- __wt_btree_lsm_switch_primary(session, true));
- }
+ if (!btree->lsm_primary && btree->original)
+ btree->lsm_primary = true;
+ if (btree->lsm_primary)
+ clsm->primary_chunk = chunk;
}
clsm->dsk_gen = lsm_tree->dsk_gen;
@@ -1213,7 +1215,8 @@ __clsm_lookup(WT_CURSOR_LSM *clsm, WT_ITEM *value)
WT_LSM_TREE_STAT_INCR(
session, clsm->lsm_tree->bloom_miss);
continue;
- } else if (ret == 0)
+ }
+ if (ret == 0)
WT_LSM_TREE_STAT_INCR(
session, clsm->lsm_tree->bloom_hit);
WT_ERR(ret);
@@ -1239,10 +1242,10 @@ __clsm_lookup(WT_CURSOR_LSM *clsm, WT_ITEM *value)
WT_ERR(WT_NOTFOUND);
done:
-err: F_CLR(cursor, WT_CURSTD_KEY_SET | WT_CURSTD_VALUE_SET);
- if (ret == 0) {
- clsm->current = c;
+err: if (ret == 0) {
+ F_CLR(cursor, WT_CURSTD_KEY_SET | WT_CURSTD_VALUE_SET);
F_SET(cursor, WT_CURSTD_KEY_INT);
+ clsm->current = c;
if (value == &cursor->value)
F_SET(cursor, WT_CURSTD_VALUE_INT);
} else if (c != NULL)
@@ -1318,7 +1321,8 @@ __clsm_search_near(WT_CURSOR *cursor, int *exactp)
if ((ret = c->search_near(c, &cmp)) == WT_NOTFOUND) {
ret = 0;
continue;
- } else if (ret != 0)
+ }
+ if (ret != 0)
goto err;
/* Do we have an exact match? */
@@ -1338,7 +1342,8 @@ __clsm_search_near(WT_CURSOR *cursor, int *exactp)
if ((ret = c->next(c)) == WT_NOTFOUND) {
ret = 0;
continue;
- } else if (ret != 0)
+ }
+ if (ret != 0)
goto err;
}
@@ -1564,12 +1569,23 @@ __clsm_update(WT_CURSOR *cursor)
WT_CURSOR_NEEDVALUE(cursor);
WT_ERR(__clsm_enter(clsm, false, true));
- if (F_ISSET(cursor, WT_CURSTD_OVERWRITE) ||
- (ret = __clsm_lookup(clsm, &value)) == 0) {
- WT_ERR(__clsm_deleted_encode(
- session, &cursor->value, &value, &buf));
- ret = __clsm_put(session, clsm, &cursor->key, &value, true);
- }
+ if (!F_ISSET(cursor, WT_CURSTD_OVERWRITE))
+ WT_ERR(__clsm_lookup(clsm, &value));
+ WT_ERR(__clsm_deleted_encode(session, &cursor->value, &value, &buf));
+ WT_ERR(__clsm_put(session, clsm, &cursor->key, &value, true));
+
+ /*
+ * Set the cursor to reference the internal key/value of the positioned
+ * cursor.
+ */
+ F_CLR(cursor, WT_CURSTD_KEY_SET | WT_CURSTD_VALUE_SET);
+ WT_ITEM_SET(cursor->key, clsm->current->key);
+ WT_ITEM_SET(cursor->value, clsm->current->value);
+ WT_ASSERT(session,
+ F_MASK(clsm->current, WT_CURSTD_KEY_SET) == WT_CURSTD_KEY_INT);
+ WT_ASSERT(session,
+ F_MASK(clsm->current, WT_CURSTD_VALUE_SET) == WT_CURSTD_VALUE_INT);
+ F_SET(cursor, WT_CURSTD_KEY_INT | WT_CURSTD_VALUE_INT);
err: __wt_scr_free(session, &buf);
__clsm_leave(clsm);
@@ -1588,18 +1604,34 @@ __clsm_remove(WT_CURSOR *cursor)
WT_DECL_RET;
WT_ITEM value;
WT_SESSION_IMPL *session;
+ bool positioned;
clsm = (WT_CURSOR_LSM *)cursor;
+ /* Check if the cursor is positioned. */
+ positioned = F_ISSET(cursor, WT_CURSTD_KEY_INT);
+
CURSOR_REMOVE_API_CALL(cursor, session, NULL);
WT_CURSOR_NEEDKEY(cursor);
WT_CURSOR_NOVALUE(cursor);
WT_ERR(__clsm_enter(clsm, false, true));
- if (F_ISSET(cursor, WT_CURSTD_OVERWRITE) ||
- (ret = __clsm_lookup(clsm, &value)) == 0)
- ret = __clsm_put(
- session, clsm, &cursor->key, &__tombstone, true);
+ if (!F_ISSET(cursor, WT_CURSTD_OVERWRITE))
+ WT_ERR(__clsm_lookup(clsm, &value));
+ WT_ERR(__clsm_put(
+ session, clsm, &cursor->key, &__tombstone, positioned));
+
+ /*
+ * If the cursor was positioned, it stays positioned with a key but no
+ * no value, otherwise, there's no position, key or value. This isn't
+ * just cosmetic, without a reset, iteration on this cursor won't start
+ * at the beginning/end of the table.
+ */
+ F_CLR(cursor, WT_CURSTD_KEY_SET | WT_CURSTD_VALUE_SET);
+ if (positioned)
+ F_SET(cursor, WT_CURSTD_KEY_INT);
+ else
+ WT_TRET(cursor->reset(cursor));
err: __clsm_leave(clsm);
CURSOR_UPDATE_API_END(session, ret);
@@ -1692,8 +1724,8 @@ __wt_clsm_open(WT_SESSION_IMPL *session,
bulk = cval.val != 0;
/* Get the LSM tree. */
- WT_WITH_HANDLE_LIST_LOCK(session,
- ret = __wt_lsm_tree_get(session, uri, bulk, &lsm_tree));
+ ret = __wt_lsm_tree_get(session, uri, bulk, &lsm_tree);
+
/*
* Check whether the exclusive open for a bulk load succeeded, and
* if it did ensure that it's safe to bulk load into the tree.
diff --git a/src/lsm/lsm_manager.c b/src/lsm/lsm_manager.c
index cbd83a5cd30..e33e119aa41 100644
--- a/src/lsm/lsm_manager.c
+++ b/src/lsm/lsm_manager.c
@@ -89,7 +89,6 @@ __lsm_general_worker_start(WT_SESSION_IMPL *session)
if (manager->lsm_workers % 2 == 0)
FLD_SET(worker_args->type, WT_LSM_WORK_MERGE);
}
- F_SET(worker_args, WT_LSM_WORKER_RUN);
WT_RET(__wt_lsm_worker_start(session, worker_args));
}
@@ -129,17 +128,13 @@ __lsm_stop_workers(WT_SESSION_IMPL *session)
manager->lsm_workers--) {
worker_args =
&manager->lsm_worker_cookies[manager->lsm_workers - 1];
- /*
- * Clear this worker's flag so it stops.
- */
- F_CLR(worker_args, WT_LSM_WORKER_RUN);
- WT_ASSERT(session, worker_args->tid != 0);
- WT_RET(__wt_thread_join(session, worker_args->tid));
- worker_args->tid = 0;
+ WT_ASSERT(session, worker_args->tid_set);
+
+ WT_RET(__wt_lsm_worker_stop(session, worker_args));
worker_args->type = 0;
- worker_args->flags = 0;
+
/*
- * We do not clear the session because they are allocated
+ * We do not clear the other fields because they are allocated
* statically when the connection was opened.
*/
}
@@ -237,12 +232,12 @@ __wt_lsm_manager_start(WT_SESSION_IMPL *session)
manager->lsm_worker_cookies[i].session = worker_session;
}
+ F_SET(conn, WT_CONN_SERVER_LSM);
+
/* Start the LSM manager thread. */
WT_ERR(__wt_thread_create(session, &manager->lsm_worker_cookies[0].tid,
__lsm_worker_manager, &manager->lsm_worker_cookies[0]));
- F_SET(conn, WT_CONN_SERVER_LSM);
-
if (0) {
err: for (i = 0;
(worker_session =
@@ -289,13 +284,18 @@ __wt_lsm_manager_destroy(WT_SESSION_IMPL *session)
manager = &conn->lsm_manager;
removed = 0;
+ /*
+ * Clear the LSM server flag and flush to ensure running threads see
+ * the state change.
+ */
+ F_CLR(conn, WT_CONN_SERVER_LSM);
+ WT_FULL_BARRIER();
+
WT_ASSERT(session, !F_ISSET(conn, WT_CONN_READONLY) ||
manager->lsm_workers == 0);
if (manager->lsm_workers > 0) {
- /*
- * Stop the main LSM manager thread first.
- */
- while (F_ISSET(conn, WT_CONN_SERVER_LSM))
+ /* Wait for the main LSM manager thread to finish. */
+ while (!F_ISSET(manager, WT_LSM_MANAGER_SHUTDOWN))
__wt_yield();
/* Clean up open LSM handles. */
@@ -303,7 +303,6 @@ __wt_lsm_manager_destroy(WT_SESSION_IMPL *session)
WT_TRET(__wt_thread_join(
session, manager->lsm_worker_cookies[0].tid));
- manager->lsm_worker_cookies[0].tid = 0;
/* Release memory from any operations left on the queue. */
while ((current = TAILQ_FIRST(&manager->switchqh)) != NULL) {
@@ -342,7 +341,7 @@ __wt_lsm_manager_destroy(WT_SESSION_IMPL *session)
/*
* __lsm_manager_worker_shutdown --
- * Shutdown the LSM manager and worker threads.
+ * Shutdown the LSM worker threads.
*/
static int
__lsm_manager_worker_shutdown(WT_SESSION_IMPL *session)
@@ -354,14 +353,13 @@ __lsm_manager_worker_shutdown(WT_SESSION_IMPL *session)
manager = &S2C(session)->lsm_manager;
/*
- * Wait for the rest of the LSM workers to shutdown. Stop at index
+ * Wait for the rest of the LSM workers to shutdown. Start at index
* one - since we (the manager) are at index 0.
*/
for (i = 1; i < manager->lsm_workers; i++) {
- WT_ASSERT(session, manager->lsm_worker_cookies[i].tid != 0);
- __wt_cond_signal(session, manager->work_cond);
- WT_TRET(__wt_thread_join(
- session, manager->lsm_worker_cookies[i].tid));
+ WT_ASSERT(session, manager->lsm_worker_cookies[i].tid_set);
+ WT_TRET(__wt_lsm_worker_stop(
+ session, &manager->lsm_worker_cookies[i]));
}
return (ret);
}
@@ -383,12 +381,12 @@ __lsm_manager_run_server(WT_SESSION_IMPL *session)
conn = S2C(session);
dhandle_locked = false;
- while (F_ISSET(conn, WT_CONN_SERVER_RUN)) {
+ while (F_ISSET(conn, WT_CONN_SERVER_LSM)) {
__wt_sleep(0, 10000);
if (TAILQ_EMPTY(&conn->lsmqh))
continue;
- __wt_spin_lock(session, &conn->dhandle_lock);
- F_SET(session, WT_SESSION_LOCKED_HANDLE_LIST);
+ __wt_readlock(session, &conn->dhandle_lock);
+ F_SET(session, WT_SESSION_LOCKED_HANDLE_LIST_READ);
dhandle_locked = true;
TAILQ_FOREACH(lsm_tree, &S2C(session)->lsmqh, q) {
if (!lsm_tree->active)
@@ -448,14 +446,14 @@ __lsm_manager_run_server(WT_SESSION_IMPL *session)
session, WT_LSM_WORK_MERGE, 0, lsm_tree));
}
}
- __wt_spin_unlock(session, &conn->dhandle_lock);
- F_CLR(session, WT_SESSION_LOCKED_HANDLE_LIST);
+ __wt_readunlock(session, &conn->dhandle_lock);
+ F_CLR(session, WT_SESSION_LOCKED_HANDLE_LIST_READ);
dhandle_locked = false;
}
err: if (dhandle_locked) {
- __wt_spin_unlock(session, &conn->dhandle_lock);
- F_CLR(session, WT_SESSION_LOCKED_HANDLE_LIST);
+ __wt_readunlock(session, &conn->dhandle_lock);
+ F_CLR(session, WT_SESSION_LOCKED_HANDLE_LIST_READ);
}
return (ret);
}
@@ -469,11 +467,13 @@ static WT_THREAD_RET
__lsm_worker_manager(void *arg)
{
WT_DECL_RET;
+ WT_LSM_MANAGER *manager;
WT_LSM_WORKER_ARGS *cookie;
WT_SESSION_IMPL *session;
cookie = (WT_LSM_WORKER_ARGS *)arg;
session = cookie->session;
+ manager = &S2C(session)->lsm_manager;
WT_ERR(__lsm_general_worker_start(session));
WT_ERR(__lsm_manager_run_server(session));
@@ -482,7 +482,11 @@ __lsm_worker_manager(void *arg)
if (ret != 0) {
err: WT_PANIC_MSG(session, ret, "LSM worker manager thread error");
}
- F_CLR(S2C(session), WT_CONN_SERVER_LSM);
+
+ /* Connection close waits on us to shutdown, let it know we're done. */
+ F_SET(manager, WT_LSM_MANAGER_SHUTDOWN);
+ WT_FULL_BARRIER();
+
return (WT_THREAD_RET_VALUE);
}
diff --git a/src/lsm/lsm_merge.c b/src/lsm/lsm_merge.c
index ceb5f03a2f5..8838638f388 100644
--- a/src/lsm/lsm_merge.c
+++ b/src/lsm/lsm_merge.c
@@ -187,7 +187,7 @@ __lsm_merge_span(WT_SESSION_IMPL *session, WT_LSM_TREE *lsm_tree,
continue;
if (F_ISSET(chunk, WT_LSM_CHUNK_BLOOM) || chunk->generation > 0)
break;
- else if (FLD_ISSET(lsm_tree->bloom, WT_LSM_BLOOM_OFF) &&
+ if (FLD_ISSET(lsm_tree->bloom, WT_LSM_BLOOM_OFF) &&
F_ISSET(chunk, WT_LSM_CHUNK_ONDISK))
break;
}
@@ -625,7 +625,7 @@ err: if (locked)
else
__wt_verbose(session, WT_VERB_LSM,
"Merge failed with %s",
- __wt_strerror(session, ret, NULL, 0));
+ __wt_strerror(session, ret, NULL, 0));
}
F_CLR(session, WT_SESSION_NO_CACHE | WT_SESSION_NO_EVICTION);
return (ret);
diff --git a/src/lsm/lsm_meta.c b/src/lsm/lsm_meta.c
index 46ead6d6ac4..fc4dde82470 100644
--- a/src/lsm/lsm_meta.c
+++ b/src/lsm/lsm_meta.c
@@ -229,7 +229,7 @@ __lsm_meta_read_v1(
cv.len -= 2;
}
WT_ERR(__wt_config_check(session,
- WT_CONFIG_REF(session, WT_SESSION_create), cv.str, cv.len));
+ WT_CONFIG_REF(session, WT_SESSION_create), cv.str, cv.len));
WT_ERR(__wt_strndup(session, cv.str, cv.len, &lsm_tree->bloom_config));
WT_ERR(__wt_config_getones(
session, lsmconf, "lsm.bloom_hash_count", &cv));
diff --git a/src/lsm/lsm_stat.c b/src/lsm/lsm_stat.c
index 150de968722..411655878af 100644
--- a/src/lsm/lsm_stat.c
+++ b/src/lsm/lsm_stat.c
@@ -29,24 +29,22 @@ __curstat_lsm_init(
const char *cfg[] = {
WT_CONFIG_BASE(session, WT_SESSION_open_cursor), NULL, NULL };
const char *disk_cfg[] = {
- WT_CONFIG_BASE(session, WT_SESSION_open_cursor),
- "checkpoint=" WT_CHECKPOINT, NULL, NULL };
+ WT_CONFIG_BASE(session, WT_SESSION_open_cursor),
+ "checkpoint=" WT_CHECKPOINT, NULL, NULL };
locked = false;
- WT_WITH_HANDLE_LIST_LOCK(session,
- ret = __wt_lsm_tree_get(session, uri, false, &lsm_tree));
- WT_RET(ret);
+ WT_RET(__wt_lsm_tree_get(session, uri, false, &lsm_tree));
WT_ERR(__wt_scr_alloc(session, 0, &uribuf));
/* Propagate all, fast and/or clear to the cursors we open. */
if (cst->flags != 0) {
- (void)snprintf(config, sizeof(config),
+ WT_ERR(__wt_snprintf(config, sizeof(config),
"statistics=(%s%s%s%s)",
F_ISSET(cst, WT_STAT_TYPE_ALL) ? "all," : "",
F_ISSET(cst, WT_STAT_CLEAR) ? "clear," : "",
!F_ISSET(cst, WT_STAT_TYPE_ALL) &&
F_ISSET(cst, WT_STAT_TYPE_FAST) ? "fast," : "",
- F_ISSET(cst, WT_STAT_TYPE_SIZE) ? "size," : "");
+ F_ISSET(cst, WT_STAT_TYPE_SIZE) ? "size," : ""));
cfg[1] = disk_cfg[1] = config;
}
diff --git a/src/lsm/lsm_tree.c b/src/lsm/lsm_tree.c
index 38d87dd852b..a9275976023 100644
--- a/src/lsm/lsm_tree.c
+++ b/src/lsm/lsm_tree.c
@@ -38,7 +38,7 @@ __lsm_tree_discard(WT_SESSION_IMPL *session, WT_LSM_TREE *lsm_tree, bool final)
/* We may be destroying an lsm_tree before it was added. */
if (F_ISSET(lsm_tree, WT_LSM_TREE_OPEN)) {
WT_ASSERT(session, final ||
- F_ISSET(session, WT_SESSION_LOCKED_HANDLE_LIST));
+ F_ISSET(session, WT_SESSION_LOCKED_HANDLE_LIST_WRITE));
TAILQ_REMOVE(&S2C(session)->lsmqh, lsm_tree, q);
}
@@ -321,9 +321,7 @@ __wt_lsm_tree_create(WT_SESSION_IMPL *session,
metadata = NULL;
/* If the tree can be opened, it already exists. */
- WT_WITH_HANDLE_LIST_LOCK(session,
- ret = __wt_lsm_tree_get(session, uri, false, &lsm_tree));
- if (ret == 0) {
+ if ((ret = __wt_lsm_tree_get(session, uri, false, &lsm_tree)) == 0) {
__wt_lsm_tree_release(session, lsm_tree);
return (exclusive ? EEXIST : 0);
}
@@ -339,7 +337,7 @@ __wt_lsm_tree_create(WT_SESSION_IMPL *session,
* error: the returned handle is NULL on error, and the metadata
* tracking macros handle cleaning up on failure.
*/
- WT_WITH_HANDLE_LIST_LOCK(session,
+ WT_WITH_HANDLE_LIST_WRITE_LOCK(session,
ret = __lsm_tree_open(session, uri, true, &lsm_tree));
if (ret == 0)
__wt_lsm_tree_release(session, lsm_tree);
@@ -404,6 +402,9 @@ __lsm_tree_find(WT_SESSION_IMPL *session,
}
*treep = lsm_tree;
+
+ WT_ASSERT(session, lsm_tree->excl_session ==
+ (exclusive ? session : NULL));
return (0);
}
@@ -456,7 +457,8 @@ __lsm_tree_open(WT_SESSION_IMPL *session,
conn = S2C(session);
lsm_tree = NULL;
- WT_ASSERT(session, F_ISSET(session, WT_SESSION_LOCKED_HANDLE_LIST));
+ WT_ASSERT(session,
+ F_ISSET(session, WT_SESSION_LOCKED_HANDLE_LIST_WRITE));
/* Start the LSM manager thread if it isn't running. */
if (__wt_atomic_cas32(&conn->lsm_manager.lsm_workers, 0, 1))
@@ -469,7 +471,7 @@ __lsm_tree_open(WT_SESSION_IMPL *session,
/* Try to open the tree. */
WT_RET(__wt_calloc_one(session, &lsm_tree));
- WT_ERR(__wt_rwlock_alloc(session, &lsm_tree->rwlock, "lsm tree"));
+ __wt_rwlock_init(session, &lsm_tree->rwlock);
WT_ERR(__lsm_tree_set_name(session, lsm_tree, uri));
@@ -520,14 +522,21 @@ __wt_lsm_tree_get(WT_SESSION_IMPL *session,
{
WT_DECL_RET;
- WT_ASSERT(session, F_ISSET(session, WT_SESSION_LOCKED_HANDLE_LIST));
-
- ret = __lsm_tree_find(session, uri, exclusive, treep);
+ /*
+ * Dropping and re-acquiring the lock is safe here, since the tree open
+ * call checks to see if another thread beat it to opening the tree
+ * before proceeding.
+ */
+ if (exclusive)
+ WT_WITH_HANDLE_LIST_WRITE_LOCK(session,
+ ret = __lsm_tree_find(session, uri, exclusive, treep));
+ else
+ WT_WITH_HANDLE_LIST_READ_LOCK(session,
+ ret = __lsm_tree_find(session, uri, exclusive, treep));
if (ret == WT_NOTFOUND)
- ret = __lsm_tree_open(session, uri, exclusive, treep);
+ WT_WITH_HANDLE_LIST_WRITE_LOCK(session,
+ ret = __lsm_tree_open(session, uri, exclusive, treep));
- WT_ASSERT(session, ret != 0 ||
- (*treep)->excl_session == (exclusive ? session : NULL));
return (ret);
}
@@ -857,9 +866,7 @@ __wt_lsm_tree_alter(
locked = false;
/* Get the LSM tree. */
- WT_WITH_HANDLE_LIST_LOCK(session,
- ret = __wt_lsm_tree_get(session, uri, false, &lsm_tree));
- WT_RET(ret);
+ WT_RET(__wt_lsm_tree_get(session, uri, false, &lsm_tree));
/* Prevent any new opens. */
__wt_lsm_tree_writelock(session, lsm_tree);
@@ -899,9 +906,7 @@ __wt_lsm_tree_drop(
locked = false;
/* Get the LSM tree. */
- WT_WITH_HANDLE_LIST_LOCK(session,
- ret = __wt_lsm_tree_get(session, name, true, &lsm_tree));
- WT_RET(ret);
+ WT_RET(__wt_lsm_tree_get(session, name, true, &lsm_tree));
WT_ASSERT(session, !lsm_tree->active);
/* Prevent any new opens. */
@@ -934,7 +939,7 @@ __wt_lsm_tree_drop(
WT_ASSERT(session, !lsm_tree->active);
err: if (locked)
__wt_lsm_tree_writeunlock(session, lsm_tree);
- WT_WITH_HANDLE_LIST_LOCK(session,
+ WT_WITH_HANDLE_LIST_WRITE_LOCK(session,
tret = __lsm_tree_discard(session, lsm_tree, false));
WT_TRET(tret);
return (ret);
@@ -960,9 +965,7 @@ __wt_lsm_tree_rename(WT_SESSION_IMPL *session,
locked = false;
/* Get the LSM tree. */
- WT_WITH_HANDLE_LIST_LOCK(session,
- ret = __wt_lsm_tree_get(session, olduri, true, &lsm_tree));
- WT_RET(ret);
+ WT_RET(__wt_lsm_tree_get(session, olduri, true, &lsm_tree));
/* Prevent any new opens. */
__wt_lsm_tree_writelock(session, lsm_tree);
@@ -1007,7 +1010,7 @@ err: if (locked)
* Discard this LSM tree structure. The first operation on the renamed
* tree will create a new one.
*/
- WT_WITH_HANDLE_LIST_LOCK(session,
+ WT_WITH_HANDLE_LIST_WRITE_LOCK(session,
tret = __lsm_tree_discard(session, lsm_tree, false));
WT_TRET(tret);
return (ret);
@@ -1032,9 +1035,7 @@ __wt_lsm_tree_truncate(
locked = false;
/* Get the LSM tree. */
- WT_WITH_HANDLE_LIST_LOCK(session,
- ret = __wt_lsm_tree_get(session, name, true, &lsm_tree));
- WT_RET(ret);
+ WT_RET(__wt_lsm_tree_get(session, name, true, &lsm_tree));
/* Prevent any new opens. */
__wt_lsm_tree_writelock(session, lsm_tree);
@@ -1068,7 +1069,7 @@ err: if (locked)
* the last good version of the metadata will be used, resulting
* in a valid (not truncated) tree.
*/
- WT_WITH_HANDLE_LIST_LOCK(session,
+ WT_WITH_HANDLE_LIST_WRITE_LOCK(session,
tret = __lsm_tree_discard(session, lsm_tree, false));
WT_TRET(tret);
}
@@ -1082,7 +1083,7 @@ err: if (locked)
void
__wt_lsm_tree_readlock(WT_SESSION_IMPL *session, WT_LSM_TREE *lsm_tree)
{
- __wt_readlock(session, lsm_tree->rwlock);
+ __wt_readlock(session, &lsm_tree->rwlock);
/*
* Diagnostic: avoid deadlocks with the schema lock: if we need it for
@@ -1100,7 +1101,7 @@ __wt_lsm_tree_readunlock(WT_SESSION_IMPL *session, WT_LSM_TREE *lsm_tree)
{
F_CLR(session, WT_SESSION_NO_EVICTION | WT_SESSION_NO_SCHEMA_LOCK);
- __wt_readunlock(session, lsm_tree->rwlock);
+ __wt_readunlock(session, &lsm_tree->rwlock);
}
/*
@@ -1110,7 +1111,7 @@ __wt_lsm_tree_readunlock(WT_SESSION_IMPL *session, WT_LSM_TREE *lsm_tree)
void
__wt_lsm_tree_writelock(WT_SESSION_IMPL *session, WT_LSM_TREE *lsm_tree)
{
- __wt_writelock(session, lsm_tree->rwlock);
+ __wt_writelock(session, &lsm_tree->rwlock);
/*
* Diagnostic: avoid deadlocks with the schema lock: if we need it for
@@ -1128,7 +1129,7 @@ __wt_lsm_tree_writeunlock(WT_SESSION_IMPL *session, WT_LSM_TREE *lsm_tree)
{
F_CLR(session, WT_SESSION_NO_EVICTION | WT_SESSION_NO_SCHEMA_LOCK);
- __wt_writeunlock(session, lsm_tree->rwlock);
+ __wt_writeunlock(session, &lsm_tree->rwlock);
}
/*
@@ -1157,9 +1158,7 @@ __wt_lsm_compact(WT_SESSION_IMPL *session, const char *name, bool *skipp)
/* Tell __wt_schema_worker not to look inside the LSM tree. */
*skipp = true;
- WT_WITH_HANDLE_LIST_LOCK(session,
- ret = __wt_lsm_tree_get(session, name, false, &lsm_tree));
- WT_RET(ret);
+ WT_RET(__wt_lsm_tree_get(session, name, false, &lsm_tree));
if (!F_ISSET(S2C(session), WT_CONN_LSM_MERGE))
WT_ERR_MSG(session, EINVAL,
@@ -1356,9 +1355,7 @@ __wt_lsm_tree_worker(WT_SESSION_IMPL *session,
locked = false;
exclusive = FLD_ISSET(open_flags, WT_DHANDLE_EXCLUSIVE);
- WT_WITH_HANDLE_LIST_LOCK(session,
- ret = __wt_lsm_tree_get(session, uri, exclusive, &lsm_tree));
- WT_RET(ret);
+ WT_RET(__wt_lsm_tree_get(session, uri, exclusive, &lsm_tree));
/*
* We mark that we're busy using the tree to coordinate
diff --git a/src/lsm/lsm_work_unit.c b/src/lsm/lsm_work_unit.c
index d9c185a3f58..e6a29666094 100644
--- a/src/lsm/lsm_work_unit.c
+++ b/src/lsm/lsm_work_unit.c
@@ -230,7 +230,7 @@ __wt_lsm_work_bloom(WT_SESSION_IMPL *session, WT_LSM_TREE *lsm_tree)
if (__wt_atomic_cas32(&chunk->bloom_busy, 0, 1)) {
if (!F_ISSET(chunk, WT_LSM_CHUNK_BLOOM)) {
ret = __lsm_bloom_create(
- session, lsm_tree, chunk, (u_int)i);
+ session, lsm_tree, chunk, i);
/*
* Record if we were successful so that we can
* later push a merge work unit.
@@ -265,9 +265,9 @@ __wt_lsm_checkpoint_chunk(WT_SESSION_IMPL *session,
{
WT_DECL_RET;
WT_TXN_ISOLATION saved_isolation;
- bool flush_set;
+ bool flush_set, release_btree;
- flush_set = false;
+ flush_set = release_btree = false;
/*
* If the chunk is already checkpointed, make sure it is also evicted.
@@ -276,7 +276,7 @@ __wt_lsm_checkpoint_chunk(WT_SESSION_IMPL *session,
if (F_ISSET(chunk, WT_LSM_CHUNK_ONDISK) &&
!F_ISSET(chunk, WT_LSM_CHUNK_STABLE) &&
!chunk->evicted) {
- WT_WITH_HANDLE_LIST_LOCK(session,
+ WT_WITH_HANDLE_LIST_WRITE_LOCK(session,
ret = __lsm_discard_handle(session, chunk->uri, NULL));
if (ret == 0)
chunk->evicted = 1;
@@ -318,20 +318,18 @@ __wt_lsm_checkpoint_chunk(WT_SESSION_IMPL *session,
* We can wait here for checkpoints and fsyncs to complete, which can
* take a long time.
*/
- if ((ret = __wt_session_get_btree(
- session, chunk->uri, NULL, NULL, 0)) == 0) {
- /*
- * Set read-uncommitted: we have already checked that all of the
- * updates in this chunk are globally visible, use the cheapest
- * possible check in reconciliation.
- */
- saved_isolation = session->txn.isolation;
- session->txn.isolation = WT_ISO_READ_UNCOMMITTED;
- ret = __wt_cache_op(session, WT_SYNC_WRITE_LEAVES);
- session->txn.isolation = saved_isolation;
- WT_TRET(__wt_session_release_btree(session));
- }
- WT_ERR(ret);
+ WT_ERR(__wt_session_get_btree(session, chunk->uri, NULL, NULL, 0));
+ release_btree = true;
+
+ /*
+ * Set read-uncommitted: we have already checked that all of the updates
+ * in this chunk are globally visible, use the cheapest possible check
+ * in reconciliation.
+ */
+ saved_isolation = session->txn.isolation;
+ session->txn.isolation = WT_ISO_READ_UNCOMMITTED;
+ WT_ERR(__wt_cache_op(session, WT_SYNC_WRITE_LEAVES));
+ session->txn.isolation = saved_isolation;
__wt_verbose(session, WT_VERB_LSM, "LSM worker checkpointing %s",
chunk->uri);
@@ -348,12 +346,14 @@ __wt_lsm_checkpoint_chunk(WT_SESSION_IMPL *session,
WT_ERR(__wt_meta_track_on(session));
WT_WITH_CHECKPOINT_LOCK(session,
WT_WITH_SCHEMA_LOCK(session,
- ret = __wt_schema_worker(
- session, chunk->uri, __wt_checkpoint, NULL, NULL, 0)));
+ ret = __wt_checkpoint(session, NULL)));
WT_TRET(__wt_meta_track_off(session, false, ret != 0));
if (ret != 0)
WT_ERR_MSG(session, ret, "LSM checkpoint");
+ release_btree = false;
+ WT_ERR(__wt_session_release_btree(session));
+
/* Now the file is written, get the chunk size. */
WT_ERR(__wt_lsm_tree_set_chunk_size(session, chunk));
@@ -376,16 +376,6 @@ __wt_lsm_checkpoint_chunk(WT_SESSION_IMPL *session,
WT_PUBLISH(chunk->flushing, 0);
flush_set = false;
- /*
- * Clear the no-eviction flag so the primary can be evicted and
- * eventually closed. Only do this once the checkpoint has succeeded:
- * otherwise, accessing the leaf page during the checkpoint can trigger
- * forced eviction.
- */
- WT_ERR(__wt_session_get_btree(session, chunk->uri, NULL, NULL, 0));
- __wt_btree_lsm_switch_primary(session, false);
- WT_ERR(__wt_session_release_btree(session));
-
/* Make sure we aren't pinning a transaction ID. */
__wt_txn_release_snapshot(session);
@@ -402,6 +392,8 @@ __wt_lsm_checkpoint_chunk(WT_SESSION_IMPL *session,
err: if (flush_set)
WT_PUBLISH(chunk->flushing, 0);
+ if (release_btree)
+ WT_TRET(__wt_session_release_btree(session));
return (ret);
}
@@ -517,8 +509,8 @@ __lsm_drop_file(WT_SESSION_IMPL *session, const char *uri)
*
* This will fail with EBUSY if the file is still in use.
*/
- WT_WITH_HANDLE_LIST_LOCK(session,
- ret = __lsm_discard_handle(session, uri, WT_CHECKPOINT));
+ WT_WITH_HANDLE_LIST_WRITE_LOCK(session,
+ ret = __lsm_discard_handle(session, uri, WT_CHECKPOINT));
WT_RET(ret);
/*
@@ -610,7 +602,8 @@ __wt_lsm_free_chunks(WT_SESSION_IMPL *session, WT_LSM_TREE *lsm_tree)
if (drop_ret == EBUSY) {
++skipped;
continue;
- } else if (drop_ret != ENOENT)
+ }
+ if (drop_ret != ENOENT)
WT_ERR(drop_ret);
flush_metadata = true;
@@ -621,7 +614,8 @@ __wt_lsm_free_chunks(WT_SESSION_IMPL *session, WT_LSM_TREE *lsm_tree)
if (drop_ret == EBUSY) {
++skipped;
continue;
- } else if (drop_ret != ENOENT)
+ }
+ if (drop_ret != ENOENT)
WT_ERR(drop_ret);
flush_metadata = true;
}
diff --git a/src/lsm/lsm_worker.c b/src/lsm/lsm_worker.c
index b0d0758775d..1cabbd4888d 100644
--- a/src/lsm/lsm_worker.c
+++ b/src/lsm/lsm_worker.c
@@ -21,7 +21,23 @@ __wt_lsm_worker_start(WT_SESSION_IMPL *session, WT_LSM_WORKER_ARGS *args)
{
__wt_verbose(session, WT_VERB_LSM_MANAGER,
"Start LSM worker %u type %#" PRIx32, args->id, args->type);
- return (__wt_thread_create(session, &args->tid, __lsm_worker, args));
+
+ args->running = true;
+ WT_RET(__wt_thread_create(session, &args->tid, __lsm_worker, args));
+ args->tid_set = true;
+ return (0);
+}
+
+/*
+ * __wt_lsm_worker_stop --
+ * A wrapper around the LSM worker thread stop.
+ */
+int
+__wt_lsm_worker_stop(WT_SESSION_IMPL *session, WT_LSM_WORKER_ARGS *args)
+{
+ args->running = false;
+ args->tid_set = false;
+ return (__wt_thread_join(session, args->tid));
}
/*
@@ -84,7 +100,6 @@ err: __wt_lsm_manager_free_work_unit(session, entry);
static WT_THREAD_RET
__lsm_worker(void *arg)
{
- WT_CONNECTION_IMPL *conn;
WT_DECL_RET;
WT_LSM_WORK_UNIT *entry;
WT_LSM_WORKER_ARGS *cookie;
@@ -93,11 +108,9 @@ __lsm_worker(void *arg)
cookie = (WT_LSM_WORKER_ARGS *)arg;
session = cookie->session;
- conn = S2C(session);
entry = NULL;
- while (F_ISSET(conn, WT_CONN_SERVER_RUN) &&
- F_ISSET(cookie, WT_LSM_WORKER_RUN)) {
+ while (cookie->running) {
progress = false;
/*
@@ -154,7 +167,7 @@ __lsm_worker(void *arg)
/* Don't busy wait if there was any work to do. */
if (!progress) {
- __wt_cond_wait(session, cookie->work_cond, 10000);
+ __wt_cond_wait(session, cookie->work_cond, 10000, NULL);
continue;
}
}