summaryrefslogtreecommitdiff
path: root/src/third_party/wiredtiger/src/txn/txn.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/third_party/wiredtiger/src/txn/txn.c')
-rw-r--r--src/third_party/wiredtiger/src/txn/txn.c56
1 files changed, 44 insertions, 12 deletions
diff --git a/src/third_party/wiredtiger/src/txn/txn.c b/src/third_party/wiredtiger/src/txn/txn.c
index 53bde4a499b..f7c94399710 100644
--- a/src/third_party/wiredtiger/src/txn/txn.c
+++ b/src/third_party/wiredtiger/src/txn/txn.c
@@ -804,13 +804,13 @@ __wt_txn_commit(WT_SESSION_IMPL *session, const char *cfg[])
int64_t resolved_update_count, visited_update_count;
uint32_t fileid;
u_int i;
- bool locked, prepare, readonly, update_timestamp;
+ bool locked, prepare, readonly, skip_update_assert, update_timestamp;
txn = &session->txn;
conn = S2C(session);
txn_global = &conn->txn_global;
prev_commit_timestamp = 0; /* -Wconditional-uninitialized */
- locked = false;
+ locked = skip_update_assert = false;
resolved_update_count = visited_update_count = 0;
WT_ASSERT(session, F_ISSET(txn, WT_TXN_RUNNING));
@@ -843,7 +843,7 @@ __wt_txn_commit(WT_SESSION_IMPL *session, const char *cfg[])
"transaction");
WT_ASSERT(session,
- txn->prepare_timestamp <= txn->commit_timestamp);
+ txn->prepare_timestamp <= txn->commit_timestamp);
} else {
if (F_ISSET(txn, WT_TXN_HAS_TS_PREPARE))
WT_ERR_MSG(session, EINVAL,
@@ -987,10 +987,15 @@ __wt_txn_commit(WT_SESSION_IMPL *session, const char *cfg[])
* it would have happened on a previous
* modification in this txn.
*/
- if (!F_ISSET(op, WT_TXN_OP_KEY_REPEATED))
+ if (!F_ISSET(op, WT_TXN_OP_KEY_REPEATED)) {
+ skip_update_assert =
+ skip_update_assert ||
+ F_ISSET(op, WT_TXN_OP_KEY_RESERVED);
WT_ERR(__wt_txn_resolve_prepared_op(
session, op, true,
&resolved_update_count));
+ }
+
/*
* We should resolve at least one or more
* updates each time we call
@@ -1015,7 +1020,8 @@ __wt_txn_commit(WT_SESSION_IMPL *session, const char *cfg[])
__wt_txn_op_free(session, op);
}
- WT_ASSERT(session, resolved_update_count == visited_update_count);
+ WT_ASSERT(session, skip_update_assert ||
+ resolved_update_count == visited_update_count);
WT_STAT_CONN_INCRV(session, txn_prepared_updates_resolved,
resolved_update_count);
@@ -1123,8 +1129,14 @@ __wt_txn_prepare(WT_SESSION_IMPL *session, const char *cfg[])
WT_RET(__wt_session_copy_values(session));
}
- /* Prepare updates. */
- for (i = 0, op = txn->mod; i < txn->mod_count; i++, op++) {
+ /*
+ * Prepare updates, traverse the modification array in reverse order
+ * so that we visit the update chain in newest to oldest order
+ * allowing us to set the key repeated flag with reserved updates in
+ * the chain.
+ */
+ for (i = txn->mod_count; i > 0; i--) {
+ op = &txn->mod[i - 1];
/* Assert it's not an update to the lookaside file. */
WT_ASSERT(session, S2C(session)->cache->las_fileid == 0 ||
!F_ISSET(op->btree, WT_BTREE_LOOKASIDE));
@@ -1165,9 +1177,23 @@ __wt_txn_prepare(WT_SESSION_IMPL *session, const char *cfg[])
* Set the key repeated flag which tells us that we've
* got multiple updates to the same key by the same txn.
* This is later used in txn commit.
+ *
+ * When we see a reserved update we set the
+ * WT_UPDATE_RESERVED flag instead. We do this as we
+ * cannot know if our current update should specify the
+ * key repeated flag as we don't want to traverse the
+ * entire update chain to find out. i.e. if there is
+ * an update with our txnid after the reserved update
+ * we should set key repeated, but if there isn't we
+ * shouldn't.
*/
- if (upd->next != NULL && upd->txnid == upd->next->txnid)
- F_SET(op, WT_TXN_OP_KEY_REPEATED);
+ if (upd->next != NULL &&
+ upd->txnid == upd->next->txnid) {
+ if (upd->next->type == WT_UPDATE_RESERVE)
+ F_SET(op, WT_TXN_OP_KEY_RESERVED);
+ else
+ F_SET(op, WT_TXN_OP_KEY_REPEATED);
+ }
break;
case WT_TXN_OP_REF_DELETE:
__wt_txn_op_apply_prepare_state(
@@ -1209,12 +1235,13 @@ __wt_txn_rollback(WT_SESSION_IMPL *session, const char *cfg[])
WT_UPDATE *upd;
int64_t resolved_update_count, visited_update_count;
u_int i;
- bool readonly;
+ bool readonly, skip_update_assert;
WT_UNUSED(cfg);
resolved_update_count = visited_update_count = 0;
txn = &session->txn;
readonly = txn->mod_count == 0;
+ skip_update_assert = false;
WT_ASSERT(session, F_ISSET(txn, WT_TXN_RUNNING));
/* Rollback notification. */
@@ -1254,10 +1281,14 @@ __wt_txn_rollback(WT_SESSION_IMPL *session, const char *cfg[])
* it would have happened on a previous
* modification in this txn.
*/
- if (!F_ISSET(op, WT_TXN_OP_KEY_REPEATED))
+ if (!F_ISSET(op, WT_TXN_OP_KEY_REPEATED)) {
+ skip_update_assert =
+ skip_update_assert ||
+ F_ISSET(op, WT_TXN_OP_KEY_RESERVED);
WT_RET(__wt_txn_resolve_prepared_op(
session, op, false,
&resolved_update_count));
+ }
/*
* We should resolve at least one or more
* updates each time we call
@@ -1290,7 +1321,8 @@ __wt_txn_rollback(WT_SESSION_IMPL *session, const char *cfg[])
__wt_txn_op_free(session, op);
}
- WT_ASSERT(session, resolved_update_count == visited_update_count);
+ WT_ASSERT(session, skip_update_assert ||
+ resolved_update_count == visited_update_count);
WT_STAT_CONN_INCRV(session, txn_prepared_updates_resolved,
resolved_update_count);