diff -cpr HEAD/doc/src/sgml/config.sgml pgsql-bgwriter/doc/src/sgml/config.sgml
*** HEAD/doc/src/sgml/config.sgml	Mon Mar  5 09:48:58 2007
--- pgsql-bgwriter/doc/src/sgml/config.sgml	Mon Mar  5 12:39:42 2007
*************** SET ENABLE_SEQSCAN TO OFF;
*** 1208,1248 ****
         </listitem>
        </varlistentry>
  
-       <varlistentry id="guc-bgwriter-lru-percent" xreflabel="bgwriter_lru_percent">
-        <term><varname>bgwriter_lru_percent</varname> (<type>floating point</type>)</term>
-        <indexterm>
-         <primary><varname>bgwriter_lru_percent</> configuration parameter</primary>
-        </indexterm>
-        <listitem>
-         <para>
-          To reduce the probability that server processes will need to issue
-          their own writes, the background writer tries to write buffers that
-          are likely to be recycled soon.  In each round, it examines up to
-          <varname>bgwriter_lru_percent</> of the buffers that are nearest to
-          being recycled, and writes any that are dirty.
-          The default value is 1.0 (1% of the total number of shared buffers).
-          This parameter can only be set in the <filename>postgresql.conf</>
-          file or on the server command line.
-         </para>
-        </listitem>
-       </varlistentry>
- 
-       <varlistentry id="guc-bgwriter-lru-maxpages" xreflabel="bgwriter_lru_maxpages">
-        <term><varname>bgwriter_lru_maxpages</varname> (<type>integer</type>)</term>
-        <indexterm>
-         <primary><varname>bgwriter_lru_maxpages</> configuration parameter</primary>
-        </indexterm>
-        <listitem>
-         <para>
-          In each round, no more than this many buffers will be written
-          as a result of scanning soon-to-be-recycled buffers.
-          The default value is five buffers.
-          This parameter can only be set in the <filename>postgresql.conf</>
-          file or on the server command line.
-         </para>
-        </listitem>
-       </varlistentry>
- 
        <varlistentry id="guc-bgwriter-all-percent" xreflabel="bgwriter_all_percent">
         <term><varname>bgwriter_all_percent</varname> (<type>floating point</type>)</term>
         <indexterm>
--- 1208,1213 ----
*************** SET ENABLE_SEQSCAN TO OFF;
*** 1290,1303 ****
        caused by the background writer, but leave more work to be done
        at checkpoint time.  To reduce load spikes at checkpoints,
        increase these two values.
-       Similarly, smaller values of <varname>bgwriter_lru_percent</varname> and
-       <varname>bgwriter_lru_maxpages</varname> reduce the extra I/O load
-       caused by the background writer, but make it more likely that server
-       processes will have to issue writes for themselves, delaying interactive
-       queries.
        To disable background writing entirely,
!       set both <varname>maxpages</varname> values and/or both
!       <varname>percent</varname> values to zero.
       </para>
      </sect2>
     </sect1>
--- 1255,1269 ----
        caused by the background writer, but leave more work to be done
        at checkpoint time.  To reduce load spikes at checkpoints,
        increase these two values.
        To disable background writing entirely,
!       set <varname>bgwriter_all_percent</varname> value and/or
!       <varname>bgwriter_all_maxpages</varname> value to zero.
!      </para>
!      <para>
!       Also, to reduce the probability that server processes will need to
!       issue their own writes, the background writer tries to write buffers
!       that are likely to be recycled soon. The amount of writes are adjusted
!       automatically.
       </para>
      </sect2>
     </sect1>
diff -cpr HEAD/src/backend/postmaster/bgwriter.c pgsql-bgwriter/src/backend/postmaster/bgwriter.c
*** HEAD/src/backend/postmaster/bgwriter.c	Mon Jan 22 13:08:10 2007
--- pgsql-bgwriter/src/backend/postmaster/bgwriter.c	Mon Mar  5 12:40:14 2007
*************** static volatile sig_atomic_t shutdown_re
*** 141,147 ****
  /*
   * Private state
   */
! static bool am_bg_writer = false;
  
  static bool ckpt_active = false;
  
--- 141,147 ----
  /*
   * Private state
   */
