Index: src/test/regress/expected/rules.out
===================================================================
*** src/test/regress/expected/rules.out	(revision 4)
--- src/test/regress/expected/rules.out	(working copy)
***************
*** 1292,1298 ****
   pg_stat_activity         | SELECT d.oid AS datid, d.datname, pg_stat_get_backend_pid(s.backendid) AS procpid, pg_stat_get_backend_userid(s.backendid) AS usesysid, u.rolname AS usename, pg_stat_get_backend_activity(s.backendid) AS current_query, pg_stat_get_backend_waiting(s.backendid) AS waiting, pg_stat_get_backend_txn_start(s.backendid) AS txn_start, pg_stat_get_backend_activity_start(s.backendid) AS query_start, pg_stat_get_backend_start(s.backendid) AS backend_start, pg_stat_get_backend_client_addr(s.backendid) AS client_addr, pg_stat_get_backend_client_port(s.backendid) AS client_port FROM pg_database d, (SELECT pg_stat_get_backend_idset() AS backendid) s, pg_authid u WHERE ((pg_stat_get_backend_dbid(s.backendid) = d.oid) AND (pg_stat_get_backend_userid(s.backendid) = u.oid));
   pg_stat_all_indexes      | SELECT c.oid AS relid, i.oid AS indexrelid, n.nspname AS schemaname, c.relname, i.relname AS indexrelname, pg_stat_get_numscans(i.oid) AS idx_scan, pg_stat_get_tuples_returned(i.oid) AS idx_tup_read, pg_stat_get_tuples_fetched(i.oid) AS idx_tup_fetch FROM (((pg_class c JOIN pg_index x ON ((c.oid = x.indrelid))) JOIN pg_class i ON ((i.oid = x.indexrelid))) LEFT JOIN pg_namespace n ON ((n.oid = c.relnamespace))) WHERE (c.relkind = ANY (ARRAY['r'::"char", 't'::"char"]));
   pg_stat_all_tables       | SELECT c.oid AS relid, n.nspname AS schemaname, c.relname, pg_stat_get_numscans(c.oid) AS seq_scan, pg_stat_get_tuples_returned(c.oid) AS seq_tup_read, (sum(pg_stat_get_numscans(i.indexrelid)))::bigint AS idx_scan, ((sum(pg_stat_get_tuples_fetched(i.indexrelid)))::bigint + pg_stat_get_tuples_fetched(c.oid)) AS idx_tup_fetch, pg_stat_get_tuples_inserted(c.oid) AS n_tup_ins, pg_stat_get_tuples_updated(c.oid) AS n_tup_upd, pg_stat_get_tuples_deleted(c.oid) AS n_tup_del, pg_stat_get_live_tuples(c.oid) AS n_live_tup, pg_stat_get_dead_tuples(c.oid) AS n_dead_tup, pg_stat_get_last_vacuum_time(c.oid) AS last_vacuum, pg_stat_get_last_autovacuum_time(c.oid) AS last_autovacuum, pg_stat_get_last_analyze_time(c.oid) AS last_analyze, pg_stat_get_last_autoanalyze_time(c.oid) AS last_autoanalyze FROM ((pg_class c LEFT JOIN pg_index i ON ((c.oid = i.indrelid))) LEFT JOIN pg_namespace n ON ((n.oid = c.relnamespace))) WHERE (c.relkind = ANY (ARRAY['r'::"char", 't'::"char"])) GROUP BY c.oid, n.nspname, c.relname;
