diff --git a/src/backend/bootstrap/bootstrap.c b/src/backend/bootstrap/bootstrap.c
index cfd8a553582451edba1c44f1dc68a2a978ab4814..bb67feab71fc3716d6e2e8d89de2c0a9f858901e 100644
--- a/src/backend/bootstrap/bootstrap.c
+++ b/src/backend/bootstrap/bootstrap.c
@@ -8,7 +8,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/bootstrap/bootstrap.c,v 1.166 2003/09/02 19:04:12 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/bootstrap/bootstrap.c,v 1.167 2003/11/19 15:55:07 wieck Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -428,8 +428,20 @@ BootstrapMain(int argc, char *argv[])
 
 	BaseInit();
 
+	/* needed to get LWLocks */
 	if (IsUnderPostmaster)
-		InitDummyProcess();		/* needed to get LWLocks */
+	{
+		switch (xlogop)
+		{
+			case BS_XLOG_BGWRITER:
+				InitDummyProcess(DUMMY_PROC_BGWRITER);	
+				break;
+		
+			default:
+				InitDummyProcess(DUMMY_PROC_DEFAULT);	
+				break;
+		}
+	}
 
 	/*
 	 * XLOG operations
@@ -453,6 +465,11 @@ BootstrapMain(int argc, char *argv[])
 										 * postmaster */
 			proc_exit(0);		/* done */
 
+		case BS_XLOG_BGWRITER:
+			CreateDummyCaches();
+			BufferBackgroundWriter();
+			proc_exit(0);		/* done */
+
 		case BS_XLOG_STARTUP:
 			StartupXLOG();
 			LoadFreeSpaceMap();
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 72f76b01b06d2e18e7e81fed3aee12932d3bd716..3d6c71e4e89fe6f356c11fd1eea8ba39a6c3d5af 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/catalog/index.c,v 1.221 2003/11/12 21:15:48 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/catalog/index.c,v 1.222 2003/11/19 15:55:07 wieck Exp $
  *
  *
  * INTERFACE ROUTINES
@@ -1043,7 +1043,7 @@ setRelhasindex(Oid relid, bool hasindex, bool isprimary, Oid reltoastidxid)
 		/* Send out shared cache inval if necessary */
 		if (!IsBootstrapProcessingMode())
 			CacheInvalidateHeapTuple(pg_class, tuple);
-		BufferSync();
+		BufferSync(-1, -1);
 	}
 	else if (dirty)
 	{
diff --git a/src/backend/commands/dbcommands.c b/src/backend/commands/dbcommands.c
index 320f1fc0deddf1f54d01980786250bf0ac9f0f9d..9abdb9555c67d546ce866300b21c6c5a0d4b9a62 100644
--- a/src/backend/commands/dbcommands.c
+++ b/src/backend/commands/dbcommands.c
@@ -9,7 +9,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/commands/dbcommands.c,v 1.126 2003/11/12 21:15:50 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/commands/dbcommands.c,v 1.127 2003/11/19 15:55:07 wieck Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -317,7 +317,7 @@ createdb(const CreatedbStmt *stmt)
 	 * up-to-date for the copy.  (We really only need to flush buffers for
 	 * the source database...)
 	 */
-	BufferSync();
+	BufferSync(-1, -1);
 
 	/*
 	 * Close virtual file descriptors so the kernel has more available for
@@ -454,7 +454,7 @@ createdb(const CreatedbStmt *stmt)
 	 * will see the new database in pg_database right away.  (They'll see
 	 * an uncommitted tuple, but they don't care; see GetRawDatabaseInfo.)
 	 */
-	BufferSync();
+	BufferSync(-1, -1);
 }
 
 
@@ -591,7 +591,7 @@ dropdb(const char *dbname)
 	 * (They'll see an uncommitted deletion, but they don't care; see
 	 * GetRawDatabaseInfo.)
 	 */
-	BufferSync();
+	BufferSync(-1, -1);
 }
 
 
@@ -688,7 +688,7 @@ RenameDatabase(const char *oldname, const char *newname)
 	 * see an uncommitted tuple, but they don't care; see
 	 * GetRawDatabaseInfo.)
 	 */
-	BufferSync();
+	BufferSync(-1, -1);
 }
 
 
