diff options
Diffstat (limited to 'src/backend/access/transam/xact.c')
-rw-r--r-- | src/backend/access/transam/xact.c | 41 |
1 files changed, 39 insertions, 2 deletions
diff --git a/src/backend/access/transam/xact.c b/src/backend/access/transam/xact.c index b467b5c89d1..ad0d19c4a90 100644 --- a/src/backend/access/transam/xact.c +++ b/src/backend/access/transam/xact.c @@ -148,6 +148,7 @@ typedef struct TransactionStateData int prevSecContext; /* previous SecurityRestrictionContext */ bool prevXactReadOnly; /* entry-time xact r/o state */ bool startedInRecovery; /* did we start in recovery? */ + bool didLogXid; /* has xid been included in WAL record? */ struct TransactionStateData *parent; /* back link to parent */ } TransactionStateData; @@ -177,6 +178,7 @@ static TransactionStateData TopTransactionStateData = { 0, /* previous SecurityRestrictionContext */ false, /* entry-time xact r/o state */ false, /* startedInRecovery */ + false, /* didLogXid */ NULL /* link to parent state block */ }; @@ -395,6 +397,19 @@ GetCurrentTransactionIdIfAny(void) } /* + * MarkCurrentTransactionIdLoggedIfAny + * + * Remember that the current xid - if it is assigned - now has been wal logged. + */ +void +MarkCurrentTransactionIdLoggedIfAny(void) +{ + if (TransactionIdIsValid(CurrentTransactionState->transactionId)) + CurrentTransactionState->didLogXid = true; +} + + +/* * GetStableLatestTransactionId * * Get the transaction's XID if it has one, else read the next-to-be-assigned @@ -435,6 +450,7 @@ AssignTransactionId(TransactionState s) { bool isSubXact = (s->parent != NULL); ResourceOwner currentOwner; + bool log_unknown_top = false; /* Assert that caller didn't screw up */ Assert(!TransactionIdIsValid(s->transactionId)); @@ -470,6 +486,20 @@ AssignTransactionId(TransactionState s) } /* + * When wal_level=logical, guarantee that a subtransaction's xid can only + * be seen in the WAL stream if its toplevel xid has been logged + * before. If necessary we log a xact_assignment record with fewer than + * PGPROC_MAX_CACHED_SUBXIDS. Note that it is fine if didLogXid isn't set + * for a transaction even though it appears in a WAL record, we just might + * superfluously log something. That can happen when an xid is included + * somewhere inside a wal record, but not in XLogRecord->xl_xid, like in + * xl_standby_locks. + */ + if (isSubXact && XLogLogicalInfoActive() && + !TopTransactionStateData.didLogXid) + log_unknown_top = true; + + /* * Generate a new Xid and record it in PG_PROC and pg_subtrans. * * NB: we must make the subtrans entry BEFORE the Xid appears anywhere in @@ -523,6 +553,9 @@ AssignTransactionId(TransactionState s) * top-level transaction that each subxact belongs to. This is correct in * recovery only because aborted subtransactions are separately WAL * logged. + * + * This is correct even for the case where several levels above us didn't + * have an xid assigned as we recursed up to them beforehand. */ if (isSubXact && XLogStandbyInfoActive()) { @@ -533,7 +566,8 @@ AssignTransactionId(TransactionState s) * ensure this test matches similar one in * RecoverPreparedTransactions() */ - if (nUnreportedXids >= PGPROC_MAX_CACHED_SUBXIDS) + if (nUnreportedXids >= PGPROC_MAX_CACHED_SUBXIDS || + log_unknown_top) { XLogRecData rdata[2]; xl_xact_assignment xlrec; @@ -552,13 +586,15 @@ AssignTransactionId(TransactionState s) rdata[0].next = &rdata[1]; rdata[1].data = (char *) unreportedXids; - rdata[1].len = PGPROC_MAX_CACHED_SUBXIDS * sizeof(TransactionId); + rdata[1].len = nUnreportedXids * sizeof(TransactionId); rdata[1].buffer = InvalidBuffer; rdata[1].next = NULL; (void) XLogInsert(RM_XACT_ID, XLOG_XACT_ASSIGNMENT, rdata); nUnreportedXids = 0; + /* mark top, not current xact as having been logged */ + TopTransactionStateData.didLogXid = true; } } } @@ -1737,6 +1773,7 @@ StartTransaction(void) * initialize reported xid accounting */ nUnreportedXids = 0; + s->didLogXid = false; /* * must initialize resource-management stuff first |