Attached patch implements a "low watermark wal location" in the
walsender shmem array. Setting this value in a walsender prevents
transaction log removal prior to this point - similar to how
wal_keep_segments work, except with an absolute number rather than
relative. For now, this is set when running a base backup with WAL
included - to prevent the required WAL to be recycled away while the
backup is running, without having to guestimate the value for
wal_keep_segments. (There could be other ways added to set it in the
future, but that's the only one I've done for now)

It obviously needs some documentation updates as well, but I wanted to
get some comments on the way it's done before I work on those.

-- 
 Magnus Hagander
 Me: http://www.hagander.net/
 Work: http://www.redpill-linpro.com/
*** a/src/backend/access/transam/xlog.c
--- b/src/backend/access/transam/xlog.c
***************
*** 8194,8199 **** CreateRestartPoint(int flags)
--- 8194,8206 ----
   * Calculate the last segment that we need to retain because of
   * wal_keep_segments, by subtracting wal_keep_segments from
   * the given xlog location, recptr.
+  *
+  * Also check if there any in-progress base backup that has set
+  * a low watermark preventing us from removing it.
+  *
+  * NOTE! If the last segment calculated is later than the one
+  * passed in through logId and logSeg, do *not* update the
+  * values.
   */
  static void
  KeepLogSeg(XLogRecPtr recptr, uint32 *logId, uint32 *logSeg)
***************
*** 8202,8211 **** KeepLogSeg(XLogRecPtr recptr, uint32 *logId, uint32 *logSeg)
--- 8209,8260 ----
  	uint32		seg;
  	int			d_log;
  	int			d_seg;
+ 	XLogRecPtr	lowwater = {0,0};
+ 	uint32		lowwater_log = 0;
+ 	uint32		lowwater_seg = 0;
+ 
+ 	if (max_wal_senders > 0)
+ 	{
+ 		int i;
+ 
+ 		/* Check if there is a WAL sender with a low watermark */
+ 		for (i = 0; i < max_wal_senders; i++)
+ 		{
+ 			/* use volatile pointer to prevent code rearrangement */
+ 			volatile WalSnd *walsnd = &WalSndCtl->walsnds[i];
+ 			XLogRecPtr	this_lowwater;
+ 
+ 			if (walsnd->pid == 0)
+ 				continue;
+ 
+ 			SpinLockAcquire(&walsnd->mutex);
+ 			this_lowwater = walsnd->lowwater;
+ 			SpinLockRelease(&walsnd->mutex);
+ 
+ 			if (XLByteLT(lowwater, this_lowwater))
+ 				lowwater = this_lowwater;
+ 		}
+ 
+ 		XLByteToSeg(lowwater, lowwater_log, lowwater_seg);
+ 	}
  
  	if (wal_keep_segments == 0)
+ 	{
+ 		/* No wal_keep_segments, so let low watermark decide */
+ 		if (lowwater_log == 0 && lowwater_seg == 0)
+ 			return;
+ 
+ 		if (lowwater_log < *logId || (lowwater_log == *logId && lowwater_seg < *logSeg))
+ 		{
+ 			*logId = lowwater_log;
+ 			*logSeg = lowwater_seg;
+ 		}
  		return;
+ 	}
  
+ 	/*
+ 	 * Calculate the cutoff point caused by wal_keep_segments
+ 	 */
  	XLByteToSeg(recptr, log, seg);
  
  	d_seg = wal_keep_segments % XLogSegsPerFile;
***************
*** 8226,8231 **** KeepLogSeg(XLogRecPtr recptr, uint32 *logId, uint32 *logSeg)
--- 8275,8293 ----
  	else
  		log = log - d_log;
  
+ 	/*
+ 	 * If the low watermark is earlier than wal_keep_segments, let
+ 	 * it decide if we keep or not.
+ 	 */
+ 	if (lowwater_log > 0 || lowwater_seg > 0)
+ 	{
+ 		if (lowwater_log < log || (lowwater_log == log && lowwater_seg < seg))
+ 		{
+ 			log = lowwater_log;
+ 			seg = lowwater_seg;
+ 		}
+ 	}
+ 
  	/* don't delete WAL segments newer than the calculated segment */
  	if (log < *logId || (log == *logId && seg < *logSeg))
  	{
*** a/src/backend/replication/basebackup.c
--- b/src/backend/replication/basebackup.c
***************
*** 96,101 **** perform_base_backup(basebackup_options *opt, DIR *tblspcdir)
--- 96,115 ----
  	startptr = do_pg_start_backup(opt->label, opt->fastcheckpoint, &labelfile);
  	SendXlogRecPtrResult(startptr);
  
+ 	/*
+ 	 * If we are including WAL, set a low watermark so that ordinary
+ 	 * WAL rotation won't remove the files for us.
+ 	 */
+ 	if (opt->includewal)
+ 	{
+ 		/* use volatile pointer to prevent code rearrangement */
+ 		volatile WalSnd *walsnd = MyWalSnd;
+ 
+ 		SpinLockAcquire(&walsnd->mutex);
+ 		walsnd->lowwater = startptr;
+ 		SpinLockRelease(&walsnd->mutex);
+ 	}
+ 
  	PG_ENSURE_ERROR_CLEANUP(base_backup_cleanup, (Datum) 0);
  	{
  		List	   *tablespaces = NIL;
*** a/src/backend/replication/walsender.c
--- b/src/backend/replication/walsender.c
***************
*** 899,904 **** InitWalSnd(void)
--- 899,905 ----
  			 */
  			walsnd->pid = MyProcPid;
  			MemSet(&walsnd->sentPtr, 0, sizeof(XLogRecPtr));
+ 			MemSet(&walsnd->lowwater, 0, sizeof(XLogRecPtr));
  			walsnd->state = WALSNDSTATE_STARTUP;
  			SpinLockRelease(&walsnd->mutex);
  			/* don't need the lock anymore */
*** a/src/include/replication/walsender.h
--- b/src/include/replication/walsender.h
***************
*** 46,51 **** typedef struct WalSnd
--- 46,57 ----
  	XLogRecPtr	flush;
  	XLogRecPtr	apply;
  
+ 	/*
+ 	 * Prevent xlog rotation prior to the low watermark (used during base
+ 	 * backups that include the transaction log)
+ 	 */
+ 	XLogRecPtr	lowwater;
+ 
  	/* Protects shared variables shown above. */
  	slock_t		mutex;
  
-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

Reply via email to