@@ -330,7 +330,7 @@ typedef struct OldSerXidControlData
330330int headPage ;/* newest initialized page */
331331TransactionId headXid ;/* newest valid Xid in the SLRU */
332332TransactionId tailXid ;/* oldest xmin we might be interested in */
333- bool warningIssued ;
333+ bool warningIssued ;/* have we issued SLRU wrap-around warning? */
334334}OldSerXidControlData ;
335335
336336typedef struct OldSerXidControlData * OldSerXidControl ;
@@ -738,7 +738,6 @@ OldSerXidAdd(TransactionId xid, SerCommitSeqNo minConflictCommitSeqNo)
738738int targetPage ;
739739int slotno ;
740740int firstZeroPage ;
741- int xidSpread ;
742741bool isNewPage ;
743742
744743Assert (TransactionIdIsValid (xid ));
@@ -779,18 +778,45 @@ OldSerXidAdd(TransactionId xid, SerCommitSeqNo minConflictCommitSeqNo)
779778if (isNewPage )
780779oldSerXidControl -> headPage = targetPage ;
781780
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+ */
783796if (oldSerXidControl -> warningIssued )
784797{
785- if (xidSpread < 800000000 )
798+ TransactionId lowWatermark ;
799+
800+ lowWatermark = tailXid + 800000000 ;
801+ if (lowWatermark < FirstNormalTransactionId )
802+ lowWatermark = FirstNormalTransactionId ;
803+ if (TransactionIdPrecedes (xid ,lowWatermark ))
786804oldSerXidControl -> warningIssued = false;
787805}
788- else if ( xidSpread >= 1000000000 )
806+ else
789807{
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+ }
794820}
795821
796822if (isNewPage )
@@ -931,18 +957,16 @@ CheckPointPredicate(void)
931957else
932958{
933959/*
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.
938962 *
939- *While the API asks you to specify truncation by page, it silently
940- *ignores the request unless thespecified page is in a segmentpast
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 segmentcontaining 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 .
944968 */
945- tailPage = oldSerXidControl -> headPage + SLRU_PAGES_PER_SEGMENT ;
969+ tailPage = oldSerXidControl -> headPage ;
946970oldSerXidControl -> headPage = -1 ;
947971}
948972