diff --git a/src/backend/postmaster/postmaster.c b/src/backend/postmaster/postmaster.c
index 01c3a363c8f6d553d8a55b6a4b643c97023b4cc6..52c91fa97d903bcd33175ea4e90c141c868dd879 100644
--- a/src/backend/postmaster/postmaster.c
+++ b/src/backend/postmaster/postmaster.c
@@ -37,7 +37,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/postmaster/postmaster.c,v 1.348 2003/11/11 01:09:42 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/postmaster/postmaster.c,v 1.349 2003/11/19 15:55:07 wieck Exp $
  *
  * NOTES
  *
@@ -104,6 +104,7 @@
 #include "storage/pg_shmem.h"
 #include "storage/pmsignal.h"
 #include "storage/proc.h"
+#include "storage/bufmgr.h"
 #include "access/xlog.h"
 #include "tcop/tcopprot.h"
 #include "utils/guc.h"
@@ -224,7 +225,8 @@ char	   *preload_libraries_string = NULL;
 /* Startup/shutdown state */
 static pid_t StartupPID = 0,
 			ShutdownPID = 0,
-			CheckPointPID = 0;
+			CheckPointPID = 0,
+			BgWriterPID = 0;
 static time_t checkpointed = 0;
 
 #define			NoShutdown		0
@@ -298,6 +300,7 @@ __attribute__((format(printf, 1, 2)));
 
 #define StartupDataBase()		SSDataBase(BS_XLOG_STARTUP)
 #define CheckPointDataBase()	SSDataBase(BS_XLOG_CHECKPOINT)
+#define StartBackgroundWriter()	SSDataBase(BS_XLOG_BGWRITER)
 #define ShutdownDataBase()		SSDataBase(BS_XLOG_SHUTDOWN)
 
 
@@ -1055,6 +1058,17 @@ ServerLoop(void)
 			}
 		}
 
+		/*
+		 * If no background writer process is running and we should
+		 * do background writing, start one. It doesn't matter if
+		 * this fails, we'll just try again later.
+		 */
+		if (BgWriterPID == 0 && BgWriterPercent > 0 &&
+				Shutdown == NoShutdown && !FatalError && random_seed != 0)
+		{
+			BgWriterPID = StartBackgroundWriter();
+		}
+
 		/*
 		 * Wait for something to happen.
 		 */
@@ -1478,6 +1492,13 @@ processCancelRequest(Port *port, void *pkt)
 								 backendPID)));
 		return;
 	}
+	else if (backendPID == BgWriterPID)
+	{
+		ereport(DEBUG2,
+				(errmsg_internal("ignoring cancel request for bgwriter process %d",
+								 backendPID)));
+		return;
+	}
 	else if (ExecBackend)
 		AttachSharedMemoryAndSemaphores();
 
@@ -1660,6 +1681,13 @@ SIGHUP_handler(SIGNAL_ARGS)
 		SignalChildren(SIGHUP);
 		load_hba();
 		load_ident();
+
+		/*
+		 * Tell the background writer to terminate so that we
+		 * will start a new one with a possibly changed config
+		 */
+		if (BgWriterPID != 0)
+			kill(BgWriterPID, SIGTERM);
 	}
 
 	PG_SETMASK(&UnBlockSig);
@@ -1692,6 +1720,8 @@ pmdie(SIGNAL_ARGS)
 			 *
 			 * Wait for children to end their work and ShutdownDataBase.
 			 */
+			if (BgWriterPID != 0)
+				kill(BgWriterPID, SIGTERM);
 			if (Shutdown >= SmartShutdown)
 				break;
 			Shutdown = SmartShutdown;
@@ -1724,6 +1754,8 @@ pmdie(SIGNAL_ARGS)
 			 * abort all children with SIGTERM (rollback active transactions
 			 * and exit) and ShutdownDataBase when they are gone.
 			 */
