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