summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorsueloverso <sue@mongodb.com>2017-08-11 07:06:33 -0400
committerSusan LoVerso <sue@mongodb.com>2017-08-15 13:06:09 -0400
commit3166629c1d7461e329ba88f358aaa7f3d1dc0b5d (patch)
treed894160e7769dbb996658914808d01edd048ef54
parent74510affecfd4c274988a3f7b8e71448492f2103 (diff)
downloadmongo-3166629c1d7461e329ba88f358aaa7f3d1dc0b5d.tar.gz
WT-3499 Add a visibility rwlock between transactions and checkpoints. (#3575)
* WT-3499 Add a visibility rwlock between transactions and checkpoints. * Typo * Just acquire/release the lock immediately for synchronization. (cherry picked from commit 80c6cee91faf84c4772a98c40e60d0a6890ccb52)
-rw-r--r--src/include/txn.h2
-rw-r--r--src/txn/txn.c21
-rw-r--r--src/txn/txn_log.c11
3 files changed, 33 insertions, 1 deletions
diff --git a/src/include/txn.h b/src/include/txn.h
index 7e802c188ab..fdf9c714afa 100644
--- a/src/include/txn.h
+++ b/src/include/txn.h
@@ -93,6 +93,8 @@ struct __wt_txn_global {
* the global transaction state.
*/
WT_RWLOCK scan_rwlock;
+ /* Protects logging, checkpoints and transaction visibility. */
+ WT_RWLOCK visibility_rwlock;
/*
* Track information about the running checkpoint. The transaction
diff --git a/src/txn/txn.c b/src/txn/txn.c
index ea7faa2e966..7665ba56adc 100644
--- a/src/txn/txn.c
+++ b/src/txn/txn.c
@@ -503,13 +503,17 @@ __wt_txn_commit(WT_SESSION_IMPL *session, const char *cfg[])
WT_CONNECTION_IMPL *conn;
WT_DECL_RET;
WT_TXN *txn;
+ WT_TXN_GLOBAL *txn_global;
WT_TXN_OP *op;
u_int i;
- bool did_update;
+ bool did_update, locked;
txn = &session->txn;
conn = S2C(session);
+ txn_global = &conn->txn_global;
did_update = txn->mod_count != 0;
+ locked = false;
+
WT_ASSERT(session, !F_ISSET(txn, WT_TXN_ERROR) || !did_update);
if (!F_ISSET(txn, WT_TXN_RUNNING))
@@ -580,6 +584,14 @@ __wt_txn_commit(WT_SESSION_IMPL *session, const char *cfg[])
* This is particularly important for checkpoints.
*/
__wt_txn_release_snapshot(session);
+ /*
+ * We hold the visibility lock for reading from the time
+ * we write our log record until the time we release our
+ * transaction so that the LSN any checkpoint gets will
+ * always reflect visible data.
+ */
+ __wt_readlock(session, &txn_global->visibility_rwlock);
+ locked = true;
ret = __wt_txn_log_commit(session, cfg);
}
@@ -590,6 +602,9 @@ __wt_txn_commit(WT_SESSION_IMPL *session, const char *cfg[])
* Nothing can fail after this point.
*/
if (ret != 0) {
+ if (locked)
+ __wt_readunlock(session,
+ &txn_global->visibility_rwlock);
WT_TRET(__wt_txn_rollback(session, cfg));
return (ret);
}
@@ -600,6 +615,8 @@ __wt_txn_commit(WT_SESSION_IMPL *session, const char *cfg[])
txn->mod_count = 0;
__wt_txn_release(session);
+ if (locked)
+ __wt_readunlock(session, &txn_global->visibility_rwlock);
return (0);
}
@@ -770,6 +787,7 @@ __wt_txn_global_init(WT_SESSION_IMPL *session, const char *cfg[])
&txn_global->id_lock, "transaction id lock"));
WT_RET(__wt_rwlock_init(session, &txn_global->scan_rwlock));
WT_RET(__wt_rwlock_init(session, &txn_global->nsnap_rwlock));
+ WT_RET(__wt_rwlock_init(session, &txn_global->visibility_rwlock));
txn_global->nsnap_oldest_id = WT_TXN_NONE;
TAILQ_INIT(&txn_global->nsnaph);
@@ -801,6 +819,7 @@ __wt_txn_global_destroy(WT_SESSION_IMPL *session)
__wt_spin_destroy(session, &txn_global->id_lock);
__wt_rwlock_destroy(session, &txn_global->scan_rwlock);
__wt_rwlock_destroy(session, &txn_global->nsnap_rwlock);
+ __wt_rwlock_destroy(session, &txn_global->visibility_rwlock);
__wt_free(session, txn_global->states);
}
diff --git a/src/txn/txn_log.c b/src/txn/txn_log.c
index 2931dc1ce82..cb3b3436786 100644
--- a/src/txn/txn_log.c
+++ b/src/txn/txn_log.c
@@ -294,11 +294,13 @@ __wt_txn_checkpoint_log(
WT_ITEM *ckpt_snapshot, empty;
WT_LSN *ckpt_lsn;
WT_TXN *txn;
+ WT_TXN_GLOBAL *txn_global;
uint8_t *end, *p;
size_t recsize;
uint32_t i, rectype = WT_LOGREC_CHECKPOINT;
const char *fmt = WT_UNCHECKED_STRING(IIIIu);
+ txn_global = &S2C(session)->txn_global;
txn = &session->txn;
ckpt_lsn = &txn->ckpt_lsn;
@@ -320,6 +322,15 @@ __wt_txn_checkpoint_log(
txn->full_ckpt = true;
WT_ERR(__wt_log_flush_lsn(session, ckpt_lsn, true));
/*
+ * We take and immediately release the visibility lock.
+ * Acquiring the write lock guarantees that any transaction
+ * that has written to the log has also made its transaction
+ * visible at this time.
+ */
+ __wt_writelock(session, &txn_global->visibility_rwlock);
+ __wt_writeunlock(session, &txn_global->visibility_rwlock);
+
+ /*
* We need to make sure that the log records in the checkpoint
* LSN are on disk. In particular to make sure that the
* current log file exists.