!  pg_stat_bgwriter         | SELECT pg_stat_get_bgwriter_timed_checkpoints() AS checkpoints_timed, pg_stat_get_bgwriter_requested_checkpoints() AS checkpoints_req, pg_stat_get_bgwriter_buf_written_checkpoints() AS buffers_checkpoint, pg_stat_get_bgwriter_buf_written_clean() AS buffers_clean, pg_stat_get_bgwriter_maxwritten_clean() AS maxwritten_clean;
   pg_stat_database         | SELECT d.oid AS datid, d.datname, pg_stat_get_db_numbackends(d.oid) AS numbackends, pg_stat_get_db_xact_commit(d.oid) AS xact_commit, pg_stat_get_db_xact_rollback(d.oid) AS xact_rollback, (pg_stat_get_db_blocks_fetched(d.oid) - pg_stat_get_db_blocks_hit(d.oid)) AS blks_read, pg_stat_get_db_blocks_hit(d.oid) AS blks_hit, pg_stat_get_db_tuples_returned(d.oid) AS tup_returned, pg_stat_get_db_tuples_fetched(d.oid) AS tup_fetched, pg_stat_get_db_tuples_inserted(d.oid) AS tup_inserted, pg_stat_get_db_tuples_updated(d.oid) AS tup_updated, pg_stat_get_db_tuples_deleted(d.oid) AS tup_deleted FROM pg_database d;
   pg_stat_sys_indexes      | SELECT pg_stat_all_indexes.relid, pg_stat_all_indexes.indexrelid, pg_stat_all_indexes.schemaname, pg_stat_all_indexes.relname, pg_stat_all_indexes.indexrelname, pg_stat_all_indexes.idx_scan, pg_stat_all_indexes.idx_tup_read, pg_stat_all_indexes.idx_tup_fetch FROM pg_stat_all_indexes WHERE (pg_stat_all_indexes.schemaname = ANY (ARRAY['pg_catalog'::name, 'pg_toast'::name, 'information_schema'::name]));
   pg_stat_sys_tables       | SELECT pg_stat_all_tables.relid, pg_stat_all_tables.schemaname, pg_stat_all_tables.relname, pg_stat_all_tables.seq_scan, pg_stat_all_tables.seq_tup_read, pg_stat_all_tables.idx_scan, pg_stat_all_tables.idx_tup_fetch, pg_stat_all_tables.n_tup_ins, pg_stat_all_tables.n_tup_upd, pg_stat_all_tables.n_tup_del, pg_stat_all_tables.n_live_tup, pg_stat_all_tables.n_dead_tup, pg_stat_all_tables.last_vacuum, pg_stat_all_tables.last_autovacuum, pg_stat_all_tables.last_analyze, pg_stat_all_tables.last_autoanalyze FROM pg_stat_all_tables WHERE (pg_stat_all_tables.schemaname = ANY (ARRAY['pg_catalog'::name, 'pg_toast'::name, 'information_schema'::name]));
--- 1292,1298 ----
   pg_stat_activity         | SELECT d.oid AS datid, d.datname, pg_stat_get_backend_pid(s.backendid) AS procpid, pg_stat_get_backend_userid(s.backendid) AS usesysid, u.rolname AS usename, pg_stat_get_backend_activity(s.backendid) AS current_query, pg_stat_get_backend_waiting(s.backendid) AS waiting, pg_stat_get_backend_txn_start(s.backendid) AS txn_start, pg_stat_get_backend_activity_start(s.backendid) AS query_start, pg_stat_get_backend_start(s.backendid) AS backend_start, pg_stat_get_backend_client_addr(s.backendid) AS client_addr, pg_stat_get_backend_client_port(s.backendid) AS client_port FROM pg_database d, (SELECT pg_stat_get_backend_idset() AS backendid) s, pg_authid u WHERE ((pg_stat_get_backend_dbid(s.backendid) = d.oid) AND (pg_stat_get_backend_userid(s.backendid) = u.oid));
   pg_stat_all_indexes      | SELECT c.oid AS relid, i.oid AS indexrelid, n.nspname AS schemaname, c.relname, i.relname AS indexrelname, pg_stat_get_numscans(i.oid) AS idx_scan, pg_stat_get_tuples_returned(i.oid) AS idx_tup_read, pg_stat_get_tuples_fetched(i.oid) AS idx_tup_fetch FROM (((pg_class c JOIN pg_index x ON ((c.oid = x.indrelid))) JOIN pg_class i ON ((i.oid = x.indexrelid))) LEFT JOIN pg_namespace n ON ((n.oid = c.relnamespace))) WHERE (c.relkind = ANY (ARRAY['r'::"char", 't'::"char"]));
   pg_stat_all_tables       | SELECT c.oid AS relid, n.nspname AS schemaname, c.relname, pg_stat_get_numscans(c.oid) AS seq_scan, pg_stat_get_tuples_returned(c.oid) AS seq_tup_read, (sum(pg_stat_get_numscans(i.indexrelid)))::bigint AS idx_scan, ((sum(pg_stat_get_tuples_fetched(i.indexrelid)))::bigint + pg_stat_get_tuples_fetched(c.oid)) AS idx_tup_fetch, pg_stat_get_tuples_inserted(c.oid) AS n_tup_ins, pg_stat_get_tuples_updated(c.oid) AS n_tup_upd, pg_stat_get_tuples_deleted(c.oid) AS n_tup_del, pg_stat_get_live_tuples(c.oid) AS n_live_tup, pg_stat_get_dead_tuples(c.oid) AS n_dead_tup, pg_stat_get_last_vacuum_time(c.oid) AS last_vacuum, pg_stat_get_last_autovacuum_time(c.oid) AS last_autovacuum, pg_stat_get_last_analyze_time(c.oid) AS last_analyze, pg_stat_get_last_autoanalyze_time(c.oid) AS last_autoanalyze FROM ((pg_class c LEFT JOIN pg_index i ON ((c.oid = i.indrelid))) LEFT JOIN pg_namespace n ON ((n.oid = c.relnamespace))) WHERE (c.relkind = ANY (ARRAY['r'::"char", 't'::"char"])) GROUP BY c.oid, n.nspname, c.relname;
