@@ -330,7 +330,7 @@ typedef struct OldSerXidControlData
330
330
int headPage ; /* newest initialized page */
331
331
TransactionId headXid ; /* newest valid Xid in the SLRU */
332
332
TransactionId tailXid ; /* oldest xmin we might be interested in */
333
- bool warningIssued ;
333
+ bool warningIssued ; /* have we issued SLRU wrap-around warning? */
334
334
} OldSerXidControlData ;
335
335
336
336
typedef struct OldSerXidControlData * OldSerXidControl ;
@@ -738,7 +738,6 @@ OldSerXidAdd(TransactionId xid, SerCommitSeqNo minConflictCommitSeqNo)
738
738
int targetPage ;
739
739
int slotno ;
740
740
int firstZeroPage ;
741
- int xidSpread ;
742
741
bool isNewPage ;
743
742
744
743
Assert (TransactionIdIsValid (xid ));
@@ -779,18 +778,45 @@ OldSerXidAdd(TransactionId xid, SerCommitSeqNo minConflictCommitSeqNo)
779
778
if (isNewPage )
780
779
oldSerXidControl -> headPage = targetPage ;
781
780
782
- xidSpread = (((uint32 ) xid ) - ((uint32 ) tailXid ));
781
+ /*
782
+ * Give a warning if we're about to run out of SLRU pages.
783
+ *
784
+ * slru.c has a maximum of 64k segments, with 32 (SLRU_PAGES_PER_SEGMENT)
785
+ * pages each. We need to store a 64-bit integer for each Xid, and with
786
+ * default 8k block size, 65536*32 pages is only enough to cover 2^30
787
+ * XIDs. If we're about to hit that limit and wrap around, warn the user.
788
+ *
789
+ * To avoid spamming the user, we only give one warning when we've used 1
790
+ * billion XIDs, and stay silent until the situation is fixed and the
791
+ * number of XIDs used falls below 800 million again.
792
+ *
793
+ * XXX: We have no safeguard to actually *prevent* the wrap-around,
794
+ * though. All you get is a warning.
795
+ */
783
796
if (oldSerXidControl -> warningIssued )
784
797
{
785
- if (xidSpread < 800000000 )
798
+ TransactionId lowWatermark ;
799
+
800
+ lowWatermark = tailXid + 800000000 ;
801
+ if (lowWatermark < FirstNormalTransactionId )
802
+ lowWatermark = FirstNormalTransactionId ;
803
+ if (TransactionIdPrecedes (xid , lowWatermark ))
786
804
oldSerXidControl -> warningIssued = false;
787
805
}
788
- else if ( xidSpread >= 1000000000 )
806
+ else
789
807
{
790
- oldSerXidControl -> warningIssued = true;
791
- ereport (WARNING ,
792
- (errmsg ("memory for serializable conflict tracking is nearly exhausted" ),
793
- errhint ("There may be an idle transaction or a forgotten prepared transaction causing this." )));
808
+ TransactionId highWatermark ;
809
+
810
+ highWatermark = tailXid + 1000000000 ;
811
+ if (highWatermark < FirstNormalTransactionId )
812
+ highWatermark = FirstNormalTransactionId ;
813
+ if (TransactionIdFollows (xid , highWatermark ))
814
+ {
815
+ oldSerXidControl -> warningIssued = true;
816
+ ereport (WARNING ,
817
+ (errmsg ("memory for serializable conflict tracking is nearly exhausted" ),
818
+ errhint ("There may be an idle transaction or a forgotten prepared transaction causing this." )));
819
+ }
794
820
}
795
821
796
822
if (isNewPage )
@@ -931,18 +957,16 @@ CheckPointPredicate(void)
931
957
else
932
958
{
933
959
/*
934
- * The SLRU is no longer needed. Truncate everything. If we try to
935
- * leave the head page around to avoid re-zeroing it, we might not use
936
- * the SLRU again until we're past the wrap-around point, which makes
937
- * SLRU unhappy.
960
+ * The SLRU is no longer needed. Truncate to head before we set head
961
+ * invalid.
938
962
*
939
- * While the API asks you to specify truncation by page, it silently
940
- * ignores the request unless the specified page is in a segment past
941
- * some allocated portion of the SLRU. We don't care which page in a
942
- * later segment we hit, so just add the number of pages per segment
943
- * to the head page to land us *somewhere* in the next segment .
963
+ * XXX: It's possible that the SLRU is not needed again until XID
964
+ * wrap-around has happened, so that the segment containing headPage
965
+ * that we leave behind will appear to be new again. In that case it
966
+ * won't be removed until XID horizon advances enough to make it
967
+ * current again .
944
968
*/
945
- tailPage = oldSerXidControl -> headPage + SLRU_PAGES_PER_SEGMENT ;
969
+ tailPage = oldSerXidControl -> headPage ;
946
970
oldSerXidControl -> headPage = -1 ;
947
971
}
948
972
0 commit comments