diff --git a/doc/src/sgml/backup.sgml b/doc/src/sgml/backup.sgml
index 09f9386066c99738bee7ca3c0a74341a84a7294a..b732b2ae7dd6f87f937690158f19d09baf025c1f 100644
--- a/doc/src/sgml/backup.sgml
+++ b/doc/src/sgml/backup.sgml
@@ -1,4 +1,4 @@
-<!-- $PostgreSQL: pgsql/doc/src/sgml/backup.sgml,v 2.82 2006/08/06 03:53:43 tgl Exp $ -->
+<!-- $PostgreSQL: pgsql/doc/src/sgml/backup.sgml,v 2.83 2006/08/17 23:04:02 tgl Exp $ -->
 
 <chapter id="backup">
  <title>Backup and Restore</title>
@@ -492,7 +492,7 @@ tar -cf backup.tar /usr/local/pgsql/data
     the archiving will be done.  Instead, <productname>PostgreSQL</> lets
     the administrator specify a shell command to be executed to copy a
     completed segment file to wherever it needs to go.  The command could be
-    as simple as a <application>cp</>, or it could invoke a complex shell
+    as simple as a <literal>cp</>, or it could invoke a complex shell
     script &mdash; it's all up to you.
    </para>
 
@@ -576,36 +576,6 @@ archive_command = 'test ! -f .../%f &amp;&amp; cp %p .../%f'
     it is working as you intend.
    </para>
 
-   <para>
-    If you are concerned about being able to recover right up to the
-    current instant, you may want to take additional steps to ensure that
-    the current, partially-filled WAL segment is also copied someplace.
-    This is particularly important if your server generates only little WAL
-    traffic (or has slack periods where it does so), since it could take a
-    long time before a WAL segment file is completely filled and ready to
-    archive.  One possible way to handle this is to set up a
-    <application>cron</> job that periodically (once a minute, perhaps)
-    identifies the current WAL segment file and saves it someplace safe.
-    Then the combination of the archived WAL segments and the saved current
-    segment will be enough to ensure you can always restore to within a
-    minute of current time.  This behavior is not presently built into
-    <productname>PostgreSQL</> because we did not want to complicate the
-    definition of the <xref linkend="guc-archive-command"> by requiring it
-    to keep track of successively archived, but different, copies of the
-    same WAL file.  The <xref linkend="guc-archive-command"> is only
-    invoked on completed WAL segments. Except in the case of retrying a
-    failure, it will be called only once for any given file name.
-   </para>
-
-   <para>
-    Another way to limit your exposure to data loss is to call
-    <function>pg_switch_xlog()</> periodically, such as once a minute.
-    This function forces the current WAL segment file to be completed
-    and made available to the archiving command.  This approach does
-    not work well for extremely short update intervals, however, since
-    copying a new 16MB segment file every few seconds is expensive.
-   </para>
-
    <para>
     In writing your archive command, you should assume that the file names to
     be archived may be up to 64 characters long and may contain any
@@ -626,6 +596,29 @@ archive_command = 'test ! -f .../%f &amp;&amp; cp %p .../%f'
     <xref linkend="runtime-config-file-locations"> for how to relocate the
     configuration files.
    </para>
+
+   <para>
+    The archive command is only invoked on completed WAL segments.  Hence,
+    if your server generates only little WAL traffic (or has slack periods 
+    where it does so), there could be a long delay between the completion
+    of a transaction and its safe recording in archive storage.  To put
+    a limit on how old unarchived data can be, you can set
+    <xref linkend="guc-archive-timeout"> to force the server to switch
+    to a new WAL segment file at least that often.  Note that archived
+    files that are ended early due to a forced switch are still the same
+    length as completely full files.  It is therefore unwise to set a very
+    short <varname>archive_timeout</> &mdash; it will bloat your archive
+    storage.  <varname>archive_timeout</> settings of a minute or so are
+    usually reasonable.
+   </para>
+
+   <para>
+    Also, you can force a segment switch manually with
+    <function>pg_switch_xlog()</>,
+    if you want to ensure that a just-finished transaction is archived
+    immediately.  Other utility functions related to WAL management are
+    listed in <xref linkend="functions-admin-backup-table">.
+   </para>
   </sect2>
 
   <sect2 id="backup-base-backup">
diff --git a/doc/src/sgml/config.sgml b/doc/src/sgml/config.sgml
index b35fa9c1ccf6f55162594a96ced1d6d49ea43c50..11df2267873ef0935757c951022f66581d95716d 100644
--- a/doc/src/sgml/config.sgml
+++ b/doc/src/sgml/config.sgml
@@ -1,4 +1,4 @@
-<!-- $PostgreSQL: pgsql/doc/src/sgml/config.sgml,v 1.74 2006/08/15 18:26:58 tgl Exp $ -->
+<!-- $PostgreSQL: pgsql/doc/src/sgml/config.sgml,v 1.75 2006/08/17 23:04:03 tgl Exp $ -->
 
 <chapter Id="runtime-config">
   <title>Server Configuration</title>
@@ -1584,6 +1584,35 @@ archive_command = 'copy "%p" /mnt/server/archivedir/"%f"'  # Windows
       </listitem>
      </varlistentry>
      
+     <varlistentry id="guc-archive-timeout" xreflabel="archive_timeout">
+      <term><varname>archive_timeout</varname> (<type>integer</type>)</term>
+      <indexterm>
+       <primary><varname>archive_timeout</> configuration parameter</primary>
+      </indexterm>
+      <listitem>
+       <para>
+        The <xref linkend="guc-archive-command"> is only invoked on completed 
+        WAL segments. Hence,
+        if your server generates only little WAL traffic (or has slack periods 
+        where it does so), there could be a long delay between the completion
+        of a transaction and its safe recording in archive storage.  To put
+        a limit on how old unarchived data can be, you can set
+        <varname>archive_timeout</> to force the server to switch
+        to a new WAL segment file periodically.  When this parameter is
+        greater than zero, the server will switch to a new segment file
+        whenever this many seconds elapse since the last segment file switch.
+        Note that archived
+        files that are ended early due to a forced switch are still the same
+        length as completely full files.  It is therefore unwise to set a very
+        short <varname>archive_timeout</> &mdash; it will bloat your archive
+        storage.  <varname>archive_timeout</> settings of a minute or so are
+        usually reasonable.
+        This parameter can only be set in the <filename>postgresql.conf</>
+        file or on the server command line.
+       </para>
+      </listitem>
+     </varlistentry>
+     
      </variablelist>
     </sect2>
    </sect1>
diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml
index 451ce5e785173076ce47f3c5e96dda0a9e8fdaaa..113411f78b542ffaea63104975f7778ee550e199 100644
--- a/doc/src/sgml/func.sgml
+++ b/doc/src/sgml/func.sgml
@@ -1,4 +1,4 @@
-<!-- $PostgreSQL: pgsql/doc/src/sgml/func.sgml,v 1.329 2006/08/06 03:53:43 tgl Exp $ -->
+<!-- $PostgreSQL: pgsql/doc/src/sgml/func.sgml,v 1.330 2006/08/17 23:04:03 tgl Exp $ -->
 
  <chapter id="functions">
   <title>Functions and Operators</title>
@@ -10148,6 +10148,9 @@ SELECT set_config('log_statement_stats', 'off', false);
    <indexterm zone="functions-admin">
     <primary>pg_current_xlog_location</primary>
    </indexterm>
+   <indexterm zone="functions-admin">
+    <primary>pg_current_xlog_insert_location</primary>
+   </indexterm>
    <indexterm zone="functions-admin">
     <primary>pg_xlogfile_name_offset</primary>
    </indexterm>
@@ -10199,13 +10202,20 @@ SELECT set_config('log_statement_stats', 'off', false);
         <literal><function>pg_current_xlog_location</function>()</literal>
         </entry>
        <entry><type>text</type></entry>
-       <entry>Get current xlog location</entry>
+       <entry>Get current xlog write location</entry>
       </row>
       <row>
        <entry>
-        <literal><function>pg_xlogfile_name_offset</function>(<parameter>location</> <type>text</>)</literal>
+        <literal><function>pg_current_xlog_insert_location</function>()</literal>
         </entry>
        <entry><type>text</type></entry>
+       <entry>Get current xlog insert location</entry>
+      </row>
+      <row>
+       <entry>
+        <literal><function>pg_xlogfile_name_offset</function>(<parameter>location</> <type>text</>)</literal>
+        </entry>
+       <entry><type>text</>, <type>integer</></entry>
        <entry>Convert xlog location string to filename and decimal byte offset within file</entry>
       </row>
       <row>
@@ -10258,9 +10268,17 @@ postgres=# select pg_start_backup('label_goes_here');
    </para>
 
    <para>
-    <function>pg_current_xlog_location</> displays the current xlog insertion
-    point in the same format used by the above functions.  This is a
-    read-only operation and does not require superuser permissions.
+    <function>pg_current_xlog_location</> displays the current xlog write
+    location in the same format used by the above functions.  Similarly
+    <function>pg_current_xlog_insert_location</> displays the current xlog
+    insertion point.  The insertion point is the <quote>logical</> end of xlog
+    at any instant, while the write location is the end of what has actually
+    been written out from the server's internal buffers.  The write location
+    is the end of what can be examined from outside the server, and is usually
+    what you want if you are interested in archiving partially-complete xlog
+    files.  The insertion point is made available primarily for server
+    debugging purposes.  These are both read-only operations and do not
+    require superuser permissions.
    </para>
 
    <para>
@@ -10268,10 +10286,10 @@ postgres=# select pg_start_backup('label_goes_here');
     corresponding xlog filename and byte offset from the results of any of the
     above functions.  For example:
 <programlisting>
-postgres=# select pg_xlogfile_name_offset(pg_stop_backup());
-     pg_xlogfile_name_offset      
-----------------------------------
- 00000001000000000000000D 4039624
+postgres=# select * from pg_xlogfile_name_offset(pg_stop_backup());
+        file_name         | file_offset 
+--------------------------+-------------
+ 00000001000000000000000D |     4039624
 (1 row)
 </programlisting>
     Similarly, <function>pg_xlogfile_name</> extracts just the xlog filename.
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 21e7b47206d5a3fe0d891e6bbcc7d46c32bc257a..d78f1c30744042b22111be36e6668076bd4204d9 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/backend/access/transam/xlog.c,v 1.247 2006/08/07 16:57:56 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/access/transam/xlog.c,v 1.248 2006/08/17 23:04:05 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -23,6 +23,7 @@
 #include <sys/time.h>
 
 #include "access/clog.h"
+#include "access/heapam.h"
 #include "access/multixact.h"
 #include "access/subtrans.h"
 #include "access/transam.h"
@@ -32,6 +33,8 @@
 #include "access/xlogutils.h"
 #include "catalog/catversion.h"
 #include "catalog/pg_control.h"
+#include "catalog/pg_type.h"
+#include "funcapi.h"
 #include "miscadmin.h"
 #include "pgstat.h"
 #include "postmaster/bgwriter.h"
@@ -128,6 +131,7 @@
 /* User-settable parameters */
 int			CheckPointSegments = 3;
 int			XLOGbuffers = 8;
+int			XLogArchiveTimeout = 0;
 char	   *XLogArchiveCommand = NULL;
 char	   *XLOG_sync_method = NULL;
 const char	XLOG_sync_method_default[] = DEFAULT_SYNC_METHOD_STR;
@@ -347,8 +351,9 @@ typedef struct XLogCtlInsert
  */
 typedef struct XLogCtlWrite
 {
-	XLogwrtResult LogwrtResult; /* current value of LogwrtResult */
-	int			curridx;		/* cache index of next block to write */
+	XLogwrtResult LogwrtResult;		/* current value of LogwrtResult */
+	int			curridx;			/* cache index of next block to write */
+	time_t		lastSegSwitchTime;	/* time of last xlog segment switch */
 } XLogCtlWrite;
 
 /*
@@ -1660,7 +1665,8 @@ XLogWrite(XLogwrtRqst WriteRqst, bool flexible, bool xlog_switch)
 			 * switch.
 			 *
 			 * This is also the right place to notify the Archiver that the
-			 * segment is ready to copy to archival storage.
+			 * segment is ready to copy to archival storage, and to update
+			 * the timer for archive_timeout.
 			 */
 			if (finishing_seg || (xlog_switch && last_iteration))
 			{
@@ -1669,6 +1675,8 @@ XLogWrite(XLogwrtRqst WriteRqst, bool flexible, bool xlog_switch)
 
 				if (XLogArchivingActive())
 					XLogArchiveNotifySeg(openLogId, openLogSeg);
+
+				Write->lastSegSwitchTime = time(NULL);
 			}
 		}
 
@@ -5124,6 +5132,9 @@ StartupXLOG(void)
 	ControlFile->time = time(NULL);
 	UpdateControlFile();
 
+	/* start the archive_timeout timer running */
+	XLogCtl->Write.lastSegSwitchTime = ControlFile->time;
+
 	/* Start up the commit log and related stuff, too */
 	StartupCLOG();
 	StartupSUBTRANS(oldestActiveXID);
@@ -5307,6 +5318,22 @@ GetRedoRecPtr(void)
 	return RedoRecPtr;
 }
 
+/*
+ * Get the time of the last xlog segment switch
+ */
+time_t
+GetLastSegSwitchTime(void)
+{
+	time_t		result;
+
+	/* Need WALWriteLock, but shared lock is sufficient */
+	LWLockAcquire(WALWriteLock, LW_SHARED);
+	result = XLogCtl->Write.lastSegSwitchTime;
+	LWLockRelease(WALWriteLock);
+
+	return result;
+}
+
 /*
  * GetRecentNextXid - get the nextXid value saved by the most recent checkpoint
  *
@@ -5728,7 +5755,7 @@ XLogPutNextOid(Oid nextOid)
  * or the end+1 address of the prior segment if we did not need to
  * write a switch record because we are already at segment start.
  */
-static XLogRecPtr
+XLogRecPtr
 RequestXLogSwitch(void)
 {
 	XLogRecPtr	RecPtr;
@@ -6335,10 +6362,43 @@ pg_switch_xlog(PG_FUNCTION_ARGS)
 }
 
 /*
- * Report the current WAL location (same format as pg_start_backup etc)
+ * Report the current WAL write location (same format as pg_start_backup etc)
+ *
+ * This is useful for determining how much of WAL is visible to an external
+ * archiving process.  Note that the data before this point is written out
+ * to the kernel, but is not necessarily synced to disk.
  */
 Datum
 pg_current_xlog_location(PG_FUNCTION_ARGS)
