Index: src/include/postmaster/bgwriter.h
===================================================================
*** src/include/postmaster/bgwriter.h	(HEAD)
--- src/include/postmaster/bgwriter.h	(modified)
*************** extern int	CheckPointWarning;
*** 23,29 ****
  
  extern void BackgroundWriterMain(void);
  
! extern void RequestCheckpoint(bool waitforit, bool warnontime);
  
  extern bool ForwardFsyncRequest(RelFileNode rnode, BlockNumber segno);
  extern void AbsorbFsyncRequests(void);
--- 23,29 ----
  
  extern void BackgroundWriterMain(void);
  
! extern void RequestCheckpoint(bool waitforit);
  
  extern bool ForwardFsyncRequest(RelFileNode rnode, BlockNumber segno);
  extern void AbsorbFsyncRequests(void);
Index: src/include/access/xlog.h
===================================================================
*** src/include/access/xlog.h	(HEAD)
--- src/include/access/xlog.h	(modified)
*************** extern void BootStrapXLOG(void);
*** 162,170 ****
--- 162,172 ----
  extern void StartupXLOG(void);
  extern void ShutdownXLOG(int code, Datum arg);
  extern void InitXLOGAccess(void);
+ extern bool PrepareCheckPoint(bool shutdown, bool force);
  extern void CreateCheckPoint(bool shutdown, bool force);
  extern void XLogPutNextOid(Oid nextOid);
  extern XLogRecPtr GetRedoRecPtr(void);
+ extern XLogRecPtr GetInsertRecPtr(void);
  extern void GetNextXidAndEpoch(TransactionId *xid, uint32 *epoch);
  
  #endif   /* XLOG_H */
Index: src/include/storage/bufmgr.h
===================================================================
*** src/include/storage/bufmgr.h	(HEAD)
--- src/include/storage/bufmgr.h	(modified)
*************** extern void AbortBufferIO(void);
*** 151,157 ****
  
  extern void BufmgrCommit(void);
  extern void BufferSync(void);
! extern void BgBufferSync(void);
  
  extern void AtProcExit_LocalBuffers(void);
  
--- 151,157 ----
  
  extern void BufmgrCommit(void);
  extern void BufferSync(void);
! extern int	BgBufferSync(int num_to_scan);
  
  extern void AtProcExit_LocalBuffers(void);
  
Index: src/backend/commands/dbcommands.c
===================================================================
*** src/backend/commands/dbcommands.c	(HEAD)
--- src/backend/commands/dbcommands.c	(modified)
*************** createdb(const CreatedbStmt *stmt)
*** 504,510 ****
  		 * Perhaps if we ever implement CREATE DATABASE in a less cheesy way,
  		 * we can avoid this.
  		 */
! 		RequestCheckpoint(true, false);
  
  		/*
  		 * Close pg_database, but keep lock till commit (this is important to
--- 504,510 ----
  		 * Perhaps if we ever implement CREATE DATABASE in a less cheesy way,
  		 * we can avoid this.
  		 */
! 		RequestCheckpoint(true);
  
  		/*
  		 * Close pg_database, but keep lock till commit (this is important to
*************** dropdb(const char *dbname, bool missing_
*** 648,654 ****
  	 * open files, which would cause rmdir() to fail.
  	 */
  #ifdef WIN32
! 	RequestCheckpoint(true, false);
  #endif
  
  	/*
--- 648,654 ----
  	 * open files, which would cause rmdir() to fail.
  	 */
  #ifdef WIN32
