diff --git a/ft/cachetable.c b/ft/cachetable.c
index 33d1e41ce38d7a471f340d993026eb9661f16ea1..110af5fa6fdc2101133bd36bd0d5a6306ef7f28c 100644
--- a/ft/cachetable.c
+++ b/ft/cachetable.c
@@ -3068,8 +3068,7 @@ log_open_txn (OMTVALUE txnv, u_int32_t UU(index), void *extra) {
     FILENUMS open_filenums;
     uint32_t num_filenums = toku_omt_size(txn->open_fts);
     FILENUM array[num_filenums];
-    if (!txn->begin_was_logged) {
-        invariant(num_filenums == 0);
+    if (toku_txn_is_read_only(txn)) {
         goto cleanup;
     }
     else {
diff --git a/ft/txn.c b/ft/txn.c
index b05e21a38979eeb08ae9eeb412ca671e3e0dfdb5..67c32eb2069661e23bb7aa739aa06cd003b6bfda 100644
--- a/ft/txn.c
+++ b/ft/txn.c
@@ -349,7 +349,10 @@ static void copy_xid (TOKU_XA_XID *dest, TOKU_XA_XID *source) {
 int toku_txn_prepare_txn (TOKUTXN txn, TOKU_XA_XID *xa_xid) {
     int r = 0;
     if (txn->parent || toku_txn_is_read_only(txn)) {
-        // nothing to do if there's a parent, or if it's read-only
+        // We do not prepare children.
+        //
+        // Readonly transactions do the same if they commit or abort, so
+        // XA guarantees are free.  No need to pay for overhead of prepare.
         goto cleanup;
     }
     toku_txn_manager_add_prepared_txn(txn->logger->txn_manager, txn);
diff --git a/ft/txn_manager.c b/ft/txn_manager.c
index 1a00697ba5d42021d784291fc77d5f85b2a46736..b7cf89a006c4db0716b5d46a5651e0b514d993b4 100644
--- a/ft/txn_manager.c
+++ b/ft/txn_manager.c
@@ -551,7 +551,7 @@ void toku_txn_manager_finish_txn(TXN_MANAGER txn_manager, TOKUTXN txn) {
         r = toku_omt_delete_at(txn_manager->live_root_txns, idx);
         invariant_zero(r);
 
-        if (txn->begin_was_logged || garbage_collection_debug) {
+        if (!toku_txn_is_read_only(txn) || garbage_collection_debug) {
             if (!is_snapshot) {
                 // If it's a snapshot, we already calculated index_in_snapshot_txnids.
                 // Otherwise, calculate it now.
@@ -693,7 +693,14 @@ static void invalidate_xa_xid (TOKU_XA_XID *xid) {
 }
 
 void toku_txn_manager_note_abort_txn(TXN_MANAGER txn_manager, TOKUTXN txn) {
+    // Purpose:
+    //  Delay until any indexer is done pinning this transaction.
+    //  Update status of a transaction from live->aborting (or prepared->aborting)
+    //  Do so in a thread-safe manner that does not conflict with hot indexing or
+    //  begin checkpoint.
     if (toku_txn_is_read_only(txn)) {
+        // Neither hot indexing nor checkpoint do any work with readonly txns,
+        // so we can skip taking the txn_manager lock here.
         invariant(txn->state==TOKUTXN_LIVE);
         txn->state = TOKUTXN_ABORTING;
         goto done;
@@ -720,7 +727,14 @@ void toku_txn_manager_note_abort_txn(TXN_MANAGER txn_manager, TOKUTXN txn) {
 }
 
 void toku_txn_manager_note_commit_txn(TXN_MANAGER txn_manager, TOKUTXN txn) {
+    // Purpose:
+    //  Delay until any indexer is done pinning this transaction.
+    //  Update status of a transaction from live->committing (or prepared->committing)
+    //  Do so in a thread-safe manner that does not conflict with hot indexing or
+    //  begin checkpoint.
     if (toku_txn_is_read_only(txn)) {
+        // Neither hot indexing nor checkpoint do any work with readonly txns,
+        // so we can skip taking the txn_manager lock here.
         invariant(txn->state==TOKUTXN_LIVE);
         txn->state = TOKUTXN_COMMITTING;
         goto done;