diff --git a/src/backend/access/transam/twophase.c b/src/backend/access/transam/twophase.c
index a65048b..f33cd41 100644
--- a/src/backend/access/transam/twophase.c
+++ b/src/backend/access/transam/twophase.c
@@ -2053,12 +2053,10 @@ RecordTransactionCommitPrepared(TransactionId xid,
 	MyPgXact->delayChkpt = true;
 
 	/* Emit the XLOG commit record */
-	recptr = XactLogCommitRecord(committs,
+	recptr = XactLogCommitRecord(committs, xid, true,
 								 nchildren, children, nrels, rels,
 								 ninvalmsgs, invalmsgs,
-								 initfileinval, false,
-								 xid);
-
+								 initfileinval, false);
 
 	if (replorigin)
 		/* Move LSNs forward for this replication origin */
diff --git a/src/backend/access/transam/xact.c b/src/backend/access/transam/xact.c
index 7e37331..71ab3f4 100644
--- a/src/backend/access/transam/xact.c
+++ b/src/backend/access/transam/xact.c
@@ -1149,7 +1149,7 @@ RecordTransactionCommit(void)
 	 * If we haven't been assigned an XID yet, we neither can, nor do we want
 	 * to write a COMMIT record.
 	 */
-	if (!markXidCommitted)
+	if (!markXidCommitted && nmsgs == 0)
 	{
 		/*
 		 * We expect that every smgrscheduleunlink is followed by a catalog
@@ -1212,10 +1212,10 @@ RecordTransactionCommit(void)
 		SetCurrentTransactionStopTimestamp();
 
 		XactLogCommitRecord(xactStopTimestamp,
+							xid, false, /* plain commit */
 							nchildren, children, nrels, rels,
 							nmsgs, invalMessages,
-							RelcacheInitFileInval, forceSyncCommit,
-							InvalidTransactionId /* plain commit */ );
+							RelcacheInitFileInval, forceSyncCommit);
 
 		if (replorigin)
 			/* Move LSNs forward for this replication origin */
@@ -1235,7 +1235,8 @@ RecordTransactionCommit(void)
 		if (!replorigin || replorigin_session_origin_timestamp == 0)
 			replorigin_session_origin_timestamp = xactStopTimestamp;
 
-		TransactionTreeSetCommitTsData(xid, nchildren, children,
+		if (markXidCommitted)
+			TransactionTreeSetCommitTsData(xid, nchildren, children,
 									   replorigin_session_origin_timestamp,
 									   replorigin_session_origin, false);
 	}
@@ -1305,7 +1306,7 @@ RecordTransactionCommit(void)
 	 * If we entered a commit critical section, leave it now, and let
 	 * checkpoints proceed.
 	 */
