Add -f/--follow option to pg_xlogdump.
authorHeikki Linnakangas <heikki.linnakangas@iki.fi>
Wed, 26 Mar 2014 11:48:20 +0000 (13:48 +0200)
committerHeikki Linnakangas <heikki.linnakangas@iki.fi>
Wed, 26 Mar 2014 11:48:20 +0000 (13:48 +0200)
This is useful for seeing what WAL records are inserted in real-time, by
pointing pg_xlogdump to a live server.

contrib/pg_xlogdump/pg_xlogdump.c
doc/src/sgml/pg_xlogdump.sgml

index 024ab01efa08c076d0bc9e3811a4678c2f141d3d..e947696429d754907da8b828cad9852575dac84a 100644 (file)
@@ -32,6 +32,7 @@ typedef struct XLogDumpPrivate
        char       *inpath;
        XLogRecPtr      startptr;
        XLogRecPtr      endptr;
+       bool            endptr_reached;
 } XLogDumpPrivate;
 
 typedef struct XLogDumpConfig
@@ -40,6 +41,7 @@ typedef struct XLogDumpConfig
        bool            bkp_details;
        int                     stop_after_records;
        int                     already_displayed_records;
+       bool            follow;
 
        /* filter options */
        int                     filter_by_rmgr;
@@ -308,7 +310,10 @@ XLogDumpReadPage(XLogReaderState *state, XLogRecPtr targetPagePtr, int reqLen,
                else if (targetPagePtr + reqLen <= private->endptr)
                        count = private->endptr - targetPagePtr;
                else
+               {
+                       private->endptr_reached = true;
                        return -1;
+               }
        }
 
        XLogDumpXLogRead(private->inpath, private->timeline, targetPagePtr,
@@ -386,6 +391,7 @@ usage(void)
        printf("\nOptions:\n");
        printf("  -b, --bkp-details      output detailed information about backup blocks\n");
        printf("  -e, --end=RECPTR       stop reading at log position RECPTR\n");
+       printf("  -f, --follow           keep retrying after reaching end of WAL\n");
        printf("  -n, --limit=N          number of records to display\n");
        printf("  -p, --path=PATH        directory in which to find log segment files\n");
        printf("                         (default: ./pg_xlog)\n");
@@ -414,6 +420,7 @@ main(int argc, char **argv)
        static struct option long_options[] = {
                {"bkp-details", no_argument, NULL, 'b'},
                {"end", required_argument, NULL, 'e'},
+               {"follow", no_argument, NULL, 'f'},
                {"help", no_argument, NULL, '?'},
                {"limit", required_argument, NULL, 'n'},
                {"path", required_argument, NULL, 'p'},
@@ -436,10 +443,12 @@ main(int argc, char **argv)
        private.timeline = 1;
        private.startptr = InvalidXLogRecPtr;
        private.endptr = InvalidXLogRecPtr;
+       private.endptr_reached = false;
 
        config.bkp_details = false;
        config.stop_after_records = -1;
        config.already_displayed_records = 0;
+       config.follow = false;
        config.filter_by_rmgr = -1;
        config.filter_by_xid = InvalidTransactionId;
        config.filter_by_xid_enabled = false;
@@ -450,7 +459,7 @@ main(int argc, char **argv)
                goto bad_argument;
        }
 
-       while ((option = getopt_long(argc, argv, "be:?n:p:r:s:t:Vx:",
+       while ((option = getopt_long(argc, argv, "be:?fn:p:r:s:t:Vx:",
                                                                 long_options, &optindex)) != -1)
        {
                switch (option)
@@ -467,6 +476,9 @@ main(int argc, char **argv)
                                }
                                private.endptr = (uint64) xlogid << 32 | xrecoff;
                                break;
+                       case 'f':
+                               config.follow = true;
+                               break;
                        case '?':
                                usage();
                                exit(EXIT_SUCCESS);
@@ -683,9 +695,22 @@ main(int argc, char **argv)
                           (uint32) (first_record >> 32), (uint32) first_record,
                           (uint32) (first_record - private.startptr));
 
-       while ((record = XLogReadRecord(xlogreader_state, first_record, &errormsg)))
+       for (;;)
        {
-               /* continue after the last record */
+               /* try to read the next record */
+               record = XLogReadRecord(xlogreader_state, first_record, &errormsg);
+               if (!record)
+               {
+                       if (!config.follow || private.endptr_reached)
+                               break;
+                       else
+                       {
+                               sleep(1);
+                               continue;
+                       }
+               }
+
+               /* after reading the first record, continue at next one */
                first_record = InvalidXLogRecPtr;
                XLogDumpDisplayRecord(&config, xlogreader_state->ReadRecPtr, record);
 
index 173962211981acadadf7c26d39422af441eb271b..1d1a2cea8702f0ce6f3cbe8db98c656aa5ad5aed 100644 (file)
@@ -91,6 +91,17 @@ PostgreSQL documentation
       </listitem>
      </varlistentry>
 
+     <varlistentry>
+      <term><option>-f</option></term>
+      <term><option>--follow</option></term>
+      <listitem>
+       <para>
+        After reaching the end of valid WAL, keep polling once per second for
+        new WAL to appear.
+       </para>
+      </listitem>
+     </varlistentry>
+
      <varlistentry>
       <term><option>-n <replaceable>limit</replaceable></option></term>
       <term><option>--limit=<replaceable>limit</replaceable></option></term>