! 	RequestCheckpoint(true);
  #endif
  
  	/*
Index: src/backend/postmaster/bgwriter.c
===================================================================
*** src/backend/postmaster/bgwriter.c	(HEAD)
--- src/backend/postmaster/bgwriter.c	(modified)
***************
*** 90,99 ****
   *	6. If ckpt_failed is different from the originally saved value,
   *	   assume request failed; otherwise it was definitely successful.
   *
!  * An additional field is ckpt_time_warn; this is also sig_atomic_t for
   * simplicity, but is only used as a boolean.  If a backend is requesting
!  * a checkpoint for which a checkpoints-too-close-together warning is
!  * reasonable, it should set this field TRUE just before sending the signal.
   *
   * The requests array holds fsync requests sent by backends and not yet
   * absorbed by the bgwriter.  Unlike the checkpoint fields, the requests
--- 90,101 ----
   *	6. If ckpt_failed is different from the originally saved value,
   *	   assume request failed; otherwise it was definitely successful.
   *
!  * An additional field is ckpt_immediate; this is also sig_atomic_t for
   * simplicity, but is only used as a boolean.  If a backend is requesting
!  * an immediate checkpoint, set this field TRUE just before sending the
!  * signal. If do so, checkpoint is performed as soon as possible. Otherwise,
!  * checkpoint is run asynchronously to avoid i/o impacts and a checkpoints-
!  * too-close-together warning may be reported.
   *
   * The requests array holds fsync requests sent by backends and not yet
   * absorbed by the bgwriter.  Unlike the checkpoint fields, the requests
*************** typedef struct
*** 115,121 ****
  	sig_atomic_t ckpt_done;		/* advances when checkpoint done */
  	sig_atomic_t ckpt_failed;	/* advances when checkpoint fails */
  
! 	sig_atomic_t ckpt_time_warn;	/* warn if too soon since last ckpt? */
  
  	int			num_requests;	/* current # of requests */
  	int			max_requests;	/* allocated array size */
--- 117,123 ----
  	sig_atomic_t ckpt_done;		/* advances when checkpoint done */
  	sig_atomic_t ckpt_failed;	/* advances when checkpoint fails */
  
! 	sig_atomic_t ckpt_immediate;	/* immediate checkpoint requested? */
  
  	int			num_requests;	/* current # of requests */
  	int			max_requests;	/* allocated array size */
*************** static bool am_bg_writer = false;
*** 145,154 ****
--- 147,167 ----
  
  static bool ckpt_active = false;
  
+ /* Number of scanned pages during asynchronous checkpoint, otherwise -1. */
+ static int	ckpt_progress = -1;
+ 
+ /* WAL position at starting asynchronous checkpoint. */
+ static XLogRecPtr ckpt_recptr;
+ 
+ /* safety margin for smgrsync */
+ #define CHECKPOINT_MARGIN		0.1
+ 
  static time_t last_checkpoint_time;
  static time_t last_xlog_switch_time;
  
  
+ static void BgCreateCheckPoint(bool immediate);
+ static int	BgGetScanPages(void);
  static void bg_quickdie(SIGNAL_ARGS);
  static void BgSigHupHandler(SIGNAL_ARGS);
  static void ReqCheckpointHandler(SIGNAL_ARGS);
*************** BackgroundWriterMain(void)
*** 285,290 ****
--- 298,306 ----
  			ckpt_active = false;
  		}
  
+ 		/* Discard prepared checkpoint */
+ 		ckpt_progress = -1;
+ 
  		/*
  		 * Now return to normal top-level context and clear ErrorContext for
  		 * next time.
*************** BackgroundWriterMain(void)
*** 327,333 ****
  	for (;;)
  	{
  		bool		do_checkpoint = false;
! 		bool		force_checkpoint = false;
  		time_t		now;
  		int			elapsed_secs;
  		long		udelay;
--- 343,349 ----
  	for (;;)
  	{
  		bool		do_checkpoint = false;
! 		bool		immediate = false;
  		time_t		now;
  		int			elapsed_secs;
  		long		udelay;
*************** BackgroundWriterMain(void)
*** 353,359 ****
  		{
  			checkpoint_requested = false;
  			do_checkpoint = true;
! 			force_checkpoint = true;
  		}
  		if (shutdown_requested)
  		{
--- 369,376 ----
  		{
  			checkpoint_requested = false;
  			do_checkpoint = true;
! 			immediate = BgWriterShmem->ckpt_immediate;
! 			BgWriterShmem->ckpt_immediate = false;
  		}
  		if (shutdown_requested)
  		{
*************** BackgroundWriterMain(void)
*** 385,423 ****
  		if (do_checkpoint)
  		{
  			/*
- 			 * We will warn if (a) too soon since last checkpoint (whatever
- 			 * caused it) and (b) somebody has set the ckpt_time_warn flag
- 			 * since the last checkpoint start.  Note in particular that this
- 			 * implementation will not generate warnings caused by
- 			 * CheckPointTimeout < CheckPointWarning.
- 			 */
- 			if (BgWriterShmem->ckpt_time_warn &&
- 				elapsed_secs < CheckPointWarning)
- 				ereport(LOG,
- 						(errmsg("checkpoints are occurring too frequently (%d seconds apart)",
- 								elapsed_secs),
- 						 errhint("Consider increasing the configuration parameter \"checkpoint_segments\".")));
- 			BgWriterShmem->ckpt_time_warn = false;
- 
- 			/*
  			 * Indicate checkpoint start to any waiting backends.
  			 */
  			ckpt_active = true;
  			BgWriterShmem->ckpt_started++;
  
