Attached patch adds some more "metadata" to walsender results:

* Adds the current xlog insert location as a third column in IDENTIFY_SYSTEM
* Adds a resultset at the start of a base backup that contains the
start xlog location (as returned by do_pg_start_backup)
* Adds a resultset at the end of a base backup that contains the end
xlog location (as returned by do_pg_stop_backup)

These are all information that's interesting for the "log receiver"
version of pg_basebackup (the changes to BASE_BACKUP) and the
pg_streamrecv program (the IDENTIFY_SYSTEM) once integrated.

I still haven't had the time to clean up those programs enough to
submit as a patch yet (it has progressed past that early post from a
month ago or so, but isn't done yet), but I wanted to make sure that
the backend parts gets reviewed and added as soon as possible. And
they're also quite trivial. That way if I don't find time to clean up
the streaming mode receiver in time for 9.1, it can be maintained
outside of the main tree until 9.2 - but the small backend changes
would still be required.

-- 
 Magnus Hagander
 Me: http://www.hagander.net/
 Work: http://www.redpill-linpro.com/
diff --git a/doc/src/sgml/protocol.sgml b/doc/src/sgml/protocol.sgml
index 73c05ed..5e9b5d4 100644
--- a/doc/src/sgml/protocol.sgml
+++ b/doc/src/sgml/protocol.sgml
@@ -1315,7 +1315,7 @@ The commands accepted in walsender mode are:
     <listitem>
      <para>
       Requests the server to identify itself. Server replies with a result
-      set of a single row, containing two fields:
+      set of a single row, containing three fields:
      </para>
 
      <para>
@@ -1344,6 +1344,19 @@ The commands accepted in walsender mode are:
       </para>
       </listitem>
       </varlistentry>
+
+      <varlistentry>
+      <term>
+       xlogpos
+      </term>
+      <listitem>
+      <para>
+       Current xlog write location. Useful to get a known location in the
+       transaction log where streaming can start.
+      </para>
+      </listitem>
+      </varlistentry>
+
       </variablelist>
      </para>
     </listitem>
@@ -1520,15 +1533,16 @@ The commands accepted in walsender mode are:
       </variablelist>
      </para>
      <para>
-      When the backup is started, the server will first send a header in
-      ordinary result set format, followed by one or more CopyResponse
-      results, one for PGDATA and one for each additional tablespace other
-      than <literal>pg_default</> and <literal>pg_global</>. The data in
-      the CopyResponse results will be a tar format (using ustar00
-      extensions) dump of the tablespace contents.
+      When the backup is started, the server will first send two
+      ordinary result sets, followed by one or more CopyResponse
+      results.
+     </para>
+     <para>
+      The first ordinary result set contains the starting position of the
+      backup, given in XLogRecPtr format as a single column in a single row.
      </para>
      <para>
-      The header is an ordinary resultset with one row for each tablespace.
+      The second ordinary result set has one row for each tablespace.
       The fields in this row are:
       <variablelist>
        <varlistentry>
@@ -1561,6 +1575,15 @@ The commands accepted in walsender mode are:
       </variablelist>
      </para>
      <para>
+      After the two regular result set, one or more CopyResponse results
+      will be sent, one for PGDATA and one for each additional tablespace other
+      than <literal>pg_default</> and <literal>pg_global</>. The data in
+      the CopyResponse results will be a tar format (using ustar00
+      extensions) dump of the tablespace contents. After the tar data is
+      complete, a final ordinary result set will be sent.
+     </para>
+
+     <para>
       The tar archive for the data directory and each tablespace will contain
       all files in the directories, regardless of whether they are
       <productname>PostgreSQL</> files or other files added to the same
@@ -1583,6 +1606,11 @@ The commands accepted in walsender mode are:
       Owner, group and file mode are set if the underlying filesystem on
       the server supports it.
      </para>
+     <para>
+      Once all tablespaces have been sent, a final regular result set will
+      be sent. This result set contains the end position of the
+      backup, given in XLogRecPtr format as a single column in a single row.
+     </para>
     </listitem>
   </varlistentry>
 </variablelist>
diff --git a/src/backend/replication/basebackup.c b/src/backend/replication/basebackup.c
index 29284a6..840d577 100644
--- a/src/backend/replication/basebackup.c
+++ b/src/backend/replication/basebackup.c
@@ -52,6 +52,7 @@ static void SendBackupHeader(List *tablespaces);
 static void base_backup_cleanup(int code, Datum arg);
 static void perform_base_backup(basebackup_options *opt, DIR *tblspcdir);
 static void parse_basebackup_options(List *options, basebackup_options *opt);
+static void SendXlogRecPtrResult(XLogRecPtr ptr);
 
 /*
  * Size of each block sent into the tar stream for larger files.
@@ -92,6 +93,7 @@ perform_base_backup(basebackup_options *opt, DIR *tblspcdir)
 	char	   *labelfile;
 
 	startptr = do_pg_start_backup(opt->label, opt->fastcheckpoint, &labelfile);
+	SendXlogRecPtrResult(startptr);
 
 	PG_ENSURE_ERROR_CLEANUP(base_backup_cleanup, (Datum) 0);
 	{
@@ -239,6 +241,7 @@ perform_base_backup(basebackup_options *opt, DIR *tblspcdir)
 		/* Send CopyDone message for the last tar file */
 		pq_putemptymessage('c');
 	}
