summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Cahill <michael.cahill@mongodb.com>2015-12-02 22:13:33 +1100
committerMichael Cahill <michael.cahill@mongodb.com>2015-12-02 22:13:47 +1100
commiteb8bc24a0d36b673022faa83976a4b33bc8f676b (patch)
treee14db1a16010a86f89241c85bc9b3015d2aace52
parenta5ddbdfcd2ab0e05f31fa56af8e9e9a887d63dc1 (diff)
downloadmongo-eb8bc24a0d36b673022faa83976a4b33bc8f676b.tar.gz
Import wiredtiger-wiredtiger-mongodb-3.0.7-20-g27d0cbd.tar.gz from wiredtiger branch mongodb-3.0
ref: deb2d81..27d0cbd 6feaa28 WT-2251 Fix leaf of deleted page addresses. 1da2d3a SERVER-21568 Fix a use-after-free. 4228295 SERVER-21553 Free blocks during reverse splits. 0398515 WT-2241 Use a lock to protect transaction ID allocation. 06a5c7b WT-2237 Avoid yields if we race allocating transaction IDs. 16a418b WT-2237 Have threads publish unique transaction IDs so that updates always become visible immediately on commit.
-rw-r--r--src/third_party/wiredtiger/src/btree/bt_delete.c12
-rw-r--r--src/third_party/wiredtiger/src/btree/bt_discard.c5
-rw-r--r--src/third_party/wiredtiger/src/btree/bt_slvg.c8
-rw-r--r--src/third_party/wiredtiger/src/btree/bt_split.c64
-rw-r--r--src/third_party/wiredtiger/src/btree/bt_walk.c4
-rw-r--r--src/third_party/wiredtiger/src/evict/evict_page.c14
-rw-r--r--src/third_party/wiredtiger/src/include/btree.i55
-rw-r--r--src/third_party/wiredtiger/src/include/txn.h1
-rw-r--r--src/third_party/wiredtiger/src/include/txn.i117
-rw-r--r--src/third_party/wiredtiger/src/lsm/lsm_tree.c4
-rw-r--r--src/third_party/wiredtiger/src/reconcile/rec_track.c2
-rw-r--r--src/third_party/wiredtiger/src/reconcile/rec_write.c44
-rw-r--r--src/third_party/wiredtiger/src/txn/txn.c7
13 files changed, 191 insertions, 146 deletions
diff --git a/src/third_party/wiredtiger/src/btree/bt_delete.c b/src/third_party/wiredtiger/src/btree/bt_delete.c
index 7313e31267f..e19085830bd 100644
--- a/src/third_party/wiredtiger/src/btree/bt_delete.c
+++ b/src/third_party/wiredtiger/src/btree/bt_delete.c
@@ -250,6 +250,18 @@ __wt_delete_page_skip(WT_SESSION_IMPL *session, WT_REF *ref, bool visible_all)
__wt_txn_visible_all(session, ref->page_del->txnid) :
__wt_txn_visible(session, ref->page_del->txnid));
+ /*
+ * The page_del structure can be freed as soon as the delete is stable:
+ * it is only read when the ref state is WT_REF_DELETED. It is worth
+ * checking every time we come through because once this is freed, we
+ * no longer need synchronization to check the ref.
+ */
+ if (skip && ref->page_del != NULL && (visible_all ||
+ __wt_txn_visible_all(session, ref->page_del->txnid))) {
+ __wt_free(session, ref->page_del->update_list);
+ __wt_free(session, ref->page_del);
+ }
+
WT_PUBLISH(ref->state, WT_REF_DELETED);
return (skip);
}
diff --git a/src/third_party/wiredtiger/src/btree/bt_discard.c b/src/third_party/wiredtiger/src/btree/bt_discard.c
index c876da6309c..30e19147e12 100644
--- a/src/third_party/wiredtiger/src/btree/bt_discard.c
+++ b/src/third_party/wiredtiger/src/btree/bt_discard.c
@@ -252,10 +252,7 @@ __wt_free_ref(
}
/* Free any address allocation. */
- if (ref->addr != NULL && __wt_off_page(page, ref->addr)) {
- __wt_free(session, ((WT_ADDR *)ref->addr)->addr);
- __wt_free(session, ref->addr);
- }
+ __wt_ref_addr_free(session, ref);
/* Free any page-deleted information. */
if (ref->page_del != NULL) {
diff --git a/src/third_party/wiredtiger/src/btree/bt_slvg.c b/src/third_party/wiredtiger/src/btree/bt_slvg.c
index 89355baeb5c..e4e611f947a 100644
--- a/src/third_party/wiredtiger/src/btree/bt_slvg.c
+++ b/src/third_party/wiredtiger/src/btree/bt_slvg.c
@@ -1299,9 +1299,7 @@ __slvg_col_build_leaf(WT_SESSION_IMPL *session, WT_TRACK *trk, WT_REF *ref)
* would have been lost.) Clear the reference addr so eviction doesn't
* free the underlying blocks.
*/
- __wt_free(session, ((WT_ADDR *)ref->addr)->addr);
- __wt_free(session, ref->addr);
- ref->addr = NULL;
+ __wt_ref_addr_free(session, ref);
/* Write the new version of the leaf page to disk. */
WT_ERR(__slvg_modify_init(session, page));
@@ -2008,9 +2006,7 @@ __slvg_row_build_leaf(
* would have been lost.) Clear the reference addr so eviction doesn't
* free the underlying blocks.
*/
- __wt_free(session, ((WT_ADDR *)ref->addr)->addr);
- __wt_free(session, ref->addr);
- ref->addr = NULL;
+ __wt_ref_addr_free(session, ref);
/* Write the new version of the leaf page to disk. */
WT_ERR(__slvg_modify_init(session, page));
diff --git a/src/third_party/wiredtiger/src/btree/bt_split.c b/src/third_party/wiredtiger/src/btree/bt_split.c
index 6f31ff89aa7..6e0436bb01f 100644
--- a/src/third_party/wiredtiger/src/btree/bt_split.c
+++ b/src/third_party/wiredtiger/src/btree/bt_split.c
@@ -502,7 +502,7 @@ __split_deepen(WT_SESSION_IMPL *session, WT_PAGE *parent)
* array, a thread might see a freed WT_REF. Set the eviction
* transaction requirement for the newly created internal pages.
*/
- child->modify->mod_split_txn = __wt_txn_new_id(session);
+ child->modify->mod_split_txn = __wt_txn_id_alloc(session, false);
/*
* The newly allocated child's page index references the same
@@ -1030,6 +1030,16 @@ __split_parent(WT_SESSION_IMPL *session, WT_REF *ref,
#endif
/*
+ * Page-delete information is only read when the WT_REF state is
+ * WT_REF_DELETED. The page-delete memory wasn't added to the
+ * parent's footprint, ignore it here.
+ */
+ if (ref->page_del != NULL) {
+ __wt_free(session, ref->page_del->update_list);
+ __wt_free(session, ref->page_del);
+ }
+
+ /*
* Reset the page's original WT_REF field to split. Threads cursoring
* through the tree were blocked because that WT_REF state was set to
* locked. This update changes the locked state to split, unblocking
@@ -1090,19 +1100,15 @@ __split_parent(WT_SESSION_IMPL *session, WT_REF *ref,
session, split_gen, 0, ikey, size));
parent_decr += size;
}
- /*
- * The page_del structure can be freed immediately: it
- * is only read when the ref state is WT_REF_DELETED.
- * The size of the structure wasn't added to the parent,
- * don't decrement.
- */
- if (next_ref->page_del != NULL) {
- __wt_free(session,
- next_ref->page_del->update_list);
- __wt_free(session, next_ref->page_del);
- }
}
+ /*
+ * If this page was fast-truncated, any attached structure
+ * should have been freed before now.
+ */
+ WT_ASSERT(session, next_ref->page_del == NULL);
+
+ WT_TRET(__wt_ref_block_free(session, next_ref));
WT_TRET(__split_safe_free(
session, split_gen, 0, next_ref, sizeof(WT_REF)));
parent_decr += sizeof(WT_REF);
@@ -1213,21 +1219,30 @@ __split_insert(WT_SESSION_IMPL *session, WT_REF *ref)
* The first page in the split is the current page, but we still have
* to create a replacement WT_REF, the original WT_REF will be set to
* split status and eventually freed.
+ *
+ * The new WT_REF is not quite identical: we have to instantiate a key,
+ * and the new reference is visible to readers once the split completes.
+ *
+ * The key-instantiation code checks for races, leave the key fields
+ * zeroed we don't trigger them.
+ *
+ * Don't copy any deleted page state: we may be splitting a page that
+ * was instantiated after a truncate and that history should not be
+ * carried onto these new child pages.
*/
WT_ERR(__wt_calloc_one(session, &split_ref[0]));
child = split_ref[0];
- *child = *ref;
+ child->page = ref->page;
+ child->home = ref->home;
+ child->pindex_hint = ref->pindex_hint;
+ child->state = WT_REF_MEM;
+ child->addr = ref->addr;
/*
- * The new WT_REF is not quite identical: we have to instantiate a key,
- * and the new reference is visible to readers once the split completes.
- *
- * The key-instantiation code checks for races, clear the key fields so
- * we don't trigger them.
+ * The address has moved to the replacement WT_REF. Make sure it isn't
+ * freed when the original ref is discarded.
*/
- child->key.recno = 0;
- child->key.ikey = NULL;
- child->state = WT_REF_MEM;
+ ref->addr = NULL;
/*
* Copy the first key from the original page into first ref in the new
@@ -1383,7 +1398,7 @@ __split_insert(WT_SESSION_IMPL *session, WT_REF *ref)
* threads will not try to forcibly evict the page again until
* all concurrent transactions commit.
*/
- page->modify->inmem_split_txn = __wt_txn_new_id(session);
+ page->modify->inmem_split_txn = __wt_txn_id_alloc(session, false);
/*
* Update the page accounting.
@@ -1429,6 +1444,11 @@ __split_insert(WT_SESSION_IMPL *session, WT_REF *ref)
return (0);
err: if (split_ref[0] != NULL) {
+ /*
+ * The address was moved to the replacement WT_REF, restore it.
+ */
+ ref->addr = split_ref[0]->addr;
+
__wt_free(session, split_ref[0]->key.ikey);
__wt_free(session, split_ref[0]);
}
diff --git a/src/third_party/wiredtiger/src/btree/bt_walk.c b/src/third_party/wiredtiger/src/btree/bt_walk.c
index 8e0f4036b79..c7d83d8dfff 100644
--- a/src/third_party/wiredtiger/src/btree/bt_walk.c
+++ b/src/third_party/wiredtiger/src/btree/bt_walk.c
@@ -244,7 +244,8 @@ ascend: /*
* If we see any child states other than deleted, the
* page isn't empty.
*/
- if (ref->state != WT_REF_DELETED)
+ if (ref->state != WT_REF_DELETED &&
+ !LF_ISSET(WT_READ_TRUNCATE))
empty_internal = false;
if (LF_ISSET(WT_READ_CACHE)) {
@@ -270,6 +271,7 @@ ascend: /*
WT_ERR(__wt_delete_page(session, ref, &skip));
if (skip)
break;
+ empty_internal = false;
} else if (LF_ISSET(WT_READ_COMPACT)) {
/*
* Skip deleted pages, rewriting them doesn't
diff --git a/src/third_party/wiredtiger/src/evict/evict_page.c b/src/third_party/wiredtiger/src/evict/evict_page.c
index 9de66922931..046d8bb3eba 100644
--- a/src/third_party/wiredtiger/src/evict/evict_page.c
+++ b/src/third_party/wiredtiger/src/evict/evict_page.c
@@ -222,19 +222,14 @@ __evict_page_dirty_update(WT_SESSION_IMPL *session, WT_REF *ref, bool closing)
{
WT_ADDR *addr;
WT_DECL_RET;
- WT_PAGE *parent;
WT_PAGE_MODIFY *mod;
- parent = ref->home;
mod = ref->page->modify;
+ WT_ASSERT(session, ref->addr == NULL);
+
switch (mod->rec_result) {
case WT_PM_REC_EMPTY: /* Page is empty */
- if (ref->addr != NULL && __wt_off_page(parent, ref->addr)) {
- __wt_free(session, ((WT_ADDR *)ref->addr)->addr);
- __wt_free(session, ref->addr);
- }
-
/*
* Update the parent to reference a deleted page. The fact that
* reconciliation left the page "empty" means there's no older
@@ -261,11 +256,6 @@ __evict_page_dirty_update(WT_SESSION_IMPL *session, WT_REF *ref, bool closing)
WT_RET(__wt_split_multi(session, ref, closing));
break;
case WT_PM_REC_REPLACE: /* 1-for-1 page swap */
- if (ref->addr != NULL && __wt_off_page(parent, ref->addr)) {
- __wt_free(session, ((WT_ADDR *)ref->addr)->addr);
- __wt_free(session, ref->addr);
- }
-
/*
* Update the parent to reference the replacement page.
*
diff --git a/src/third_party/wiredtiger/src/include/btree.i b/src/third_party/wiredtiger/src/include/btree.i
index 1c416c99e13..4029b29d207 100644
--- a/src/third_party/wiredtiger/src/include/btree.i
+++ b/src/third_party/wiredtiger/src/include/btree.i
@@ -1008,6 +1008,61 @@ __wt_page_can_split(WT_SESSION_IMPL *session, WT_PAGE *page)
}
/*
+ * __wt_ref_addr_free --
+ * Free the address in a reference, if necessary.
+ */
+static inline void
+__wt_ref_addr_free(WT_SESSION_IMPL *session, WT_REF *ref)
+ {
+ if (ref->addr == NULL)
+ return;
+
+ if (ref->home == NULL || __wt_off_page(ref->home, ref->addr)) {
+ __wt_free(session, ((WT_ADDR *)ref->addr)->addr);
+ __wt_free(session, ref->addr);
+ }
+ ref->addr = NULL;
+}
+
+/*
+ * __wt_btree_block_free --
+ * Helper function to free a block from the current tree.
+ */
+static inline int
+__wt_btree_block_free(
+ WT_SESSION_IMPL *session, const uint8_t *addr, size_t addr_size)
+{
+ WT_BM *bm;
+ WT_BTREE *btree;
+
+ btree = S2BT(session);
+ bm = btree->bm;
+
+ return (bm->free(bm, session, addr, addr_size));
+}
+
+/*
+ * __wt_ref_block_free --
+ * Free the on-disk block for a reference and clear the address.
+ */
+static inline int
+__wt_ref_block_free(WT_SESSION_IMPL *session, WT_REF *ref)
+{
+ const uint8_t *addr;
+ size_t addr_size;
+
+ if (ref->addr == NULL)
+ return (0);
+
+ WT_RET(__wt_ref_info(session, ref, &addr, &addr_size, NULL));
+ WT_RET(__wt_btree_block_free(session, addr, addr_size));
+
+ /* Clear the address (so we don't free it twice). */
+ __wt_ref_addr_free(session, ref);
+ return (0);
+}
+
+/*
* __wt_page_can_evict --
* Check whether a page can be evicted.
*/
diff --git a/src/third_party/wiredtiger/src/include/txn.h b/src/third_party/wiredtiger/src/include/txn.h
index 0d5f337fff0..9f9f282bfa4 100644
--- a/src/third_party/wiredtiger/src/include/txn.h
+++ b/src/third_party/wiredtiger/src/include/txn.h
@@ -34,6 +34,7 @@ struct WT_COMPILER_TYPE_ALIGN(WT_CACHE_LINE_ALIGNMENT) __wt_txn_state {
};
struct __wt_txn_global {
+ WT_SPINLOCK id_lock;
volatile uint64_t current; /* Current transaction ID. */
/* The oldest running transaction ID (may race). */
diff --git a/src/third_party/wiredtiger/src/include/txn.i b/src/third_party/wiredtiger/src/include/txn.i
index 73d7f1f0518..d7d958e801e 100644
--- a/src/third_party/wiredtiger/src/include/txn.i
+++ b/src/third_party/wiredtiger/src/include/txn.i
@@ -280,23 +280,6 @@ __wt_txn_autocommit_check(WT_SESSION_IMPL *session)
}
/*
- * __wt_txn_new_id --
- * Allocate a new transaction ID.
- */
-static inline uint64_t
-__wt_txn_new_id(WT_SESSION_IMPL *session)
-{
- /*
- * We want the global value to lead the allocated values, so that any
- * allocated transaction ID eventually becomes globally visible. When
- * there are no transactions running, the oldest_id will reach the
- * global current ID, so we want post-increment semantics. Our atomic
- * add primitive does pre-increment, so adjust the result here.
- */
- return (__wt_atomic_addv64(&S2C(session)->txn_global.current, 1) - 1);
-}
-
-/*
* __wt_txn_idle_cache_check --
* If there is no transaction active in this thread and we haven't checked
* if the cache is full, do it now. If we have to block for eviction,
@@ -323,6 +306,54 @@ __wt_txn_idle_cache_check(WT_SESSION_IMPL *session)
}
/*
+ * __wt_txn_id_alloc --
+ * Allocate a new transaction ID.
+ */
+static inline uint64_t
+__wt_txn_id_alloc(WT_SESSION_IMPL *session, bool publish)
+{
+ WT_TXN_GLOBAL *txn_global;
+ uint64_t id;
+
+ txn_global = &S2C(session)->txn_global;
+
+ /*
+ * Allocating transaction IDs involves several steps.
+ *
+ * Firstly, we do an atomic increment to allocate a unique ID. The
+ * field we increment is not used anywhere else.
+ *
+ * Then we optionally publish the allocated ID into the global
+ * transaction table. It is critical that this becomes visible before
+ * the global current value moves past our ID, or some concurrent
+ * reader could get a snapshot that makes our changes visible before we
+ * commit.
+ *
+ * Lastly, we spin to update the current ID. This is the only place
+ * that the current ID is updated, and it is in the same cache line as
+ * the field we allocate from, so we should usually succeed on the
+ * first try.
+ *
+ * We want the global value to lead the allocated values, so that any
+ * allocated transaction ID eventually becomes globally visible. When
+ * there are no transactions running, the oldest_id will reach the
+ * global current ID, so we want post-increment semantics. Our atomic
+ * add primitive does pre-increment, so adjust the result here.
+ */
+ __wt_spin_lock(session, &txn_global->id_lock);
+ id = txn_global->current;
+
+ if (publish) {
+ session->txn.id = id;
+ WT_PUBLISH(WT_SESSION_TXN_STATE(session)->id, id);
+ }
+
+ ++txn_global->current;
+ __wt_spin_unlock(session, &txn_global->id_lock);
+ return (id);
+}
+
+/*
* __wt_txn_id_check --
* A transaction is going to do an update, start an auto commit
* transaction if required and allocate a transaction ID.
@@ -330,57 +361,27 @@ __wt_txn_idle_cache_check(WT_SESSION_IMPL *session)
static inline int
__wt_txn_id_check(WT_SESSION_IMPL *session)
{
- WT_CONNECTION_IMPL *conn;
WT_TXN *txn;
- WT_TXN_GLOBAL *txn_global;
- WT_TXN_STATE *txn_state;
txn = &session->txn;
WT_ASSERT(session, F_ISSET(txn, WT_TXN_RUNNING));
+ if (F_ISSET(txn, WT_TXN_HAS_ID))
+ return (0);
+
/* If the transaction is idle, check that the cache isn't full. */
WT_RET(__wt_txn_idle_cache_check(session));
- if (!F_ISSET(txn, WT_TXN_HAS_ID)) {
- conn = S2C(session);
- txn_global = &conn->txn_global;
- txn_state = WT_SESSION_TXN_STATE(session);
+ (void)__wt_txn_id_alloc(session, true);
- WT_ASSERT(session, txn_state->id == WT_TXN_NONE);
-
- /*
- * Allocate a transaction ID.
- *
- * We use an atomic compare and swap to ensure that we get a
- * unique ID that is published before the global counter is
- * updated.
- *
- * If two threads race to allocate an ID, only the latest ID
- * will proceed. The winning thread can be sure its snapshot
- * contains all of the earlier active IDs. Threads that race
- * and get an earlier ID may not appear in the snapshot, but
- * they will loop and allocate a new ID before proceeding to
- * make any updates.
- *
- * This potentially wastes transaction IDs when threads race to
- * begin transactions: that is the price we pay to keep this
- * path latch free.
- */
- do {
- txn_state->id = txn->id = txn_global->current;
- } while (!__wt_atomic_casv64(
- &txn_global->current, txn->id, txn->id + 1) ||
- WT_TXNID_LT(txn->id, txn_global->last_running));
-
- /*
- * If we have used 64-bits of transaction IDs, there is nothing
- * more we can do.
- */
- if (txn->id == WT_TXN_ABORTED)
- WT_RET_MSG(session, ENOMEM, "Out of transaction IDs");
- F_SET(txn, WT_TXN_HAS_ID);
- }
+ /*
+ * If we have used 64-bits of transaction IDs, there is nothing
+ * more we can do.
+ */
+ if (txn->id == WT_TXN_ABORTED)
+ WT_RET_MSG(session, ENOMEM, "Out of transaction IDs");
+ F_SET(txn, WT_TXN_HAS_ID);
return (0);
}
diff --git a/src/third_party/wiredtiger/src/lsm/lsm_tree.c b/src/third_party/wiredtiger/src/lsm/lsm_tree.c
index 0680d98bdde..d3979da0da1 100644
--- a/src/third_party/wiredtiger/src/lsm/lsm_tree.c
+++ b/src/third_party/wiredtiger/src/lsm/lsm_tree.c
@@ -858,7 +858,7 @@ __wt_lsm_tree_switch(WT_SESSION_IMPL *session, WT_LSM_TREE *lsm_tree)
*/
if (last_chunk != NULL && last_chunk->switch_txn == WT_TXN_NONE &&
!F_ISSET(last_chunk, WT_LSM_CHUNK_ONDISK))
- last_chunk->switch_txn = __wt_txn_new_id(session);
+ last_chunk->switch_txn = __wt_txn_id_alloc(session, false);
/*
* If a maximum number of chunks are configured, drop the any chunks
@@ -1257,7 +1257,7 @@ __wt_lsm_compact(WT_SESSION_IMPL *session, const char *name, bool *skipp)
if (lsm_tree->nchunks > 0 &&
(chunk = lsm_tree->chunk[lsm_tree->nchunks - 1]) != NULL) {
if (chunk->switch_txn == WT_TXN_NONE)
- chunk->switch_txn = __wt_txn_new_id(session);
+ chunk->switch_txn = __wt_txn_id_alloc(session, false);
/*
* If we have a chunk, we want to look for it to be on-disk.
* So we need to add a reference to keep it available.
diff --git a/src/third_party/wiredtiger/src/reconcile/rec_track.c b/src/third_party/wiredtiger/src/reconcile/rec_track.c
index 36e85713421..17ad1c5fdc4 100644
--- a/src/third_party/wiredtiger/src/reconcile/rec_track.c
+++ b/src/third_party/wiredtiger/src/reconcile/rec_track.c
@@ -820,7 +820,7 @@ __wt_ovfl_txnc_add(WT_SESSION_IMPL *session, WT_PAGE *page,
txnc->value_offset = WT_PTRDIFF32(p, txnc);
txnc->value_size = WT_STORE_SIZE(value_size);
memcpy(p, value, value_size);
- txnc->current = __wt_txn_new_id(session);
+ txnc->current = __wt_txn_id_alloc(session, false);
__wt_cache_page_inmem_incr(
session, page, WT_OVFL_SIZE(txnc, WT_OVFL_TXNC));
diff --git a/src/third_party/wiredtiger/src/reconcile/rec_write.c b/src/third_party/wiredtiger/src/reconcile/rec_write.c
index 73b7f4968e9..67b43057c8a 100644
--- a/src/third_party/wiredtiger/src/reconcile/rec_write.c
+++ b/src/third_party/wiredtiger/src/reconcile/rec_write.c
@@ -1066,10 +1066,7 @@ static int
__rec_child_deleted(WT_SESSION_IMPL *session,
WT_RECONCILE *r, WT_REF *ref, WT_CHILD_STATE *statep)
{
- WT_BM *bm;
WT_PAGE_DELETED *page_del;
- size_t addr_size;
- const uint8_t *addr;
page_del = ref->page_del;
@@ -1117,17 +1114,8 @@ __rec_child_deleted(WT_SESSION_IMPL *session,
*/
if (ref->addr != NULL &&
(page_del == NULL ||
- __wt_txn_visible_all(session, page_del->txnid))) {
- WT_RET(__wt_ref_info(session, ref, &addr, &addr_size, NULL));
- bm = S2BT(session)->bm;
- WT_RET(bm->free(bm, session, addr, addr_size));
-
- if (__wt_off_page(ref->home, ref->addr)) {
- __wt_free(session, ((WT_ADDR *)ref->addr)->addr);
- __wt_free(session, ref->addr);
- }
- ref->addr = NULL;
- }
+ __wt_txn_visible_all(session, page_del->txnid)))
+ WT_RET(__wt_ref_block_free(session, ref));
/*
* If the original page is gone, we can skip the slot on the internal
@@ -4790,13 +4778,11 @@ __rec_row_leaf_insert(WT_SESSION_IMPL *session, WT_RECONCILE *r, WT_INSERT *ins)
static int
__rec_split_discard(WT_SESSION_IMPL *session, WT_PAGE *page)
{
- WT_BM *bm;
WT_DECL_RET;
WT_PAGE_MODIFY *mod;
WT_MULTI *multi;
uint32_t i;
- bm = S2BT(session)->bm;
mod = page->modify;
/*
@@ -4816,7 +4802,7 @@ __rec_split_discard(WT_SESSION_IMPL *session, WT_PAGE *page)
if (multi->addr.reuse)
multi->addr.addr = NULL;
else {
- WT_RET(bm->free(bm, session,
+ WT_RET(__wt_btree_block_free(session,
multi->addr.addr, multi->addr.size));
__wt_free(session, multi->addr.addr);
}
@@ -4862,8 +4848,6 @@ __rec_write_wrapup(WT_SESSION_IMPL *session, WT_RECONCILE *r, WT_PAGE *page)
WT_MULTI *multi;
WT_PAGE_MODIFY *mod;
WT_REF *ref;
- size_t addr_size;
- const uint8_t *addr;
btree = S2BT(session);
bm = btree->bm;
@@ -4888,21 +4872,7 @@ __rec_write_wrapup(WT_SESSION_IMPL *session, WT_RECONCILE *r, WT_PAGE *page)
*/
if (__wt_ref_is_root(ref))
break;
- if (ref->addr != NULL) {
- /*
- * Free the page and clear the address (so we don't free
- * it twice).
- */
- WT_RET(__wt_ref_info(
- session, ref, &addr, &addr_size, NULL));
- WT_RET(bm->free(bm, session, addr, addr_size));
- if (__wt_off_page(ref->home, ref->addr)) {
- __wt_free(
- session, ((WT_ADDR *)ref->addr)->addr);
- __wt_free(session, ref->addr);
- }
- ref->addr = NULL;
- }
+ WT_RET(__wt_ref_block_free(session, ref));
break;
case WT_PM_REC_EMPTY: /* Page deleted */
break;
@@ -4921,7 +4891,7 @@ __rec_write_wrapup(WT_SESSION_IMPL *session, WT_RECONCILE *r, WT_PAGE *page)
* are checkpoints, and must be explicitly dropped.
*/
if (!__wt_ref_is_root(ref))
- WT_RET(bm->free(bm, session,
+ WT_RET(__wt_btree_block_free(session,
mod->mod_replace.addr, mod->mod_replace.size));
/* Discard the replacement page's address. */
@@ -5126,14 +5096,12 @@ err: __wt_scr_free(session, &tkey);
static int
__rec_write_wrapup_err(WT_SESSION_IMPL *session, WT_RECONCILE *r, WT_PAGE *page)
{
- WT_BM *bm;
WT_BOUNDARY *bnd;
WT_DECL_RET;
WT_MULTI *multi;
WT_PAGE_MODIFY *mod;
uint32_t i;
- bm = S2BT(session)->bm;
mod = page->modify;
/*
@@ -5164,7 +5132,7 @@ __rec_write_wrapup_err(WT_SESSION_IMPL *session, WT_RECONCILE *r, WT_PAGE *page)
if (bnd->addr.reuse)
bnd->addr.addr = NULL;
else {
- WT_TRET(bm->free(bm, session,
+ WT_TRET(__wt_btree_block_free(session,
bnd->addr.addr, bnd->addr.size));
__wt_free(session, bnd->addr.addr);
}
diff --git a/src/third_party/wiredtiger/src/txn/txn.c b/src/third_party/wiredtiger/src/txn/txn.c
index eb2b621f315..f9af9589172 100644
--- a/src/third_party/wiredtiger/src/txn/txn.c
+++ b/src/third_party/wiredtiger/src/txn/txn.c
@@ -597,6 +597,9 @@ __wt_txn_global_init(WT_SESSION_IMPL *session, const char *cfg[])
txn_global->current = txn_global->last_running =
txn_global->oldest_id = WT_TXN_FIRST;
+ WT_RET(__wt_spin_init(session,
+ &txn_global->id_lock, "transaction id lock"));
+
WT_RET(__wt_calloc_def(
session, conn->session_size, &txn_global->states));
for (i = 0, s = txn_global->states; i < conn->session_size; i++, s++)
@@ -618,6 +621,6 @@ __wt_txn_global_destroy(WT_SESSION_IMPL *session)
conn = S2C(session);
txn_global = &conn->txn_global;
- if (txn_global != NULL)
- __wt_free(session, txn_global->states);
+ __wt_spin_destroy(session, &txn_global->id_lock);
+ __wt_free(session, txn_global->states);
}