! 			CreateCheckPoint(false, force_checkpoint);
! 
! 			/*
! 			 * After any checkpoint, close all smgr files.	This is so we
! 			 * won't hang onto smgr references to deleted files indefinitely.
! 			 */
! 			smgrcloseall();
  
! 			/*
! 			 * Indicate checkpoint completion to any waiting backends.
! 			 */
! 			BgWriterShmem->ckpt_done = BgWriterShmem->ckpt_started;
! 			ckpt_active = false;
  
  			/*
  			 * Note we record the checkpoint start time not end time as
--- 402,457 ----
  		if (do_checkpoint)
  		{
  			/*
  			 * Indicate checkpoint start to any waiting backends.
  			 */
  			ckpt_active = true;
  			BgWriterShmem->ckpt_started++;
  
! 			if (immediate)
! 			{
! 				/* Cancel previous asynchronous checkpoint if running */
! 				if (ckpt_progress >= 0)
! 				{
! 					elog(DEBUG1, "cancel previous asynchronous checkpoint");
! 					ckpt_progress = -1;
! 				}
! 				BgCreateCheckPoint(true);
! 			}
! 			else
! 			{
! 				/*
! 				 * We will warn if (a) too soon since last checkpoint
! 				 * (whatever caused it) and (b) the checkpoint is not forced.
! 				 * Note in particular that this implementation will not generate
! 				 * warnings caused by CheckPointTimeout < CheckPointWarning.
! 				 */
! 				if (elapsed_secs < CheckPointTimeout &&
! 					elapsed_secs < CheckPointWarning)
! 					ereport(LOG,
! 						(errmsg("checkpoints are occurring too frequently (%d seconds apart)",
! 								elapsed_secs),
! 						 errhint("Consider increasing the configuration parameter \"checkpoint_segments\".")));
  
! 				/* Finish previous asynchronous checkpoint if running. */
! 				if (ckpt_progress >= 0)
! 				{
! 					int	num_to_scan = NBuffers - ckpt_progress;
! 					if (num_to_scan > 0)
! 					{
! 						elog(DEBUG1, "finish previous checkpoint, writing %d buffers", num_to_scan);
! 						BgBufferSync(num_to_scan);
! 					}
! 					BgCreateCheckPoint(false);
! 				}
! 
! 				/* Start an asynchronous checkpoint */
! 				elog(DEBUG1, "prepare asynchronous checkpoint");
! 				if (PrepareCheckPoint(false, false))
! 				{
! 					ckpt_progress = 0;	/* >=0 means 'prepared' */
! 					ckpt_recptr = GetInsertRecPtr();
! 				}
! 			}
  
  			/*
  			 * Note we record the checkpoint start time not end time as
*************** BackgroundWriterMain(void)
*** 426,433 ****
  			 */
  			last_checkpoint_time = now;
  		}
  		else
! 			BgBufferSync();
  
  		/*
  		 * Check for archive_timeout, if so, switch xlog files.  First we do a
--- 460,482 ----
  			 */
  			last_checkpoint_time = now;
  		}
+ 		else if (ckpt_progress >= 0)
+ 		{
+ 			/* asynchronous checkpoint is running */
+ 			ckpt_progress += BgBufferSync(BgGetScanPages());
+ 
+ 			/*
+ 			 * If all dirty buffers have been written, we can continue
+ 			 * the rest of the checkpoint.
+ 			 */
+ 			if (ckpt_progress >= NBuffers)
+ 				BgCreateCheckPoint(false);
+ 		}
  		else
