PostgreSQL Source Code git master
filemap.c File Reference
#include "postgres_fe.h"
#include <sys/stat.h>
#include <unistd.h>
#include "access/xlog_internal.h"
#include "catalog/pg_tablespace_d.h"
#include "common/file_utils.h"
#include "common/hashfn_unstable.h"
#include "common/string.h"
#include "datapagemap.h"
#include "filemap.h"
#include "pg_rewind.h"
#include "lib/simplehash.h"
Include dependency graph for filemap.c:

Go to the source code of this file.

Data Structures

struct  keepwal_entry
 
struct  exclude_list_item
 

Macros

#define SH_PREFIX   filehash
 
#define SH_ELEMENT_TYPE   file_entry_t
 
#define SH_KEY_TYPE   const char *
 
#define SH_KEY   path
 
#define SH_HASH_KEY(tb, key)   hash_string(key)
 
#define SH_EQUAL(tb, a, b)   (strcmp(a, b) == 0)
 
#define SH_SCOPE   static inline
 
#define SH_RAW_ALLOCATOR   pg_malloc0
 
#define SH_DECLARE
 
#define SH_DEFINE
 
#define FILEHASH_INITIAL_SIZE   1000
 
#define SH_PREFIX   keepwal
 
#define SH_ELEMENT_TYPE   keepwal_entry
 
#define SH_KEY_TYPE   const char *
 
#define SH_KEY   path
 
#define SH_HASH_KEY(tb, key)   hash_string(key)
 
#define SH_EQUAL(tb, a, b)   (strcmp(a, b) == 0)
 
#define SH_SCOPE   static inline
 
#define SH_RAW_ALLOCATOR   pg_malloc0
 
#define SH_DECLARE
 
#define SH_DEFINE
 
#define KEEPWAL_INITIAL_SIZE   1000
 

Typedefs

typedef struct keepwal_entry keepwal_entry
 

Functions

static file_content_type_t getFileContentType (const char *path)
 
static char * datasegpath (RelFileLocator rlocator, ForkNumber forknum, BlockNumber segno)
 
static file_entry_tinsert_filehash_entry (const char *path)
 
static file_entry_tlookup_filehash_entry (const char *path)
 
static bool keepwal_entry_exists (const char *path)
 
static int final_filemap_cmp (const void *a, const void *b)
 
static bool check_file_excluded (const char *path, bool is_source)
 
void filehash_init (void)
 
void keepwal_init (void)
 
void keepwal_add_entry (const char *path)
 
void process_source_file (const char *path, file_type_t type, size_t size, const char *link_target)
 
void process_target_file (const char *path, file_type_t type, size_t size, const char *link_target)
 
void process_target_wal_block_change (ForkNumber forknum, RelFileLocator rlocator, BlockNumber blkno)
 
static const char * action_to_str (file_action_t action)
 
void calculate_totals (filemap_t *filemap)
 
void print_filemap (filemap_t *filemap)
 
static file_action_t decide_wal_file_action (const char *fname, XLogSegNo last_common_segno, size_t source_size, size_t target_size)
 
static file_action_t decide_file_action (file_entry_t *entry, XLogSegNo last_common_segno)
 
filemap_tdecide_file_actions (XLogSegNo last_common_segno)
 

Variables

static filehash_hash * filehash
 
static keepwal_hash * keepwal = NULL
 
static const char *const excludeDirContents []
 
static const struct exclude_list_item excludeFiles []
 

Macro Definition Documentation

◆ FILEHASH_INITIAL_SIZE

#define FILEHASH_INITIAL_SIZE   1000

Definition at line 54 of file filemap.c.

◆ KEEPWAL_INITIAL_SIZE

#define KEEPWAL_INITIAL_SIZE   1000

Definition at line 86 of file filemap.c.

◆ SH_DECLARE [1/2]

#define SH_DECLARE

Definition at line 82 of file filemap.c.

◆ SH_DECLARE [2/2]

#define SH_DECLARE

Definition at line 82 of file filemap.c.

◆ SH_DEFINE [1/2]

#define SH_DEFINE

Definition at line 83 of file filemap.c.

◆ SH_DEFINE [2/2]

#define SH_DEFINE

Definition at line 83 of file filemap.c.

◆ SH_ELEMENT_TYPE [1/2]

#define SH_ELEMENT_TYPE   file_entry_t

Definition at line 75 of file filemap.c.

◆ SH_ELEMENT_TYPE [2/2]

#define SH_ELEMENT_TYPE   keepwal_entry

Definition at line 75 of file filemap.c.

◆ SH_EQUAL [1/2]

#define SH_EQUAL (   tb,
  a,
  b 
)    (strcmp(a, b) == 0)

Definition at line 79 of file filemap.c.

◆ SH_EQUAL [2/2]

#define SH_EQUAL (   tb,
  a,
  b 
)    (strcmp(a, b) == 0)

Definition at line 79 of file filemap.c.

◆ SH_HASH_KEY [1/2]

#define SH_HASH_KEY (   tb,
  key 
)    hash_string(key)

Definition at line 78 of file filemap.c.

