@@ -108,6 +108,7 @@ int wal_level = WAL_LEVEL_MINIMAL;
108108int CommitDelay = 0 ; /* precommit delay in microseconds */
109109int CommitSiblings = 5 ; /* # concurrent xacts needed to sleep */
110110int wal_retrieve_retry_interval = 5000 ;
111+ int max_slot_wal_keep_size_mb = -1 ;
111112
112113#ifdef WAL_DEBUG
113114bool XLOG_DEBUG = false;
@@ -759,7 +760,7 @@ static ControlFileData *ControlFile = NULL;
759760 */
760761#define UsableBytesInPage (XLOG_BLCKSZ - SizeOfXLogShortPHD)
761762
762- /* Convert min_wal_size_mb and max_wal_size_mb to equivalent segment count */
763+ /* Convert values of GUCs measured in megabytes to equiv. segment count */
763764#define ConvertToXSegs (x , segsize ) \
764765 (x / ((segsize) / (1024 * 1024)))
765766
@@ -3963,9 +3964,10 @@ XLogGetLastRemovedSegno(void)
39633964 return lastRemovedSegNo ;
39643965}
39653966
3967+
39663968/*
3967- * Update the last removed segno pointer in shared memory, to reflect
3968- * that the given XLOG file has been removed.
3969+ * Update the last removed segno pointer in shared memory, to reflect that the
3970+ * given XLOG file has been removed.
39693971 */
39703972static void
39713973UpdateLastRemovedPtr (char * filename )
@@ -9043,6 +9045,7 @@ CreateCheckPoint(int flags)
90439045 */
90449046 XLByteToSeg (RedoRecPtr , _logSegNo , wal_segment_size );
90459047 KeepLogSeg (recptr , & _logSegNo );
9048+ InvalidateObsoleteReplicationSlots (_logSegNo );
90469049 _logSegNo -- ;
90479050 RemoveOldXlogFiles (_logSegNo , RedoRecPtr , recptr );
90489051
@@ -9377,6 +9380,7 @@ CreateRestartPoint(int flags)
93779380 replayPtr = GetXLogReplayRecPtr (& replayTLI );
93789381 endptr = (receivePtr < replayPtr ) ? replayPtr : receivePtr ;
93799382 KeepLogSeg (endptr , & _logSegNo );
9383+ InvalidateObsoleteReplicationSlots (_logSegNo );
93809384 _logSegNo -- ;
93819385
93829386 /*
@@ -9445,48 +9449,143 @@ CreateRestartPoint(int flags)
94459449 return true;
94469450}
94479451
9452+ /*
9453+ * Report availability of WAL for the given target LSN
9454+ * (typically a slot's restart_lsn)
9455+ *
9456+ * Returns one of the following enum values:
9457+ * * WALAVAIL_NORMAL means targetLSN is available because it is in the range
9458+ * of max_wal_size.
9459+ *
9460+ * * WALAVAIL_PRESERVED means it is still available by preserving extra
9461+ * segments beyond max_wal_size. If max_slot_wal_keep_size is smaller
9462+ * than max_wal_size, this state is not returned.
9463+ *
9464+ * * WALAVAIL_REMOVED means it is definitely lost. A replication stream on
9465+ * a slot with this LSN cannot continue.
9466+ *
9467+ * * WALAVAIL_INVALID_LSN means the slot hasn't been set to reserve WAL.
9468+ */
9469+ WALAvailability
9470+ GetWALAvailability (XLogRecPtr targetLSN )
9471+ {
9472+ XLogRecPtr currpos ; /* current write LSN */
9473+ XLogSegNo currSeg ; /* segid of currpos */
9474+ XLogSegNo targetSeg ; /* segid of targetLSN */
9475+ XLogSegNo oldestSeg ; /* actual oldest segid */
9476+ XLogSegNo oldestSegMaxWalSize ; /* oldest segid kept by max_wal_size */
9477+ XLogSegNo oldestSlotSeg = InvalidXLogRecPtr ; /* oldest segid kept by
9478+ * slot */
9479+ uint64 keepSegs ;
9480+
9481+ /* slot does not reserve WAL. Either deactivated, or has never been active */
9482+ if (XLogRecPtrIsInvalid (targetLSN ))
9483+ return WALAVAIL_INVALID_LSN ;
9484+
9485+ currpos = GetXLogWriteRecPtr ();
9486+
9487+ /* calculate oldest segment currently needed by slots */
9488+ XLByteToSeg (targetLSN , targetSeg , wal_segment_size );
9489+ KeepLogSeg (currpos , & oldestSlotSeg );
9490+
9491+ /*
9492+ * Find the oldest extant segment file. We get 1 until checkpoint removes
9493+ * the first WAL segment file since startup, which causes the status being
9494+ * wrong under certain abnormal conditions but that doesn't actually harm.
9495+ */
9496+ oldestSeg = XLogGetLastRemovedSegno () + 1 ;
9497+
9498+ /* calculate oldest segment by max_wal_size and wal_keep_segments */
9499+ XLByteToSeg (currpos , currSeg , wal_segment_size );
9500+ keepSegs = ConvertToXSegs (Max (max_wal_size_mb , wal_keep_segments ),
9501+ wal_segment_size ) + 1 ;
9502+
9503+ if (currSeg > keepSegs )
9504+ oldestSegMaxWalSize = currSeg - keepSegs ;
9505+ else
9506+ oldestSegMaxWalSize = 1 ;
9507+
9508+ /*
9509+ * If max_slot_wal_keep_size has changed after the last call, the segment
9510+ * that would been kept by the current setting might have been lost by the
9511+ * previous setting. No point in showing normal or keeping status values
9512+ * if the targetSeg is known to be lost.
9513+ */
9514+ if (targetSeg >= oldestSeg )
9515+ {
9516+ /*
9517+ * show "normal" when targetSeg is within max_wal_size, even if
9518+ * max_slot_wal_keep_size is smaller than max_wal_size.
9519+ */
9520+ if ((max_slot_wal_keep_size_mb <= 0 ||
9521+ max_slot_wal_keep_size_mb >= max_wal_size_mb ) &&
9522+ oldestSegMaxWalSize <= targetSeg )
9523+ return WALAVAIL_NORMAL ;
9524+
9525+ /* being retained by slots */
9526+ if (oldestSlotSeg <= targetSeg )
9527+ return WALAVAIL_RESERVED ;
9528+ }
9529+
9530+ /* Definitely lost */
9531+ return WALAVAIL_REMOVED ;
9532+ }
9533+
9534+
94489535/*
94499536 * Retreat *logSegNo to the last segment that we need to retain because of
94509537 * either wal_keep_segments or replication slots.
94519538 *
94529539 * This is calculated by subtracting wal_keep_segments from the given xlog
94539540 * location, recptr and by making sure that that result is below the
9454- * requirement of replication slots.
9541+ * requirement of replication slots. For the latter criterion we do consider
9542+ * the effects of max_slot_wal_keep_size: reserve at most that much space back
9543+ * from recptr.
94559544 */
94569545static void
94579546KeepLogSeg (XLogRecPtr recptr , XLogSegNo * logSegNo )
94589547{
9548+ XLogSegNo currSegNo ;
94599549 XLogSegNo segno ;
94609550 XLogRecPtr keep ;
94619551
9462- XLByteToSeg (recptr , segno , wal_segment_size );
9463- keep = XLogGetReplicationSlotMinimumLSN () ;
9552+ XLByteToSeg (recptr , currSegNo , wal_segment_size );
9553+ segno = currSegNo ;
94649554
9465- /* compute limit for wal_keep_segments first */
9466- if (wal_keep_segments > 0 )
9555+ /*
9556+ * Calculate how many segments are kept by slots first, adjusting for
9557+ * max_slot_wal_keep_size.
9558+ */
9559+ keep = XLogGetReplicationSlotMinimumLSN ();
9560+ if (keep != InvalidXLogRecPtr )
94679561 {
9468- /* avoid underflow, don't go below 1 */
9469- if (segno <= wal_keep_segments )
9470- segno = 1 ;
9471- else
9472- segno = segno - wal_keep_segments ;
9473- }
9562+ XLByteToSeg (keep , segno , wal_segment_size );
94749563
9475- /* then check whether slots limit removal further */
9476- if (max_replication_slots > 0 && keep != InvalidXLogRecPtr )
9477- {
9478- XLogSegNo slotSegNo ;
9564+ /* Cap by max_slot_wal_keep_size ... */
9565+ if (max_slot_wal_keep_size_mb >= 0 )
9566+ {
9567+ XLogRecPtr slot_keep_segs ;
94799568
9480- XLByteToSeg (keep , slotSegNo , wal_segment_size );
9569+ slot_keep_segs =
9570+ ConvertToXSegs (max_slot_wal_keep_size_mb , wal_segment_size );
94819571
9482- if (slotSegNo <= 0 )
9572+ if (currSegNo - segno > slot_keep_segs )
9573+ segno = currSegNo - slot_keep_segs ;
9574+ }
9575+ }
9576+
9577+ /* but, keep at least wal_keep_segments if that's set */
9578+ if (wal_keep_segments > 0 && currSegNo - segno < wal_keep_segments )
9579+ {
9580+ /* avoid underflow, don't go below 1 */
9581+ if (currSegNo <= wal_keep_segments )
94839582 segno = 1 ;
9484- else if ( slotSegNo < segno )
9485- segno = slotSegNo ;
9583+ else
9584+ segno = currSegNo - wal_keep_segments ;
94869585 }
94879586
94889587 /* don't delete WAL segments newer than the calculated segment */
9489- if (segno < * logSegNo )
9588+ if (XLogRecPtrIsInvalid ( * logSegNo ) || segno < * logSegNo )
94909589 * logSegNo = segno ;
94919590}
94929591
0 commit comments