diff options
Diffstat (limited to 'src/third_party/wiredtiger/src/txn/txn.c')
-rw-r--r-- | src/third_party/wiredtiger/src/txn/txn.c | 56 |
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); |