◆ SH_HASH_KEY [2/2]

#define SH_HASH_KEY (   tb,
  key 
)    hash_string(key)

Definition at line 78 of file filemap.c.

◆ SH_KEY [1/2]

#define SH_KEY   path

Definition at line 77 of file filemap.c.

◆ SH_KEY [2/2]

#define SH_KEY   path

Definition at line 77 of file filemap.c.

◆ SH_KEY_TYPE [1/2]

#define SH_KEY_TYPE   const char *

Definition at line 76 of file filemap.c.

◆ SH_KEY_TYPE [2/2]

#define SH_KEY_TYPE   const char *

Definition at line 76 of file filemap.c.

◆ SH_PREFIX [1/2]

#define SH_PREFIX   filehash

Definition at line 74 of file filemap.c.

◆ SH_PREFIX [2/2]

#define SH_PREFIX   keepwal

Definition at line 74 of file filemap.c.

◆ SH_RAW_ALLOCATOR [1/2]

#define SH_RAW_ALLOCATOR   pg_malloc0

Definition at line 81 of file filemap.c.

◆ SH_RAW_ALLOCATOR [2/2]

#define SH_RAW_ALLOCATOR   pg_malloc0

Definition at line 81 of file filemap.c.

◆ SH_SCOPE [1/2]

#define SH_SCOPE   static inline

Definition at line 80 of file filemap.c.

◆ SH_SCOPE [2/2]

#define SH_SCOPE   static inline

Definition at line 80 of file filemap.c.

Typedef Documentation

◆ keepwal_entry

typedef struct keepwal_entry keepwal_entry

Function Documentation

◆ action_to_str()

static const char * action_to_str ( file_action_t  action)
static

Definition at line 474 of file filemap.c.

475{
476 switch (action)
477 {
478 case FILE_ACTION_NONE:
479 return "NONE";
480 case FILE_ACTION_COPY:
481 return "COPY";
483 return "TRUNCATE";
485 return "COPY_TAIL";
487 return "CREATE";
489 return "REMOVE";
490
491 default:
492 return "unknown";
493 }
494}
@ FILE_ACTION_REMOVE
Definition: filemap.h:28
@ FILE_ACTION_COPY
Definition: filemap.h:22
@ FILE_ACTION_NONE
Definition: filemap.h:25
@ FILE_ACTION_COPY_TAIL
Definition: filemap.h:23
@ FILE_ACTION_TRUNCATE
Definition: filemap.h:27
@ FILE_ACTION_CREATE
Definition: filemap.h:21

References generate_unaccent_rules::action, FILE_ACTION_COPY, FILE_ACTION_COPY_TAIL, FILE_ACTION_CREATE, FILE_ACTION_NONE, FILE_ACTION_REMOVE, and FILE_ACTION_TRUNCATE.

Referenced by print_filemap().

◆ calculate_totals()

void calculate_totals ( filemap_t filemap)

Definition at line 500 of file filemap.c.

501{
502 file_entry_t *entry;
503 int i;
504
505 filemap->total_size = 0;
506 filemap->fetch_size = 0;
507
508 for (i = 0; i < filemap->nentries; i++)
509 {
510 entry = filemap->entries[i];
511
512 if (entry->source_type != FILE_TYPE_REGULAR)
513 continue;
514
515 filemap->total_size += entry->source_size;
516
517 if (entry->action == FILE_ACTION_COPY)
518 {
519 filemap->fetch_size += entry->source_size;
520 continue;
521 }
522
523 if (entry->action == FILE_ACTION_COPY_TAIL)
524 filemap->fetch_size += (entry->source_size - entry->target_size);
525
527 {
529 BlockNumber blk;
530
532 while (datapagemap_next(iter, &blk))
533 filemap->fetch_size += BLCKSZ;
534
535 pg_free(iter);
536 }
537 }
538}
uint32 BlockNumber
Definition: block.h:31
bool datapagemap_next(datapagemap_iterator_t *iter, BlockNumber *blkno)
Definition: datapagemap.c:87
datapagemap_iterator_t * datapagemap_iterate(datapagemap_t *map)
Definition: datapagemap.c:75
void pg_free(void *ptr)
Definition: fe_memutils.c:105
@ FILE_TYPE_REGULAR
Definition: filemap.h:35
int i
Definition: isn.c:77
int bitmapsize
Definition: datapagemap.h:17
Definition: filemap.h:58
datapagemap_t target_pages_to_overwrite
Definition: filemap.h:76
size_t source_size
Definition: filemap.h:83
file_type_t source_type
Definition: filemap.h:82
size_t target_size
Definition: filemap.h:69
file_action_t action
Definition: filemap.h:89
file_entry_t * entries[FLEXIBLE_ARRAY_MEMBER]
Definition: filemap.h:104
int nentries
Definition: filemap.h:103
uint64 total_size
Definition: filemap.h:100
uint64 fetch_size
Definition: filemap.h:101