+	SendXlogRecPtrResult(endptr);
 }
 
 /*
@@ -432,6 +435,42 @@ SendBackupHeader(List *tablespaces)
 }
 
 /*
+ * Send a single resultset containing just a single
+ * XlogRecPtr record (in text format)
+ */
+static void
+SendXlogRecPtrResult(XLogRecPtr ptr)
+{
+	StringInfoData buf;
+	char		   str[MAXFNAMELEN];
+
+	snprintf(str, sizeof(str), "%X/%X", ptr.xlogid, ptr.xrecoff);
+
+	pq_beginmessage(&buf, 'T'); /* RowDescription */
+	pq_sendint(&buf, 1, 2);		/* 1 field */
+
+	/* Field header */
+	pq_sendstring(&buf, "recptr");
+	pq_sendint(&buf, 0, 4);		/* table oid */
+	pq_sendint(&buf, 0, 2);		/* attnum */
+	pq_sendint(&buf, TEXTOID, 4); 	/* type oid */
+	pq_sendint(&buf, -1, 2);
+	pq_sendint(&buf, 0, 4);
+	pq_sendint(&buf, 0, 2);
+	pq_endmessage(&buf);
+
+	/* Data row */
+	pq_beginmessage(&buf, 'D');
+	pq_sendint(&buf, 1, 2); /* number of columns */
+	pq_sendint(&buf, strlen(str), 4); /* length */
+	pq_sendbytes(&buf, str, strlen(str));
+	pq_endmessage(&buf);
+
+	/* Send a CommandComplete message */
+	pq_puttextmessage('C', "SELECT");
+}
+
+/*
  * Inject a file with given name and content in the output tar stream.
  */
 static void
diff --git a/src/backend/replication/walsender.c b/src/backend/replication/walsender.c
index f70458e..78963c1 100644
--- a/src/backend/replication/walsender.c
+++ b/src/backend/replication/walsender.c
@@ -258,19 +258,26 @@ IdentifySystem(void)
 	StringInfoData buf;
 	char		sysid[32];
 	char		tli[11];
+	char		xpos[MAXFNAMELEN];
+	XLogRecPtr	logptr;
 
 	/*
-	 * Reply with a result set with one row, two columns. First col is system
-	 * ID, and second is timeline ID
+	 * Reply with a result set with one row, three columns. First col is system
+	 * ID, second is timeline ID, and third is current xlog location.
 	 */
 
 	snprintf(sysid, sizeof(sysid), UINT64_FORMAT,
 			 GetSystemIdentifier());
 	snprintf(tli, sizeof(tli), "%u", ThisTimeLineID);
 
+	logptr = GetInsertRecPtr();
+
+	snprintf(xpos, sizeof(xpos), "%X/%X",
+			 logptr.xlogid, logptr.xrecoff);
+
 	/* Send a RowDescription message */
 	pq_beginmessage(&buf, 'T');
-	pq_sendint(&buf, 2, 2);		/* 2 fields */
+	pq_sendint(&buf, 3, 2);		/* 3 fields */
 
 	/* first field */
 	pq_sendstring(&buf, "systemid");	/* col name */
@@ -289,15 +296,27 @@ IdentifySystem(void)
 	pq_sendint(&buf, 4, 2);		/* typlen */
 	pq_sendint(&buf, 0, 4);		/* typmod */
 	pq_sendint(&buf, 0, 2);		/* format code */
+
+	/* third field */
+	pq_sendstring(&buf, "xlogpos");
+	pq_sendint(&buf, 0, 4);
+	pq_sendint(&buf, 0, 2);
+	pq_sendint(&buf, TEXTOID, 4);
+	pq_sendint(&buf, -1, 2);
+	pq_sendint(&buf, 0, 4);
+	pq_sendint(&buf, 0, 2);
 	pq_endmessage(&buf);
 
 	/* Send a DataRow message */
 	pq_beginmessage(&buf, 'D');
-	pq_sendint(&buf, 2, 2);		/* # of columns */
+	pq_sendint(&buf, 3, 2);		/* # of columns */
 	pq_sendint(&buf, strlen(sysid), 4); /* col1 len */
 	pq_sendbytes(&buf, (char *) &sysid, strlen(sysid));
 	pq_sendint(&buf, strlen(tli), 4);	/* col2 len */
 	pq_sendbytes(&buf, (char *) tli, strlen(tli));
+	pq_sendint(&buf, strlen(xpos), 4);	/* col3 len */
+	pq_sendbytes(&buf, (char *) xpos, strlen(xpos));
+
 	pq_endmessage(&buf);
 
 	/* Send CommandComplete and ReadyForQuery messages */
-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

Reply via email to