diff --git a/src/btree/bt_discard.c b/src/btree/bt_discard.c
index bfa8eb2..e26cb9e 100644
--- a/src/btree/bt_discard.c
+++ b/src/btree/bt_discard.c
@@ -457,8 +457,11 @@ void
 __wt_free_update_list(WT_SESSION_IMPL *session, WT_UPDATE *upd)
 {
 	WT_UPDATE *next;
+	WT_TXN_STATE *checkpoint_state =
+	    &S2C(session)->txn_global.checkpoint_state;
 
 	for (; upd != NULL; upd = next) {
+		WT_ASSERT(session, checkpoint_state->pinned_id == WT_TXN_NONE || __wt_timestamp_cmp(checkpoint_state->read_timestamp, upd->timestamp) > 0);
 		next = upd->next;
 		__wt_free(session, upd);
 	}
diff --git a/src/include/txn.h b/src/include/txn.h
index bf2d9aa..5950dee 100644
--- a/src/include/txn.h
+++ b/src/include/txn.h
@@ -69,7 +69,7 @@ struct __wt_named_snapshot {
 
 struct __wt_txn_state {
 	WT_CACHE_LINE_PAD_BEGIN
-	WT_RWLOCK rwlock;
+
 	volatile uint64_t id;
 	volatile uint64_t pinned_id;
 	volatile uint64_t metadata_pinned;
diff --git a/src/txn/txn.c b/src/txn/txn.c
index 02adad6..81d355a 100644
--- a/src/txn/txn.c
+++ b/src/txn/txn.c
@@ -518,6 +518,9 @@ __wt_txn_release(WT_SESSION_IMPL *session)
 		txn->id = txn_global->checkpoint_state.id =
 		    txn_global->checkpoint_state.pinned_id = WT_TXN_NONE;
 
+		WT_ASSERT(session, __wt_timestamp_iszero(txn->read_timestamp) ||
+		    __wt_timestamp_cmp(txn_global->pinned_timestamp, txn->read_timestamp) <= 0);
+
 		/*
 		 * Be extra careful to cleanup everything for checkpoints: once
 		 * the global checkpoint ID is cleared, we can no longer tell
@@ -701,9 +704,15 @@ __wt_txn_commit(WT_SESSION_IMPL *session, const char *cfg[])
 
 #ifdef HAVE_TIMESTAMPS
 			if (F_ISSET(txn, WT_TXN_HAS_TS_COMMIT) &&
-			    op->type != WT_TXN_OP_BASIC_TS)
+			    op->type != WT_TXN_OP_BASIC_TS) {
+				WT_UPDATE *next = op->u.upd->next;
+				WT_ASSERT(session, next == NULL ||
+				    next->txnid == WT_TXN_ABORTED ||
+				    __wt_timestamp_cmp(txn->commit_timestamp,
+				    next->timestamp) >= 0);
 				__wt_timestamp_set(op->u.upd->timestamp,
 				    txn->commit_timestamp);
+			}
 #endif
 			break;
 
diff --git a/src/txn/txn_timestamp.c b/src/txn/txn_timestamp.c
index ebef032..245b6e1 100644
--- a/src/txn/txn_timestamp.c
+++ b/src/txn/txn_timestamp.c
@@ -115,10 +115,13 @@ __txn_global_query_timestamp(
 			__wt_timestamp_set(ts, s->read_timestamp);
 		WT_ORDERED_READ(session_cnt, conn->session_cnt);
 		for (i = 0, s = txn_global->states; i < session_cnt; i++, s++) {
-			if (s->pinned_id == WT_TXN_NONE ||
-			    __wt_timestamp_iszero(s->read_timestamp))
+			if (s->pinned_id == WT_TXN_NONE)
 				continue;
-			if (__wt_timestamp_cmp(s->read_timestamp, ts) < 0)
+			if (!__wt_timestamp_iszero(s->commit_timestamp) &&
+			    __wt_timestamp_cmp(s->commit_timestamp, ts) < 0)
+				__wt_timestamp_set(ts, s->commit_timestamp);
+			if (!__wt_timestamp_iszero(s->read_timestamp) &&
+			    __wt_timestamp_cmp(s->read_timestamp, ts) < 0)
 				__wt_timestamp_set(ts, s->read_timestamp);
 		}
 		__wt_readunlock(session, &txn_global->rwlock);
@@ -281,9 +284,16 @@ __wt_txn_set_timestamp(WT_SESSION_IMPL *session, const char *cfg[])
 		WT_TXN *txn = &session->txn;
 		WT_TXN_GLOBAL *txn_global = &S2C(session)->txn_global;
 		WT_TXN_STATE *txn_state = WT_SESSION_TXN_STATE(session);
+		wt_timestamp_t oldest_timestamp;
 
 		WT_RET(__wt_txn_parse_timestamp(
 		    session, "commit", txn->commit_timestamp, &cval));
+		__wt_readlock(session, &txn_global->rwlock);
+		__wt_timestamp_set(
+		    oldest_timestamp, txn_global->oldest_timestamp);
+		__wt_readunlock(session, &txn_global->rwlock);
+		WT_ASSERT(session, __wt_timestamp_cmp(
+		    oldest_timestamp, txn->commit_timestamp) < 0);
 		if (!F_ISSET(txn, WT_TXN_HAS_TS_COMMIT)) {
 			__wt_writelock(session, &txn_global->rwlock);
 			__wt_timestamp_set(txn_state->commit_timestamp,
diff --git a/test/checkpoint/checkpointer.c b/test/checkpoint/checkpointer.c
index c735c03..b8c5468 100644
--- a/test/checkpoint/checkpointer.c
+++ b/test/checkpoint/checkpointer.c
@@ -83,6 +83,7 @@ static int
 real_checkpointer(void)
 {
 	WT_SESSION *session;
+	uint64_t ts;
 	char *checkpoint_config, _buf[128];
 	int ret;
 
@@ -103,16 +104,32 @@ real_checkpointer(void)
 			testutil_check(__wt_snprintf(
 			    _buf, sizeof(_buf), "name=%s", g.checkpoint_name));
 
-		if (g.use_timestamps && g.timestamp > 0)
+		/*
+		 * Prevent the oldest timestamp moving forward during the
+		 * checkpoint.  The internal "read_timestamp" interface relies
+		 * on the timestamp staying valid for the duration of the
+		 * checkpoint.
+		 */
+		__wt_spin_lock((WT_SESSION_IMPL *)session, &g.checkpoint_lock);
+
+		if (g.use_timestamps) {
+			ts = __wt_atomic_add64(&g.timestamp, 1);
 			testutil_check(__wt_snprintf(
 			    _buf + strlen(_buf), sizeof(_buf) - strlen(_buf),
-			    ",read_timestamp=%" PRIx64, g.timestamp));
+			    ",read_timestamp=%" PRIx64, ts));
+
+			/* Wait for active transactions to drain. */
+			__wt_writelock((WT_SESSION_IMPL *)session, &g.txn_active);
+			__wt_writeunlock((WT_SESSION_IMPL *)session, &g.txn_active);
+		}
 
 		checkpoint_config = strlen(_buf) > 0 ? _buf : NULL;
 		/* Execute a checkpoint */
 		if ((ret = session->checkpoint(
 		    session, checkpoint_config)) != 0)
 			return (log_print_err("session.checkpoint", ret, 1));
+
+		__wt_spin_unlock((WT_SESSION_IMPL *)session, &g.checkpoint_lock);
 		printf("Finished a checkpoint\n");
 
 		if (!g.running)
diff --git a/test/checkpoint/test_checkpoint.c b/test/checkpoint/test_checkpoint.c
index 2ee5aa9..6786ecb 100644
--- a/test/checkpoint/test_checkpoint.c
+++ b/test/checkpoint/test_checkpoint.c
@@ -207,6 +207,18 @@ wt_connect(const char *config_open)
 	if ((ret = wiredtiger_open(
 	    g.home, &event_handler, config, &g.conn)) != 0)
 		return (log_print_err("wiredtiger_open", ret, 1));
+
+	testutil_check(g.conn->open_session(
+	    g.conn, NULL, NULL, &g.wt_session));
+	g.session = (WT_SESSION_IMPL *)g.wt_session;
+
+	/* Initialize the locks. */
+	testutil_check(__wt_spin_init(
+	    g.session, &g.checkpoint_lock, "checkpoint"));
+	testutil_check(__wt_spin_init(
+	    g.session, &g.commit_lock, "commit"));
+	testutil_check(__wt_rwlock_init(g.session, &g.txn_active));
+
 	return (0);
 }
 