! 		{
! 			/* Normal activity, not in checkpoints */
! 			BgBufferSync(0);
! 		}
  
  		/*
  		 * Check for archive_timeout, if so, switch xlog files.  First we do a
*************** BackgroundWriterMain(void)
*** 506,511 ****
--- 555,627 ----
  	}
  }
  
+ /*
+  * BgCreateCheckPoint -- create checkpoint and close all smgr files.
+  */
+ static void
+ BgCreateCheckPoint(bool immediate)
+ {
+ 	elog(DEBUG1, "start %s checkpoint",
+ 		(immediate ? "immediate" : "asynchronous"));
+ 
+ 	ckpt_active = true;
+ 
+ 	CreateCheckPoint(false, immediate);
+ 
+ 	/*
+ 	 * After any checkpoint, close all smgr files.	This is so we
+ 	 * won't hang onto smgr references to deleted files indefinitely.
+ 	 */
+ 	smgrcloseall();
+ 
+ 	/*
+ 	 * Indicate checkpoint completion to any waiting backends.
+ 	 */
+ 	BgWriterShmem->ckpt_done = BgWriterShmem->ckpt_started;
+ 
+ 	ckpt_progress = -1;
+ 	ckpt_active = false;
+ }
+ 
+ /*
+  * BgGetScanPages -- Returns the number of pages recommemded to be scanned.
+  */
+ static int
+ BgGetScanPages(void)
+ {
+ 	struct timeval	now;
+ 	XLogRecPtr		recptr;
+ 	double			progress_in_time,
+ 					progress_in_xlog;
+ 	int				pos;
+ 
+ 	/* coordinate the progress with checkpoint_timeout */
+ 	gettimeofday(&now, NULL);
+ 	progress_in_time = ((double)(int)(now.tv_sec - last_checkpoint_time) +
+ 						now.tv_usec / 1000000.0) / CheckPointTimeout;
+ 
+ 	/* coordinate the progress with checkpoint_segments */
+ 	recptr = GetInsertRecPtr();
+ 	progress_in_xlog =
+ 		((double) (recptr.xlogid - ckpt_recptr.xlogid) * XLogSegsPerFile +
+ 		 (double) (recptr.xrecoff - ckpt_recptr.xrecoff) / XLogSegSize) /
+ 		CheckPointSegments;
+ 
+ 	pos = (int) (NBuffers * (1.0 + CHECKPOINT_MARGIN) *
+ 					Max(progress_in_time, progress_in_xlog));
+ 	if (pos > NBuffers)
+ 		pos = NBuffers;
+ 
+ 	elog(DEBUG1, "checkpoint progress : %d->%d(%+d) (time=%.3f, xlog=%.3f)",
+ 		ckpt_progress, pos, pos - ckpt_progress,
+ 		progress_in_time, progress_in_xlog);
+ 
+ 	if (pos > ckpt_progress)
+ 		return pos - ckpt_progress;
+ 	else
+ 		return 0;
+ }
+ 
  
  /* --------------------------------
   *		signal handler routines
*************** BgWriterShmemInit(void)
*** 612,625 ****
   *
   * If waitforit is true, wait until the checkpoint is completed
   * before returning; otherwise, just signal the request and return
!  * immediately.
!  *
!  * If warnontime is true, and it's "too soon" since the last checkpoint,
!  * the bgwriter will log a warning.  This should be true only for checkpoints
!  * caused due to xlog filling, else the warning will be misleading.
   */
  void