! /*static*/ bool am_bg_writer = false;	/* ONLY FOR DEBUG */
  
  static bool ckpt_active = false;
  
*************** BackgroundWriterMain(void)
*** 484,491 ****
  		 *
  		 * We absorb pending requests after each short sleep.
  		 */
! 		if ((bgwriter_all_percent > 0.0 && bgwriter_all_maxpages > 0) ||
! 			(bgwriter_lru_percent > 0.0 && bgwriter_lru_maxpages > 0))
  			udelay = BgWriterDelay * 1000L;
  		else if (XLogArchiveTimeout > 0)
  			udelay = 1000000L;	/* One second */
--- 484,490 ----
  		 *
  		 * We absorb pending requests after each short sleep.
  		 */
! 		if (bgwriter_all_percent > 0.0 && bgwriter_all_maxpages > 0)
  			udelay = BgWriterDelay * 1000L;
  		else if (XLogArchiveTimeout > 0)
  			udelay = 1000000L;	/* One second */
diff -cpr HEAD/src/backend/storage/buffer/bufmgr.c pgsql-bgwriter/src/backend/storage/buffer/bufmgr.c
*** HEAD/src/backend/storage/buffer/bufmgr.c	Mon Feb  5 10:35:58 2007
--- pgsql-bgwriter/src/backend/storage/buffer/bufmgr.c	Mon Mar  5 12:41:09 2007
***************
*** 62,72 ****
  
  /* GUC variables */
  bool		zero_damaged_pages = false;
- double		bgwriter_lru_percent = 1.0;
  double		bgwriter_all_percent = 0.333;
- int			bgwriter_lru_maxpages = 5;
  int			bgwriter_all_maxpages = 5;
  
  
  long		NDirectFileRead;	/* some I/O's are direct file access. bypass
  								 * bufmgr */
--- 62,71 ----
  
  /* GUC variables */
  bool		zero_damaged_pages = false;
  double		bgwriter_all_percent = 0.333;
  int			bgwriter_all_maxpages = 5;
  
+ static int	bgwriter_lru_maxpages = 5;	/* adjusted automatically */
  
  long		NDirectFileRead;	/* some I/O's are direct file access. bypass
  								 * bufmgr */
*************** BufferSync(void)
*** 945,956 ****
  {
  	int			buf_id;
  	int			num_to_scan;
  	int			absorb_counter;
  
  	/*
  	 * Find out where to start the circular scan.
  	 */
! 	buf_id = StrategySyncStart();
  
  	/* Make sure we can handle the pin inside SyncOneBuffer */
  	ResourceOwnerEnlargeBuffers(CurrentResourceOwner);
--- 944,956 ----
  {
  	int			buf_id;
  	int			num_to_scan;
+ 	int			num_to_clean;
  	int			absorb_counter;
  
  	/*
  	 * Find out where to start the circular scan.
  	 */
! 	buf_id = StrategySyncStart(&num_to_clean);
  
  	/* Make sure we can handle the pin inside SyncOneBuffer */
  	ResourceOwnerEnlargeBuffers(CurrentResourceOwner);
*************** BgBufferSync(void)
*** 992,997 ****
--- 992,998 ----
  	static int	buf_id1 = 0;
  	int			buf_id2;
  	int			num_to_scan;
+ 	int			num_to_clean;
  	int			num_written;
  
  	/* Make sure we can handle the pin inside SyncOneBuffer */
*************** BgBufferSync(void)
*** 1036,1058 ****
  	 * This loop considers only unpinned buffers close to the clock sweep
  	 * point.
  	 */
! 	if (bgwriter_lru_percent > 0.0 && bgwriter_lru_maxpages > 0)
! 	{
! 		num_to_scan = (int) ((NBuffers * bgwriter_lru_percent + 99) / 100);
! 		num_written = 0;
  
! 		buf_id2 = StrategySyncStart();
  
! 		while (num_to_scan-- > 0)
! 		{
! 			if (SyncOneBuffer(buf_id2, true))
! 			{
! 				if (++num_written >= bgwriter_lru_maxpages)
! 					break;
! 			}
! 			if (++buf_id2 >= NBuffers)
! 				buf_id2 = 0;
! 		}
  	}
  }
  
--- 1037,1061 ----
  	 * This loop considers only unpinned buffers close to the clock sweep
  	 * point.
  	 */
! 	buf_id2 = StrategySyncStart(&num_to_clean);
! 	if (bgwriter_lru_maxpages < num_to_clean)
! 		bgwriter_lru_maxpages -= 1;
! 	else
! 		bgwriter_lru_maxpages += 1;
  
! 	{
! 		static int counter = 0;
! 		if ((++counter) % 50 == 0)
! 		    elog(LOG, "bgwriter_lru_maxpages = %d", bgwriter_lru_maxpages);
! 	}
  
! 	num_written = 0;
! 	while (num_written < bgwriter_lru_maxpages)
! 	{
! 		if (SyncOneBuffer(buf_id2, true))
!             ++num_written;
! 		if (++buf_id2 >= NBuffers)
! 			buf_id2 = 0;
  	}
  }
  