!  pg_stat_bgwriter         | SELECT pg_stat_get_bgwriter_timed_checkpoints() AS checkpoints_timed, pg_stat_get_bgwriter_requested_checkpoints() AS checkpoints_req, pg_stat_get_bgwriter_buf_written_checkpoints() AS buffers_checkpoint, pg_stat_get_bgwriter_buf_written_clean() AS buffers_clean, pg_stat_get_bgwriter_maxwritten_clean() AS maxwritten_clean, pg_stat_get_bgwriter_buf_written_backend() AS buffers_backend, pg_stat_get_bgwriter_buf_alloc() AS buffers_alloc;
   pg_stat_database         | SELECT d.oid AS datid, d.datname, pg_stat_get_db_numbackends(d.oid) AS numbackends, pg_stat_get_db_xact_commit(d.oid) AS xact_commit, pg_stat_get_db_xact_rollback(d.oid) AS xact_rollback, (pg_stat_get_db_blocks_fetched(d.oid) - pg_stat_get_db_blocks_hit(d.oid)) AS blks_read, pg_stat_get_db_blocks_hit(d.oid) AS blks_hit, pg_stat_get_db_tuples_returned(d.oid) AS tup_returned, pg_stat_get_db_tuples_fetched(d.oid) AS tup_fetched, pg_stat_get_db_tuples_inserted(d.oid) AS tup_inserted, pg_stat_get_db_tuples_updated(d.oid) AS tup_updated, pg_stat_get_db_tuples_deleted(d.oid) AS tup_deleted FROM pg_database d;
   pg_stat_sys_indexes      | SELECT pg_stat_all_indexes.relid, pg_stat_all_indexes.indexrelid, pg_stat_all_indexes.schemaname, pg_stat_all_indexes.relname, pg_stat_all_indexes.indexrelname, pg_stat_all_indexes.idx_scan, pg_stat_all_indexes.idx_tup_read, pg_stat_all_indexes.idx_tup_fetch FROM pg_stat_all_indexes WHERE (pg_stat_all_indexes.schemaname = ANY (ARRAY['pg_catalog'::name, 'pg_toast'::name, 'information_schema'::name]));
   pg_stat_sys_tables       | SELECT pg_stat_all_tables.relid, pg_stat_all_tables.schemaname, pg_stat_all_tables.relname, pg_stat_all_tables.seq_scan, pg_stat_all_tables.seq_tup_read, pg_stat_all_tables.idx_scan, pg_stat_all_tables.idx_tup_fetch, pg_stat_all_tables.n_tup_ins, pg_stat_all_tables.n_tup_upd, pg_stat_all_tables.n_tup_del, pg_stat_all_tables.n_live_tup, pg_stat_all_tables.n_dead_tup, pg_stat_all_tables.last_vacuum, pg_stat_all_tables.last_autovacuum, pg_stat_all_tables.last_analyze, pg_stat_all_tables.last_autoanalyze FROM pg_stat_all_tables WHERE (pg_stat_all_tables.schemaname = ANY (ARRAY['pg_catalog'::name, 'pg_toast'::name, 'information_schema'::name]));