References file_entry_t::action, datapagemap::bitmapsize, datapagemap_iterate(), datapagemap_next(), filemap_t::entries, filemap_t::fetch_size, FILE_ACTION_COPY, FILE_ACTION_COPY_TAIL, FILE_TYPE_REGULAR, i, filemap_t::nentries, pg_free(), file_entry_t::source_size, file_entry_t::source_type, file_entry_t::target_pages_to_overwrite, file_entry_t::target_size, and filemap_t::total_size.

Referenced by main().

◆ check_file_excluded()

static bool check_file_excluded ( const char *  path,
bool  is_source 
)
static

Definition at line 410 of file filemap.c.

411{
412 char localpath[MAXPGPATH];
413 int excludeIdx;
414 const char *filename;
415
416 /*
417 * Skip all temporary files, .../pgsql_tmp/... and .../pgsql_tmp.*
418 */
419 if (strstr(path, "/" PG_TEMP_FILE_PREFIX) != NULL ||
420 strstr(path, "/" PG_TEMP_FILES_DIR "/") != NULL)
421 {
422 return true;
423 }
424
425 /* check individual files... */
426 for (excludeIdx = 0; excludeFiles[excludeIdx].name != NULL; excludeIdx++)
427 {
428 int cmplen = strlen(excludeFiles[excludeIdx].name);
429
431 if (filename == NULL)
432 filename = path;
433 else
434 filename++;
435
436 if (!excludeFiles[excludeIdx].match_prefix)
437 cmplen++;
438 if (strncmp(filename, excludeFiles[excludeIdx].name, cmplen) == 0)
439 {
440 if (is_source)
441 pg_log_debug("entry \"%s\" excluded from source file list",
442 path);
443 else
444 pg_log_debug("entry \"%s\" excluded from target file list",
445 path);
446 return true;
447 }
448 }
449
450 /*
451 * ... And check some directories. Note that this includes any contents
452 * within the directories themselves.
453 */
454 for (excludeIdx = 0; excludeDirContents[excludeIdx] != NULL; excludeIdx++)
455 {
456 snprintf(localpath, sizeof(localpath), "%s/",
457 excludeDirContents[excludeIdx]);
458 if (strstr(path, localpath) == path)
459 {
460 if (is_source)
461 pg_log_debug("entry \"%s\" excluded from source file list",
462 path);
463 else
464 pg_log_debug("entry \"%s\" excluded from target file list",
465 path);
466 return true;
467 }
468 }
469
470 return false;
471}
#define PG_TEMP_FILES_DIR
Definition: file_utils.h:63
#define PG_TEMP_FILE_PREFIX
Definition: file_utils.h:64
static const struct exclude_list_item excludeFiles[]
Definition: filemap.c:158
static const char *const excludeDirContents[]
Definition: filemap.c:117
#define pg_log_debug(...)
Definition: logging.h:133
#define MAXPGPATH
static char * filename
Definition: pg_dumpall.c:120
char * last_dir_separator(const char *filename)
Definition: path.c:145
#define snprintf
Definition: port.h:260
const char * name
Definition: basebackup.c:139
const char * name

References excludeDirContents, excludeFiles, filename, last_dir_separator(), exclude_list_item::match_prefix, MAXPGPATH, exclude_list_item::name, name, pg_log_debug, PG_TEMP_FILE_PREFIX, PG_TEMP_FILES_DIR, and snprintf.

Referenced by decide_file_action().

◆ datasegpath()

static char * datasegpath ( RelFileLocator  rlocator,
ForkNumber  forknum,
BlockNumber  segno 
)
static

Definition at line 669 of file filemap.c.

670{
671 RelPathStr path;
672 char *segpath;
673
674 path = relpathperm(rlocator, forknum);
675 if (segno > 0)
676 {
677 segpath = psprintf("%s.%u", path.str, segno);
678 return segpath;
679 }
680 else
681 return pstrdup(path.str);
682}
char * pstrdup(const char *in)
Definition: mcxt.c:1759
char * psprintf(const char *fmt,...)
Definition: psprintf.c:43
#define relpathperm(rlocator, forknum)
Definition: relpath.h:146
char str[REL_PATH_STR_MAXLEN+1]
Definition: relpath.h:123

References psprintf(), pstrdup(), relpathperm, and RelPathStr::str.

Referenced by getFileContentType(), and process_target_wal_block_change().

◆ decide_file_action()

static file_action_t decide_file_action ( file_entry_t entry,
XLogSegNo  last_common_segno 
)
static

Definition at line 749 of file filemap.c.

