pg_rewind: Extend code detecting relation files to work with WAL files
authorMichael Paquier <michael@paquier.xyz>
Thu, 23 Oct 2025 06:57:46 +0000 (15:57 +0900)
committerMichael Paquier <michael@paquier.xyz>
Thu, 23 Oct 2025 06:57:46 +0000 (15:57 +0900)
isRelDataFile() is renamed to getFileContentType(), extended so as it
becomes able to detect more file patterns than only relation files.  The
new file name pattern that can be detected is WAL files.

This refactoring has been suggested by Robert Haas.  This will be used
in a follow-up patch where we are looking at improving how WAL files are
processed by pg_rewind.  As of this change, WAL files are still handled
the same way as previously, always copied from the source to the target
server.

Extracted from a larger patch by the same authors.

Author: John Hsu <johnhyvr@gmail.com>
Author: Justin Kwan <justinpkwan@outlook.com>
Reviewed-by: Japin Li <japinli@hotmail.com>
Reviewed-by: Srinath Reddy Sadipiralla <srinath2133@gmail.com>
Discussion: https://postgr.es/m/181b4c6fa9c.b8b725681941212.7547232617810891479@viggy28.dev

src/bin/pg_rewind/filemap.c
src/bin/pg_rewind/filemap.h
src/tools/pgindent/typedefs.list

index c933871ca9fda2f8f4881f435181039e8cbb0c4d..00f5d60d6209f1515fa07639fd218ede8f1cd080 100644 (file)
@@ -55,7 +55,7 @@
 
 static filehash_hash *filehash;
 
-static bool isRelDataFile(const char *path);
+static file_content_type_t getFileContentType(const char *path);
 static char *datasegpath(RelFileLocator rlocator, ForkNumber forknum,
                         BlockNumber segno);
 