Index: src/include/storage/buf_internals.h
===================================================================
*** src/include/storage/buf_internals.h	(revision 4)
--- src/include/storage/buf_internals.h	(working copy)
***************
*** 188,194 ****
  extern bool StrategyRejectBuffer(BufferAccessStrategy strategy,
  								 volatile BufferDesc *buf);
  
! extern int	StrategySyncStart(void);
  extern Size StrategyShmemSize(void);
  extern void StrategyInitialize(bool init);
  
--- 188,195 ----
  extern bool StrategyRejectBuffer(BufferAccessStrategy strategy,
  								 volatile BufferDesc *buf);
  
! extern int	StrategySyncStart(int *num_buf_alloc, int *num_backend_writes);
! extern void StrategyReportWrite(void);
  extern Size StrategyShmemSize(void);
  extern void StrategyInitialize(bool init);
  
Index: src/include/pgstat.h
===================================================================
*** src/include/pgstat.h	(revision 4)
--- src/include/pgstat.h	(working copy)
***************
*** 293,298 ****
--- 293,300 ----
  	PgStat_Counter	m_buf_written_checkpoints;
  	PgStat_Counter	m_buf_written_clean;
  	PgStat_Counter	m_maxwritten_clean;
+ 	PgStat_Counter  m_buf_written_backend;
+ 	PgStat_Counter  m_buf_alloc;
  } PgStat_MsgBgWriter;
  
  
***************
*** 392,397 ****
--- 394,401 ----
  	PgStat_Counter  buf_written_checkpoints;
  	PgStat_Counter  buf_written_clean;
  	PgStat_Counter  maxwritten_clean;
+ 	PgStat_Counter  buf_written_backend;
+ 	PgStat_Counter  buf_alloc;
  } PgStat_GlobalStats;
  
  
Index: src/include/catalog/pg_proc.h
===================================================================
*** src/include/catalog/pg_proc.h	(revision 4)
--- src/include/catalog/pg_proc.h	(working copy)
***************
*** 2937,2942 ****
--- 2937,2947 ----
  DESCR("Statistics: Number of buffers written by the bgwriter for cleaning dirty buffers");
  DATA(insert OID = 2773 ( pg_stat_get_bgwriter_maxwritten_clean PGNSP PGUID 12 1 0 f f t f s 0 20 "" _null_ _null_ _null_ pg_stat_get_bgwriter_maxwritten_clean - _null_ ));
  DESCR("Statistics: Number of times the bgwriter stopped processing when it had written too many buffers while cleaning");
+ DATA(insert OID = 2774 ( pg_stat_get_bgwriter_buf_written_backend PGNSP PGUID 12 1 0 f f t f s 0 20 "" _null_ _null_ _null_ pg_stat_get_bgwriter_buf_written_backend - _null_ ));
+ DESCR("Statistics: Number of buffers written by backends such as clients");
+ DATA(insert OID = 2775 ( pg_stat_get_bgwriter_buf_alloc PGNSP PGUID 12 1 0 f f t f s 0 20 "" _null_ _null_ _null_ pg_stat_get_bgwriter_buf_alloc - _null_ ));
+ DESCR("Statistics: Number of buffers allocated for the shared buffer cache");
+ 
  DATA(insert OID = 2230 (  pg_stat_clear_snapshot		PGNSP PGUID 12 1 0 f f f f v 0 2278  "" _null_ _null_ _null_	pg_stat_clear_snapshot - _null_ ));
  DESCR("Statistics: Discard current transaction's statistics snapshot");
  DATA(insert OID = 2274 (  pg_stat_reset					PGNSP PGUID 12 1 0 f f f f v 0 2278  "" _null_ _null_ _null_	pg_stat_reset - _null_ ));
