summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/btree/bt_compact.c7
-rw-r--r--src/btree/bt_cursor.c124
-rw-r--r--src/btree/bt_page.c17
-rw-r--r--src/btree/bt_sync.c7
-rw-r--r--src/conn/conn_dhandle.c21
-rw-r--r--src/conn/conn_stat.c8
-rw-r--r--src/evict/evict_file.c11
-rw-r--r--src/evict/evict_lru.c40
-rw-r--r--src/include/dhandle.h13
-rw-r--r--src/include/extern.h2
-rw-r--r--src/log/log.c16
-rw-r--r--src/log/log_slot.c3
-rw-r--r--src/meta/meta_apply.c3
-rw-r--r--src/schema/schema_truncate.c10
-rw-r--r--src/schema/schema_worker.c3
-rw-r--r--src/session/session_api.c40
-rw-r--r--src/txn/txn_ckpt.c5
-rw-r--r--src/utilities/util_main.c32
18 files changed, 195 insertions, 167 deletions
diff --git a/src/btree/bt_compact.c b/src/btree/bt_compact.c
index d8b3a638de3..1528d65b8c8 100644
--- a/src/btree/bt_compact.c
+++ b/src/btree/bt_compact.c
@@ -76,7 +76,7 @@ __wt_compact(WT_SESSION_IMPL *session, const char *cfg[])
WT_CONNECTION_IMPL *conn;
WT_DECL_RET;
WT_REF *ref;
- int block_manager_begin, skip;
+ int block_manager_begin, evict_reset, skip;
WT_UNUSED(cfg);
@@ -133,8 +133,9 @@ __wt_compact(WT_SESSION_IMPL *session, const char *cfg[])
* then let eviction continue;
*/
conn->compact_in_memory_pass = 1;
- WT_ERR(__wt_evict_file_exclusive_on(session));
- __wt_evict_file_exclusive_off(session);
+ WT_ERR(__wt_evict_file_exclusive_on(session, &evict_reset));
+ if (evict_reset)
+ __wt_evict_file_exclusive_off(session);
/* Start compaction. */
WT_ERR(bm->compact_start(bm, session));
diff --git a/src/btree/bt_cursor.c b/src/btree/bt_cursor.c
index 1960e4605ef..8409b0cd6a2 100644
--- a/src/btree/bt_cursor.c
+++ b/src/btree/bt_cursor.c
@@ -936,36 +936,22 @@ __cursor_truncate(WT_SESSION_IMPL *session,
* instantiated the end cursor, so we know that page is pinned in memory
* and we can proceed without concern.
*/
- if (start == NULL) {
- do {
- WT_RET(__wt_btcur_remove(stop));
- for (;;) {
- if ((ret = __wt_btcur_prev(stop, 1)) != 0)
- break;
- stop->compare = 0; /* Exact match */
- if ((ret = rmfunc(session, stop, 1)) != 0)
- break;
- }
- } while (ret == WT_RESTART);
- } else {
- do {
- WT_RET(__wt_btcur_remove(start));
- /*
- * Reset ret each time through so that we don't loop
- * forever in the cursor equals case.
- */
- for (ret = 0;;) {
- if (stop != NULL &&
- __cursor_equals(start, stop))
- break;
- if ((ret = __wt_btcur_next(start, 1)) != 0)
- break;
- start->compare = 0; /* Exact match */
- if ((ret = rmfunc(session, start, 1)) != 0)
- break;
- }
- } while (ret == WT_RESTART);
- }
+ do {
+ WT_RET(__wt_btcur_remove(start));
+ /*
+ * Reset ret each time through so that we don't loop forever in
+ * the cursor equals case.
+ */
+ for (ret = 0;;) {
+ if (stop != NULL && __cursor_equals(start, stop))
+ break;
+ if ((ret = __wt_btcur_next(start, 1)) != 0)
+ break;
+ start->compare = 0; /* Exact match */
+ if ((ret = rmfunc(session, start, 1)) != 0)
+ break;
+ }
+ } while (ret == WT_RESTART);
WT_RET_NOTFOUND_OK(ret);
return (0);
@@ -999,40 +985,24 @@ __cursor_truncate_fix(WT_SESSION_IMPL *session,
* other thread of control; in that case, repeat the full search to
* refresh the page's modification information.
*/
- if (start == NULL) {
- do {
- WT_RET(__wt_btcur_remove(stop));
- for (;;) {
- if ((ret = __wt_btcur_prev(stop, 1)) != 0)
- break;
- stop->compare = 0; /* Exact match */
- value = (uint8_t *)stop->iface.value.data;
- if (*value != 0 &&
- (ret = rmfunc(session, stop, 1)) != 0)
- break;
- }
- } while (ret == WT_RESTART);
- } else {
- do {
- WT_RET(__wt_btcur_remove(start));
- /*
- * Reset ret each time through so that we don't loop
- * forever in the cursor equals case.
- */
- for (ret = 0;;) {
- if (stop != NULL &&
- __cursor_equals(start, stop))
- break;
- if ((ret = __wt_btcur_next(start, 1)) != 0)
- break;
- start->compare = 0; /* Exact match */
- value = (uint8_t *)start->iface.value.data;
- if (*value != 0 &&
- (ret = rmfunc(session, start, 1)) != 0)
- break;
- }
- } while (ret == WT_RESTART);
- }
+ do {
+ WT_RET(__wt_btcur_remove(start));
+ /*
+ * Reset ret each time through so that we don't loop forever in
+ * the cursor equals case.
+ */
+ for (ret = 0;;) {
+ if (stop != NULL && __cursor_equals(start, stop))
+ break;
+ if ((ret = __wt_btcur_next(start, 1)) != 0)
+ break;
+ start->compare = 0; /* Exact match */
+ value = (uint8_t *)start->iface.value.data;
+ if (*value != 0 &&
+ (ret = rmfunc(session, start, 1)) != 0)
+ break;
+ }
+ } while (ret == WT_RESTART);
WT_RET_NOTFOUND_OK(ret);
return (0);
@@ -1055,9 +1025,15 @@ __wt_btcur_range_truncate(WT_CURSOR_BTREE *start, WT_CURSOR_BTREE *stop)
btree = cbt->btree;
/*
- * For recovery, we log the start and stop keys for a truncate
- * operation, not the individual records removed. On the other hand,
- * for rollback we need to keep track of all the in-memory operations.
+ * We always delete in a forward direction because it's faster, assert
+ * our caller provided us with a start cursor.
+ */
+ WT_ASSERT(session, start != NULL);
+
+ /*
+ * For recovery, log the start and stop keys for a truncate operation,
+ * not the individual records removed. On the other hand, for rollback
+ * we need to keep track of all the in-memory operations.
*
* We deal with this here by logging the truncate range first, then (in
* the logging code) disabling writing of the in-memory remove records
@@ -1081,15 +1057,13 @@ __wt_btcur_range_truncate(WT_CURSOR_BTREE *start, WT_CURSOR_BTREE *stop)
* fully instantiated when truncating row-store objects because
* it's comparing page and/or skiplist positions, not keys. (Key
* comparison would work, it's only that a key comparison would
- * be relatively expensive. Column-store objects have record
- * number keys, so the key comparison is cheap.) Cursors may
- * have only had their keys set, so we must ensure the cursors
- * are positioned in the tree.
+ * be relatively expensive, especially with custom collators.
+ * Column-store objects have record number keys, so the key
+ * comparison is cheap.) The session truncate code did cursor
+ * searches when setting up the truncate so we're good to go: if
+ * that ever changes, we'd need to do something here to ensure a
+ * fully instantiated cursor.
*/
- if (start != NULL)
- WT_ERR(__wt_btcur_search(start));
- if (stop != NULL)
- WT_ERR(__wt_btcur_search(stop));
WT_ERR(__cursor_truncate(
session, start, stop, __cursor_row_modify));
break;
diff --git a/src/btree/bt_page.c b/src/btree/bt_page.c
index 2f2ce4cf4f7..b5140beb792 100644
--- a/src/btree/bt_page.c
+++ b/src/btree/bt_page.c
@@ -129,15 +129,24 @@ __wt_page_in_func(WT_SESSION_IMPL *session, WT_REF *ref, uint32_t flags
__evict_force_check(session, page, flags)) {
++force_attempts;
ret = __wt_page_release_evict(session, ref);
+ /* If forced eviction fails, stall. */
if (ret == EBUSY) {
- /* If forced eviction fails, stall. */
ret = 0;
wait_cnt += 1000;
+ WT_STAT_FAST_CONN_INCR(session,
+ page_forcible_evict_blocked);
+ break;
} else
WT_RET(ret);
- WT_STAT_FAST_CONN_INCR(
- session, page_forcible_evict_blocked);
- break;
+
+ /*
+ * The result of a successful forced eviction
+ * is a page-state transition (potentially to
+ * an in-memory page we can use, or a restart
+ * return for our caller), continue the outer
+ * page-acquisition loop.
+ */
+ continue;
}
/* Check if we need an autocommit transaction. */
diff --git a/src/btree/bt_sync.c b/src/btree/bt_sync.c
index a75af03d8c8..d925eefc2fe 100644
--- a/src/btree/bt_sync.c
+++ b/src/btree/bt_sync.c
@@ -25,6 +25,7 @@ __sync_file(WT_SESSION_IMPL *session, int syncop)
uint64_t internal_bytes, leaf_bytes;
uint64_t internal_pages, leaf_pages;
uint32_t flags;
+ int evict_reset;
btree = S2BT(session);
@@ -99,11 +100,11 @@ __sync_file(WT_SESSION_IMPL *session, int syncop)
* eviction to complete.
*/
btree->checkpointing = 1;
+ WT_FULL_BARRIER();
- if (!F_ISSET(btree, WT_BTREE_NO_EVICTION)) {
- WT_ERR(__wt_evict_file_exclusive_on(session));
+ WT_ERR(__wt_evict_file_exclusive_on(session, &evict_reset));
+ if (evict_reset)
__wt_evict_file_exclusive_off(session);
- }
/* Write all dirty in-cache pages. */
flags |= WT_READ_NO_EVICT;
diff --git a/src/conn/conn_dhandle.c b/src/conn/conn_dhandle.c
index 8ed656d6416..a5512352f2c 100644
--- a/src/conn/conn_dhandle.c
+++ b/src/conn/conn_dhandle.c
@@ -475,16 +475,15 @@ __conn_btree_apply_internal(WT_SESSION_IMPL *session, WT_DATA_HANDLE *dhandle,
WT_DECL_RET;
/*
- * We need to pull the handle into the session handle
- * cache and make sure it's referenced to stop other
- * internal code dropping the handle (e.g in LSM when
- * cleaning up obsolete chunks). Holding the metadata
- * lock isn't enough.
+ * We need to pull the handle into the session handle cache and make
+ * sure it's referenced to stop other internal code dropping the handle
+ * (e.g in LSM when cleaning up obsolete chunks).
*/
ret = __wt_session_get_btree(session,
dhandle->name, dhandle->checkpoint, NULL, 0);
if (ret == 0) {
- ret = func(session, cfg);
+ WT_SAVE_DHANDLE(session,
+ ret = func(session, cfg));
if (WT_META_TRACKING(session))
WT_TRET(__wt_meta_track_handle_lock(session, 0));
else
@@ -550,12 +549,11 @@ __wt_conn_btree_apply_single(WT_SESSION_IMPL *session,
int (*func)(WT_SESSION_IMPL *, const char *[]), const char *cfg[])
{
WT_CONNECTION_IMPL *conn;
- WT_DATA_HANDLE *dhandle, *saved_dhandle;
+ WT_DATA_HANDLE *dhandle;
WT_DECL_RET;
uint64_t bucket, hash;
conn = S2C(session);
- saved_dhandle = session->dhandle;
WT_ASSERT(session, F_ISSET(session, WT_SESSION_HANDLE_LIST_LOCKED));
@@ -578,15 +576,14 @@ __wt_conn_btree_apply_single(WT_SESSION_IMPL *session,
*/
__wt_spin_lock(session, &dhandle->close_lock);
if (F_ISSET(dhandle, WT_DHANDLE_OPEN)) {
- session->dhandle = dhandle;
- ret = func(session, cfg);
+ WT_WITH_DHANDLE(session, dhandle,
+ ret = func(session, cfg));
}
__wt_spin_unlock(session, &dhandle->close_lock);
WT_ERR(ret);
}
-err: session->dhandle = saved_dhandle;
- return (ret);
+err: return (ret);
}
/*
diff --git a/src/conn/conn_stat.c b/src/conn/conn_stat.c
index be2172ea8d8..67814dc330b 100644
--- a/src/conn/conn_stat.c
+++ b/src/conn/conn_stat.c
@@ -193,6 +193,7 @@ static int
__statlog_apply(WT_SESSION_IMPL *session, const char *cfg[])
{
WT_DATA_HANDLE *dhandle;
+ WT_DECL_RET;
char **p;
WT_UNUSED(cfg);
@@ -201,8 +202,11 @@ __statlog_apply(WT_SESSION_IMPL *session, const char *cfg[])
/* Check for a match on the set of sources. */
for (p = S2C(session)->stat_sources; *p != NULL; ++p)
- if (WT_PREFIX_MATCH(dhandle->name, *p))
- return (__statlog_dump(session, dhandle->name, 0));
+ if (WT_PREFIX_MATCH(dhandle->name, *p)) {
+ WT_WITHOUT_DHANDLE(session,
+ ret = __statlog_dump(session, dhandle->name, 0));
+ WT_RET(ret);
+ }
return (0);
}
diff --git a/src/evict/evict_file.c b/src/evict/evict_file.c
index 910aef070ca..9e39fcc7a2c 100644
--- a/src/evict/evict_file.c
+++ b/src/evict/evict_file.c
@@ -15,21 +15,16 @@
int
__wt_evict_file(WT_SESSION_IMPL *session, int syncop)
{
- WT_BTREE *btree;
WT_DECL_RET;
WT_PAGE *page;
WT_REF *next_ref, *ref;
- int eviction_enabled;
-
- btree = S2BT(session);
- eviction_enabled = !F_ISSET(btree, WT_BTREE_NO_EVICTION);
+ int evict_reset;
/*
* We need exclusive access to the file -- disable ordinary eviction
* and drain any blocks already queued.
*/
- if (eviction_enabled)
- WT_RET(__wt_evict_file_exclusive_on(session));
+ WT_RET(__wt_evict_file_exclusive_on(session, &evict_reset));
/* Make sure the oldest transaction ID is up-to-date. */
__wt_txn_update_oldest(session);
@@ -140,7 +135,7 @@ err: /* On error, clear any left-over tree walk. */
session, next_ref, WT_READ_NO_EVICT));
}
- if (eviction_enabled)
+ if (evict_reset)
__wt_evict_file_exclusive_off(session);
return (ret);
diff --git a/src/evict/evict_lru.c b/src/evict/evict_lru.c
index 83a9aa5c8c5..35be3df9185 100644
--- a/src/evict/evict_lru.c
+++ b/src/evict/evict_lru.c
@@ -653,7 +653,7 @@ __wt_evict_page(WT_SESSION_IMPL *session, WT_REF *ref)
* blocks queued for eviction.
*/
int
-__wt_evict_file_exclusive_on(WT_SESSION_IMPL *session)
+__wt_evict_file_exclusive_on(WT_SESSION_IMPL *session, int *evict_resetp)
{
WT_BTREE *btree;
WT_CACHE *cache;
@@ -664,6 +664,15 @@ __wt_evict_file_exclusive_on(WT_SESSION_IMPL *session)
cache = S2C(session)->cache;
/*
+ * If the file isn't evictable, there's no work to do.
+ */
+ if (F_ISSET(btree, WT_BTREE_NO_EVICTION)) {
+ *evict_resetp = 0;
+ return (0);
+ }
+ *evict_resetp = 1;
+
+ /*
* Hold the walk lock to set the "no eviction" flag: no new pages from
* the file will be queued for eviction after this point.
*/
@@ -979,7 +988,7 @@ retry: while (slot < max_entries && ret == 0) {
* exclusive access when a handle is being closed.
*/
if (!F_ISSET(btree, WT_BTREE_NO_EVICTION)) {
- WT_WITH_BTREE(session, btree,
+ WT_WITH_DHANDLE(session, dhandle,
ret = __evict_walk_file(session, &slot, flags));
WT_ASSERT(session, session->split_gen == 0);
}
@@ -1072,34 +1081,37 @@ __evict_walk_file(WT_SESSION_IMPL *session, u_int *slotp, uint32_t flags)
WT_PAGE_MODIFY *mod;
uint64_t pages_walked;
uint32_t walk_flags;
- int internal_pages, modified, restarts;
+ int enough, internal_pages, modified, restarts;
btree = S2BT(session);
cache = S2C(session)->cache;
start = cache->evict + *slotp;
end = WT_MIN(start + WT_EVICT_WALK_PER_FILE,
cache->evict + cache->evict_slots);
+ enough = internal_pages = restarts = 0;
walk_flags =
WT_READ_CACHE | WT_READ_NO_EVICT | WT_READ_NO_GEN | WT_READ_NO_WAIT;
/*
* Get some more eviction candidate pages.
+ *
+ * !!! Take care terminating this loop.
+ *
+ * Don't make an extra call to __wt_tree_walk after we hit the end of a
+ * tree: that will leave a page pinned, which may prevent any work from
+ * being done.
+ *
+ * Once we hit the page limit, do one more step through the walk in
+ * case we are appending and only the last page in the file is live.
*/
- for (evict = start, pages_walked = 0, internal_pages = restarts = 0;
- evict < end && pages_walked < WT_EVICT_MAX_PER_FILE &&
- (ret == 0 || ret == WT_NOTFOUND);
+ for (evict = start, pages_walked = 0;
+ evict < end && !enough && (ret == 0 || ret == WT_NOTFOUND);
ret = __wt_tree_walk(
session, &btree->evict_ref, &pages_walked, walk_flags)) {
+ enough = (pages_walked > WT_EVICT_MAX_PER_FILE);
if (btree->evict_ref == NULL) {
- /*
- * Take care with terminating this loop.
- *
- * Don't make an extra call to __wt_tree_walk: that will
- * leave a page pinned, which may prevent any work from
- * being done.
- */
- if (++restarts == 2)
+ if (++restarts == 2 || enough)
break;
continue;
}
diff --git a/src/include/dhandle.h b/src/include/dhandle.h
index 423bb84d00d..300e8e735b9 100644
--- a/src/include/dhandle.h
+++ b/src/include/dhandle.h
@@ -6,6 +6,10 @@
* See the file LICENSE for redistribution information.
*/
+/*
+ * Helpers for calling a function with a data handle in session->dhandle
+ * then restoring afterwards.
+ */
#define WT_WITH_DHANDLE(s, d, e) do { \
WT_DATA_HANDLE *__saved_dhandle = (s)->dhandle; \
(s)->dhandle = (d); \
@@ -15,6 +19,15 @@
#define WT_WITH_BTREE(s, b, e) WT_WITH_DHANDLE(s, (b)->dhandle, e)
+/* Call a function without the caller's data handle, restore afterwards. */
+#define WT_WITHOUT_DHANDLE(s, e) WT_WITH_DHANDLE(s, NULL, e)
+
+/*
+ * Call a function with the caller's data handle, restore it afterwards in case
+ * it is overwritten.
+ */
+#define WT_SAVE_DHANDLE(s, e) WT_WITH_DHANDLE(s, (s)->dhandle, e)
+
/*
* WT_DATA_HANDLE --
* A handle for a generic named data source.
diff --git a/src/include/extern.h b/src/include/extern.h
index 23bb36623e5..5d3ee5bc8f8 100644
--- a/src/include/extern.h
+++ b/src/include/extern.h
@@ -297,7 +297,7 @@ extern int __wt_evict_server_wake(WT_SESSION_IMPL *session);
extern int __wt_evict_create(WT_SESSION_IMPL *session);
extern int __wt_evict_destroy(WT_SESSION_IMPL *session);
extern int __wt_evict_page(WT_SESSION_IMPL *session, WT_REF *ref);
-extern int __wt_evict_file_exclusive_on(WT_SESSION_IMPL *session);
+extern int __wt_evict_file_exclusive_on(WT_SESSION_IMPL *session, int *evict_resetp);
extern void __wt_evict_file_exclusive_off(WT_SESSION_IMPL *session);
extern int __wt_evict_lru_page(WT_SESSION_IMPL *session, int is_server);
extern int __wt_cache_wait(WT_SESSION_IMPL *session, int full);
diff --git a/src/log/log.c b/src/log/log.c
index f6c8602faff..f76ec402b0d 100644
--- a/src/log/log.c
+++ b/src/log/log.c
@@ -50,27 +50,29 @@ __wt_log_needs_recovery(WT_SESSION_IMPL *session, WT_LSN *ckp_lsn, int *rec)
conn = S2C(session);
log = conn->log;
- c = NULL;
+
/*
- * Default is to run recovery always.
+ * Default is to run recovery always (regardless of whether this
+ * connection has logging enabled).
*/
*rec = 1;
-
if (log == NULL)
return (0);
+
WT_RET(__wt_curlog_open(session, "log:", NULL, &c));
c->set_key(c, ckp_lsn->file, ckp_lsn->offset, 0);
WT_ERR(c->search(c));
+
/*
- * If the checkpoint LSN we're given is the last record,
- * then recovery is not needed.
+ * If the checkpoint LSN we're given is the last record, then recovery
+ * is not needed.
*/
if ((ret = c->next(c)) == WT_NOTFOUND) {
*rec = 0;
ret = 0;
}
-err: if (c != NULL)
- (void)c->close(c);
+
+err: WT_TRET(c->close(c));
return (ret);
}
diff --git a/src/log/log_slot.c b/src/log/log_slot.c
index ff61afb698c..8dcb2f9f165 100644
--- a/src/log/log_slot.c
+++ b/src/log/log_slot.c
@@ -203,8 +203,7 @@ retry:
* churn is used to change how long we pause before closing
* the slot - which leads to more consolidation and less churn.
*/
- if (++switch_fails % SLOT_POOL == 0 &&
- switch_fails != 0 && slot->slot_churn < 5)
+ if (++switch_fails % SLOT_POOL == 0 && slot->slot_churn < 5)
++slot->slot_churn;
__wt_yield();
goto retry;
diff --git a/src/meta/meta_apply.c b/src/meta/meta_apply.c
index 8ef5cc38db4..6d08ce3aa6a 100644
--- a/src/meta/meta_apply.c
+++ b/src/meta/meta_apply.c
@@ -43,7 +43,8 @@ __wt_meta_btree_apply(WT_SESSION_IMPL *session,
*/
ret = __wt_session_get_btree(session, uri, NULL, NULL, 0);
if (ret == 0) {
- ret = func(session, cfg);
+ WT_SAVE_DHANDLE(session,
+ ret = func(session, cfg));
if (WT_META_TRACKING(session))
WT_TRET(
__wt_meta_track_handle_lock(session, 0));
diff --git a/src/schema/schema_truncate.c b/src/schema/schema_truncate.c
index 383e860cc7b..1eb76226aad 100644
--- a/src/schema/schema_truncate.c
+++ b/src/schema/schema_truncate.c
@@ -170,11 +170,15 @@ __wt_schema_range_truncate(
cursor = (start != NULL) ? start : stop;
uri = cursor->internal_uri;
- if (WT_PREFIX_MATCH(uri, "file:"))
+ if (WT_PREFIX_MATCH(uri, "file:")) {
+ if (start != NULL)
+ WT_CURSOR_NEEDKEY(start);
+ if (stop != NULL)
+ WT_CURSOR_NEEDKEY(stop);
WT_WITH_BTREE(session, ((WT_CURSOR_BTREE *)cursor)->btree,
ret = __wt_btcur_range_truncate(
(WT_CURSOR_BTREE *)start, (WT_CURSOR_BTREE *)stop));
- else if (WT_PREFIX_MATCH(uri, "table:"))
+ } else if (WT_PREFIX_MATCH(uri, "table:"))
ret = __wt_table_range_truncate(
(WT_CURSOR_TABLE *)start, (WT_CURSOR_TABLE *)stop);
else if ((dsrc = __wt_schema_get_source(session, uri)) != NULL &&
@@ -182,6 +186,6 @@ __wt_schema_range_truncate(
ret = dsrc->range_truncate(dsrc, &session->iface, start, stop);
else
ret = __wt_range_truncate(start, stop);
-
+err:
return (ret);
}
diff --git a/src/schema/schema_worker.c b/src/schema/schema_worker.c
index 94eb3170175..3dfd068cf9c 100644
--- a/src/schema/schema_worker.c
+++ b/src/schema/schema_worker.c
@@ -57,7 +57,8 @@ __wt_schema_worker(WT_SESSION_IMPL *session,
WT_ERR(__wt_session_get_btree_ckpt(
session, uri, cfg, open_flags));
- ret = file_func(session, cfg);
+ WT_SAVE_DHANDLE(session,
+ ret = file_func(session, cfg));
WT_TRET(__wt_session_release_btree(session));
}
} else if (WT_PREFIX_MATCH(uri, "colgroup:")) {
diff --git a/src/session/session_api.c b/src/session/session_api.c
index e54553aa071..e95bea3f75b 100644
--- a/src/session/session_api.c
+++ b/src/session/session_api.c
@@ -570,7 +570,9 @@ __session_truncate(WT_SESSION *wt_session,
WT_DECL_RET;
WT_SESSION_IMPL *session;
WT_CURSOR *cursor;
- int cmp;
+ int cmp, local_start;
+
+ local_start = 0;
session = (WT_SESSION_IMPL *)wt_session;
SESSION_TXN_API_CALL(session, truncate, config, cfg);
@@ -642,9 +644,7 @@ __session_truncate(WT_SESSION *wt_session,
* what records currently appear in the object. For this reason, do a
* search-near, rather than a search. Additionally, we have to correct
* after calling search-near, to position the start/stop cursors on the
- * next record greater than/less than the original key. If the cursors
- * hit the beginning/end of the object, or the start/stop keys cross,
- * we're done, the range must be empty.
+ * next record greater than/less than the original key.
*/
if (start != NULL) {
WT_ERR(start->search_near(start, &cmp));
@@ -659,12 +659,28 @@ __session_truncate(WT_SESSION *wt_session,
WT_ERR_NOTFOUND_OK(ret);
goto done;
}
+ }
- if (start != NULL) {
- WT_ERR(start->compare(start, stop, &cmp));
- if (cmp > 0)
- goto done;
- }
+ /*
+ * We always truncate in the forward direction because the underlying
+ * data structures can move through pages faster forward than backward.
+ * If we don't have a start cursor, create one and position it at the
+ * first record.
+ */
+ if (start == NULL) {
+ WT_ERR(__session_open_cursor(
+ wt_session, stop->uri, NULL, NULL, &start));
+ local_start = 1;
+ WT_ERR(start->next(start));
+ }
+
+ /*
+ * If the start/stop keys cross, we're done, the range must be empty.
+ */
+ if (stop != NULL) {
+ WT_ERR(start->compare(start, stop, &cmp));
+ if (cmp > 0)
+ goto done;
}
WT_ERR(__wt_schema_range_truncate(session, start, stop));
@@ -673,6 +689,12 @@ done:
err: TXN_API_END_RETRY(session, ret, 0);
/*
+ * Close any locally-opened start cursor.
+ */
+ if (local_start)
+ WT_TRET(start->close(start));
+
+ /*
* Only map WT_NOTFOUND to ENOENT if a URI was specified.
*/
return (ret == WT_NOTFOUND && uri != NULL ? ENOENT : ret);
diff --git a/src/txn/txn_ckpt.c b/src/txn/txn_ckpt.c
index eae21d0b9f5..fb590e1a297 100644
--- a/src/txn/txn_ckpt.c
+++ b/src/txn/txn_ckpt.c
@@ -237,7 +237,6 @@ __checkpoint_data_source(WT_SESSION_IMPL *session, const char *cfg[])
int
__wt_checkpoint_list(WT_SESSION_IMPL *session, const char *cfg[])
{
- WT_DATA_HANDLE *saved_dhandle;
WT_DECL_RET;
const char *name;
@@ -253,7 +252,6 @@ __wt_checkpoint_list(WT_SESSION_IMPL *session, const char *cfg[])
/* Not strictly necessary, but cleaner to clear the current handle. */
name = session->dhandle->name;
- saved_dhandle = session->dhandle;
session->dhandle = NULL;
/* Record busy file names, we'll deal with them in the checkpoint. */
@@ -264,8 +262,7 @@ __wt_checkpoint_list(WT_SESSION_IMPL *session, const char *cfg[])
WT_ERR(__wt_strdup(session, name,
&session->ckpt_handle[session->ckpt_handle_next++].name));
-err: session->dhandle = saved_dhandle;
- return (ret);
+err: return (ret);
}
/*
diff --git a/src/utilities/util_main.c b/src/utilities/util_main.c
index 3274f3a0fd0..51a11f82c43 100644
--- a/src/utilities/util_main.c
+++ b/src/utilities/util_main.c
@@ -169,25 +169,21 @@ main(int argc, char *argv[])
if (func == NULL)
return (usage());
- /* Build the configuration string, as necessary. */
- if (cmd_config != NULL || rec_config != NULL) {
- len = 10; /* some slop */
- if (config != NULL)
- len += strlen(config);
- if (cmd_config != NULL)
- len += strlen(cmd_config);
- if (rec_config != NULL)
- len += strlen(rec_config);
- if ((p = malloc(len)) == NULL) {
- ret = util_err(errno, NULL);
- goto err;
- }
- (void)snprintf(p, len, "%s,%s,%s",
- config == NULL ? "" : config,
- cmd_config == NULL ? "" : cmd_config,
- rec_config == NULL ? "" : rec_config);
- config = p;
+ /* Build the configuration string. */
+ len = 10; /* some slop */
+ if (config != NULL)
+ len += strlen(config);
+ if (cmd_config != NULL)
+ len += strlen(cmd_config);
+ len += strlen(rec_config);
+ if ((p = malloc(len)) == NULL) {
+ ret = util_err(errno, NULL);
+ goto err;
}
+ (void)snprintf(p, len, "%s,%s,%s",
+ config == NULL ? "" : config,
+ cmd_config == NULL ? "" : cmd_config, rec_config);
+ config = p;
/* Open the database and a session. */
if ((ret = wiredtiger_open(home,