summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Cahill <michael.cahill@mongodb.com>2016-08-02 16:42:36 +1000
committerGitHub <noreply@github.com>2016-08-02 16:42:36 +1000
commit41eb2dcaac1ff25654d1503f5e29714576ff8d81 (patch)
treebef258cc1a9dd133ad750ae2b0de9860e0cdbbff
parent8f02a158b584534fc698cf93cefae85727db902b (diff)
downloadmongo-41eb2dcaac1ff25654d1503f5e29714576ff8d81.tar.gz
WT-2804 Don't read values in a tree without a snapshot. (#2924)
* Improve two recent assertions, one from WT-2798 relating to writing metadata updates to disk that are part of a running transaction, and another from WT-2802 that checks that we don't try to copy values from a cursor without a transaction pinned. The latter doesn't apply to cursors on checkpoints (including chunk cursors in an LSM tree). * 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.
-rw-r--r--src/include/api.h2
-rw-r--r--src/reconcile/rec_write.c6
-rw-r--r--src/session/session_api.c14
3 files changed, 15 insertions, 7 deletions
diff --git a/src/include/api.h b/src/include/api.h
index 50b2eab83b8..0a4593178dc 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/reconcile/rec_write.c b/src/reconcile/rec_write.c
index 0a14c027da7..b96b34594b0 100644
--- a/src/reconcile/rec_write.c
+++ b/src/reconcile/rec_write.c
@@ -1152,15 +1152,17 @@ __rec_txn_read(WT_SESSION_IMPL *session, WT_RECONCILE *r,
if (!skipped &&
(F_ISSET(btree, WT_BTREE_LOOKASIDE) ||
__wt_txn_visible_all(session, max_txn))) {
+#ifdef HAVE_DIAGNOSTIC
/*
* The checkpoint transaction is special. Make sure we never
* write (metadata) updates from a checkpoint in a concurrent
* session.
*/
- WT_ASSERT(session, *updp == NULL ||
- (txnid = (*updp)->txnid) == WT_TXN_NONE ||
+ txnid = *updp == NULL ? WT_TXN_NONE : (*updp)->txnid;
+ WT_ASSERT(session, txnid == WT_TXN_NONE ||
txnid != S2C(session)->txn_global.checkpoint_txnid ||
WT_SESSION_IS_CHECKPOINT(session));
+#endif
return (0);
}
diff --git a/src/session/session_api.c b/src/session/session_api.c
index dd5acdbbf56..752fafffda5 100644
--- a/src/session/session_api.c
+++ b/src/session/session_api.c
@@ -66,11 +66,15 @@ __wt_session_copy_values(WT_SESSION_IMPL *session)
TAILQ_FOREACH(cursor, &session->cursors, q)
if (F_ISSET(cursor, WT_CURSTD_VALUE_INT)) {
-#if 0 /* !!! LSM updates can violate this assertion. */
- /* 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 ||
+ (WT_PREFIX_MATCH(cursor->uri, "file:") &&
+ F_ISSET((WT_CURSOR_BTREE *)cursor, WT_CBT_NO_TXN)));
#endif
F_CLR(cursor, WT_CURSTD_VALUE_INT);