summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Cahill <michael.cahill@mongodb.com>2016-08-02 16:42:36 +1000
committerMichael Cahill <michael.cahill@mongodb.com>2016-08-02 16:55:09 +1000
commit1607e9204c3be422adcb293cfdc64a567c5c9987 (patch)
tree0641e338fa35e0f0a866ec24d5de4e4215660642
parent0e2688962045ecd11309f5175b77b7fb5fce7f44 (diff)
downloadmongo-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.h2
-rw-r--r--src/session/session_api.c12
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,