+			if (BgWriterPID != 0)
+				kill(BgWriterPID, SIGTERM);
 			if (Shutdown >= FastShutdown)
 				break;
 			ereport(LOG,
@@ -1770,6 +1802,8 @@ pmdie(SIGNAL_ARGS)
 			 * abort all children with SIGQUIT and exit without attempt to
 			 * properly shutdown data base system.
 			 */
+			if (BgWriterPID != 0)
+				kill(BgWriterPID, SIGQUIT);
 			ereport(LOG,
 					(errmsg("received immediate shutdown request")));
 			if (ShutdownPID > 0)
@@ -1877,6 +1911,12 @@ reaper(SIGNAL_ARGS)
 			CheckPointPID = 0;
 			checkpointed = time(NULL);
 
+			if (BgWriterPID == 0 && BgWriterPercent > 0 &&
+				Shutdown == NoShutdown && !FatalError && random_seed != 0)
+			{
+				BgWriterPID = StartBackgroundWriter();
+			}
+
 			/*
 			 * Go to shutdown mode if a shutdown request was pending.
 			 */
@@ -1983,6 +2023,8 @@ CleanupProc(int pid,
 				GetSavedRedoRecPtr();
 			}
 		}
+		else if (pid == BgWriterPID)
+			BgWriterPID = 0;
 		else
 			pgstat_beterm(pid);
 
