diff options
author | Michael Cahill <michael.cahill@mongodb.com> | 2016-08-02 16:42:36 +1000 |
---|---|---|
committer | Michael Cahill <michael.cahill@mongodb.com> | 2016-08-02 16:55:09 +1000 |
commit | 1607e9204c3be422adcb293cfdc64a567c5c9987 (patch) | |
tree | 0641e338fa35e0f0a866ec24d5de4e4215660642 | |
parent | 0e2688962045ecd11309f5175b77b7fb5fce7f44 (diff) | |
download | mongo-1607e9204c3be422adcb293cfdc64a567c5c9987.tar.gz |
WT-2804 Don't read values in a tree without a snapshot. (#2924)
* Improve an assertion from WT-2802 that checks that we don't try to copy values from a cursor without a transaction pinned.
* Copy cursor values before rollback in autocommit.
If an autocommit operation such as WT_CURSOR::update touches multiple trees (e.g., multiple column groups in a table, or index updates, or multiple chunks in an LSM tree), then some cursors may have consumed the application's key/value pair when the operation has to roll back. Take a copy of any such values before attempting to retry the operation.
(cherry picked from commit 41eb2dcaac1ff25654d1503f5e29714576ff8d81)
-rw-r--r-- | src/include/api.h | 2 | ||||
-rw-r--r-- | src/session/session_api.c | 12 |
2 files changed, 10 insertions, 4 deletions
diff --git a/src/include/api.h b/src/include/api.h index 4514f5a42fa..86e560ced78 100644 --- a/src/include/api.h +++ b/src/include/api.h @@ -66,6 +66,8 @@ else if (ret == 0 && !F_ISSET(&(s)->txn, WT_TXN_ERROR)) \ ret = __wt_txn_commit((s), NULL); \ else { \ + if (retry) \ + WT_TRET(__wt_session_copy_values(s)); \ WT_TRET(__wt_txn_rollback((s), NULL)); \ if ((ret == 0 || ret == WT_ROLLBACK) && \ (retry)) { \ diff --git a/src/session/session_api.c b/src/session/session_api.c index cfd4c13ab2d..dffd832672e 100644 --- a/src/session/session_api.c +++ b/src/session/session_api.c @@ -43,10 +43,14 @@ __wt_session_copy_values(WT_SESSION_IMPL *session) TAILQ_FOREACH(cursor, &session->cursors, q) if (F_ISSET(cursor, WT_CURSTD_VALUE_INT)) { - /* We have to do this with a transaction ID pinned. */ - WT_ASSERT(session, - WT_SESSION_TXN_STATE(session)->snap_min != - WT_TXN_NONE); +#ifdef HAVE_DIAGNOSTIC + /* + * We have to do this with a transaction ID pinned + * unless the cursor is reading from a checkpoint. + */ + WT_TXN_STATE *txn_state = WT_SESSION_TXN_STATE(session); + WT_ASSERT(session, txn_state->snap_min != WT_TXN_NONE); +#endif F_CLR(cursor, WT_CURSTD_VALUE_INT); WT_RET(__wt_buf_set(session, &cursor->value, |