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>