@@ -1996,6 +2038,7 @@ CleanupProc(int pid,
 	{
 		LogChildExit(LOG,
 				 (pid == CheckPointPID) ? gettext("checkpoint process") :
+				 (pid == BgWriterPID) ? gettext("bgwriter process") :
 					 gettext("server process"),
 					 pid, exitstatus);
 		ereport(LOG,
@@ -2044,6 +2087,10 @@ CleanupProc(int pid,
 		CheckPointPID = 0;
 		checkpointed = 0;
 	}
+	else if (pid == BgWriterPID)
+	{
+		BgWriterPID = 0;
+	}
 	else
 	{
 		/*
@@ -2754,6 +2801,8 @@ CountChildren(void)
 	}
 	if (CheckPointPID != 0)
 		cnt--;
+	if (BgWriterPID != 0)
+		cnt--;
 	return cnt;
 }
 
@@ -2827,6 +2876,9 @@ SSDataBase(int xlop)
 			case BS_XLOG_CHECKPOINT:
 				statmsg = "checkpoint subprocess";
 				break;
+			case BS_XLOG_BGWRITER:
+				statmsg = "bgwriter subprocess";
+				break;
 			case BS_XLOG_SHUTDOWN:
 				statmsg = "shutdown subprocess";
 				break;
@@ -2883,6 +2935,10 @@ SSDataBase(int xlop)
 				ereport(LOG,
 					  (errmsg("could not fork checkpoint process: %m")));
 				break;
+			case BS_XLOG_BGWRITER:
+				ereport(LOG,
+					  (errmsg("could not fork bgwriter process: %m")));
+				break;
 			case BS_XLOG_SHUTDOWN:
 				ereport(LOG,
 						(errmsg("could not fork shutdown process: %m")));
@@ -2895,19 +2951,22 @@ SSDataBase(int xlop)
 
 		/*
 		 * fork failure is fatal during startup/shutdown, but there's no
-		 * need to choke if a routine checkpoint fails.
+		 * need to choke if a routine checkpoint or starting a background
+		 * writer fails.
 		 */
 		if (xlop == BS_XLOG_CHECKPOINT)
 			return 0;
+		if (xlop == BS_XLOG_BGWRITER)
+			return 0;
 		ExitPostmaster(1);
 	}
 
 	/*
 	 * The startup and shutdown processes are not considered normal
-	 * backends, but the checkpoint process is.  Checkpoint must be added
-	 * to the list of backends.
+	 * backends, but the checkpoint and bgwriter processes are.
+	 * They must be added to the list of backends.
 	 */
-	if (xlop == BS_XLOG_CHECKPOINT)
+	if (xlop == BS_XLOG_CHECKPOINT || xlop == BS_XLOG_BGWRITER)
 	{
 		if (!(bn = (Backend *) malloc(sizeof(Backend))))
 		{
diff --git a/src/backend/storage/buffer/bufmgr.c b/src/backend/storage/buffer/bufmgr.c
index cbb23b664c6df445bce198070f0a334eafa0bc53..aab99caa9d6ecbf269418e558fe46328b1a80386 100644
--- a/src/backend/storage/buffer/bufmgr.c
+++ b/src/backend/storage/buffer/bufmgr.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/storage/buffer/bufmgr.c,v 1.144 2003/11/13 14:57:15 wieck Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/storage/buffer/bufmgr.c,v 1.145 2003/11/19 15:55:07 wieck Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -44,6 +44,7 @@
 #include <sys/file.h>
 #include <math.h>
 #include <signal.h>
+#include <unistd.h>
 
 #include "lib/stringinfo.h"
 #include "miscadmin.h"
@@ -63,6 +64,9 @@
 /* GUC variable */
 bool		zero_damaged_pages = false;
 
+int			BgWriterDelay = 200;
+int			BgWriterPercent = 1;
+int			BgWriterMaxpages = 100;
 
 static void WaitIO(BufferDesc *buf);
 static void StartBufferIO(BufferDesc *buf, bool forInput);
@@ -679,10 +683,11 @@ ReleaseAndReadBuffer(Buffer buffer,
 /*
  * BufferSync -- Write all dirty buffers in the pool.
  *
- * This is called at checkpoint time and writes out all dirty shared buffers.
+ * This is called at checkpoint time and writes out all dirty shared buffers,
+ * and by the background writer process to write out some of the dirty blocks.
  */
-void
-BufferSync(void)
+int
+BufferSync(int percent, int maxpages)
 {
 	int			i;
 	BufferDesc *bufHdr;
@@ -703,12 +708,24 @@ BufferSync(void)
 	 * have to wait until the next checkpoint.
 	 */
 	buffer_dirty = (int *)palloc(NBuffers * sizeof(int));
-	num_buffer_dirty = 0;
-
+	
 	LWLockAcquire(BufMgrLock, LW_EXCLUSIVE);
 	num_buffer_dirty = StrategyDirtyBufferList(buffer_dirty, NBuffers);
 	LWLockRelease(BufMgrLock);
 
+	/*
+	 * If called by the background writer, we are usually asked to
+	 * only write out some percentage of dirty buffers now, to prevent
+	 * the IO storm at checkpoint time.
+	 */
+	if (percent > 0 && num_buffer_dirty > 10)
+	{
+		Assert(percent <= 100);
+		num_buffer_dirty = (num_buffer_dirty * percent) / 100;
+		if (maxpages > 0 && num_buffer_dirty > maxpages)
+			num_buffer_dirty = maxpages;
+	}
+
 	for (i = 0; i < num_buffer_dirty; i++)
 	{
 		Buffer		buffer;
@@ -854,6 +871,8 @@ BufferSync(void)
 
 	/* Pop the error context stack */
 	error_context_stack = errcontext.previous;
+
+	return num_buffer_dirty;
 }
 
 /*
@@ -984,10 +1003,56 @@ AtEOXact_Buffers(bool isCommit)
 void
 FlushBufferPool(void)
 {
-	BufferSync();
+	BufferSync(-1, -1);
 	smgrsync();
 }
 
+
+/*
+ * BufferBackgroundWriter
+ *
+ * Periodically flushes dirty blocks from the buffer pool to keep
+ * the LRU list clean, preventing regular backends from writing.
+ */
+void
+BufferBackgroundWriter(void)
+{
+	if (BgWriterPercent == 0)
+		return;
+
+	/*
+	 * Loop forever 
+	 */
+	for (;;)
+	{
+		int			n, i;
+
+		/*
+		 * Call BufferSync() with instructions to keep just the
+		 * LRU heads clean.
+		 */
+		n = BufferSync(BgWriterPercent, BgWriterMaxpages);
+
+		/*
+		 * Whatever signal is sent to us, let's just die galantly. If
+		 * it wasn't meant that way, the postmaster will reincarnate us.
+		 */
+		if (InterruptPending)
+			return;
+
+		/*
+		 * Nap for the configured time or sleep for 10 seconds if
+		 * there was nothing to do at all.
+		 */
+		if (n > 0)
+		{
+			PG_DELAY(BgWriterDelay);
+		}
+		else
+			sleep(10);
+	}
+}
+
 /*
  * Do whatever is needed to prepare for commit at the bufmgr and smgr levels
  */
diff --git a/src/backend/storage/buffer/freelist.c b/src/backend/storage/buffer/freelist.c
index 12d67b1342461ef593bc374d1d3892626dbfd722..84bcb1554d1957fd5d6db299a52bf46bb830698e 100644
--- a/src/backend/storage/buffer/freelist.c
+++ b/src/backend/storage/buffer/freelist.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/storage/buffer/freelist.c,v 1.35 2003/11/16 16:41:00 wieck Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/storage/buffer/freelist.c,v 1.36 2003/11/19 15:55:07 wieck Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -190,8 +190,28 @@ StrategyBufferLookup(BufferTag *tagPtr, bool recheck)
 		if (StrategyControl->stat_report + DebugSharedBuffers < now)
 		{
 			long	all_hit, b1_hit, t1_hit, t2_hit, b2_hit;
+			int		id, t1_clean, t2_clean;
 			ErrorContextCallback	*errcxtold;
 
+			id = StrategyControl->listHead[STRAT_LIST_T1];
+			t1_clean = 0;
+			while (id >= 0)
+			{
+				if (BufferDescriptors[StrategyCDB[id].buf_id].flags & BM_DIRTY)
+					break;
+				t1_clean++;
+				id = StrategyCDB[id].next;
+			}
+			id = StrategyControl->listHead[STRAT_LIST_T2];
+			t2_clean = 0;
+			while (id >= 0)
+			{
+				if (BufferDescriptors[StrategyCDB[id].buf_id].flags & BM_DIRTY)
+					break;
+				t2_clean++;
+				id = StrategyCDB[id].next;
+			}
+
 			if (StrategyControl->num_lookup == 0)
 			{
 				all_hit = b1_hit = t1_hit = t2_hit = b2_hit = 0;
@@ -215,6 +235,8 @@ StrategyBufferLookup(BufferTag *tagPtr, bool recheck)
 					T1_TARGET, B1_LENGTH, T1_LENGTH, T2_LENGTH, B2_LENGTH);
 			elog(DEBUG1, "ARC total   =%4ld%% B1hit=%4ld%% T1hit=%4ld%% T2hit=%4ld%% B2hit=%4ld%%",
 					all_hit, b1_hit, t1_hit, t2_hit, b2_hit);
+			elog(DEBUG1, "ARC clean buffers at LRU       T1=   %5d T2=   %5d",
+					t1_clean, t2_clean);
 			error_context_stack = errcxtold;
 
 			StrategyControl->num_lookup = 0;
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 6ffac1d43cf29fb0b2c9b710aaa0401222b4d39d..cea8ffe4c76e42797863999c73486aca63530bc7 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/storage/lmgr/proc.c,v 1.136 2003/10/16 20:59:35 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/storage/lmgr/proc.c,v 1.137 2003/11/19 15:55:07 wieck Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -71,6 +71,7 @@ static slock_t *ProcStructLock = NULL;
 static PROC_HDR *ProcGlobal = NULL;
 
 static PGPROC *DummyProc = NULL;
+static int	dummy_proc_type = -1;
 
 static bool waitingForLock = false;
 static bool waitingForSignal = false;
@@ -163,14 +164,17 @@ InitProcGlobal(int maxBackends)
 		 * processes, too.	This does not get linked into the freeProcs
 		 * list.
 		 */
-		DummyProc = (PGPROC *) ShmemAlloc(sizeof(PGPROC));
+		DummyProc = (PGPROC *) ShmemAlloc(sizeof(PGPROC) * NUM_DUMMY_PROCS);
 		if (!DummyProc)
 			ereport(FATAL,
 					(errcode(ERRCODE_OUT_OF_MEMORY),
 					 errmsg("out of shared memory")));
-		MemSet(DummyProc, 0, sizeof(PGPROC));
-		DummyProc->pid = 0;		/* marks DummyProc as not in use */
-		PGSemaphoreCreate(&DummyProc->sem);
+		MemSet(DummyProc, 0, sizeof(PGPROC) * NUM_DUMMY_PROCS);
+		for (i = 0; i < NUM_DUMMY_PROCS; i++)
+		{
+			DummyProc[i].pid = 0;		/* marks DummyProc as not in use */
+			PGSemaphoreCreate(&(DummyProc[i].sem));
+		}
 
 		/* Create ProcStructLock spinlock, too */
 		ProcStructLock = (slock_t *) ShmemAlloc(sizeof(slock_t));
@@ -270,8 +274,10 @@ InitProcess(void)
  * sema that are assigned are the extra ones created during InitProcGlobal.
  */
 void
-InitDummyProcess(void)
+InitDummyProcess(int proctype)
 {
+	PGPROC	*dummyproc;
+
 	/*
 	 * ProcGlobal should be set by a previous call to InitProcGlobal (we
 	 * inherit this by fork() from the postmaster).
@@ -282,12 +288,17 @@ InitDummyProcess(void)
 	if (MyProc != NULL)
 		elog(ERROR, "you already exist");
 
+	Assert(dummy_proc_type < 0);
+	dummy_proc_type = proctype;
+	dummyproc = &DummyProc[proctype];
+
 	/*
-	 * DummyProc should not presently be in use by anyone else
+	 * dummyproc should not presently be in use by anyone else
 	 */
-	if (DummyProc->pid != 0)
-		elog(FATAL, "DummyProc is in use by PID %d", DummyProc->pid);
-	MyProc = DummyProc;
+	if (dummyproc->pid != 0)
+		elog(FATAL, "DummyProc[%d] is in use by PID %d",
+				proctype, dummyproc->pid);
+	MyProc = dummyproc;
 
 	/*
 	 * Initialize all fields of MyProc, except MyProc->sem which was set
@@ -310,7 +321,7 @@ InitDummyProcess(void)
 	/*
 	 * Arrange to clean up at process exit.
 	 */
-	on_shmem_exit(DummyProcKill, 0);
+	on_shmem_exit(DummyProcKill, proctype);
 
 	/*
 	 * We might be reusing a semaphore that belonged to a failed process.
@@ -446,7 +457,13 @@ ProcKill(void)
 static void
 DummyProcKill(void)
 {
-	Assert(MyProc != NULL && MyProc == DummyProc);
+	PGPROC	*dummyproc;
+
+	Assert(dummy_proc_type >= 0 && dummy_proc_type < NUM_DUMMY_PROCS);
+
+	dummyproc = &DummyProc[dummy_proc_type];
+
+	Assert(MyProc != NULL && MyProc == dummyproc);
 
 	/* Release any LW locks I am holding */
 	LWLockReleaseAll();
@@ -463,6 +480,8 @@ DummyProcKill(void)
 
 	/* PGPROC struct isn't mine anymore */
 	MyProc = NULL;
+
+	dummy_proc_type = -1;
 }
 
 
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
index bd8db1bb85b964ae115c12e7fb9ffcb71337a31d..25aef118e3547600568732543271a98727e35a92 100644
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -10,7 +10,7 @@
  * Written by Peter Eisentraut <peter_e@gmx.net>.
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/utils/misc/guc.c,v 1.170 2003/11/16 16:41:01 wieck Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/utils/misc/guc.c,v 1.171 2003/11/19 15:55:08 wieck Exp $
  *
  *--------------------------------------------------------------------
  */
@@ -44,6 +44,7 @@
 #include "optimizer/prep.h"
 #include "parser/parse_expr.h"
 #include "parser/parse_relation.h"
+#include "storage/bufmgr.h"
 #include "storage/fd.h"
 #include "storage/freespace.h"
 #include "storage/lock.h"
@@ -1200,6 +1201,33 @@ static struct config_int ConfigureNamesInt[] =
 		0, 0, 600, NULL, NULL
 	},
 
+	{
+		{"bgwriter_delay", PGC_SIGHUP, RESOURCES,
+			gettext_noop("Background writer sleep time between rounds in milliseconds"),
+			NULL
+		},
+		&BgWriterDelay,
+		200, 10, 5000, NULL, NULL
+	},
+
+	{
+		{"bgwriter_percent", PGC_SIGHUP, RESOURCES,
+			gettext_noop("Background writer percentage of dirty buffers to flush per round"),
+			NULL
+		},
+		&BgWriterPercent,
+		1, 0, 100, NULL, NULL
+	},
+
+	{
+		{"bgwriter_maxpages", PGC_SIGHUP, RESOURCES,
+			gettext_noop("Background writer maximum number of pages to flush per round"),
+			NULL
+		},
+		&BgWriterMaxpages,
+		100, 1, 1000, NULL, NULL
+	},
+
 	/* End-of-list marker */
 	{
 		{NULL, 0, 0, NULL, NULL}, NULL, 0, 0, 0, NULL, NULL
diff --git a/src/backend/utils/misc/postgresql.conf.sample b/src/backend/utils/misc/postgresql.conf.sample
index 64e94edab965e0a7034f786a4be536e1278ecee8..e4305d98596c86eb6d6f9d0902cad5022460b45e 100644
--- a/src/backend/utils/misc/postgresql.conf.sample
+++ b/src/backend/utils/misc/postgresql.conf.sample
@@ -60,6 +60,11 @@
 #vacuum_mem = 8192		# min 1024, size in KB
 #debug_shared_buffers = 0	# 0-600 seconds
 
+# - Background writer -
+#bgwriter_delay = 200		# 10-5000 milliseconds
+#bgwriter_percent = 1		# 0-100% of dirty buffers
+#bgwriter_maxpages = 100	# 1-1000 buffers max at once
+
 # - Free Space Map -
 
 #max_fsm_pages = 20000		# min max_fsm_relations*16, 6 bytes each
diff --git a/src/include/bootstrap/bootstrap.h b/src/include/bootstrap/bootstrap.h
index e444aeef43cb89afcf48d0aadc758dd8bdbf0278..0367522da3a3a490d04e293030fd703b80c9ae01 100644
--- a/src/include/bootstrap/bootstrap.h
+++ b/src/include/bootstrap/bootstrap.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: bootstrap.h,v 1.31 2003/08/04 02:40:10 momjian Exp $
+ * $Id: bootstrap.h,v 1.32 2003/11/19 15:55:08 wieck Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -59,6 +59,7 @@ extern void Int_yyerror(const char *str);
 #define BS_XLOG_BOOTSTRAP	1
 #define BS_XLOG_STARTUP		2
 #define BS_XLOG_CHECKPOINT	3
-#define BS_XLOG_SHUTDOWN	4
+#define BS_XLOG_BGWRITER	4
+#define BS_XLOG_SHUTDOWN	5
 
 #endif   /* BOOTSTRAP_H */
diff --git a/src/include/storage/bufmgr.h b/src/include/storage/bufmgr.h
index bfbf64e207f5dc9b0f0eaca8edf9cd0f97acd9c9..df0708f9092eef4d5b7ba681c51543498cf4ad89 100644
--- a/src/include/storage/bufmgr.h
+++ b/src/include/storage/bufmgr.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: bufmgr.h,v 1.70 2003/08/10 19:48:08 tgl Exp $
+ * $Id: bufmgr.h,v 1.71 2003/11/19 15:55:08 wieck Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -28,6 +28,11 @@ extern DLLIMPORT int NBuffers;
 /* in bufmgr.c */
 extern bool zero_damaged_pages;
 
+extern int	BgWriterDelay;
+extern int	BgWriterPercent;
+extern int	BgWriterMaxpages;
+
+
 /* in buf_init.c */
 extern DLLIMPORT Block *BufferBlockPointers;
 extern long *PrivateRefCount;
@@ -186,7 +191,10 @@ extern void LockBufferForCleanup(Buffer buffer);
 extern void AbortBufferIO(void);
 
 extern void BufmgrCommit(void);
-extern void BufferSync(void);
+extern int	BufferSync(int percent, int maxpages);
+extern void BufferBackgroundWriter(void);
+extern const char *BgWriterAssignSyncMethod(const char *method,
+			bool doid, bool interactive);
 
 extern void InitLocalBuffer(void);
 
diff --git a/src/include/storage/proc.h b/src/include/storage/proc.h
index 3cad0c5b63c2f298a4de8be45d6e50189e8b9dd4..235ed751b4139ca656e1638b6b151142966e8637 100644
--- a/src/include/storage/proc.h
+++ b/src/include/storage/proc.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: proc.h,v 1.64 2003/08/04 02:40:15 momjian Exp $
+ * $Id: proc.h,v 1.65 2003/11/19 15:55:08 wieck Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -86,6 +86,11 @@ typedef struct PROC_HDR
 } PROC_HDR;
 
 
+#define	DUMMY_PROC_DEFAULT	0
+#define	DUMMY_PROC_BGWRITER	1
+#define	NUM_DUMMY_PROCS		2
+
+
 /* configurable options */
 extern int	DeadlockTimeout;
 extern int	StatementTimeout;
@@ -97,7 +102,7 @@ extern int	StatementTimeout;
 extern int	ProcGlobalSemas(int maxBackends);
 extern void InitProcGlobal(int maxBackends);
 extern void InitProcess(void);
-extern void InitDummyProcess(void);
+extern void InitDummyProcess(int proctype);
 extern void ProcReleaseLocks(bool isCommit);
 
 extern void ProcQueueInit(PROC_QUEUE *queue);