750{
751 const char *path = entry->path;
752
753 /*
754 * Don't touch the control file. It is handled specially, after copying
755 * all the other files.
756 */
757 if (strcmp(path, XLOG_CONTROL_FILE) == 0)
758 return FILE_ACTION_NONE;
759
760 /* Skip macOS system files */
761 if (strstr(path, ".DS_Store") != NULL)
762 return FILE_ACTION_NONE;
763
764 /*
765 * Remove all files matching the exclusion filters in the target.
766 */
767 if (check_file_excluded(path, true))
768 {
769 if (entry->target_exists)
770 return FILE_ACTION_REMOVE;
771 else
772 return FILE_ACTION_NONE;
773 }
774
775 /*
776 * Handle cases where the file is missing from one of the systems.
777 */
778 if (!entry->target_exists && entry->source_exists)
779 {
780 /*
781 * File exists in source, but not in target. Copy it in toto. (If it's
782 * a relation data file, WAL replay after rewinding should re-create
783 * it anyway. But there's no harm in copying it now.)
784 */
785 switch (entry->source_type)
786 {
789 return FILE_ACTION_CREATE;
791 return FILE_ACTION_COPY;
793 pg_fatal("unknown file type for \"%s\"", entry->path);
794 break;
795 }
796 }
797 else if (entry->target_exists && !entry->source_exists)
798 {
799 /*
800 * For files that exist in target but not in source, we check the
801 * keepwal hash table; any files listed therein must not be removed.
802 */
803 if (keepwal_entry_exists(path))
804 {
805 pg_log_debug("Not removing file \"%s\" because it is required for recovery", path);
806 return FILE_ACTION_NONE;
807 }
808 return FILE_ACTION_REMOVE;
809 }
810 else if (!entry->target_exists && !entry->source_exists)
811 {
812 /*
813 * Doesn't exist in either server. Why does it have an entry in the
814 * first place??
815 */
816 Assert(false);
817 return FILE_ACTION_NONE;
818 }
819
820 /*
821 * Otherwise, the file exists on both systems
822 */
823 Assert(entry->target_exists && entry->source_exists);
824
825 if (entry->source_type != entry->target_type)
826 {
827 /* But it's a different kind of object. Strange.. */
828 pg_fatal("file \"%s\" is of different type in source and target", entry->path);
829 }
830
831 /*
832 * PG_VERSION files should be identical on both systems, but avoid
833 * overwriting them for paranoia.
834 */
835 if (pg_str_endswith(entry->path, "PG_VERSION"))
836 return FILE_ACTION_NONE;
837
838 switch (entry->source_type)
839 {
841 return FILE_ACTION_NONE;
842
844
845 /*
846 * XXX: Should we check if it points to the same target?
847 */
848 return FILE_ACTION_NONE;
849
852 {
853 /* Handle WAL segment file */
854 const char *filename = last_dir_separator(entry->path);
855
856 if (filename == NULL)
857 filename = entry->path;
858 else
859 filename++; /* Skip the separator */
860
861 return decide_wal_file_action(filename, last_common_segno,
862 entry->source_size,
863 entry->target_size);
864 }
865 else if (entry->content_type != FILE_CONTENT_TYPE_RELATION)
866 {
867 /*
868 * It's a non-data file that we have no special processing
869 * for. Copy it in toto.
870 */
871 return FILE_ACTION_COPY;
872 }
873 else
874 {
875 /*
876 * It's a data file that exists in both systems.
877 *
878 * If it's larger in target, we can truncate it. There will
879 * also be a WAL record of the truncation in the source
880 * system, so WAL replay would eventually truncate the target
881 * too, but we might as well do it now.
882 *
883 * If it's smaller in the target, it means that it has been
884 * truncated in the target, or enlarged in the source, or
885 * both. If it was truncated in the target, we need to copy
886 * the missing tail from the source system. If it was enlarged
887 * in the source system, there will be WAL records in the
888 * source system for the new blocks, so we wouldn't need to
889 * copy them here. But we don't know which scenario we're
890 * dealing with, and there's no harm in copying the missing
891 * blocks now, so do it now.
892 *
893 * If it's the same size, do nothing here. Any blocks modified
894 * in the target will be copied based on parsing the target
895 * system's WAL, and any blocks modified in the source will be
896 * updated after rewinding, when the source system's WAL is
897 * replayed.
898 */
899 if (entry->target_size < entry->source_size)
901 else if (entry->target_size > entry->source_size)
903 else
904 return FILE_ACTION_NONE;
905 }
906 break;
907
909 pg_fatal("unknown file type for \"%s\"", path);
910 break;
911 }
912
913 /* unreachable */
914 pg_fatal("could not decide what to do with file \"%s\"", path);
915}
static bool keepwal_entry_exists(const char *path)
Definition: filemap.c:267
static file_action_t decide_wal_file_action(const char *fname, XLogSegNo last_common_segno, size_t source_size, size_t target_size)
Definition: filemap.c:719
static bool check_file_excluded(const char *path, bool is_source)
Definition: filemap.c:410
@ FILE_CONTENT_TYPE_RELATION
Definition: filemap.h:43
@ FILE_CONTENT_TYPE_WAL
Definition: filemap.h:44
@ FILE_TYPE_UNDEFINED
Definition: filemap.h:33
@ FILE_TYPE_SYMLINK
Definition: filemap.h:37
@ FILE_TYPE_DIRECTORY
Definition: filemap.h:36
Assert(PointerIsAligned(start, uint64))
#define pg_fatal(...)
bool pg_str_endswith(const char *str, const char *end)
Definition: string.c:31
const char * path
Definition: filemap.h:61
bool source_exists
Definition: filemap.h:81
bool target_exists
Definition: filemap.h:67
file_content_type_t content_type
Definition: filemap.h:62
file_type_t target_type
Definition: filemap.h:68
#define XLOG_CONTROL_FILE