Index: src/backend/utils/adt/pgstatfuncs.c
===================================================================
*** src/backend/utils/adt/pgstatfuncs.c	(revision 4)
--- src/backend/utils/adt/pgstatfuncs.c	(working copy)
***************
*** 66,71 ****
--- 66,73 ----
  extern Datum pg_stat_get_bgwriter_buf_written_checkpoints(PG_FUNCTION_ARGS);
  extern Datum pg_stat_get_bgwriter_buf_written_clean(PG_FUNCTION_ARGS);
  extern Datum pg_stat_get_bgwriter_maxwritten_clean(PG_FUNCTION_ARGS);
+ extern Datum pg_stat_get_bgwriter_buf_written_backend(PG_FUNCTION_ARGS);
+ extern Datum pg_stat_get_bgwriter_buf_alloc(PG_FUNCTION_ARGS);
  
  extern Datum pg_stat_clear_snapshot(PG_FUNCTION_ARGS);
  extern Datum pg_stat_reset(PG_FUNCTION_ARGS);
***************
*** 796,801 ****
--- 798,814 ----
  	PG_RETURN_INT64(pgstat_fetch_global()->maxwritten_clean);
  }
  
+ Datum
+ pg_stat_get_bgwriter_buf_written_backend(PG_FUNCTION_ARGS)
+ {
+ 	PG_RETURN_INT64(pgstat_fetch_global()->buf_written_backend);
+ }
+ 
+ Datum
+ pg_stat_get_bgwriter_buf_alloc(PG_FUNCTION_ARGS)
+ {
+ 	PG_RETURN_INT64(pgstat_fetch_global()->buf_alloc);
+ }
  
  /* Discard the active statistics snapshot */
  Datum
Index: src/backend/postmaster/pgstat.c
===================================================================
*** src/backend/postmaster/pgstat.c	(revision 4)
--- src/backend/postmaster/pgstat.c	(working copy)
***************
*** 3176,3179 ****
--- 3176,3181 ----
  	globalStats.buf_written_checkpoints += msg->m_buf_written_checkpoints;
  	globalStats.buf_written_clean += msg->m_buf_written_clean;
  	globalStats.maxwritten_clean += msg->m_maxwritten_clean;
+ 	globalStats.buf_written_backend += msg->m_buf_written_backend;
+ 	globalStats.buf_alloc += msg->m_buf_alloc;
  }
Index: src/backend/postmaster/bgwriter.c
===================================================================
*** src/backend/postmaster/bgwriter.c	(revision 4)
--- src/backend/postmaster/bgwriter.c	(working copy)
***************
*** 148,157 ****
  static volatile sig_atomic_t shutdown_requested = false;
  
  /*
!  * Private state
   */
! static bool am_bg_writer = false;
  
  static bool ckpt_active = false;
  
  /* these values are valid when ckpt_active is true: */
--- 148,161 ----
  static volatile sig_atomic_t shutdown_requested = false;
  
  /*
!  * Buffer activity statistics reporting works differently 
!  * when the current process is the background writer
   */
! bool am_bg_writer = false;
  
+ /*
+  * Private state
+  */
  static bool ckpt_active = false;
  
  /* these values are valid when ckpt_active is true: */
Index: src/backend/storage/buffer/bufmgr.c
===================================================================
*** src/backend/storage/buffer/bufmgr.c	(revision 4)
--- src/backend/storage/buffer/bufmgr.c	(working copy)
***************
*** 995,1000 ****
--- 995,1002 ----
  	int			num_to_scan;
  	int			num_to_write;
  	int			num_written;
+ 	int			recent_alloc;
+ 	int			num_backend_writes;
  
  	/* Make sure we can handle the pin inside SyncOneBuffer */
  	ResourceOwnerEnlargeBuffers(CurrentResourceOwner);
***************
*** 1044,1050 ****
  	 * BM_CHECKPOINT_NEEDED.  In this loop, we start at the clock sweep
  	 * point since we might as well dump soon-to-be-recycled buffers first.
  	 */
! 	buf_id = StrategySyncStart();
  	num_to_scan = NBuffers;
  	num_written = 0;
  	while (num_to_scan-- > 0)
--- 1046,1055 ----
  	 * BM_CHECKPOINT_NEEDED.  In this loop, we start at the clock sweep
  	 * point since we might as well dump soon-to-be-recycled buffers first.
  	 */