@@ -222,6 +234,10 @@ wt_shutdown(void)
 	if (g.conn == NULL)
 		return (0);
 
+	__wt_spin_destroy(g.session, &g.checkpoint_lock);
+	__wt_spin_destroy(g.session, &g.commit_lock);
+	__wt_rwlock_destroy(g.session, &g.txn_active);
+
 	printf("Closing connection\n");
 	ret = g.conn->close(g.conn, NULL);
 	g.conn = NULL;
diff --git a/test/checkpoint/test_checkpoint.h b/test/checkpoint/test_checkpoint.h
index 3737131..ceb733b 100644
--- a/test/checkpoint/test_checkpoint.h
+++ b/test/checkpoint/test_checkpoint.h
@@ -55,10 +55,17 @@ typedef struct {
 	char *home;				/* Home directory */
 	const char *checkpoint_name;		/* Checkpoint name */
 	WT_CONNECTION *conn;			/* WiredTiger connection */
+	WT_SESSION *wt_session;			/* WiredTiger session */
+	WT_SESSION_IMPL *session;		/* Internal session */
 	u_int nkeys;				/* Keys to load */
 	u_int nops;				/* Operations per thread */
 	uint64_t timestamp;			/* Current timestamp */
 	bool use_timestamps;			/* Test with timestamps */
+	WT_RWLOCK txn_active;			/* Held (read) while txns
+						   running. */
+	WT_SPINLOCK checkpoint_lock;		/* Protect timestamp
+						   for checkpoints */
+	WT_SPINLOCK commit_lock;		/* Make commits serial */
 	FILE *logfp;				/* Message log file. */
 	int nworkers;				/* Number workers configured */
 	int ntables;				/* Number tables configured */
diff --git a/test/checkpoint/workers.c b/test/checkpoint/workers.c
index 8d6d2c5..cddc06a 100644
--- a/test/checkpoint/workers.c
+++ b/test/checkpoint/workers.c
@@ -130,7 +130,7 @@ worker_op(WT_CURSOR *cursor, uint64_t keyno, u_int new_val)
 	    valuebuf, sizeof(valuebuf), "%037u", new_val));
 	cursor->set_value(cursor, valuebuf);
 	if ((ret = cursor->insert(cursor)) != 0) {
-		if (ret == WT_ROLLBACK)
+		if (ret == WT_DUPLICATE_KEY || ret == WT_ROLLBACK)
 			return (WT_ROLLBACK);
 		return (log_print_err("cursor.insert", ret, 1));
 	}
