134134 * SerializableXactHashLock
135135 * - Protects both PredXact and SerializableXidHash.
136136 *
137+ * SerialControlLock
138+ * - Protects SerialControlData members
139+ *
140+ * SerialSLRULock
141+ * - Protects SerialSlruCtl
137142 *
138143 * Portions Copyright (c) 1996-2024, PostgreSQL Global Development Group
139144 * Portions Copyright (c) 1994, Regents of the University of California
@@ -828,9 +833,11 @@ SerialInit(void)
828833 /*
829834 * Set control information to reflect empty SLRU.
830835 */
836+ LWLockAcquire (SerialControlLock , LW_EXCLUSIVE );
831837 serialControl -> headPage = -1 ;
832838 serialControl -> headXid = InvalidTransactionId ;
833839 serialControl -> tailXid = InvalidTransactionId ;
840+ LWLockRelease (SerialControlLock );
834841 }
835842}
836843
@@ -852,7 +859,12 @@ SerialAdd(TransactionId xid, SerCommitSeqNo minConflictCommitSeqNo)
852859
853860 targetPage = SerialPage (xid );
854861
855- LWLockAcquire (SerialSLRULock , LW_EXCLUSIVE );
862+ /*
863+ * In this routine, we must hold both SerialControlLock and SerialSLRULock
864+ * simultaneously while making the SLRU data catch up with the new state
865+ * that we determine.
866+ */
867+ LWLockAcquire (SerialControlLock , LW_EXCLUSIVE );
856868
857869 /*
858870 * If no serializable transactions are active, there shouldn't be anything
@@ -886,6 +898,8 @@ SerialAdd(TransactionId xid, SerCommitSeqNo minConflictCommitSeqNo)
886898 if (isNewPage )
887899 serialControl -> headPage = targetPage ;
888900
901+ LWLockAcquire (SerialSLRULock , LW_EXCLUSIVE );
902+
889903 if (isNewPage )
890904 {
891905 /* Initialize intervening pages. */
@@ -903,6 +917,7 @@ SerialAdd(TransactionId xid, SerCommitSeqNo minConflictCommitSeqNo)
903917 SerialSlruCtl -> shared -> page_dirty [slotno ] = true;
904918
905919 LWLockRelease (SerialSLRULock );
920+ LWLockRelease (SerialControlLock );
906921}
907922
908923/*
@@ -920,10 +935,10 @@ SerialGetMinConflictCommitSeqNo(TransactionId xid)
920935
921936 Assert (TransactionIdIsValid (xid ));
922937
923- LWLockAcquire (SerialSLRULock , LW_SHARED );
938+ LWLockAcquire (SerialControlLock , LW_SHARED );
924939 headXid = serialControl -> headXid ;
925940 tailXid = serialControl -> tailXid ;
926- LWLockRelease (SerialSLRULock );
941+ LWLockRelease (SerialControlLock );
927942
928943 if (!TransactionIdIsValid (headXid ))
929944 return 0 ;
@@ -954,7 +969,7 @@ SerialGetMinConflictCommitSeqNo(TransactionId xid)
954969static void
955970SerialSetActiveSerXmin (TransactionId xid )
956971{
957- LWLockAcquire (SerialSLRULock , LW_EXCLUSIVE );
972+ LWLockAcquire (SerialControlLock , LW_EXCLUSIVE );
958973
959974 /*
960975 * When no sxacts are active, nothing overlaps, set the xid values to
@@ -966,7 +981,7 @@ SerialSetActiveSerXmin(TransactionId xid)
966981 {
967982 serialControl -> tailXid = InvalidTransactionId ;
968983 serialControl -> headXid = InvalidTransactionId ;
969- LWLockRelease (SerialSLRULock );
984+ LWLockRelease (SerialControlLock );
970985 return ;
971986 }
972987
@@ -984,7 +999,7 @@ SerialSetActiveSerXmin(TransactionId xid)
984999 {
9851000 serialControl -> tailXid = xid ;
9861001 }
987- LWLockRelease (SerialSLRULock );
1002+ LWLockRelease (SerialControlLock );
9881003 return ;
9891004 }
9901005
@@ -993,7 +1008,7 @@ SerialSetActiveSerXmin(TransactionId xid)
9931008
9941009 serialControl -> tailXid = xid ;
9951010
996- LWLockRelease (SerialSLRULock );
1011+ LWLockRelease (SerialControlLock );
9971012}
9981013
9991014/*
@@ -1007,12 +1022,12 @@ CheckPointPredicate(void)
10071022{
10081023 int truncateCutoffPage ;
10091024
1010- LWLockAcquire (SerialSLRULock , LW_EXCLUSIVE );
1025+ LWLockAcquire (SerialControlLock , LW_EXCLUSIVE );
10111026
10121027 /* Exit quickly if the SLRU is currently not in use. */
10131028 if (serialControl -> headPage < 0 )
10141029 {
1015- LWLockRelease (SerialSLRULock );
1030+ LWLockRelease (SerialControlLock );
10161031 return ;
10171032 }
10181033
@@ -1072,9 +1087,13 @@ CheckPointPredicate(void)
10721087 serialControl -> headPage = -1 ;
10731088 }
10741089
1075- LWLockRelease (SerialSLRULock );
1090+ LWLockRelease (SerialControlLock );
10761091
1077- /* Truncate away pages that are no longer required */
1092+ /*
1093+ * Truncate away pages that are no longer required. Note that no
1094+ * additional locking is required, because this is only called as part of
1095+ * a checkpoint, and the validity limits have already been determined.
1096+ */
10781097 SimpleLruTruncate (SerialSlruCtl , truncateCutoffPage );
10791098
10801099 /*
0 commit comments