!     buf_id = StrategySyncStart(&recent_alloc,&num_backend_writes);
!     BgWriterStats.m_buf_alloc+=recent_alloc;
!     BgWriterStats.m_buf_written_backend+=num_backend_writes;
! 
  	num_to_scan = NBuffers;
  	num_written = 0;
  	while (num_to_scan-- > 0)
***************
*** 1115,1125 ****
--- 1120,1141 ----
  	int			buf_id;
  	int			num_to_scan;
  	int			num_written;
+ 	int			recent_alloc;
+ 	int			num_backend_writes;
  
  	/* Make sure we can handle the pin inside SyncOneBuffer */
  	ResourceOwnerEnlargeBuffers(CurrentResourceOwner);
  
  	/*
+ 	 * Find out where to start the circular scan and track how active
+ 	 * the freelist buffer manipulation code has been since our last call
+ 	 */
+ 
+ 	buf_id = StrategySyncStart(&recent_alloc,&num_backend_writes);
+ 	BgWriterStats.m_buf_alloc+=recent_alloc;
+ 	BgWriterStats.m_buf_written_backend+=num_backend_writes;
+ 
+ 	/*
  	 * The purpose of this sweep is to ensure that buffers that
  	 * will be recycled soon are clean when needed; these buffers are the ones
  	 * just ahead of the StrategySyncStart point. 
***************
*** 1127,1139 ****
  	 * 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_id = StrategySyncStart();
- 
  		while (num_to_scan-- > 0)
  		{
  			if (SyncOneBuffer(buf_id, true))
--- 1143,1154 ----
  	 * 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;
  
  		while (num_to_scan-- > 0)
  		{
  			if (SyncOneBuffer(buf_id, true))
***************
*** 1499,1504 ****
--- 1514,1520 ----
  			  false);
  
  	BufferFlushCount++;
+ 	StrategyReportWrite();
  
  	/*
  	 * Mark the buffer as clean (unless BM_JUST_DIRTIED has become set) and
Index: src/backend/storage/buffer/freelist.c
===================================================================
*** src/backend/storage/buffer/freelist.c	(revision 4)
--- src/backend/storage/buffer/freelist.c	(working copy)
***************
*** 29,34 ****
--- 29,36 ----
  
  	int			firstFreeBuffer;	/* Head of list of unused buffers */
  	int			lastFreeBuffer; /* Tail of list of unused buffers */
+ 	int			numGetBuffer; /* Calls to BufferAlloc since last reset */
+ 	int			numBackendWrites; /* Buffers written by backends since last reset */
  
  	/*
  	 * NOTE: lastFreeBuffer is undefined when firstFreeBuffer is -1 (that is,
***************
*** 70,75 ****
--- 72,79 ----
  	Buffer		buffers[1];				/* VARIABLE SIZE ARRAY */
  } BufferAccessStrategyData;
  
+ /* Used to determine which type of process we're running as */
+ extern bool am_bg_writer;
  
  /* Prototypes for internal functions */
  static volatile BufferDesc *GetBufferFromRing(BufferAccessStrategy strategy);
***************
*** 117,122 ****
--- 121,129 ----
  	/* Nope, so lock the freelist */
  	*lock_held = true;
  	LWLockAcquire(BufFreelistLock, LW_EXCLUSIVE);
+     /* XXX Selecting a strategy object isn't counted as a buffer allocations; 
+ 	 * is this the right thing to do? */
+ 	StrategyControl->numGetBuffer++;
  
  	/*
  	 * Try to get a buffer from the freelist.  Note that the freeNext fields
***************
*** 228,234 ****
   * BufferSync() will proceed circularly around the buffer array from there.
   */
  int