! RequestCheckpoint(bool waitforit, bool warnontime)
  {
  	/* use volatile pointer to prevent code rearrangement */
  	volatile BgWriterShmemStruct *bgs = BgWriterShmem;
--- 728,739 ----
   *
   * If waitforit is true, wait until the checkpoint is completed
   * before returning; otherwise, just signal the request and return
!  * immediately. If false, checkpoints are caused due to xlog filling.
!  * Then if it's "too soon" since the last checkpoint, the bgwriter will
!  * log a warning, else the warning will be misleading.
   */
  void
! RequestCheckpoint(bool waitforit)
  {
  	/* use volatile pointer to prevent code rearrangement */
  	volatile BgWriterShmemStruct *bgs = BgWriterShmem;
*************** RequestCheckpoint(bool waitforit, bool w
*** 642,650 ****
  		return;
  	}
  
! 	/* Set warning request flag if appropriate */
! 	if (warnontime)
! 		bgs->ckpt_time_warn = true;
  
  	/*
  	 * Send signal to request checkpoint.  When waitforit is false, we
--- 756,764 ----
  		return;
  	}
  
! 	/* Set immediate request flag if appropriate */
! 	if (waitforit)
! 		bgs->ckpt_immediate = true;
  
  	/*
  	 * Send signal to request checkpoint.  When waitforit is false, we
Index: src/backend/access/transam/xlog.c
===================================================================
*** src/backend/access/transam/xlog.c	(HEAD)
--- src/backend/access/transam/xlog.c	(modified)
***************
*** 43,48 ****
--- 43,49 ----
  #include "storage/fd.h"
  #include "storage/pmsignal.h"
  #include "storage/procarray.h"
+ #include "storage/smgr.h"
  #include "storage/spin.h"
  #include "utils/builtins.h"
  #include "utils/nabstime.h"
*************** static TransactionId recoveryStopXid;
*** 191,196 ****
--- 192,200 ----
  static time_t recoveryStopTime;
  static bool recoveryStopAfter;
  
+ /* checkpoint */
+ static CheckPoint checkPoint;
+ 
  /*
   * During normal operation, the only timeline we care about is ThisTimeLineID.
   * During recovery, however, things are more complicated.  To simplify life
*************** static void readRecoveryCommandFile(void
*** 469,475 ****
  static void exitArchiveRecovery(TimeLineID endTLI,
  					uint32 endLogId, uint32 endLogSeg);
  static bool recoveryStopsHere(XLogRecord *record, bool *includeThis);
! static void CheckPointGuts(XLogRecPtr checkPointRedo);
  
  static bool XLogCheckBuffer(XLogRecData *rdata, bool doPageWrites,
  				XLogRecPtr *lsn, BkpBlock *bkpb);
--- 473,479 ----
  static void exitArchiveRecovery(TimeLineID endTLI,
  					uint32 endLogId, uint32 endLogSeg);
  static bool recoveryStopsHere(XLogRecord *record, bool *includeThis);
! static void CheckPointGuts(XLogRecPtr checkPointRedo, bool flush);
  
  static bool XLogCheckBuffer(XLogRecData *rdata, bool doPageWrites,
  				XLogRecPtr *lsn, BkpBlock *bkpb);
*************** XLogWrite(XLogwrtRqst WriteRqst, bool fl
*** 1666,1672 ****
  						if (XLOG_DEBUG)
  							elog(LOG, "time for a checkpoint, signaling bgwriter");
  #endif
! 						RequestCheckpoint(false, true);
  					}
  				}
  			}
--- 1670,1676 ----
  						if (XLOG_DEBUG)
  							elog(LOG, "time for a checkpoint, signaling bgwriter");
  #endif
! 						RequestCheckpoint(false);
  					}
  				}
  			}
*************** GetRedoRecPtr(void)
*** 5343,5348 ****
--- 5347,5369 ----
  }
  
  /*
+  * GetInsertRecPtr -- Returns the current insert position.
+  */
+ XLogRecPtr
+ GetInsertRecPtr(void)
+ {
+ 	volatile XLogCtlData *xlogctl = XLogCtl;
+ 	XLogCtlInsert  *Insert = &XLogCtl->Insert;
+ 	XLogRecPtr		recptr;
+ 
+ 	SpinLockAcquire(&xlogctl->info_lck);
+ 	INSERT_RECPTR(recptr, Insert, Insert->curridx);
+ 	SpinLockRelease(&xlogctl->info_lck);
+ 
+ 	return recptr;
+ }
+ 
+ /*
   * Get the time of the last xlog segment switch
   */
  time_t
*************** ShutdownXLOG(int code, Datum arg)
*** 5417,5448 ****
  }
  
  /*
!  * Perform a checkpoint --- either during shutdown, or on-the-fly
   *
   * If force is true, we force a checkpoint regardless of whether any XLOG
   * activity has occurred since the last one.
   */
! void
! CreateCheckPoint(bool shutdown, bool force)
  {
- 	CheckPoint	checkPoint;
- 	XLogRecPtr	recptr;
  	XLogCtlInsert *Insert = &XLogCtl->Insert;
- 	XLogRecData rdata;
  	uint32		freespace;
- 	uint32		_logId;
- 	uint32		_logSeg;
- 	int			nsegsadded = 0;
- 	int			nsegsremoved = 0;
- 	int			nsegsrecycled = 0;
- 
- 	/*
- 	 * Acquire CheckpointLock to ensure only one checkpoint happens at a time.
- 	 * (This is just pro forma, since in the present system structure there is
- 	 * only one process that is allowed to issue checkpoints at any given
- 	 * time.)
- 	 */
- 	LWLockAcquire(CheckpointLock, LW_EXCLUSIVE);
  
  	/*
  	 * Use a critical section to force system panic if we have trouble.
--- 5438,5453 ----
  }
  
  /*
!  * PrepareCheckPoint -- prepare a checkpoint
   *
   * If force is true, we force a checkpoint regardless of whether any XLOG
   * activity has occurred since the last one.
   */
! bool
! PrepareCheckPoint(bool shutdown, bool force)
  {
  	XLogCtlInsert *Insert = &XLogCtl->Insert;
  	uint32		freespace;
  
  	/*
  	 * Use a critical section to force system panic if we have trouble.
*************** CreateCheckPoint(bool shutdown, bool for
*** 5501,5509 ****
  		{
  			LWLockRelease(WALInsertLock);
  			LWLockRelease(CheckpointStartLock);
- 			LWLockRelease(CheckpointLock);
  			END_CRIT_SECTION();
! 			return;
  		}
  	}
  
--- 5506,5514 ----
  		{
  			LWLockRelease(WALInsertLock);
  			LWLockRelease(CheckpointStartLock);
  			END_CRIT_SECTION();
! 			elog(DEBUG1, "checkpoint is not needed");
! 			return false;
  		}
  	}
  
*************** CreateCheckPoint(bool shutdown, bool for
*** 5552,5561 ****
  
  	LWLockRelease(CheckpointStartLock);
  
- 	if (!shutdown)
- 		ereport(DEBUG2,
- 				(errmsg("checkpoint starting")));
- 
  	/*
  	 * Get the other info we need for the checkpoint record.
  	 */
--- 5557,5562 ----
*************** CreateCheckPoint(bool shutdown, bool for
*** 5578,5583 ****
--- 5579,5624 ----
  							 &checkPoint.nextMulti,
  							 &checkPoint.nextMultiOffset);
  
+ 	END_CRIT_SECTION();
+ 
+ 	if (!shutdown)
+ 		ereport(DEBUG2,
+ 				(errmsg("checkpoint starting")));
+ 
+ 	return true;
+ }
+ 
+ /*
+  * CreateCheckPoint -- finish a checkpoint
+  */
+ void
+ CreateCheckPoint(bool shutdown, bool force)
+ {
+ 	XLogRecPtr	recptr;
+ 	XLogRecData rdata;
+ 	uint32		_logId;
+ 	uint32		_logSeg;
+ 	int			nsegsadded = 0;
+ 	int			nsegsremoved = 0;
+ 	int			nsegsrecycled = 0;
+ 
+ 	Assert(!shutdown || (shutdown && force));	/* must force on shutdown */
+ 
+ 	/* Do a force checkpoint if not prepared. (should not happen) */
+ 	if (!TransactionIdIsValid(checkPoint.nextXid))
+ 		force = true;
+ 
+ 	/*
+ 	 * Acquire CheckpointLock to ensure only one checkpoint happens at a time.
+ 	 * (This is just pro forma, since in the present system structure there is
+ 	 * only one process that is allowed to issue checkpoints at any given
+ 	 * time.)
+ 	 */
+ 	LWLockAcquire(CheckpointLock, LW_EXCLUSIVE);
+ 
+ 	if (shutdown || force)
+ 		PrepareCheckPoint(shutdown, force);
+ 
  	/*
  	 * Having constructed the checkpoint record, ensure all shmem disk buffers
  	 * and commit-log buffers are flushed to disk.
*************** CreateCheckPoint(bool shutdown, bool for
*** 5586,5594 ****
  	 * complete the checkpoint, but there is no reason to force a system
  	 * panic. Accordingly, exit critical section while doing it.
  	 */
! 	END_CRIT_SECTION();
! 
! 	CheckPointGuts(checkPoint.redo);
  
  	START_CRIT_SECTION();
  
--- 5627,5633 ----
  	 * complete the checkpoint, but there is no reason to force a system
  	 * panic. Accordingly, exit critical section while doing it.
  	 */
! 	CheckPointGuts(checkPoint.redo, force);
  
  	START_CRIT_SECTION();
  
*************** CreateCheckPoint(bool shutdown, bool for
*** 5684,5689 ****
--- 5723,5730 ----
  				(errmsg("checkpoint complete; %d transaction log file(s) added, %d removed, %d recycled",
  						nsegsadded, nsegsremoved, nsegsrecycled)));
  
+ 	checkPoint.nextXid = InvalidTransactionId;	/* done */
+ 
  	LWLockRelease(CheckpointLock);
  }
  
*************** CreateCheckPoint(bool shutdown, bool for
*** 5694,5705 ****
   * recovery restartpoints.
   */
  static void
! CheckPointGuts(XLogRecPtr checkPointRedo)
  {
  	CheckPointCLOG();
  	CheckPointSUBTRANS();
  	CheckPointMultiXact();
! 	FlushBufferPool();			/* performs all required fsyncs */
  	/* We deliberately delay 2PC checkpointing as long as possible */
  	CheckPointTwoPhase(checkPointRedo);
  }
--- 5735,5752 ----
   * recovery restartpoints.
   */
  static void
! CheckPointGuts(XLogRecPtr checkPointRedo, bool flush)
  {
  	CheckPointCLOG();
  	CheckPointSUBTRANS();
  	CheckPointMultiXact();
! 
! 	elog(DEBUG1, "CheckPointGuts %s flush", (flush ? "WITH" : "WITHOUT"));
! 
! 	if (flush)
! 		BufferSync();
! 	smgrsync();	/* performs all required fsyncs */
! 
  	/* We deliberately delay 2PC checkpointing as long as possible */
  	CheckPointTwoPhase(checkPointRedo);
  }
*************** RecoveryRestartPoint(const CheckPoint *c
*** 5748,5754 ****
  	/*
  	 * OK, force data out to disk
  	 */
! 	CheckPointGuts(checkPoint->redo);
  
  	/*
  	 * Update pg_control so that any subsequent crash will restart from this
--- 5795,5801 ----
  	/*
  	 * OK, force data out to disk
  	 */
! 	CheckPointGuts(checkPoint->redo, true);
  
  	/*
  	 * Update pg_control so that any subsequent crash will restart from this
*************** pg_start_backup(PG_FUNCTION_ARGS)
*** 6167,6173 ****
  		 * have different checkpoint positions and hence different history
  		 * file names, even if nothing happened in between.
  		 */
! 		RequestCheckpoint(true, false);
  
  		/*
  		 * Now we need to fetch the checkpoint record location, and also its
--- 6214,6220 ----
  		 * have different checkpoint positions and hence different history
  		 * file names, even if nothing happened in between.
  		 */
! 		RequestCheckpoint(true);
  
  		/*
  		 * Now we need to fetch the checkpoint record location, and also its
Index: src/backend/storage/buffer/bufmgr.c
===================================================================
*** src/backend/storage/buffer/bufmgr.c	(HEAD)
--- src/backend/storage/buffer/bufmgr.c	(modified)
*************** BufferSync(void)
*** 985,1005 ****
   * BgBufferSync -- Write out some dirty buffers in the pool.
   *
   * This is called periodically by the background writer process.
   */
! void
! BgBufferSync(void)
  {
  	static int	buf_id1 = 0;
  	int			buf_id2;
- 	int			num_to_scan;
  	int			num_written;
  
  	/* Make sure we can handle the pin inside SyncOneBuffer */
  	ResourceOwnerEnlargeBuffers(CurrentResourceOwner);
  
  	/*
! 	 * To minimize work at checkpoint time, we want to try to keep all the
! 	 * buffers clean; this motivates a scan that proceeds sequentially through
  	 * all buffers.  But we are also charged with ensuring that buffers that
  	 * will be recycled soon are clean when needed; these buffers are the ones
  	 * just ahead of the StrategySyncStart point.  We make a separate scan
--- 985,1009 ----
   * BgBufferSync -- Write out some dirty buffers in the pool.
   *
   * This is called periodically by the background writer process.
+  * num_to_scan buffers are always scanned and written by the 'all' activity.
+  * Returns the number of scanned buffers by the 'all' activity.
   */
! int
! BgBufferSync(int num_to_scan)
  {
  	static int	buf_id1 = 0;
  	int			buf_id2;
  	int			num_written;
+ 	int			num_scanned = 0;
+ 
+ 	Assert(num_to_scan >= 0);
  
  	/* Make sure we can handle the pin inside SyncOneBuffer */
  	ResourceOwnerEnlargeBuffers(CurrentResourceOwner);
  
  	/*
! 	 * To distribute work at checkpoint time, we want to try to write buffers
! 	 * by increments; this motivates a scan that proceeds sequentially through
  	 * all buffers.  But we are also charged with ensuring that buffers that
  	 * will be recycled soon are clean when needed; these buffers are the ones
  	 * just ahead of the StrategySyncStart point.  We make a separate scan
*************** BgBufferSync(void)
*** 1007,1027 ****
  	 */
  
  	/*
! 	 * This loop runs over all buffers, including pinned ones.	The starting
! 	 * point advances through the buffer pool on successive calls.
  	 *
  	 * Note that we advance the static counter *before* trying to write. This
  	 * ensures that, if we have a persistent write failure on a dirty buffer,
  	 * we'll still be able to make progress writing other buffers. (The
  	 * bgwriter will catch the error and just call us again later.)
  	 */
! 	if (bgwriter_all_percent > 0.0 && bgwriter_all_maxpages > 0)
  	{
! 		num_to_scan = (int) ((NBuffers * bgwriter_all_percent + 99) / 100);
! 		num_written = 0;
  
  		while (num_to_scan-- > 0)
  		{
  			if (++buf_id1 >= NBuffers)
  				buf_id1 = 0;
  			if (SyncOneBuffer(buf_id1, false))
--- 1011,1043 ----
  	 */
  
  	/*
! 	 * These two loops run over all buffers, including pinned ones.	The
! 	 * starting point advances through the buffer pool on successive calls.
  	 *
  	 * Note that we advance the static counter *before* trying to write. This
  	 * ensures that, if we have a persistent write failure on a dirty buffer,
  	 * we'll still be able to make progress writing other buffers. (The
  	 * bgwriter will catch the error and just call us again later.)
  	 */
! 
! 	num_written = 0;
! 	while (num_to_scan-- > 0)
  	{
! 		num_scanned += 1;
! 		if (++buf_id1 >= NBuffers)
! 			buf_id1 = 0;
! 		if (SyncOneBuffer(buf_id1, false))
! 			++num_written;
! 	}
! 
! 	if (bgwriter_all_percent > 0.0 && bgwriter_all_maxpages > num_written)
! 	{
! 		num_to_scan = (int) ((NBuffers * bgwriter_all_percent + 99) / 100)
! 					- num_scanned;
  
  		while (num_to_scan-- > 0)
  		{
+ 			num_scanned += 1;
  			if (++buf_id1 >= NBuffers)
  				buf_id1 = 0;
  			if (SyncOneBuffer(buf_id1, false))
*************** BgBufferSync(void)
*** 1054,1059 ****
--- 1070,1077 ----
  				buf_id2 = 0;
  		}
  	}
+ 
+ 	return num_scanned;
  }
  
  /*
Index: src/backend/tcop/utility.c
===================================================================
*** src/backend/tcop/utility.c	(HEAD)
--- src/backend/tcop/utility.c	(modified)
*************** ProcessUtility(Node *parsetree,
*** 1055,1061 ****
  				ereport(ERROR,
  						(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
  						 errmsg("must be superuser to do CHECKPOINT")));
! 			RequestCheckpoint(true, false);
  			break;
  
  		case T_ReindexStmt:
--- 1055,1061 ----
  				ereport(ERROR,
  						(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
  						 errmsg("must be superuser to do CHECKPOINT")));
! 			RequestCheckpoint(true);
  			break;
  
  		case T_ReindexStmt:
