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