diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/btree/bt_compact.c | 7 | ||||
-rw-r--r-- | src/btree/bt_cursor.c | 124 | ||||
-rw-r--r-- | src/btree/bt_page.c | 17 | ||||
-rw-r--r-- | src/btree/bt_sync.c | 7 | ||||
-rw-r--r-- | src/conn/conn_dhandle.c | 21 | ||||
-rw-r--r-- | src/conn/conn_stat.c | 8 | ||||
-rw-r--r-- | src/evict/evict_file.c | 11 | ||||
-rw-r--r-- | src/evict/evict_lru.c | 40 | ||||
-rw-r--r-- | src/include/dhandle.h | 13 | ||||
-rw-r--r-- | src/include/extern.h | 2 | ||||
-rw-r--r-- | src/log/log.c | 16 | ||||
-rw-r--r-- | src/log/log_slot.c | 3 | ||||
-rw-r--r-- | src/meta/meta_apply.c | 3 | ||||
-rw-r--r-- | src/schema/schema_truncate.c | 10 | ||||
-rw-r--r-- | src/schema/schema_worker.c | 3 | ||||
-rw-r--r-- | src/session/session_api.c | 40 | ||||
-rw-r--r-- | src/txn/txn_ckpt.c | 5 | ||||
-rw-r--r-- | src/utilities/util_main.c | 32 |
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, |