+{
+	text	   *result;
+	char		location[MAXFNAMELEN];
+
+	/* Make sure we have an up-to-date local LogwrtResult */
+	{
+		/* use volatile pointer to prevent code rearrangement */
+		volatile XLogCtlData *xlogctl = XLogCtl;
+
+		SpinLockAcquire(&xlogctl->info_lck);
+		LogwrtResult = xlogctl->LogwrtResult;
+		SpinLockRelease(&xlogctl->info_lck);
+	}
+
+	snprintf(location, sizeof(location), "%X/%X",
+			 LogwrtResult.Write.xlogid, LogwrtResult.Write.xrecoff);
+
+	result = DatumGetTextP(DirectFunctionCall1(textin,
+											   CStringGetDatum(location)));
+	PG_RETURN_TEXT_P(result);
+}
+
+/*
+ * Report the current WAL insert location (same format as pg_start_backup etc)
+ *
+ * This function is mostly for debugging purposes.
+ */
+Datum
+pg_current_xlog_insert_location(PG_FUNCTION_ARGS)
 {
 	text	   *result;
 	XLogCtlInsert *Insert = &XLogCtl->Insert;
@@ -6372,7 +6432,6 @@ Datum
 pg_xlogfile_name_offset(PG_FUNCTION_ARGS)
 {
 	text	   *location = PG_GETARG_TEXT_P(0);
-	text	   *result;
 	char	   *locationstr;
 	unsigned int uxlogid;
 	unsigned int uxrecoff;
@@ -6381,7 +6440,15 @@ pg_xlogfile_name_offset(PG_FUNCTION_ARGS)
 	uint32		xrecoff;
 	XLogRecPtr	locationpoint;
 	char		xlogfilename[MAXFNAMELEN];
+	Datum       values[2];
+	bool        isnull[2];
+	TupleDesc   resultTupleDesc;
+	HeapTuple   resultHeapTuple;
+	Datum	    result;
 
+	/*
+	 * Read input and parse
+	 */
 	locationstr = DatumGetCString(DirectFunctionCall1(textout,
 												PointerGetDatum(location)));
 
@@ -6394,18 +6461,44 @@ pg_xlogfile_name_offset(PG_FUNCTION_ARGS)
 	locationpoint.xlogid = uxlogid;
 	locationpoint.xrecoff = uxrecoff;
 
+	/*
+	 * Construct a tuple descriptor for the result row.  This must match
+	 * this function's pg_proc entry!
+	 */
+	resultTupleDesc = CreateTemplateTupleDesc(2, false);
+	TupleDescInitEntry(resultTupleDesc, (AttrNumber) 1, "file_name",
+					   TEXTOID, -1, 0);
+	TupleDescInitEntry(resultTupleDesc, (AttrNumber) 2, "file_offset",
+					   INT4OID, -1, 0);
+
+	resultTupleDesc = BlessTupleDesc(resultTupleDesc);
+
+	/*
+	 * xlogfilename
+	 */
 	XLByteToPrevSeg(locationpoint, xlogid, xlogseg);
 	XLogFileName(xlogfilename, ThisTimeLineID, xlogid, xlogseg);
 
+	values[0] = DirectFunctionCall1(textin,
+									CStringGetDatum(xlogfilename));
+	isnull[0] = false;
+
+	/*
+	 * offset
+	 */
 	xrecoff = locationpoint.xrecoff - xlogseg * XLogSegSize;
-	snprintf(xlogfilename + strlen(xlogfilename),
-			 sizeof(xlogfilename) - strlen(xlogfilename),
-			 " %u",
-			 (unsigned int) xrecoff);
 
-	result = DatumGetTextP(DirectFunctionCall1(textin,
-											   CStringGetDatum(xlogfilename)));
-	PG_RETURN_TEXT_P(result);
+	values[1] = UInt32GetDatum(xrecoff);
+	isnull[1] = false;
+
+	/*
+	 * Tuple jam: Having first prepared your Datums, then squash together
+	 */
+	resultHeapTuple = heap_form_tuple(resultTupleDesc, values, isnull);
+
+	result = HeapTupleGetDatum(resultHeapTuple);
+
+	PG_RETURN_DATUM(result);
 }
 
 /*
diff --git a/src/backend/postmaster/bgwriter.c b/src/backend/postmaster/bgwriter.c
index 62af504ff84fd9f9f3b38761d348389650e5eb7b..679b8a5c7239425eb04aab9e86026c15019e2c78 100644
--- a/src/backend/postmaster/bgwriter.c
+++ b/src/backend/postmaster/bgwriter.c
@@ -37,7 +37,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/postmaster/bgwriter.c,v 1.26 2006/07/14 14:52:22 momjian Exp $
+ *	  $PostgreSQL: pgsql/src/backend/postmaster/bgwriter.c,v 1.27 2006/08/17 23:04:06 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -46,6 +46,7 @@
 #include <signal.h>
 #include <time.h>
 
+#include "access/xlog_internal.h"
 #include "libpq/pqsignal.h"
 #include "miscadmin.h"
 #include "postmaster/bgwriter.h"
@@ -144,6 +145,7 @@ static bool am_bg_writer = false;
 static bool ckpt_active = false;
 
 static time_t last_checkpoint_time;
+static time_t last_xlog_switch_time;
 
 
 static void bg_quickdie(SIGNAL_ARGS);
@@ -205,10 +207,10 @@ BackgroundWriterMain(void)
 #endif
 
 	/*
-	 * Initialize so that first time-driven checkpoint happens at the correct
+	 * Initialize so that first time-driven event happens at the correct
 	 * time.
 	 */
-	last_checkpoint_time = time(NULL);
+	last_checkpoint_time = last_xlog_switch_time = time(NULL);
 
 	/*
 	 * Create a resource owner to keep track of our resources (currently
@@ -403,6 +405,49 @@ BackgroundWriterMain(void)
 		else
 			BgBufferSync();
 
+		/*
+		 * Check for archive_timeout, if so, switch xlog files.  First
+		 * we do a quick check using possibly-stale local state.
+		 */
+		if (XLogArchiveTimeout > 0 &&
+			(int) (now - last_xlog_switch_time) >= XLogArchiveTimeout)
+		{
+			/*
+			 * Update local state ... note that last_xlog_switch_time is
+			 * the last time a switch was performed *or requested*.
+			 */
+			time_t	last_time = GetLastSegSwitchTime();
+
+			last_xlog_switch_time = Max(last_xlog_switch_time, last_time);
+
+			/* if we did a checkpoint, 'now' might be stale too */
+			if (do_checkpoint)
+				now = time(NULL);
+
+			/* Now we can do the real check */
+			if ((int) (now - last_xlog_switch_time) >= XLogArchiveTimeout)
+			{
+				XLogRecPtr switchpoint;
+
+				/* OK, it's time to switch */
+				switchpoint = RequestXLogSwitch();
+
+				/*
+				 * If the returned pointer points exactly to a segment
+				 * boundary, assume nothing happened.
+				 */
+				if ((switchpoint.xrecoff % XLogSegSize) != 0)
+					ereport(DEBUG1,
+							(errmsg("xlog switch forced (archive_timeout=%d)",
+									XLogArchiveTimeout)));
+				/*
+				 * Update state in any case, so we don't retry constantly
+				 * when the system is idle.
+				 */
+				last_xlog_switch_time = now;
+			}
+		}
+
 		/*
 		 * Nap for the configured time, or sleep for 10 seconds if there is no
 		 * bgwriter activity configured.
@@ -417,9 +462,12 @@ BackgroundWriterMain(void)
 		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 */
 		else
-			udelay = 10000000L;
-		while (udelay > 1000000L)
+			udelay = 10000000L;  /* Ten seconds */
+
+		while (udelay > 999999L)
 		{
 			if (got_SIGHUP || checkpoint_requested || shutdown_requested)
 				break;
@@ -427,6 +475,7 @@ BackgroundWriterMain(void)
 			AbsorbFsyncRequests();
 			udelay -= 1000000L;
 		}
+
 		if (!(got_SIGHUP || checkpoint_requested || shutdown_requested))
 			pg_usleep(udelay);
 	}
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
index 69c67471fc0d1ef19ae25d1b3cdcb5156ba8471c..208231ecd5cce8b2ca2a7b425df5929d0f227637 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
- *	  $PostgreSQL: pgsql/src/backend/utils/misc/guc.c,v 1.342 2006/08/15 18:26:59 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/backend/utils/misc/guc.c,v 1.343 2006/08/17 23:04:06 tgl Exp $
  *
  *--------------------------------------------------------------------
  */
