summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorsueloverso <sue@mongodb.com>2017-08-11 07:06:33 -0400
committerGitHub <noreply@github.com>2017-08-11 07:06:33 -0400
commit80c6cee91faf84c4772a98c40e60d0a6890ccb52 (patch)
tree15bcf5f8f5c64eaba452360817a3fe67cc71b0b0
parentf85cd47fb290b4a3939714f52f5232a33da26e21 (diff)
downloadmongo-80c6cee91faf84c4772a98c40e60d0a6890ccb52.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.
-rw-r--r--src/include/txn.h3
-rw-r--r--src/txn/txn.c17
-rw-r--r--src/txn/txn_log.c11
3 files changed, 30 insertions, 1 deletions
diff --git a/src/include/txn.h b/src/include/txn.h
index 61ab343151c..f3e377b3380 100644
--- a/src/include/txn.h
+++ b/src/include/txn.h
@@ -105,6 +105,9 @@ struct __wt_txn_global {
/* Protects the active transaction states. */
WT_RWLOCK rwlock;
+ /* Protects logging, checkpoints and transaction visibility. */
+ WT_RWLOCK visibility_rwlock;
+
/* List of transactions sorted by commit timestamp. */
WT_RWLOCK commit_timestamp_rwlock;
TAILQ_HEAD(__wt_txn_cts_qh, __wt_txn) commit_timestamph;
diff --git a/src/txn/txn.c b/src/txn/txn.c
index 24e7ccff2b1..9d4677a46f6 100644
--- a/src/txn/txn.c
+++ b/src/txn/txn.c
@@ -575,11 +575,12 @@ __wt_txn_commit(WT_SESSION_IMPL *session, const char *cfg[])
bool update_timestamp;
#endif
u_int i;
- bool did_update;
+ bool did_update, locked;
txn = &session->txn;
conn = S2C(session);
did_update = txn->mod_count != 0;
+ locked = false;
WT_ASSERT(session, F_ISSET(txn, WT_TXN_RUNNING));
WT_ASSERT(session, !F_ISSET(txn, WT_TXN_ERROR) || !did_update);
@@ -665,6 +666,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;
WT_ERR(__wt_txn_log_commit(session, cfg));
}
@@ -727,6 +736,8 @@ __wt_txn_commit(WT_SESSION_IMPL *session, const char *cfg[])
#endif
__wt_txn_release(session);
+ if (locked)
+ __wt_readunlock(session, &txn_global->visibility_rwlock);
#ifdef HAVE_TIMESTAMPS
/* First check if we've already committed something in the future. */
@@ -763,6 +774,8 @@ err: /*
* !!!
* Nothing can fail after this point.
*/
+ if (locked)
+ __wt_readunlock(session, &txn_global->visibility_rwlock);
WT_TRET(__wt_txn_rollback(session, cfg));
return (ret);
}
@@ -933,6 +946,7 @@ __wt_txn_global_init(WT_SESSION_IMPL *session, const char *cfg[])
WT_RET(__wt_spin_init(
session, &txn_global->id_lock, "transaction id lock"));
WT_RET(__wt_rwlock_init(session, &txn_global->rwlock));
+ WT_RET(__wt_rwlock_init(session, &txn_global->visibility_rwlock));
WT_RET(__wt_rwlock_init(session, &txn_global->commit_timestamp_rwlock));
TAILQ_INIT(&txn_global->commit_timestamph);
@@ -974,6 +988,7 @@ __wt_txn_global_destroy(WT_SESSION_IMPL *session)
__wt_rwlock_destroy(session, &txn_global->commit_timestamp_rwlock);
__wt_rwlock_destroy(session, &txn_global->read_timestamp_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 1fc74fb53a1..a03047b5392 100644
--- a/src/txn/txn_log.c
+++ b/src/txn/txn_log.c
@@ -357,12 +357,14 @@ __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;
const char *fmt;
conn = S2C(session);
+ txn_global = &conn->txn_global;
txn = &session->txn;
ckpt_lsn = &txn->ckpt_lsn;
@@ -408,6 +410,15 @@ __wt_txn_checkpoint_log(
}
/*
+ * 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.