References Assert(), check_file_excluded(), file_entry_t::content_type, decide_wal_file_action(), FILE_ACTION_COPY, FILE_ACTION_COPY_TAIL, FILE_ACTION_CREATE, FILE_ACTION_NONE, FILE_ACTION_REMOVE, FILE_ACTION_TRUNCATE, FILE_CONTENT_TYPE_RELATION, FILE_CONTENT_TYPE_WAL, FILE_TYPE_DIRECTORY, FILE_TYPE_REGULAR, FILE_TYPE_SYMLINK, FILE_TYPE_UNDEFINED, filename, keepwal_entry_exists(), last_dir_separator(), file_entry_t::path, pg_fatal, pg_log_debug, pg_str_endswith(), file_entry_t::source_exists, file_entry_t::source_size, file_entry_t::source_type, file_entry_t::target_exists, file_entry_t::target_size, file_entry_t::target_type, and XLOG_CONTROL_FILE.

Referenced by decide_file_actions().

◆ decide_file_actions()

filemap_t * decide_file_actions ( XLogSegNo  last_common_segno)

Definition at line 924 of file filemap.c.

925{
926 int i;
927 filehash_iterator it;
928 file_entry_t *entry;
929 filemap_t *filemap;
930
931 filehash_start_iterate(filehash, &it);
932 while ((entry = filehash_iterate(filehash, &it)) != NULL)
933 {
934 entry->action = decide_file_action(entry, last_common_segno);
935 }
936
937 /*
938 * Turn the hash table into an array, and sort in the order that the
939 * actions should be performed.
940 */
941 filemap = pg_malloc(offsetof(filemap_t, entries) +
942 filehash->members * sizeof(file_entry_t *));
943 filemap->nentries = filehash->members;
944 filehash_start_iterate(filehash, &it);
945 i = 0;
946 while ((entry = filehash_iterate(filehash, &it)) != NULL)
947 {
948 filemap->entries[i++] = entry;
949 }
950
951 qsort(&filemap->entries, filemap->nentries, sizeof(file_entry_t *),
953
954 return filemap;
955}
void * pg_malloc(size_t size)
Definition: fe_memutils.c:47
static file_action_t decide_file_action(file_entry_t *entry, XLogSegNo last_common_segno)
Definition: filemap.c:749
static filehash_hash * filehash
Definition: filemap.c:56
static int final_filemap_cmp(const void *a, const void *b)
Definition: filemap.c:695
#define qsort(a, b, c, d)
Definition: port.h:500

References file_entry_t::action, decide_file_action(), filemap_t::entries, filehash, final_filemap_cmp(), i, filemap_t::nentries, pg_malloc(), and qsort.

Referenced by main().

◆ decide_wal_file_action()

static file_action_t decide_wal_file_action ( const char *  fname,
XLogSegNo  last_common_segno,
size_t  source_size,
size_t  target_size 
)
static

Definition at line 719 of file filemap.c.

721{
722 TimeLineID file_tli;
723 XLogSegNo file_segno;
724
725 /* Get current WAL segment number given current segment file name */
726 XLogFromFileName(fname, &file_tli, &file_segno, WalSegSz);
727
728 /*
729 * Avoid copying files before the last common segment.
730 *
731 * These files exist on the source and the target servers, so they should
732 * be identical and located strictly before the segment that contains the
733 * LSN where target and source servers have diverged.
734 *
735 * While we are on it, double-check the size of each file and copy the
736 * file if they do not match, in case.
737 */
738 if (file_segno < last_common_segno &&
739 source_size == target_size)
740 return FILE_ACTION_NONE;
741
742 return FILE_ACTION_COPY;
743}
int WalSegSz
Definition: streamutil.c:32
static void XLogFromFileName(const char *fname, TimeLineID *tli, XLogSegNo *logSegNo, int wal_segsz_bytes)
uint32 TimeLineID
Definition: xlogdefs.h:63
uint64 XLogSegNo
Definition: xlogdefs.h:52

References FILE_ACTION_COPY, FILE_ACTION_NONE, WalSegSz, and XLogFromFileName().

Referenced by decide_file_action().

◆ filehash_init()

void filehash_init ( void  )

Definition at line 197 of file filemap.c.

198{
199 filehash = filehash_create(FILEHASH_INITIAL_SIZE, NULL);
200}
#define FILEHASH_INITIAL_SIZE
Definition: filemap.c:54

References filehash, and FILEHASH_INITIAL_SIZE.

Referenced by main().

◆ final_filemap_cmp()

static int final_filemap_cmp ( const void *  a,
const void *  b 
)
static

Definition at line 695 of file filemap.c.

696{
697 file_entry_t *fa = *((file_entry_t **) a);
698 file_entry_t *fb = *((file_entry_t **) b);
699
700 if (fa->action > fb->action)
701 return 1;
702 if (fa->action < fb->action)
703 return -1;
704
705 if (fa->action == FILE_ACTION_REMOVE)
706 return strcmp(fb->path, fa->path);
707 else
708 return strcmp(fa->path, fb->path);
709}
int b
Definition: isn.c:74
int a
Definition: isn.c:73
static int fa(void)
Definition: preproc-init.c:85
static int fb(int x)
Definition: preproc-init.c:92

References a, b, fa(), fb(), and FILE_ACTION_REMOVE.

Referenced by decide_file_actions().

◆ getFileContentType()

static file_content_type_t getFileContentType ( const char *  path)
static

Definition at line 568 of file filemap.c.

569{
570 RelFileLocator rlocator;
571 unsigned int segNo;
572 int nmatch;
574
575 /* Check if it is a WAL file. */
576 if (strncmp("pg_wal/", path, 7) == 0)
577 {
578 const char *filename = path + 7; /* Skip "pg_wal/" */
579
582 else
584 }
585
586 /*----
587 * Does it look like a relation data file?
588 *
589 * For our purposes, only files belonging to the main fork are considered
590 * relation files. Other forks are always copied in toto, because we
591 * cannot reliably track changes to them, because WAL only contains block
592 * references for the main fork.
593 *
594 * Relation data files can be in one of the following directories:
595 *
596 * global/
597 * shared relations
598 *
599 * base/<db oid>/
600 * regular relations, default tablespace
601 *
602 * pg_tblspc/<tblspc oid>/<tblspc version>/
603 * within a non-default tablespace (the name of the directory
604 * depends on version)
605 *
606 * And the relation data files themselves have a filename like:
607 *
608 * <oid>.<segment number>
609 *
610 *----
611 */
612 rlocator.spcOid = InvalidOid;
613 rlocator.dbOid = InvalidOid;
615 segNo = 0;
617
618 nmatch = sscanf(path, "global/%u.%u", &rlocator.relNumber, &segNo);
619 if (nmatch == 1 || nmatch == 2)
620 {
621 rlocator.spcOid = GLOBALTABLESPACE_OID;
622 rlocator.dbOid = 0;
624 }
625 else
626 {
627 nmatch = sscanf(path, "base/%u/%u.%u",
628 &rlocator.dbOid, &rlocator.relNumber, &segNo);
629 if (nmatch == 2 || nmatch == 3)
630 {
631 rlocator.spcOid = DEFAULTTABLESPACE_OID;
633 }
634 else
635 {
636 nmatch = sscanf(path, "pg_tblspc/%u/" TABLESPACE_VERSION_DIRECTORY "/%u/%u.%u",
637 &rlocator.spcOid, &rlocator.dbOid, &rlocator.relNumber,
638 &segNo);
639 if (nmatch == 3 || nmatch == 4)
641 }
642 }
643
644 /*
645 * The sscanf tests above can match files that have extra characters at
646 * the end. To eliminate such cases, cross-check that GetRelationPath
647 * creates the exact same filename, when passed the RelFileLocator
648 * information we extracted from the filename.
649 */
650 if (result == FILE_CONTENT_TYPE_RELATION)
651 {
652 char *check_path = datasegpath(rlocator, MAIN_FORKNUM, segNo);
653
654 if (strcmp(check_path, path) != 0)
656
657 pfree(check_path);
658 }
659
660 return result;
661}
static char * datasegpath(RelFileLocator rlocator, ForkNumber forknum, BlockNumber segno)
Definition: filemap.c:669
file_content_type_t
Definition: filemap.h:41
@ FILE_CONTENT_TYPE_OTHER
Definition: filemap.h:42
void pfree(void *pointer)
Definition: mcxt.c:1594
#define InvalidOid
Definition: postgres_ext.h:37
@ MAIN_FORKNUM
Definition: relpath.h:58
#define InvalidRelFileNumber
Definition: relpath.h:26
#define TABLESPACE_VERSION_DIRECTORY
Definition: relpath.h:33
RelFileNumber relNumber
static bool IsXLogFileName(const char *fname)

References datasegpath(), RelFileLocator::dbOid, FILE_CONTENT_TYPE_OTHER, FILE_CONTENT_TYPE_RELATION, FILE_CONTENT_TYPE_WAL, filename, InvalidOid, InvalidRelFileNumber, IsXLogFileName(), MAIN_FORKNUM, pfree(), RelFileLocator::relNumber, RelFileLocator::spcOid, and TABLESPACE_VERSION_DIRECTORY.

Referenced by insert_filehash_entry(), and process_source_file().

◆ insert_filehash_entry()

static file_entry_t * insert_filehash_entry ( const char *  path)
static

Definition at line 204 of file filemap.c.

205{
206 file_entry_t *entry;
207 bool found;
208
209 entry = filehash_insert(filehash, path, &found);
210 if (!found)
211 {
212 entry->path = pg_strdup(path);
213 entry->content_type = getFileContentType(path);
214
215 entry->target_exists = false;
217 entry->target_size = 0;
218 entry->target_link_target = NULL;
219 entry->target_pages_to_overwrite.bitmap = NULL;
221
222 entry->source_exists = false;
224 entry->source_size = 0;
225 entry->source_link_target = NULL;
226
228 }
229
230 return entry;
231}
char * pg_strdup(const char *in)
Definition: fe_memutils.c:85
static file_content_type_t getFileContentType(const char *path)
Definition: filemap.c:568
@ FILE_ACTION_UNDECIDED
Definition: filemap.h:19
char * bitmap
Definition: datapagemap.h:16
char * source_link_target
Definition: filemap.h:84
char * target_link_target
Definition: filemap.h:70

References file_entry_t::action, datapagemap::bitmap, datapagemap::bitmapsize, file_entry_t::content_type, FILE_ACTION_UNDECIDED, FILE_TYPE_UNDEFINED, filehash, getFileContentType(), file_entry_t::path, pg_strdup(), file_entry_t::source_exists, file_entry_t::source_link_target, file_entry_t::source_size, file_entry_t::source_type, file_entry_t::target_exists, file_entry_t::target_link_target, file_entry_t::target_pages_to_overwrite, file_entry_t::target_size, and file_entry_t::target_type.

Referenced by process_source_file(), and process_target_file().

◆ keepwal_add_entry()

void keepwal_add_entry ( const char *  path)

Definition at line 251 of file filemap.c.

252{
253 keepwal_entry *entry;
254 bool found;
255
256 /* Should only be called with keepwal initialized */
257 Assert(keepwal != NULL);
258
259 entry = keepwal_insert(keepwal, path, &found);
260
261 if (!found)
262 entry->path = pg_strdup(path);
263}
static keepwal_hash * keepwal
Definition: filemap.c:89
Definition: filemap.c:69
const char * path
Definition: filemap.c:70

References Assert(), keepwal, keepwal_entry::path, and pg_strdup().

Referenced by findLastCheckpoint().

◆ keepwal_entry_exists()

static bool keepwal_entry_exists ( const char *  path)
static

Definition at line 267 of file filemap.c.

268{
269 return keepwal_lookup(keepwal, path) != NULL;
270}

References keepwal.

Referenced by decide_file_action().

◆ keepwal_init()

void keepwal_init ( void  )

Definition at line 243 of file filemap.c.

244{
245 /* An initial hash size out of thin air */
246 keepwal = keepwal_create(KEEPWAL_INITIAL_SIZE, NULL);
247}
#define KEEPWAL_INITIAL_SIZE
Definition: filemap.c:86

References keepwal, and KEEPWAL_INITIAL_SIZE.

Referenced by main().

◆ lookup_filehash_entry()

static file_entry_t * lookup_filehash_entry ( const char *  path)
static

Definition at line 234 of file filemap.c.

235{
236 return filehash_lookup(filehash, path);
237}

References filehash.

Referenced by process_target_wal_block_change().

◆ print_filemap()

void print_filemap ( filemap_t filemap)

Definition at line 541 of file filemap.c.

542{
543 file_entry_t *entry;
544 int i;
545
546 for (i = 0; i < filemap->nentries; i++)
547 {
548 entry = filemap->entries[i];
549
550 if (entry->action != FILE_ACTION_NONE ||
553 {
554 pg_log_debug("%s (%s)", entry->path,
555 action_to_str(entry->action));
556
559 }
560 }
561 fflush(stdout);
562}
void datapagemap_print(datapagemap_t *map)
Definition: datapagemap.c:117
static const char * action_to_str(file_action_t action)
Definition: filemap.c:474

References file_entry_t::action, action_to_str(), datapagemap::bitmapsize, file_entry_t::content_type, datapagemap_print(), filemap_t::entries, FILE_ACTION_NONE, FILE_CONTENT_TYPE_WAL, i, filemap_t::nentries, file_entry_t::path, pg_log_debug, generate_unaccent_rules::stdout, and file_entry_t::target_pages_to_overwrite.

Referenced by main().

◆ process_source_file()

void process_source_file ( const char *  path,
file_type_t  type,
size_t  size,
const char *  link_target 
)

Definition at line 280 of file filemap.c.

282{
283 file_entry_t *entry;
284
285 /*
286 * Pretend that pg_wal is a directory, even if it's really a symlink. We
287 * don't want to mess with the symlink itself, nor complain if it's a
288 * symlink in source but not in target or vice versa.
289 */
290 if (strcmp(path, "pg_wal") == 0 && type == FILE_TYPE_SYMLINK)
292
293 /*
294 * sanity check: a filename that looks like a data file better be a
295 * regular file
296 */
298 pg_fatal("data file \"%s\" in source is not a regular file", path);
299
300 /* Remember this source file */
301 entry = insert_filehash_entry(path);
302 if (entry->source_exists)
303 pg_fatal("duplicate source file \"%s\"", path);
304 entry->source_exists = true;
305 entry->source_type = type;
306 entry->source_size = size;
307 entry->source_link_target = link_target ? pg_strdup(link_target) : NULL;
308}
static file_entry_t * insert_filehash_entry(const char *path)
Definition: filemap.c:204
const char * type

References FILE_CONTENT_TYPE_RELATION, FILE_TYPE_DIRECTORY, FILE_TYPE_REGULAR, FILE_TYPE_SYMLINK, getFileContentType(), insert_filehash_entry(), pg_fatal, pg_strdup(), file_entry_t::source_exists, file_entry_t::source_link_target, file_entry_t::source_size, file_entry_t::source_type, and type.

Referenced by main().

◆ process_target_file()

void process_target_file ( const char *  path,
file_type_t  type,
size_t  size,
const char *  link_target 
)

Definition at line 316 of file filemap.c.

318{
319 file_entry_t *entry;
320
321 /*
322 * Do not apply any exclusion filters here. This has advantage to remove
323 * from the target data folder all paths which have been filtered out from
324 * the source data folder when processing the source files.
325 */
326
327 /*
328 * Like in process_source_file, pretend that pg_wal is always a directory.
329 */
330 if (strcmp(path, "pg_wal") == 0 && type == FILE_TYPE_SYMLINK)
332
333 /* Remember this target file */
334 entry = insert_filehash_entry(path);
335 if (entry->target_exists)
336 pg_fatal("duplicate source file \"%s\"", path);
337 entry->target_exists = true;
338 entry->target_type = type;
339 entry->target_size = size;
340 entry->target_link_target = link_target ? pg_strdup(link_target) : NULL;
341}

References FILE_TYPE_DIRECTORY, FILE_TYPE_SYMLINK, insert_filehash_entry(), pg_fatal, pg_strdup(), file_entry_t::target_exists, file_entry_t::target_link_target, file_entry_t::target_size, file_entry_t::target_type, and type.

Referenced by main().

◆ process_target_wal_block_change()

void process_target_wal_block_change ( ForkNumber  forknum,
RelFileLocator  rlocator,
BlockNumber  blkno 
)

Definition at line 353 of file filemap.c.

355{
356 char *path;
357 file_entry_t *entry;
358 BlockNumber blkno_inseg;
359 int segno;
360
361 segno = blkno / RELSEG_SIZE;
362 blkno_inseg = blkno % RELSEG_SIZE;
363
364 path = datasegpath(rlocator, forknum, segno);
365 entry = lookup_filehash_entry(path);
366 pfree(path);
367
368 /*
369 * If the block still exists in both systems, remember it. Otherwise we
370 * can safely ignore it.
371 *
372 * If the block is beyond the EOF in the source system, or the file
373 * doesn't exist in the source at all, we're going to truncate/remove it
374 * away from the target anyway. Likewise, if it doesn't exist in the
375 * target anymore, we will copy it over with the "tail" from the source
376 * system, anyway.
377 *
378 * It is possible to find WAL for a file that doesn't exist on either
379 * system anymore. It means that the relation was dropped later in the
380 * target system, and independently on the source system too, or that it
381 * was created and dropped in the target system and it never existed in
382 * the source. Either way, we can safely ignore it.
383 */
384 if (entry)
385 {
387
388 if (entry->target_exists)
389 {
390 if (entry->target_type != FILE_TYPE_REGULAR)
391 pg_fatal("unexpected page modification for non-regular file \"%s\"",
392 entry->path);
393
394 if (entry->source_exists)
395 {
396 off_t end_offset;
397
398 end_offset = (blkno_inseg + 1) * BLCKSZ;
399 if (end_offset <= entry->source_size && end_offset <= entry->target_size)
400 datapagemap_add(&entry->target_pages_to_overwrite, blkno_inseg);
401 }
402 }
403 }
404}
void datapagemap_add(datapagemap_t *map, BlockNumber blkno)
Definition: datapagemap.c:32
static file_entry_t * lookup_filehash_entry(const char *path)
Definition: filemap.c:234

References Assert(), file_entry_t::content_type, datapagemap_add(), datasegpath(), FILE_CONTENT_TYPE_RELATION, FILE_TYPE_REGULAR, lookup_filehash_entry(), file_entry_t::path, pfree(), pg_fatal, file_entry_t::source_exists, file_entry_t::target_exists, file_entry_t::target_pages_to_overwrite, and file_entry_t::target_type.

Referenced by extractPageInfo().

Variable Documentation

◆ excludeDirContents

const char* const excludeDirContents[]
static
Initial value:
=
{
"pg_stat_tmp",
"pg_replslot",
"pg_dynshmem",
"pg_notify",
"pg_serial",
"pg_snapshots",
"pg_subtrans",
NULL
}

Definition at line 117 of file filemap.c.

Referenced by check_file_excluded().

◆ excludeFiles

const struct exclude_list_item excludeFiles[]
static
Initial value:
=
{
{"postgresql.auto.conf.tmp", false},
{"current_logfiles.tmp", false},
{"pg_internal.init", true},
{"backup_label", false},
{"tablespace_map", false},
{"backup_manifest", false},
{"postmaster.pid", false},
{"postmaster.opts", false},
{NULL, false}
}

Definition at line 158 of file filemap.c.

Referenced by check_file_excluded().

◆ filehash

filehash_hash* filehash
static

◆ keepwal

keepwal_hash* keepwal = NULL
static

Definition at line 89 of file filemap.c.

Referenced by keepwal_add_entry(), keepwal_entry_exists(), and keepwal_init().