PostgreSQL Source Code git master
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
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 bool isRelDataFile (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_file_action (file_entry_t *entry)
 
filemap_tdecide_file_actions (void)
 

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:27
@ FILE_ACTION_COPY
Definition: filemap.h:21
@ FILE_ACTION_NONE
Definition: filemap.h:24
@ FILE_ACTION_COPY_TAIL
Definition: filemap.h:22
@ FILE_ACTION_TRUNCATE
Definition: filemap.h:26
@ FILE_ACTION_CREATE
Definition: filemap.h:20

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:34
int i
Definition: isn.c:77
int bitmapsize
Definition: datapagemap.h:17
Definition: filemap.h:50
datapagemap_t target_pages_to_overwrite
Definition: filemap.h:68
size_t source_size
Definition: filemap.h:75
file_type_t source_type
Definition: filemap.h:74
size_t target_size
Definition: filemap.h:61
file_action_t action
Definition: filemap.h:81
file_entry_t * entries[FLEXIBLE_ARRAY_MEMBER]
Definition: filemap.h:96
int nentries
Definition: filemap.h:95
uint64 total_size
Definition: filemap.h:92
uint64 fetch_size
Definition: filemap.h:93

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:123
char * last_dir_separator(const char *filename)
Definition: path.c:145
#define snprintf
Definition: port.h:239
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 654 of file filemap.c.

655{
656 RelPathStr path;
657 char *segpath;
658
659 path = relpathperm(rlocator, forknum);
660 if (segno > 0)
661 {
662 segpath = psprintf("%s.%u", path.str, segno);
663 return segpath;
664 }
665 else
666 return pstrdup(path.str);
667}
char * pstrdup(const char *in)
Definition: mcxt.c:2325
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 isRelDataFile(), and process_target_wal_block_change().

◆ decide_file_action()

static file_action_t decide_file_action ( file_entry_t entry)
static

Definition at line 700 of file filemap.c.

701{
702 const char *path = entry->path;
703
704 /*
705 * Don't touch the control file. It is handled specially, after copying
706 * all the other files.
707 */
708 if (strcmp(path, XLOG_CONTROL_FILE) == 0)
709 return FILE_ACTION_NONE;
710
711 /* Skip macOS system files */
712 if (strstr(path, ".DS_Store") != NULL)
713 return FILE_ACTION_NONE;
714
715 /*
716 * Remove all files matching the exclusion filters in the target.
717 */
718 if (check_file_excluded(path, true))
719 {
720 if (entry->target_exists)
721 return FILE_ACTION_REMOVE;
722 else
723 return FILE_ACTION_NONE;
724 }
725
726 /*
727 * Handle cases where the file is missing from one of the systems.
728 */
729 if (!entry->target_exists && entry->source_exists)
730 {
731 /*
732 * File exists in source, but not in target. Copy it in toto. (If it's
733 * a relation data file, WAL replay after rewinding should re-create
734 * it anyway. But there's no harm in copying it now.)
735 */
736 switch (entry->source_type)
737 {
740 return FILE_ACTION_CREATE;
742 return FILE_ACTION_COPY;
744 pg_fatal("unknown file type for \"%s\"", entry->path);
745 break;
746 }
747 }
748 else if (entry->target_exists && !entry->source_exists)
749 {
750 /*
751 * For files that exist in target but not in source, we check the
752 * keepwal hash table; any files listed therein must not be removed.
753 */
754 if (keepwal_entry_exists(path))
755 {
756 pg_log_debug("Not removing file \"%s\" because it is required for recovery", path);
757 return FILE_ACTION_NONE;
758 }
759 return FILE_ACTION_REMOVE;
760 }
761 else if (!entry->target_exists && !entry->source_exists)
762 {
763 /*
764 * Doesn't exist in either server. Why does it have an entry in the
765 * first place??
766 */
767 Assert(false);
768 return FILE_ACTION_NONE;
769 }
770
771 /*
772 * Otherwise, the file exists on both systems
773 */
774 Assert(entry->target_exists && entry->source_exists);
775
776 if (entry->source_type != entry->target_type)
777 {
778 /* But it's a different kind of object. Strange.. */
779 pg_fatal("file \"%s\" is of different type in source and target", entry->path);
780 }
781
782 /*
783 * PG_VERSION files should be identical on both systems, but avoid
784 * overwriting them for paranoia.
785 */
786 if (pg_str_endswith(entry->path, "PG_VERSION"))
787 return FILE_ACTION_NONE;
788
789 switch (entry->source_type)
790 {
792 return FILE_ACTION_NONE;
793
795
796 /*
797 * XXX: Should we check if it points to the same target?
798 */
799 return FILE_ACTION_NONE;
800
802 if (!entry->isrelfile)
803 {
804 /*
805 * It's a non-data file that we have no special processing
806 * for. Copy it in toto.
807 */
808 return FILE_ACTION_COPY;
809 }
810 else
811 {
812 /*
813 * It's a data file that exists in both systems.
814 *
815 * If it's larger in target, we can truncate it. There will
816 * also be a WAL record of the truncation in the source
817 * system, so WAL replay would eventually truncate the target
818 * too, but we might as well do it now.
819 *
820 * If it's smaller in the target, it means that it has been
821 * truncated in the target, or enlarged in the source, or
822 * both. If it was truncated in the target, we need to copy
823 * the missing tail from the source system. If it was enlarged
824 * in the source system, there will be WAL records in the
825 * source system for the new blocks, so we wouldn't need to
826 * copy them here. But we don't know which scenario we're
827 * dealing with, and there's no harm in copying the missing
828 * blocks now, so do it now.
829 *
830 * If it's the same size, do nothing here. Any blocks modified
831 * in the target will be copied based on parsing the target
832 * system's WAL, and any blocks modified in the source will be
833 * updated after rewinding, when the source system's WAL is
834 * replayed.
835 */
836 if (entry->target_size < entry->source_size)
838 else if (entry->target_size > entry->source_size)
840 else
841 return FILE_ACTION_NONE;
842 }
843 break;
844
846 pg_fatal("unknown file type for \"%s\"", path);
847 break;
848 }
849
850 /* unreachable */
851 pg_fatal("could not decide what to do with file \"%s\"", path);
852}
static bool keepwal_entry_exists(const char *path)
Definition: filemap.c:267
static bool check_file_excluded(const char *path, bool is_source)
Definition: filemap.c:410
@ FILE_TYPE_UNDEFINED
Definition: filemap.h:32
@ FILE_TYPE_SYMLINK
Definition: filemap.h:36
@ FILE_TYPE_DIRECTORY
Definition: filemap.h:35
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:53
bool source_exists
Definition: filemap.h:73
bool target_exists
Definition: filemap.h:59
file_type_t target_type
Definition: filemap.h:60
bool isrelfile
Definition: filemap.h:54
#define XLOG_CONTROL_FILE

References Assert(), check_file_excluded(), FILE_ACTION_COPY, FILE_ACTION_COPY_TAIL, FILE_ACTION_CREATE, FILE_ACTION_NONE, FILE_ACTION_REMOVE, FILE_ACTION_TRUNCATE, FILE_TYPE_DIRECTORY, FILE_TYPE_REGULAR, FILE_TYPE_SYMLINK, FILE_TYPE_UNDEFINED, file_entry_t::isrelfile, keepwal_entry_exists(), 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 ( void  )

Definition at line 861 of file filemap.c.

862{
863 int i;
864 filehash_iterator it;
865 file_entry_t *entry;
866 filemap_t *filemap;
867
868 filehash_start_iterate(filehash, &it);
869 while ((entry = filehash_iterate(filehash, &it)) != NULL)
870 {
871 entry->action = decide_file_action(entry);
872 }
873
874 /*
875 * Turn the hash table into an array, and sort in the order that the
876 * actions should be performed.
877 */
878 filemap = pg_malloc(offsetof(filemap_t, entries) +
879 filehash->members * sizeof(file_entry_t *));
880 filemap->nentries = filehash->members;
881 filehash_start_iterate(filehash, &it);
882 i = 0;
883 while ((entry = filehash_iterate(filehash, &it)) != NULL)
884 {
885 filemap->entries[i++] = entry;
886 }
887
888 qsort(&filemap->entries, filemap->nentries, sizeof(file_entry_t *),
890
891 return filemap;
892}
void * pg_malloc(size_t size)
Definition: fe_memutils.c:47
static filehash_hash * filehash
Definition: filemap.c:56
static file_action_t decide_file_action(file_entry_t *entry)
Definition: filemap.c:700
static int final_filemap_cmp(const void *a, const void *b)
Definition: filemap.c:680
#define qsort(a, b, c, d)
Definition: port.h:479

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().

◆ 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 680 of file filemap.c.

681{
682 file_entry_t *fa = *((file_entry_t **) a);
683 file_entry_t *fb = *((file_entry_t **) b);
684
685 if (fa->action > fb->action)
686 return 1;
687 if (fa->action < fb->action)
688 return -1;
689
690 if (fa->action == FILE_ACTION_REMOVE)
691 return strcmp(fb->path, fa->path);
692 else
693 return strcmp(fa->path, fb->path);
694}
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().

◆ 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->isrelfile = isRelDataFile(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 bool isRelDataFile(const char *path)
Definition: filemap.c:571
@ FILE_ACTION_UNDECIDED
Definition: filemap.h:18
char * bitmap
Definition: datapagemap.h:16
char * source_link_target
Definition: filemap.h:76
char * target_link_target
Definition: filemap.h:62

References file_entry_t::action, datapagemap::bitmap, datapagemap::bitmapsize, FILE_ACTION_UNDECIDED, FILE_TYPE_UNDEFINED, filehash, isRelDataFile(), file_entry_t::isrelfile, 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().

◆ isRelDataFile()

static bool isRelDataFile ( const char *  path)
static

Definition at line 571 of file filemap.c.

572{
573 RelFileLocator rlocator;
574 unsigned int segNo;
575 int nmatch;
576 bool matched;
577
578 /*----
579 * Relation data files can be in one of the following directories:
580 *
581 * global/
582 * shared relations
583 *
584 * base/<db oid>/
585 * regular relations, default tablespace
586 *
587 * pg_tblspc/<tblspc oid>/<tblspc version>/
588 * within a non-default tablespace (the name of the directory
589 * depends on version)
590 *
591 * And the relation data files themselves have a filename like:
592 *
593 * <oid>.<segment number>
594 *
595 *----
596 */
597 rlocator.spcOid = InvalidOid;
598 rlocator.dbOid = InvalidOid;
600 segNo = 0;
601 matched = false;
602
603 nmatch = sscanf(path, "global/%u.%u", &rlocator.relNumber, &segNo);
604 if (nmatch == 1 || nmatch == 2)
605 {
606 rlocator.spcOid = GLOBALTABLESPACE_OID;
607 rlocator.dbOid = 0;
608 matched = true;
609 }
610 else
611 {
612 nmatch = sscanf(path, "base/%u/%u.%u",
613 &rlocator.dbOid, &rlocator.relNumber, &segNo);
614 if (nmatch == 2 || nmatch == 3)
615 {
616 rlocator.spcOid = DEFAULTTABLESPACE_OID;
617 matched = true;
618 }
619 else
620 {
621 nmatch = sscanf(path, "pg_tblspc/%u/" TABLESPACE_VERSION_DIRECTORY "/%u/%u.%u",
622 &rlocator.spcOid, &rlocator.dbOid, &rlocator.relNumber,
623 &segNo);
624 if (nmatch == 3 || nmatch == 4)
625 matched = true;
626 }
627 }
628
629 /*
630 * The sscanf tests above can match files that have extra characters at
631 * the end. To eliminate such cases, cross-check that GetRelationPath
632 * creates the exact same filename, when passed the RelFileLocator
633 * information we extracted from the filename.
634 */
635 if (matched)
636 {
637 char *check_path = datasegpath(rlocator, MAIN_FORKNUM, segNo);
638
639 if (strcmp(check_path, path) != 0)
640 matched = false;
641
642 pfree(check_path);
643 }
644
645 return matched;
646}
static char * datasegpath(RelFileLocator rlocator, ForkNumber forknum, BlockNumber segno)
Definition: filemap.c:654
void pfree(void *pointer)
Definition: mcxt.c:2150
#define InvalidOid
Definition: postgres_ext.h:35
@ MAIN_FORKNUM
Definition: relpath.h:58
#define InvalidRelFileNumber
Definition: relpath.h:26
#define TABLESPACE_VERSION_DIRECTORY
Definition: relpath.h:33
RelFileNumber relNumber

References datasegpath(), RelFileLocator::dbOid, InvalidOid, InvalidRelFileNumber, MAIN_FORKNUM, pfree(), RelFileLocator::relNumber, RelFileLocator::spcOid, and TABLESPACE_VERSION_DIRECTORY.

Referenced by insert_filehash_entry(), and process_source_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 if (entry->action != FILE_ACTION_NONE ||
551 {
552 pg_log_debug("%s (%s)", entry->path,
553 action_to_str(entry->action));
554
557 }
558 }
559 fflush(stdout);
560}
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, datapagemap_print(), filemap_t::entries, FILE_ACTION_NONE, 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 */
297 if (type != FILE_TYPE_REGULAR && isRelDataFile(path))
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_TYPE_DIRECTORY, FILE_TYPE_REGULAR, FILE_TYPE_SYMLINK, insert_filehash_entry(), isRelDataFile(), 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 {
386 Assert(entry->isrelfile);
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(), datapagemap_add(), datasegpath(), FILE_TYPE_REGULAR, file_entry_t::isrelfile, 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().