! StrategySyncStart(void)
  {
  	int			result;
  
--- 235,241 ----
   * BufferSync() will proceed circularly around the buffer array from there.
   */
  int
! StrategySyncStart(int *num_buf_alloc,int *num_backend_writes)
  {
  	int			result;
  
***************
*** 238,247 ****
--- 245,277 ----
  	 */
  	LWLockAcquire(BufFreelistLock, LW_EXCLUSIVE);
  	result = StrategyControl->nextVictimBuffer;
+ 
+ 	/* Return and reset statistics for activity since last call */
+ 	if (num_buf_alloc!=NULL) *num_buf_alloc=StrategyControl->numGetBuffer;
+ 	if (num_backend_writes!=NULL) *num_backend_writes=StrategyControl->numBackendWrites;
+ 	StrategyControl->numGetBuffer = 0;
+ 	StrategyControl->numBackendWrites = 0;
+ 
  	LWLockRelease(BufFreelistLock);
  	return result;
  }
  
+ /*
+  * StrategyReportWrite -- After a buffer is written out, update
+  * local statistics based on who did the writing
+  */
+ void
+ StrategyReportWrite(void)
+ {
+ 	/* The background writer keeps track of buffers it writes already,
+ 	 * only count backend writes */
+ 	if (!am_bg_writer) 
+ 	{
+ 		LWLockAcquire(BufFreelistLock, LW_EXCLUSIVE);
+ 		StrategyControl->numBackendWrites++;
+ 		LWLockRelease(BufFreelistLock);
+ 	}
+ }
  
  /*
   * StrategyShmemSize
***************
*** 313,318 ****
--- 343,350 ----
  
  		/* Initialize the clock sweep pointer */
  		StrategyControl->nextVictimBuffer = 0;
+ 		StrategyControl->numGetBuffer = 0;
+ 		StrategyControl->numBackendWrites = 0;
  	}
  	else
  		Assert(!init);
Index: src/backend/catalog/system_views.sql
===================================================================
*** src/backend/catalog/system_views.sql	(revision 4)
--- src/backend/catalog/system_views.sql	(working copy)
***************
*** 371,374 ****
--- 371,376 ----
          pg_stat_get_bgwriter_requested_checkpoints() AS checkpoints_req,
          pg_stat_get_bgwriter_buf_written_checkpoints() AS buffers_checkpoint,
          pg_stat_get_bgwriter_buf_written_clean() AS buffers_clean,
+         pg_stat_get_bgwriter_buf_written_backend() AS buffers_backend,
+         pg_stat_get_bgwriter_buf_alloc() AS buffers_alloc,
          pg_stat_get_bgwriter_maxwritten_clean() AS maxwritten_clean;
Index: doc/src/sgml/monitoring.sgml
===================================================================
*** doc/src/sgml/monitoring.sgml	(revision 4)
--- doc/src/sgml/monitoring.sgml	(working copy)
***************
*** 250,259 ****
       <row>
        <entry><structname>pg_stat_bgwriter</></entry>
        <entry>One row only, showing cluster-wide statistics from the
!       background writer: number of scheduled checkpoints, requested
!       checkpoints, buffers written by checkpoints and cleaning scans,
!       and the number of times the bgwriter stopped a cleaning scan
!       because it had written too many buffers.
       </entry>
       </row>
  
--- 250,262 ----
       <row>
        <entry><structname>pg_stat_bgwriter</></entry>
        <entry>One row only, showing cluster-wide statistics from the
!       background writer: number of scheduled checkpoints, requested 
!       checkpoints, buffers written by checkpoints and cleaning scans, 
!       and the number of times the bgwriter stopped a cleaning scan 
!       because it had written too many buffers.  Also includes
!       statistics about the shared buffer pool including total buffers
!       allocated and buffers written by backends (such as regular
!       database client processes).
       </entry>
       </row>
  
***************
*** 796,801 ****
--- 799,822 ----
       </row>
  
       <row>
+       <entry><literal><function>pg_stat_get_bgwriter_buf_written_backend</function>()</literal></entry>
+       <entry><type>bigint</type></entry>
+       <entry>
+        The number of buffers written by backends because they needed
+        to allocate a new buffer
+       </entry>
+      </row>
+ 
+      <row>
+       <entry><literal><function>pg_stat_get_bgwriter_buf_alloc</function>()</literal></entry>
+       <entry><type>bigint</type></entry>
+       <entry>
+        The total number of buffers allocated into the shared buffer 
+        cache
+       </entry>
+      </row>
+ 
+      <row>
        <entry><literal><function>pg_stat_clear_snapshot</function>()</literal></entry>
        <entry><type>void</type></entry>
        <entry>
