Mark commit and abort WAL records with XLR_SPECIAL_REL_UPDATE.
authorHeikki Linnakangas
Mon, 17 Aug 2020 07:52:58 +0000 (10:52 +0300)
committerHeikki Linnakangas
Mon, 17 Aug 2020 07:52:58 +0000 (10:52 +0300)
If a commit or abort record includes "dropped relfilenodes", then replaying
the record will remove data files. That is surely a "special rel update",
but the records were not marked as such. Fix that, teach pg_rewind to
expect and ignore them, and add a test case to cover it.

It's always been like this, but no backporting for fear of breaking
existing applications. If an application parsed the WAL but was not
handling commit/abort records, it would stop working. That might be a good
thing if it really needed to handle the dropped rels, but it will be caught
when the application is updated to work with PostgreSQL v14 anyway.

Discussion: https://www.postgresql.org/message-id/07b33e2c-46a6-86a1-5f9e-a7da73fddb95%40iki.fi
Reviewed-by: Amit Kapila, Michael Paquier
src/backend/access/transam/xact.c
src/bin/pg_rewind/parsexlog.c
src/bin/pg_rewind/t/001_basic.pl

index 7ccb7d68ed9a620eba64369822125780d49f46d2..af6afcebb133f8b28960d45f18b1cdefcb6cc154 100644 (file)
@@ -5565,6 +5565,7 @@ XactLogCommitRecord(TimestampTz commit_time,
    {
        xl_xinfo.xinfo |= XACT_XINFO_HAS_RELFILENODES;
        xl_relfilenodes.nrels = nrels;
+       info |= XLR_SPECIAL_REL_UPDATE;
    }
 
    if (nmsgs > 0)
@@ -5697,6 +5698,7 @@ XactLogAbortRecord(TimestampTz abort_time,
    {
        xl_xinfo.xinfo |= XACT_XINFO_HAS_RELFILENODES;
        xl_relfilenodes.nrels = nrels;
+       info |= XLR_SPECIAL_REL_UPDATE;
    }
 
    if (TransactionIdIsValid(twophase_xid))
index 2325fb5d302160f4dd4aa18b4437361459e9ac75..2229c86f9afbc5fe990ba6c9e0fd7cde258d9ffb 100644 (file)
@@ -14,6 +14,7 @@
 #include 
 
 #include "access/rmgr.h"
+#include "access/xact.h"
 #include "access/xlog_internal.h"
 #include "access/xlogreader.h"
 #include "catalog/pg_control.h"
@@ -397,6 +398,18 @@ extractPageInfo(XLogReaderState *record)
         * source system.
         */
    }
+   else if (rmid == RM_XACT_ID &&
+            ((rminfo & XLOG_XACT_OPMASK) == XLOG_XACT_COMMIT ||
+             (rminfo & XLOG_XACT_OPMASK) == XLOG_XACT_COMMIT_PREPARED ||
+             (rminfo & XLOG_XACT_OPMASK) == XLOG_XACT_ABORT ||
+             (rminfo & XLOG_XACT_OPMASK) == XLOG_XACT_ABORT_PREPARED))
+   {
+       /*
+        * These records can include "dropped rels". We can safely ignore
+        * them, we will see that they are missing and copy them from the
+        * source.
+        */
+   }
    else if (info & XLR_SPECIAL_REL_UPDATE)
    {
        /*
index fb4a0acd965af8318efbb45cd145b492fe7261eb..ba528e262f32d8219bf353b786dff67faabfa048 100644 (file)
@@ -1,7 +1,7 @@
 use strict;
 use warnings;
 use TestLib;
-use Test::More tests => 20;
+use Test::More tests => 23;
 
 use FindBin;
 use lib $FindBin::RealBin;
@@ -29,6 +29,10 @@ sub run_test
    primary_psql("CREATE TABLE tail_tbl (id integer, d text)");
    primary_psql("INSERT INTO tail_tbl VALUES (0, 'in primary')");
 
+   # This test table is dropped in the old primary after promotion.
+   primary_psql("CREATE TABLE drop_tbl (d text)");
+   primary_psql("INSERT INTO drop_tbl VALUES ('in primary')");
+
    primary_psql("CHECKPOINT");
 
    RewindTest::create_standby($test_mode);
@@ -66,6 +70,9 @@ sub run_test
    primary_psql("DELETE FROM tail_tbl WHERE id > 10");
    primary_psql("VACUUM tail_tbl");
 
+   # Drop drop_tbl. pg_rewind should copy it back.
+   primary_psql("DROP TABLE drop_tbl");
+
    # Before running pg_rewind, do a couple of extra tests with several
    # option combinations.  As the code paths taken by those tests
    # do not change for the "local" and "remote" modes, just run them
@@ -154,6 +161,12 @@ in primary, before promotion
 ),
        'tail-copy');
 
+   check_query(
+       'SELECT * FROM drop_tbl',
+       qq(in primary
+),
+       'drop');
+
    # Permissions on PGDATA should be default
   SKIP:
    {