@@ -434,19 +434,6 @@ ProcArrayClearTransaction(PGPROC *proc)
434434 proc -> subxids .overflowed = false;
435435}
436436
437- /*
438- * ProcArrayInitRecoveryInfo
439- *
440- * When trying to assemble our snapshot we only care about xids after this value.
441- * See comments for LogStandbySnapshot().
442- */
443- void
444- ProcArrayInitRecoveryInfo (TransactionId oldestActiveXid )
445- {
446- latestObservedXid = oldestActiveXid ;
447- TransactionIdRetreat (latestObservedXid );
448- }
449-
450437/*
451438 * ProcArrayApplyRecoveryInfo -- apply recovery info about xids
452439 *
@@ -523,11 +510,9 @@ ProcArrayApplyRecoveryInfo(RunningTransactions running)
523510 */
524511
525512 /*
526- * Remove all xids except xids later than the snapshot. We don't know
527- * exactly which ones that is until precisely now, so that is why we allow
528- * xids to be added only to remove most of them again here.
513+ * Release any locks belonging to old transactions that are not
514+ * running according to the running-xacts record.
529515 */
530- ExpireOldKnownAssignedTransactionIds (running -> nextXid );
531516 StandbyReleaseOldLocks (running -> nextXid );
532517
533518 /*
@@ -536,9 +521,8 @@ ProcArrayApplyRecoveryInfo(RunningTransactions running)
536521 LWLockAcquire (ProcArrayLock , LW_EXCLUSIVE );
537522
538523 /*
539- * Combine the running xact data with already known xids, if any exist.
540- * KnownAssignedXids is sorted so we cannot just add new xids, we have to
541- * combine them first, sort them and then re-add to KnownAssignedXids.
524+ * KnownAssignedXids is sorted so we cannot just add the xids, we have to
525+ * sort them first.
542526 *
543527 * Some of the new xids are top-level xids and some are subtransactions.
544528 * We don't call SubtransSetParent because it doesn't matter yet. If we
@@ -547,51 +531,32 @@ ProcArrayApplyRecoveryInfo(RunningTransactions running)
547531 * xids to subtrans. If RunningXacts is overflowed then we don't have
548532 * enough information to correctly update subtrans anyway.
549533 */
534+ Assert (procArray -> numKnownAssignedXids == 0 );
550535
551536 /*
552- * Allocate a temporary array so we can combine xids. The total of both
553- * arrays should never normally exceed TOTAL_MAX_CACHED_SUBXIDS.
554- */
555- xids = palloc (sizeof (TransactionId ) * TOTAL_MAX_CACHED_SUBXIDS );
556-
557- /*
558- * Get the remaining KnownAssignedXids. In most cases there won't be any
559- * at all since this exists only to catch a theoretical race condition.
537+ * Allocate a temporary array to avoid modifying the array passed as
538+ * argument.
560539 */
561- nxids = KnownAssignedXidsGet (xids , InvalidTransactionId );
562- if (nxids > 0 )
563- KnownAssignedXidsDisplay (trace_recovery (DEBUG3 ));
540+ xids = palloc (sizeof (TransactionId ) * running -> xcnt );
564541
565542 /*
566- * Now we have a copy of any KnownAssignedXids we can zero the array
567- * before we re-insert combined snapshot.
568- */
569- KnownAssignedXidsRemovePreceding (InvalidTransactionId );
570-
571- /*
572- * Add to the temp array any xids which have not already completed, taking
573- * care not to overflow in extreme cases.
543+ * Add to the temp array any xids which have not already completed.
574544 */
545+ nxids = 0 ;
575546 for (i = 0 ; i < running -> xcnt ; i ++ )
576547 {
577548 TransactionId xid = running -> xids [i ];
578549
579550 /*
580- * The running-xacts snapshot can contain xids that were running at
581- * the time of the snapshot, yet complete before the snapshot was
582- * written to WAL. They're running now, so ignore them.
551+ * The running-xacts snapshot can contain xids that were still visible
552+ * in the procarray when the snapshot was taken, but were already
553+ * WAL-logged as completed. They're not running anymore, so ignore
554+ * them.
583555 */
584556 if (TransactionIdDidCommit (xid ) || TransactionIdDidAbort (xid ))
585557 continue ;
586558
587559 xids [nxids ++ ] = xid ;
588-
589- /*
590- * Test for overflow only after we have filtered out already complete
591- * transactions.
592- */
593- if (nxids > TOTAL_MAX_CACHED_SUBXIDS )
594- elog (ERROR , "too many xids to add into KnownAssignedXids" );
595560 }
596561
597562 if (nxids > 0 )
@@ -602,73 +567,53 @@ ProcArrayApplyRecoveryInfo(RunningTransactions running)
602567 */
603568 qsort (xids , nxids , sizeof (TransactionId ), xidComparator );
604569
605- /*
606- * Re-initialise latestObservedXid to the highest xid we've seen.
607- */
608- latestObservedXid = xids [nxids - 1 ];
609-
610570 /*
611571 * Add the sorted snapshot into KnownAssignedXids
612572 */
613573 for (i = 0 ; i < nxids ; i ++ )
614- {
615- TransactionId xid = xids [i ];
616-
617- KnownAssignedXidsAdd (xid , xid , true);
618- }
574+ KnownAssignedXidsAdd (xids [i ], xids [i ], true);
619575
620576 KnownAssignedXidsDisplay (trace_recovery (DEBUG3 ));
621577 }
622578
623579 pfree (xids );
624580
625581 /*
626- * Now we've got the running xids we need to set the global values thare
627- * used to track snapshots as they evolve further
582+ * Now we've got the running xids we need to set the global values that
583+ * are used to track snapshots as they evolve further.
628584 *
629- * * latestCompletedXid which will be the xmax for snapshots *
630- * lastOverflowedXid which shows whether snapshots overflow * nextXid
585+ * - latestCompletedXid which will be the xmax for snapshots
586+ * - lastOverflowedXid which shows whether snapshots overflow
587+ * - nextXid
631588 *
632589 * If the snapshot overflowed, then we still initialise with what we know,
633590 * but the recovery snapshot isn't fully valid yet because we know there
634591 * are some subxids missing. We don't know the specific subxids that are
635592 * missing, so conservatively assume the last one is latestObservedXid.
636- * If no missing subxids, try to clear lastOverflowedXid.
637- *
638- * If the snapshot didn't overflow it's still possible that an overflow
639- * occurred in the gap between taking snapshot and logging record, so we
640- * also need to check if lastOverflowedXid is already ahead of us.
641593 */
594+ latestObservedXid = running -> nextXid ;
595+ TransactionIdRetreat (latestObservedXid );
596+
642597 if (running -> subxid_overflow )
643598 {
644599 standbyState = STANDBY_SNAPSHOT_PENDING ;
645600
646601 standbySnapshotPendingXmin = latestObservedXid ;
647- if (TransactionIdFollows (latestObservedXid ,
648- procArray -> lastOverflowedXid ))
649- procArray -> lastOverflowedXid = latestObservedXid ;
650- }
651- else if (TransactionIdFollows (procArray -> lastOverflowedXid ,
652- latestObservedXid ))
653- {
654- standbyState = STANDBY_SNAPSHOT_PENDING ;
655-
656- standbySnapshotPendingXmin = procArray -> lastOverflowedXid ;
602+ procArray -> lastOverflowedXid = latestObservedXid ;
657603 }
658604 else
659605 {
660606 standbyState = STANDBY_SNAPSHOT_READY ;
661607
662608 standbySnapshotPendingXmin = InvalidTransactionId ;
663- if (TransactionIdFollows (running -> oldestRunningXid ,
664- procArray -> lastOverflowedXid ))
665- procArray -> lastOverflowedXid = InvalidTransactionId ;
609+ procArray -> lastOverflowedXid = InvalidTransactionId ;
666610 }
667611
668612 /*
669- * If a transaction completed in the gap between taking and logging the
670- * snapshot then latestCompletedXid may already be higher than the value
671- * from the snapshot, so check before we use the incoming value.
613+ * If a transaction wrote a commit record in the gap between taking and
614+ * logging the snapshot then latestCompletedXid may already be higher
615+ * than the value from the snapshot, so check before we use the incoming
616+ * value.
672617 */
673618 if (TransactionIdPrecedes (ShmemVariableCache -> latestCompletedXid ,
674619 running -> latestCompletedXid ))
@@ -1407,6 +1352,10 @@ GetSnapshotData(Snapshot snapshot)
14071352 * Similar to GetSnapshotData but returns more information. We include
14081353 * all PGPROCs with an assigned TransactionId, even VACUUM processes.
14091354 *
1355+ * We acquire XidGenLock, but the caller is responsible for releasing it.
1356+ * This ensures that no new XIDs enter the proc array until the caller has
1357+ * WAL-logged this snapshot, and releases the lock.
1358+ *
14101359 * The returned data structure is statically allocated; caller should not
14111360 * modify it, and must not assume it is valid past the next call.
14121361 *
@@ -1526,7 +1475,7 @@ GetRunningTransactionData(void)
15261475 CurrentRunningXacts -> oldestRunningXid = oldestRunningXid ;
15271476 CurrentRunningXacts -> latestCompletedXid = latestCompletedXid ;
15281477
1529- LWLockRelease ( XidGenLock );
1478+ /* We don't release XidGenLock here, the caller is responsible for that */
15301479 LWLockRelease (ProcArrayLock );
15311480
15321481 Assert (TransactionIdIsValid (CurrentRunningXacts -> nextXid ));
@@ -2337,23 +2286,28 @@ DisplayXidCache(void)
23372286 * unobserved XIDs.
23382287 *
23392288 * RecordKnownAssignedTransactionIds() should be run for *every* WAL record
2340- * type apart from XLOG_RUNNING_XACTS (since that initialises the first
2341- * snapshot so that RecordKnownAssignedTransactionIds() can be called). Must
2342- * be called for each record after we have executed StartupCLOG() et al,
2343- * since we must ExtendCLOG() etc..
2289+ * associated with a transaction. Must be called for each record after we
2290+ * have executed StartupCLOG() et al, since we must ExtendCLOG() etc..
23442291 *
23452292 * Called during recovery in analogy with and in place of GetNewTransactionId()
23462293 */
23472294void
23482295RecordKnownAssignedTransactionIds (TransactionId xid )
23492296{
23502297 Assert (standbyState >= STANDBY_INITIALIZED );
2351- Assert (TransactionIdIsValid (latestObservedXid ));
23522298 Assert (TransactionIdIsValid (xid ));
23532299
23542300 elog (trace_recovery (DEBUG4 ), "record known xact %u latestObservedXid %u" ,
23552301 xid , latestObservedXid );
23562302
2303+ /*
2304+ * If the KnownAssignedXids machinery isn't up yet, do nothing.
2305+ */
2306+ if (standbyState <= STANDBY_INITIALIZED )
2307+ return ;
2308+
2309+ Assert (TransactionIdIsValid (latestObservedXid ));
2310+
23572311 /*
23582312 * When a newly observed xid arrives, it is frequently the case that it is
23592313 * *not* the next xid in sequence. When this occurs, we must treat the
0 commit comments