-	if (markXidCommitted)
+	if (markXidCommitted || nmsgs > 0)
 	{
 		MyPgXact->delayChkpt = false;
 		END_CRIT_SECTION();
@@ -5079,18 +5080,23 @@ xactGetCommittedChildren(TransactionId **ptr)
 
 
 /*
- * Log the commit record for a plain or twophase transaction commit.
+ * Log information at transaction commit.
  *
- * A 2pc commit will be emitted when twophase_xid is valid, a plain one
- * otherwise.
+ * In the common case this produces standard commit records, though we
+ * support other cases:
+ * * If xid is invalid and we have msgs, send an INVAL_ONLY record
+ * * If xid is valid and twophase is true, send a COMMIT_PREPARED record
+ *
+ * In earlier releases, as a bug fix, the XLOG_XACT_INVAL_ONLY record is
+ * sent as an XLOG_NOOP record so it can avoid screwing up archives.
  */
 XLogRecPtr
 XactLogCommitRecord(TimestampTz commit_time,
+					TransactionId xid, bool twophase,
 					int nsubxacts, TransactionId *subxacts,
 					int nrels, RelFileNode *rels,
 					int nmsgs, SharedInvalidationMessage *msgs,
-					bool relcacheInval, bool forceSync,
-					TransactionId twophase_xid)
+					bool relcacheInval, bool forceSync)
 {
 	xl_xact_commit xlrec;
 	xl_xact_xinfo xl_xinfo;
@@ -5108,10 +5114,15 @@ XactLogCommitRecord(TimestampTz commit_time,
 	xl_xinfo.xinfo = 0;
 
 	/* decide between a plain and 2pc commit */
-	if (!TransactionIdIsValid(twophase_xid))
-		info = XLOG_XACT_COMMIT;
-	else
+	if (!TransactionIdIsValid(xid))
+	{
+		Assert(nmsgs > 0);
+		info = XLOG_XACT_INVAL_ONLY;
+	}
+	else if (twophase)
 		info = XLOG_XACT_COMMIT_PREPARED;
+	else
+		info = XLOG_XACT_COMMIT;
 
 	/* First figure out and collect all the information needed */
 
@@ -5126,7 +5137,8 @@ XactLogCommitRecord(TimestampTz commit_time,
 	 * Check if the caller would like to ask standbys for immediate feedback
 	 * once this commit is applied.
 	 */
-	if (synchronous_commit >= SYNCHRONOUS_COMMIT_REMOTE_APPLY)
+	if (synchronous_commit >= SYNCHRONOUS_COMMIT_REMOTE_APPLY &&
+		info != XLOG_XACT_INVAL_ONLY)
 		xl_xinfo.xinfo |= XACT_COMPLETION_APPLY_FEEDBACK;
 
 	/*
@@ -5142,12 +5154,14 @@ XactLogCommitRecord(TimestampTz commit_time,
 
 	if (nsubxacts > 0)
 	{
+		Assert(info != XLOG_XACT_INVAL_ONLY);
 		xl_xinfo.xinfo |= XACT_XINFO_HAS_SUBXACTS;
 		xl_subxacts.nsubxacts = nsubxacts;
 	}
 
 	if (nrels > 0)
 	{
+		Assert(info != XLOG_XACT_INVAL_ONLY);
 		xl_xinfo.xinfo |= XACT_XINFO_HAS_RELFILENODES;
 		xl_relfilenodes.nrels = nrels;
 	}
@@ -5158,10 +5172,11 @@ XactLogCommitRecord(TimestampTz commit_time,
 		xl_invals.nmsgs = nmsgs;
 	}
 
-	if (TransactionIdIsValid(twophase_xid))
+	if (twophase)
 	{
+		Assert(info == XLOG_XACT_COMMIT_PREPARED);
 		xl_xinfo.xinfo |= XACT_XINFO_HAS_TWOPHASE;
-		xl_twophase.xid = twophase_xid;
+		xl_twophase.xid = xid;
 	}
 
 	/* dump transaction origin information */
@@ -5569,7 +5584,8 @@ xact_redo(XLogReaderState *record)
 	/* Backup blocks are not used in xact records */
 	Assert(!XLogRecHasAnyBlockRefs(record));
 
-	if (info == XLOG_XACT_COMMIT || info == XLOG_XACT_COMMIT_PREPARED)
+	if (info == XLOG_XACT_COMMIT || info == XLOG_XACT_COMMIT_PREPARED ||
+		info == XLOG_XACT_INVAL_ONLY)
 	{
 		xl_xact_commit *xlrec = (xl_xact_commit *) XLogRecGetData(record);
 		xl_xact_parsed_commit parsed;
@@ -5583,13 +5599,25 @@ xact_redo(XLogReaderState *record)
 			xact_redo_commit(&parsed, XLogRecGetXid(record),
 							 record->EndRecPtr, XLogRecGetOrigin(record));
 		}
-		else
+		else if (info == XLOG_XACT_COMMIT_PREPARED)
 		{
 			Assert(TransactionIdIsValid(parsed.twophase_xid));
 			xact_redo_commit(&parsed, parsed.twophase_xid,
 							 record->EndRecPtr, XLogRecGetOrigin(record));
 			RemoveTwoPhaseFile(parsed.twophase_xid, false);
 		}
+		else /* XLOG_XACT_INVAL_ONLY */
+		{
+			Assert(!TransactionIdIsValid(parsed.twophase_xid));
+
+			/*
+			 * Send cache invalidations attched to this message.
+			 */
+			ProcessCommittedInvalidationMessages(
+											 parsed.msgs, parsed.nmsgs,
+						  XactCompletionRelcacheInitFileInval(parsed.xinfo),
+											 parsed.dbId, parsed.tsId);
+		}
 	}
 	else if (info == XLOG_XACT_ABORT || info == XLOG_XACT_ABORT_PREPARED)
 	{
diff --git a/src/include/access/xact.h b/src/include/access/xact.h
index 503ae1b..cbd430f 100644
--- a/src/include/access/xact.h
+++ b/src/include/access/xact.h
@@ -118,7 +118,7 @@ typedef void (*SubXactCallback) (SubXactEvent event, SubTransactionId mySubid,
 #define XLOG_XACT_COMMIT_PREPARED	0x30
 #define XLOG_XACT_ABORT_PREPARED	0x40
 #define XLOG_XACT_ASSIGNMENT		0x50
-/* free opcode 0x60 */
+#define XLOG_XACT_INVAL_ONLY		0x60
 /* free opcode 0x70 */
 
 /* mask for filtering opcodes out of xl_info */
@@ -361,11 +361,11 @@ extern void UnregisterSubXactCallback(SubXactCallback callback, void *arg);
 extern int	xactGetCommittedChildren(TransactionId **ptr);
 
 extern XLogRecPtr XactLogCommitRecord(TimestampTz commit_time,
+					TransactionId xid, bool twophase,
 					int nsubxacts, TransactionId *subxacts,
 					int nrels, RelFileNode *rels,
 					int nmsgs, SharedInvalidationMessage *msgs,
-					bool relcacheInval, bool forceSync,
-					TransactionId twophase_xid);
+					bool relcacheInval, bool forceSync);
 
 extern XLogRecPtr XactLogAbortRecord(TimestampTz abort_time,
 				   int nsubxacts, TransactionId *subxacts,