*************** BgBufferSync(void)
*** 1062,1070 ****
   * If skip_pinned is true, we don't write currently-pinned buffers, nor
   * buffers marked recently used, as these are not replacement candidates.
   *
!  * Returns true if buffer was written, else false.	(This could be in error
!  * if FlushBuffers finds the buffer clean after locking it, but we don't
!  * care all that much.)
   *
   * Note: caller must have done ResourceOwnerEnlargeBuffers.
   */
--- 1065,1073 ----
   * If skip_pinned is true, we don't write currently-pinned buffers, nor
   * buffers marked recently used, as these are not replacement candidates.
   *
!  * Returns true if buffer was written or recyclable soon, else false.
!  * (This could be in error if FlushBuffers finds the buffer clean after
!  * locking it, but we don't care all that much.)
   *
   * Note: caller must have done ResourceOwnerEnlargeBuffers.
   */
*************** SyncOneBuffer(int buf_id, bool skip_pinn
*** 1083,1098 ****
  	 * upcoming changes and so we are not required to write such dirty buffer.
  	 */
  	LockBufHdr(bufHdr);
! 	if (!(bufHdr->flags & BM_VALID) || !(bufHdr->flags & BM_DIRTY))
  	{
  		UnlockBufHdr(bufHdr);
  		return false;
  	}
! 	if (skip_pinned &&
! 		(bufHdr->refcount != 0 || bufHdr->usage_count != 0))
  	{
  		UnlockBufHdr(bufHdr);
! 		return false;
  	}
  
  	/*
--- 1086,1101 ----
  	 * upcoming changes and so we are not required to write such dirty buffer.
  	 */
  	LockBufHdr(bufHdr);
! 	if (skip_pinned &&
! 		(bufHdr->refcount != 0 || bufHdr->usage_count != 0))
  	{
  		UnlockBufHdr(bufHdr);
  		return false;
  	}
! 	if (!(bufHdr->flags & BM_VALID) || !(bufHdr->flags & BM_DIRTY))
  	{
  		UnlockBufHdr(bufHdr);
! 		return skip_pinned;	/* We can recycle non dirty buffers soon. */
  	}
  
  	/*
*************** PrintBufferLeakWarning(Buffer buffer)
*** 1272,1279 ****
--- 1275,1284 ----
  void
  FlushBufferPool(void)
  {
+ 	StrategyShowReports();	/* ONLY FOR DEBUG */
  	BufferSync();
  	smgrsync();
+ 	StrategyShowReports();	/* ONLY FOR DEBUG */
  }
  
  
*************** FlushBuffer(volatile BufferDesc *buf, SM
*** 1365,1370 ****
--- 1370,1377 ----
  	if (!StartBufferIO(buf, false))
  		return;
  
+ 	StrategyReportWrite();	/* ONLY FOR DEBUG */
+ 
  	/* Setup error traceback support for ereport() */
  	errcontext.callback = buffer_write_error_callback;
  	errcontext.arg = (void *) buf;
diff -cpr HEAD/src/backend/storage/buffer/freelist.c pgsql-bgwriter/src/backend/storage/buffer/freelist.c
*** HEAD/src/backend/storage/buffer/freelist.c	Thu Jan 11 14:20:57 2007
--- pgsql-bgwriter/src/backend/storage/buffer/freelist.c	Mon Mar  5 12:36:35 2007
*************** typedef struct
*** 27,32 ****
--- 27,37 ----
  	/* Clock sweep hand: index of next buffer to consider grabbing */
  	int			nextVictimBuffer;
  
+ 	int			numGetBuffer;		/* Buffer request count per cycle */
+ 	
+ 	int			writtenByBgWriter;	/* ONLY FOR DEBUG */
+ 	int			writtenByBackends;	/* ONLY FOR DEBUG */
+ 
  	int			firstFreeBuffer;	/* Head of list of unused buffers */
  	int			lastFreeBuffer; /* Tail of list of unused buffers */
  
*************** StrategyGetBuffer(void)
*** 63,68 ****
--- 68,75 ----
  
  	LWLockAcquire(BufFreelistLock, LW_EXCLUSIVE);
  
+ 	StrategyControl->numGetBuffer++;
+ 
  	/*
  	 * Try to get a buffer from the freelist.  Note that the freeNext fields
  	 * are considered to be protected by the BufFreelistLock not the
*************** StrategyFreeBuffer(volatile BufferDesc *
*** 176,191 ****
   * BufferSync() will proceed circularly around the buffer array from there.
   */
  int
! StrategySyncStart(void)
  {
  	int			result;
  
- 	/*
- 	 * We could probably dispense with the locking here, but just to be safe
- 	 * ...
- 	 */
  	LWLockAcquire(BufFreelistLock, LW_EXCLUSIVE);
  	result = StrategyControl->nextVictimBuffer;
  	LWLockRelease(BufFreelistLock);
  	return result;
  }
--- 183,196 ----
   * BufferSync() will proceed circularly around the buffer array from there.
   */
  int
! StrategySyncStart(int *num_to_clean)
  {
  	int			result;
  
  	LWLockAcquire(BufFreelistLock, LW_EXCLUSIVE);
  	result = StrategyControl->nextVictimBuffer;
+ 	*num_to_clean = StrategyControl->numGetBuffer * 2;	/* safety margin */
+ 	StrategyControl->numGetBuffer = 0;
  	LWLockRelease(BufFreelistLock);
  	return result;
  }
*************** StrategyInitialize(bool init)
*** 270,276 ****
--- 275,303 ----
  
  		/* Initialize the clock sweep pointer */
  		StrategyControl->nextVictimBuffer = 0;
+ 
+ 		StrategyControl->numGetBuffer = 0;
+ 		StrategyControl->writtenByBgWriter = 0;
+ 		StrategyControl->writtenByBackends = 0;
  	}
  	else
  		Assert(!init);
  }
