]> granicus.if.org Git - postgresql/commitdiff
Fix initial sync of slot parent directory when restoring status
authorMichael Paquier <michael@paquier.xyz>
Sun, 2 Sep 2018 19:40:38 +0000 (12:40 -0700)
committerMichael Paquier <michael@paquier.xyz>
Sun, 2 Sep 2018 19:40:38 +0000 (12:40 -0700)
At the beginning of recovery, information from replication slots is
recovered from disk to memory.  In order to ensure the durability of the
information, the status file as well as its parent directory are
synced.  It happens that the sync on the parent directory was done
directly using the status file path, which is logically incorrect, and
the current code has been doing a sync on the same object twice in a
row.

Reported-by: Konstantin Knizhnik
Diagnosed-by: Konstantin Knizhnik
Author: Michael Paquier
Discussion: https://postgr.es/m/9eb1a6d5-b66f-2640-598d-c5ea46b8f68a@postgrespro.ru
Backpatch-through: 9.4-

src/backend/replication/slot.c

index 94f7a99cfa4ca437f407c5b0dfaaeaedcf123293..7368f9653ba983cbc0a4b96ae9cef2ec3fe73b0e 100644 (file)
@@ -1352,6 +1352,7 @@ RestoreSlotFromDisk(const char *name)
 {
        ReplicationSlotOnDisk cp;
        int                     i;
+       char            slotdir[MAXPGPATH + 12];
        char            path[MAXPGPATH + 22];
        int                     fd;
        bool            restored = false;
@@ -1361,13 +1362,14 @@ RestoreSlotFromDisk(const char *name)
        /* no need to lock here, no concurrent access allowed yet */
 
        /* delete temp file if it exists */
-       sprintf(path, "pg_replslot/%s/state.tmp", name);
+       sprintf(slotdir, "pg_replslot/%s", name);
+       sprintf(path, "%s/state.tmp", slotdir);
        if (unlink(path) < 0 && errno != ENOENT)
                ereport(PANIC,
                                (errcode_for_file_access(),
                                 errmsg("could not remove file \"%s\": %m", path)));
 
-       sprintf(path, "pg_replslot/%s/state", name);
+       sprintf(path, "%s/state", slotdir);
 
        elog(DEBUG1, "restoring replication slot from \"%s\"", path);
 
@@ -1402,7 +1404,7 @@ RestoreSlotFromDisk(const char *name)
 
        /* Also sync the parent directory */
        START_CRIT_SECTION();
-       fsync_fname(path, true);
+       fsync_fname(slotdir, true);
        END_CRIT_SECTION();
 
        /* read part of statefile that's guaranteed to be version independent */
@@ -1481,13 +1483,11 @@ RestoreSlotFromDisk(const char *name)
         */
        if (cp.slotdata.persistency != RS_PERSISTENT)
        {
-               sprintf(path, "pg_replslot/%s", name);
-
-               if (!rmtree(path, true))
+               if (!rmtree(slotdir, true))
                {
                        ereport(WARNING,
                                        (errcode_for_file_access(),
-                                        errmsg("could not remove directory \"%s\"", path)));
+                                        errmsg("could not remove directory \"%s\"", slotdir)));
                }
                fsync_fname("pg_replslot", true);
                return;