@@ -172,6 +172,7 @@ real_worker(void)
 	char config_buf[64];
 
 	ret = t_ret = 0;
+	ts = 0;
 
 	__wt_random_init(&rnd);
 
@@ -187,12 +188,19 @@ real_worker(void)
 
 	for (j = 0; j < g.ntables; j++)
 		if ((ret = session->open_cursor(session,
-		    g.cookies[j].uri, NULL, NULL, &cursors[j])) != 0) {
+		    g.cookies[j].uri, NULL,
+#if 0
+		    g.use_timestamps ? "overwrite=false" : NULL,
+#else
+		    NULL,
+#endif
+		    &cursors[j])) != 0) {
 			(void)log_print_err("session.open_cursor", ret, 1);
 			goto err;
 		}
 
 	for (i = 0; i < g.nops && g.running; ++i, __wt_yield()) {
+		__wt_readlock((WT_SESSION_IMPL *)session, &g.txn_active);
 		if ((ret = session->begin_transaction(session, NULL)) != 0) {
 			(void)log_print_err(
 			    "real_worker:begin_transaction", ret, 1);
@@ -205,26 +213,24 @@ real_worker(void)
 		}
 		if (ret == 0) {
 			if (g.use_timestamps) {
+				__wt_spin_lock((WT_SESSION_IMPL *)session,
+				    &g.commit_lock);
 				ts = __wt_atomic_add64(&g.timestamp, 1);
-				if (ts > 100 && ts % 100 == 0) {
-					testutil_check(__wt_snprintf(
-					    config_buf, sizeof(config_buf),
-					    "oldest_timestamp=%" PRIx64,
-					    ts - 100));
-					testutil_check(g.conn->set_timestamp(
-					    g.conn, config_buf));
-				}
 				testutil_check(__wt_snprintf(
 				    config_buf, sizeof(config_buf),
 				    "commit_timestamp=%" PRIx64, ts));
+				testutil_check(session->timestamp_transaction(
+				    session, config_buf));
+				__wt_spin_unlock((WT_SESSION_IMPL *)session,
+				    &g.commit_lock);
 			}
 
-			if ((ret = session->commit_transaction(session,
-			    g.use_timestamps ? config_buf : NULL)) != 0) {
+			if ((ret = session->commit_transaction(
+			    session, NULL)) != 0) {
 				(void)log_print_err(
 				    "real_worker:commit_transaction", ret, 1);
 				goto err;
-			    }
+			}
 		} else if (ret == WT_ROLLBACK) {
 			if ((ret = session->rollback_transaction(
 			    session, NULL)) != 0) {
@@ -236,6 +242,25 @@ real_worker(void)
 			(void)log_print_err("worker op failed", ret, 1);
 			goto err;
 		}
+
+		__wt_readunlock((WT_SESSION_IMPL *)session, &g.txn_active);
+
+#if 0
+		if (g.use_timestamps && ts > 100 && ts % 100 == 0 &&
+		    __wt_spin_trylock((WT_SESSION_IMPL *)session,
+		    &g.checkpoint_lock) == 0) {
+			/* Wait for concurrent transactions to drain. */
+			__wt_writelock((WT_SESSION_IMPL *)session, &g.txn_active);
+			__wt_writeunlock((WT_SESSION_IMPL *)session, &g.txn_active);
+
+			testutil_check(__wt_snprintf(
+			    config_buf, sizeof(config_buf),
+			    "oldest_timestamp=%" PRIx64, ts));
+			testutil_check(g.conn->set_timestamp(
+			    g.conn, config_buf));
+			__wt_spin_unlock((WT_SESSION_IMPL *)session, &g.checkpoint_lock);
+		}
+#endif
 	}
 
 err:	if ((t_ret = session->close(session, NULL)) != 0 && ret == 0) {