+ 
+ void
+ StrategyReportWrite(void)
+ {
+ 	extern bool am_bg_writer;
+ 	if (am_bg_writer)
+ 		StrategyControl->writtenByBgWriter++;
+ 	else
+ 		StrategyControl->writtenByBackends++;
+ }
+ 
+ void
+ StrategyShowReports(void)
+ {
+ 	elog(LOG, "Write stats : bgwriter/backends = %d/%d",
+ 		StrategyControl->writtenByBgWriter,
+ 		StrategyControl->writtenByBackends);
+ }
diff -cpr HEAD/src/backend/utils/misc/guc.c pgsql-bgwriter/src/backend/utils/misc/guc.c
*** HEAD/src/backend/utils/misc/guc.c	Mon Mar  5 09:48:58 2007
--- pgsql-bgwriter/src/backend/utils/misc/guc.c	Mon Mar  5 12:39:42 2007
*************** static struct config_int ConfigureNamesI
*** 1505,1519 ****
  	},
  
  	{
- 		{"bgwriter_lru_maxpages", PGC_SIGHUP, RESOURCES,
- 			gettext_noop("Background writer maximum number of LRU pages to flush per round."),
- 			NULL
- 		},
- 		&bgwriter_lru_maxpages,
- 		5, 0, 1000, NULL, NULL
- 	},
- 
- 	{
  		{"bgwriter_all_maxpages", PGC_SIGHUP, RESOURCES,
  			gettext_noop("Background writer maximum number of all pages to flush per round."),
  			NULL
--- 1505,1510 ----
*************** static struct config_real ConfigureNames
*** 1757,1771 ****
  	},
  
  	{
- 		{"bgwriter_lru_percent", PGC_SIGHUP, RESOURCES,
- 			gettext_noop("Background writer percentage of LRU buffers to flush per round."),
- 			NULL
- 		},
- 		&bgwriter_lru_percent,
- 		1.0, 0.0, 100.0, NULL, NULL
- 	},
- 
- 	{
  		{"bgwriter_all_percent", PGC_SIGHUP, RESOURCES,
  			gettext_noop("Background writer percentage of all buffers to flush per round."),
  			NULL
--- 1748,1753 ----
diff -cpr HEAD/src/backend/utils/misc/postgresql.conf.sample pgsql-bgwriter/src/backend/utils/misc/postgresql.conf.sample
*** HEAD/src/backend/utils/misc/postgresql.conf.sample	Mon Mar  5 09:48:58 2007
--- pgsql-bgwriter/src/backend/utils/misc/postgresql.conf.sample	Mon Mar  5 12:39:42 2007
***************
*** 138,146 ****
  # - Background writer -
  
  #bgwriter_delay = 200ms			# 10-10000ms between rounds
! #bgwriter_lru_percent = 1.0		# 0-100% of LRU buffers scanned/round
! #bgwriter_lru_maxpages = 5		# 0-1000 buffers max written/round
! #bgwriter_all_percent = 0.333		# 0-100% of all buffers scanned/round
  #bgwriter_all_maxpages = 5		# 0-1000 buffers max written/round
  
  
--- 138,144 ----
  # - Background writer -
  
  #bgwriter_delay = 200ms			# 10-10000ms between rounds
! #bgwriter_all_percent = 0.333		# 0-100% of buffers scanned/round
  #bgwriter_all_maxpages = 5		# 0-1000 buffers max written/round
  
  
diff -cpr HEAD/src/include/storage/buf_internals.h pgsql-bgwriter/src/include/storage/buf_internals.h
*** HEAD/src/include/storage/buf_internals.h	Thu Jan 11 14:20:57 2007
--- pgsql-bgwriter/src/include/storage/buf_internals.h	Mon Mar  5 12:36:35 2007
*************** extern long int LocalBufferFlushCount;
*** 186,195 ****
  /* freelist.c */
  extern volatile BufferDesc *StrategyGetBuffer(void);
  extern void StrategyFreeBuffer(volatile BufferDesc *buf, bool at_head);
! extern int	StrategySyncStart(void);
  extern Size StrategyShmemSize(void);
  extern void StrategyInitialize(bool init);
  
  /* buf_table.c */
  extern Size BufTableShmemSize(int size);
  extern void InitBufTable(int size);
--- 186,198 ----
  /* freelist.c */
  extern volatile BufferDesc *StrategyGetBuffer(void);
  extern void StrategyFreeBuffer(volatile BufferDesc *buf, bool at_head);
! extern int	StrategySyncStart(int *num_to_clean);
  extern Size StrategyShmemSize(void);
  extern void StrategyInitialize(bool init);
  
+ extern void StrategyReportWrite(void);	/* ONLY FOR DEBUG */
+ extern void StrategyShowReports(void);	/* ONLY FOR DEBUG */
+ 
  /* buf_table.c */
  extern Size BufTableShmemSize(int size);
  extern void InitBufTable(int size);
diff -cpr HEAD/src/include/storage/bufmgr.h pgsql-bgwriter/src/include/storage/bufmgr.h
*** HEAD/src/include/storage/bufmgr.h	Thu Jan 11 14:20:57 2007
--- pgsql-bgwriter/src/include/storage/bufmgr.h	Mon Mar  5 12:39:42 2007
*************** extern DLLIMPORT int NBuffers;
*** 24,32 ****
  
  /* in bufmgr.c */
  extern bool zero_damaged_pages;
- extern double bgwriter_lru_percent;
  extern double bgwriter_all_percent;
- extern int	bgwriter_lru_maxpages;
  extern int	bgwriter_all_maxpages;
  
  /* in buf_init.c */
--- 24,30 ----