@@ -210,7 +210,7 @@ insert_filehash_entry(const char *path)
    if (!found)
    {
        entry->path = pg_strdup(path);
-       entry->isrelfile = isRelDataFile(path);
+       entry->content_type = getFileContentType(path);
 
        entry->target_exists = false;
        entry->target_type = FILE_TYPE_UNDEFINED;
@@ -294,7 +294,7 @@ process_source_file(const char *path, file_type_t type, size_t size,
     * sanity check: a filename that looks like a data file better be a
     * regular file
     */
-   if (type != FILE_TYPE_REGULAR && isRelDataFile(path))
+   if (type != FILE_TYPE_REGULAR && getFileContentType(path) == FILE_CONTENT_TYPE_RELATION)
        pg_fatal("data file \"%s\" in source is not a regular file", path);
 
    /* Remember this source file */
@@ -383,7 +383,7 @@ process_target_wal_block_change(ForkNumber forknum, RelFileLocator rlocator,
     */
    if (entry)
    {
-       Assert(entry->isrelfile);
+       Assert(entry->content_type == FILE_CONTENT_TYPE_RELATION);
 
        if (entry->target_exists)
        {
@@ -560,22 +560,35 @@ print_filemap(filemap_t *filemap)
 }
 
 /*
- * Does it look like a relation data file?
- *
- * For our purposes, only files belonging to the main fork are considered
- * relation files. Other forks are always copied in toto, because we cannot
- * reliably track changes to them, because WAL only contains block references
- * for the main fork.
+ * Determine what kind of file this one looks like.
  */
-static bool
-isRelDataFile(const char *path)
+static file_content_type_t
+getFileContentType(const char *path)
 {
    RelFileLocator rlocator;
    unsigned int segNo;
    int         nmatch;
-   bool        matched;
+   file_content_type_t result = FILE_CONTENT_TYPE_OTHER;
+
+   /* Check if it is a WAL file. */
+   if (strncmp("pg_wal/", path, 7) == 0)
+   {
+       const char *filename = path + 7;    /* Skip "pg_wal/" */
+
+       if (IsXLogFileName(filename))
+           return FILE_CONTENT_TYPE_WAL;
+       else
+           return FILE_CONTENT_TYPE_OTHER;
+   }
 
    /*----
+    * Does it look like a relation data file?
+    *
+    * For our purposes, only files belonging to the main fork are considered
+    * relation files. Other forks are always copied in toto, because we
+    * cannot reliably track changes to them, because WAL only contains block
+    * references for the main fork.
+    *
     * Relation data files can be in one of the following directories:
     *
     * global/
@@ -598,14 +611,14 @@ isRelDataFile(const char *path)
    rlocator.dbOid = InvalidOid;
    rlocator.relNumber = InvalidRelFileNumber;
    segNo = 0;
-   matched = false;
+   result = FILE_CONTENT_TYPE_OTHER;
 
    nmatch = sscanf(path, "global/%u.%u", &rlocator.relNumber, &segNo);
    if (nmatch == 1 || nmatch == 2)
    {
        rlocator.spcOid = GLOBALTABLESPACE_OID;
        rlocator.dbOid = 0;
-       matched = true;
+       result = FILE_CONTENT_TYPE_RELATION;
    }
    else
    {
@@ -614,7 +627,7 @@ isRelDataFile(const char *path)
        if (nmatch == 2 || nmatch == 3)
        {
            rlocator.spcOid = DEFAULTTABLESPACE_OID;
-           matched = true;
+           result = FILE_CONTENT_TYPE_RELATION;
        }
        else
        {
@@ -622,7 +635,7 @@ isRelDataFile(const char *path)
                            &rlocator.spcOid, &rlocator.dbOid, &rlocator.relNumber,
                            &segNo);
            if (nmatch == 3 || nmatch == 4)
-               matched = true;
+               result = FILE_CONTENT_TYPE_RELATION;
        }
    }
 
@@ -632,17 +645,17 @@ isRelDataFile(const char *path)
     * creates the exact same filename, when passed the RelFileLocator
     * information we extracted from the filename.
     */
-   if (matched)
+   if (result == FILE_CONTENT_TYPE_RELATION)
    {
        char       *check_path = datasegpath(rlocator, MAIN_FORKNUM, segNo);
 
        if (strcmp(check_path, path) != 0)
-           matched = false;
+           result = FILE_CONTENT_TYPE_OTHER;
 
        pfree(check_path);
    }
 
-   return matched;
+   return result;
 }
 
 /*
@@ -799,7 +812,12 @@ decide_file_action(file_entry_t *entry)
            return FILE_ACTION_NONE;
 
        case FILE_TYPE_REGULAR:
-           if (!entry->isrelfile)
+           if (entry->content_type == FILE_CONTENT_TYPE_WAL)
+           {
+               /* It's a WAL file, copy it. */
+               return FILE_ACTION_COPY;
+           }
+           else if (entry->content_type != FILE_CONTENT_TYPE_RELATION)
            {
                /*
                 * It's a non-data file that we have no special processing
index df78a02e3da03db7accd0fd9424d521fa11aaa73..fada420fc230e8c0ba04ef33b0240a188ec256db 100644 (file)
@@ -36,6 +36,13 @@ typedef enum
    FILE_TYPE_SYMLINK,
 } file_type_t;
 
+typedef enum
+{
+   FILE_CONTENT_TYPE_OTHER = 0,
+   FILE_CONTENT_TYPE_RELATION,
+   FILE_CONTENT_TYPE_WAL
+} file_content_type_t;
+
 /*
  * For every file found in the local or remote system, we have a file entry
  * that contains information about the file on both systems.  For relation
@@ -51,7 +58,7 @@ typedef struct file_entry_t
    uint32      status;         /* hash status */
 
    const char *path;
-   bool        isrelfile;      /* is it a relation data file? */
+   file_content_type_t content_type;
 
    /*
     * Status of the file in the target.
index 377a794658557d232f6b2cca56ab2183bfb67b50..c13f92988ee69d93afc58e9ddb76351ab9b656b6 100644 (file)
@@ -3622,6 +3622,7 @@ fe_scram_state
 fe_scram_state_enum
 fetch_range_request
 file_action_t
+file_content_type_t
 file_entry_t
 file_type_t
 filehash_hash