@@ -528,7 +528,9 @@ StandbyAcquireAccessExclusiveLock(TransactionId xid, Oid dbOid, Oid relOid)
528
528
LOCKTAG locktag ;
529
529
530
530
/* Already processed? */
531
- if (TransactionIdDidCommit (xid ) || TransactionIdDidAbort (xid ))
531
+ if (!TransactionIdIsValid (xid ) ||
532
+ TransactionIdDidCommit (xid ) ||
533
+ TransactionIdDidAbort (xid ))
532
534
return ;
533
535
534
536
elog (trace_recovery (DEBUG4 ),
@@ -610,34 +612,86 @@ StandbyReleaseLockTree(TransactionId xid, int nsubxids, TransactionId *subxids)
610
612
}
611
613
612
614
/*
613
- * StandbyReleaseLocksMany
614
- * Release standby locks held by XIDs < removeXid
615
- *
616
- * If keepPreparedXacts is true, keep prepared transactions even if
617
- * they're older than removeXid
615
+ * Called at end of recovery and when we see a shutdown checkpoint.
618
616
*/
619
- static void
620
- StandbyReleaseLocksMany (TransactionId removeXid , bool keepPreparedXacts )
617
+ void
618
+ StandbyReleaseAllLocks (void )
619
+ {
620
+ ListCell * cell ,
621
+ * prev ,
622
+ * next ;
623
+ LOCKTAG locktag ;
624
+
625
+ elog (trace_recovery (DEBUG2 ), "release all standby locks" );
626
+
627
+ prev = NULL ;
628
+ for (cell = list_head (RecoveryLockList ); cell ; cell = next )
629
+ {
630
+ xl_standby_lock * lock = (xl_standby_lock * ) lfirst (cell );
631
+
632
+ next = lnext (cell );
633
+
634
+ elog (trace_recovery (DEBUG4 ),
635
+ "releasing recovery lock: xid %u db %u rel %u" ,
636
+ lock -> xid , lock -> dbOid , lock -> relOid );
637
+ SET_LOCKTAG_RELATION (locktag , lock -> dbOid , lock -> relOid );
638
+ if (!LockRelease (& locktag , AccessExclusiveLock , true))
639
+ elog (LOG ,
640
+ "RecoveryLockList contains entry for lock no longer recorded by lock manager: xid %u database %u relation %u" ,
641
+ lock -> xid , lock -> dbOid , lock -> relOid );
642
+ RecoveryLockList = list_delete_cell (RecoveryLockList , cell , prev );
643
+ pfree (lock );
644
+ }
645
+ }
646
+
647
+ /*
648
+ * StandbyReleaseOldLocks
649
+ * Release standby locks held by XIDs that aren't running, as long
650
+ * as they're not prepared transactions.
651
+ */
652
+ void
653
+ StandbyReleaseOldLocks (int nxids , TransactionId * xids )
621
654
{
622
655
ListCell * cell ,
623
656
* prev ,
624
657
* next ;
625
658
LOCKTAG locktag ;
626
659
627
- /*
628
- * Release all matching locks.
629
- */
630
660
prev = NULL ;
631
661
for (cell = list_head (RecoveryLockList ); cell ; cell = next )
632
662
{
633
663
xl_standby_lock * lock = (xl_standby_lock * ) lfirst (cell );
664
+ bool remove = false;
634
665
635
666
next = lnext (cell );
636
667
637
- if (!TransactionIdIsValid (removeXid ) || TransactionIdPrecedes (lock -> xid , removeXid ))
668
+ Assert (TransactionIdIsValid (lock -> xid ));
669
+
670
+ if (StandbyTransactionIdIsPrepared (lock -> xid ))
671
+ remove = false;
672
+ else
673
+ {
674
+ int i ;
675
+ bool found = false;
676
+
677
+ for (i = 0 ; i < nxids ; i ++ )
678
+ {
679
+ if (lock -> xid == xids [i ])
680
+ {
681
+ found = true;
682
+ break ;
683
+ }
684
+ }
685
+
686
+ /*
687
+ * If its not a running transaction, remove it.
688
+ */
689
+ if (!found )
690
+ remove = true;
691
+ }
692
+
693
+ if (remove )
638
694
{
639
- if (keepPreparedXacts && StandbyTransactionIdIsPrepared (lock -> xid ))
640
- continue ;
641
695
elog (trace_recovery (DEBUG4 ),
642
696
"releasing recovery lock: xid %u db %u rel %u" ,
643
697
lock -> xid , lock -> dbOid , lock -> relOid );
@@ -654,27 +708,6 @@ StandbyReleaseLocksMany(TransactionId removeXid, bool keepPreparedXacts)
654
708
}
655
709
}
656
710
657
- /*
658
- * Called at end of recovery and when we see a shutdown checkpoint.
659
- */
660
- void
661
- StandbyReleaseAllLocks (void )
662
- {
663
- elog (trace_recovery (DEBUG2 ), "release all standby locks" );
664
- StandbyReleaseLocksMany (InvalidTransactionId , false);
665
- }
666
-
667
- /*
668
- * StandbyReleaseOldLocks
669
- * Release standby locks held by XIDs < removeXid, as long
670
- * as they're not prepared transactions.
671
- */
672
- void
673
- StandbyReleaseOldLocks (TransactionId removeXid )
674
- {
675
- StandbyReleaseLocksMany (removeXid , true);
676
- }
677
-
678
711
/*
679
712
* --------------------------------------------------------------------
680
713
* Recovery handling for Rmgr RM_STANDBY_ID
@@ -816,6 +849,13 @@ standby_desc(StringInfo buf, uint8 xl_info, char *rec)
816
849
* Later, when we apply the running xact data we must be careful to ignore
817
850
* transactions already committed, since those commits raced ahead when
818
851
* making WAL entries.
852
+ *
853
+ * The loose timing also means that locks may be recorded that have a
854
+ * zero xid, since xids are removed from procs before locks are removed.
855
+ * So we must prune the lock list down to ensure we hold locks only for
856
+ * currently running xids, performed by StandbyReleaseOldLocks().
857
+ * Zero xids should no longer be possible, but we may be replaying WAL
858
+ * from a time when they were possible.
819
859
*/
820
860
void
821
861
LogStandbySnapshot (TransactionId * nextXid )
0 commit comments