@@ -1001,7 +1001,7 @@ static struct config_bool ConfigureNamesBool[] =
 
 	{
 		{"ignore_system_indexes", PGC_BACKEND, DEVELOPER_OPTIONS,
-		 gettext_noop("Disabled reading from system indexes."),
+		 gettext_noop("Disables reading from system indexes."),
 		 gettext_noop("It does not prevent updating the indexes, so it is safe "
 					  "to use.  The worst consequence is slowness."),
 		 GUC_NOT_IN_SAMPLE
@@ -1019,6 +1019,16 @@ static struct config_bool ConfigureNamesBool[] =
 
 static struct config_int ConfigureNamesInt[] =
 {
+	{
+		{"archive_timeout", PGC_SIGHUP, WAL_SETTINGS,
+		 gettext_noop("Forces a switch to the next xlog file if a "
+                      "new file has not been started within N seconds."),
+		 NULL,
+		 GUC_UNIT_S
+		},
+		&XLogArchiveTimeout,
+		0, 0, INT_MAX, NULL, NULL
+	},
 	{
 		{"post_auth_delay", PGC_BACKEND, DEVELOPER_OPTIONS,
 		 gettext_noop("Waits N seconds on connection startup after authentication."),
diff --git a/src/backend/utils/misc/postgresql.conf.sample b/src/backend/utils/misc/postgresql.conf.sample
index b0c6cdf7634d12f4281beccfc60e253181277346..fcb81d711882a8ad163eaa67abb547f7bef76588 100644
--- a/src/backend/utils/misc/postgresql.conf.sample
+++ b/src/backend/utils/misc/postgresql.conf.sample
@@ -167,8 +167,9 @@
 
 # - Archiving -
 
-#archive_command = ''			# command to use to archive a logfile 
-					# segment
+#archive_command = ''		# command to use to archive a logfile segment
+#archive_timeout = 0		# force a logfile segment switch after this
+				# many seconds; 0 is off
 
 
 #---------------------------------------------------------------------------
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index e076979a44b8dbe3a500033679bd8101c33171c5..22b0f0bb7be2eb9fd2b61f632ee80d94fdfebe7e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -6,7 +6,7 @@
  * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/access/xlog.h,v 1.72 2006/07/13 16:49:19 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/access/xlog.h,v 1.73 2006/08/17 23:04:08 tgl Exp $
  */
 #ifndef XLOG_H
 #define XLOG_H
@@ -139,6 +139,7 @@ extern XLogRecPtr ProcLastRecEnd;
 extern int	CheckPointSegments;
 extern int	XLOGbuffers;
 extern char *XLogArchiveCommand;
+extern int	XLogArchiveTimeout;
 extern char *XLOG_sync_method;
 extern const char XLOG_sync_method_default[];
 
diff --git a/src/include/access/xlog_internal.h b/src/include/access/xlog_internal.h
index 03bf0e86231def31bf33a424074110d79ff15eb2..773e85fbcdb3be92f6934603f9322f7b77c1a8f5 100644
--- a/src/include/access/xlog_internal.h
+++ b/src/include/access/xlog_internal.h
@@ -11,11 +11,13 @@
  * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/access/xlog_internal.h,v 1.15 2006/08/07 16:57:57 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/access/xlog_internal.h,v 1.16 2006/08/17 23:04:08 tgl Exp $
  */
 #ifndef XLOG_INTERNAL_H
 #define XLOG_INTERNAL_H
 
+#include <time.h>
+
 #include "access/xlog.h"
 #include "fmgr.h"
 #include "storage/block.h"
@@ -237,6 +239,12 @@ typedef struct RmgrData
 
 extern const RmgrData RmgrTable[];
 
+/* 
+ * Exported to support xlog switching from bgwriter
+ */
+extern time_t GetLastSegSwitchTime(void);
+extern XLogRecPtr RequestXLogSwitch(void);
+
 /*
  * These aren't in xlog.h because I'd rather not include fmgr.h there.
  */
@@ -244,6 +252,7 @@ extern Datum pg_start_backup(PG_FUNCTION_ARGS);
 extern Datum pg_stop_backup(PG_FUNCTION_ARGS);
 extern Datum pg_switch_xlog(PG_FUNCTION_ARGS);
 extern Datum pg_current_xlog_location(PG_FUNCTION_ARGS);
+extern Datum pg_current_xlog_insert_location(PG_FUNCTION_ARGS);
 extern Datum pg_xlogfile_name_offset(PG_FUNCTION_ARGS);
 extern Datum pg_xlogfile_name(PG_FUNCTION_ARGS);
 
diff --git a/src/include/catalog/catversion.h b/src/include/catalog/catversion.h
index d2141f1b3851efa79f36fc3b7c7b0c04605979db..6728188e501ec154b813e6c05c3a061d7f4c4d28 100644
--- a/src/include/catalog/catversion.h
+++ b/src/include/catalog/catversion.h
@@ -37,7 +37,7 @@
  * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.349 2006/08/12 02:52:06 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.350 2006/08/17 23:04:08 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -53,6 +53,6 @@
  */
 
 /*							yyyymmddN */
-#define CATALOG_VERSION_NO	200608101
+#define CATALOG_VERSION_NO	200608171
 
 #endif
diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h
index 5c0824ef0412f4c0a72d08d56d26fb763766aefe..93a1e0c1ed079b7c89756a99377f51f03da28c2b 100644
--- a/src/include/catalog/pg_proc.h
+++ b/src/include/catalog/pg_proc.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/catalog/pg_proc.h,v 1.420 2006/08/06 03:53:44 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/catalog/pg_proc.h,v 1.421 2006/08/17 23:04:10 tgl Exp $
  *
  * NOTES
  *	  The script catalog/genbki.sh reads this file and generates .bki
@@ -3104,8 +3104,10 @@ DESCR("Finish taking an online backup");
 DATA(insert OID = 2848 ( pg_switch_xlog			PGNSP PGUID 12 f f t f v 0 25 "" _null_ _null_ _null_ pg_switch_xlog - _null_ ));
 DESCR("Switch to new xlog file");
 DATA(insert OID = 2849 ( pg_current_xlog_location	PGNSP PGUID 12 f f t f v 0 25 "" _null_ _null_ _null_ pg_current_xlog_location - _null_ ));
-DESCR("current xlog location");
-DATA(insert OID = 2850 ( pg_xlogfile_name_offset	PGNSP PGUID 12 f f t f i 1 25 "25" _null_ _null_ _null_ pg_xlogfile_name_offset - _null_ ));
+DESCR("current xlog write location");
+DATA(insert OID = 2852 ( pg_current_xlog_insert_location	PGNSP PGUID 12 f f t f v 0 25 "" _null_ _null_ _null_ pg_current_xlog_insert_location - _null_ ));
+DESCR("current xlog insert location");
+DATA(insert OID = 2850 ( pg_xlogfile_name_offset	PGNSP PGUID 12 f f t f i 1 2249 "25" "{25,25,23}" "{i,o,o}" "{wal_location,file_name,file_offset}" pg_xlogfile_name_offset - _null_ ));
 DESCR("xlog filename and byte offset, given an xlog location");
 DATA(insert OID = 2851 ( pg_xlogfile_name			PGNSP PGUID 12 f f t f i 1 25 "25" _null_ _null_ _null_ pg_xlogfile_name - _null_ ));
 DESCR("xlog filename, given an xlog location");