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

Go to the source code of this file.

Data Structures

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_pointer(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
 

Functions

static uint32 hash_string_pointer (const char *s)
 
static bool isRelDataFile (const char *path)
 
static char * datasegpath (RelFileNode rnode, ForkNumber forknum, BlockNumber segno)
 
static file_entry_tinsert_filehash_entry (const char *path)
 
static file_entry_tlookup_filehash_entry (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 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, RelFileNode rnode, 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 const char * 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.

Referenced by filehash_init().

◆ SH_DECLARE

#define SH_DECLARE

Definition at line 50 of file filemap.c.

◆ SH_DEFINE

#define SH_DEFINE

Definition at line 51 of file filemap.c.

◆ SH_ELEMENT_TYPE

#define SH_ELEMENT_TYPE   file_entry_t

Definition at line 43 of file filemap.c.

◆ SH_EQUAL

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

Definition at line 47 of file filemap.c.

◆ SH_HASH_KEY

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

Definition at line 46 of file filemap.c.

◆ SH_KEY

#define SH_KEY   path

Definition at line 45 of file filemap.c.

◆ SH_KEY_TYPE

#define SH_KEY_TYPE   const char *

Definition at line 44 of file filemap.c.

◆ SH_PREFIX

#define SH_PREFIX   filehash

Definition at line 42 of file filemap.c.

◆ SH_RAW_ALLOCATOR

#define SH_RAW_ALLOCATOR   pg_malloc0

Definition at line 49 of file filemap.c.

◆ SH_SCOPE

#define SH_SCOPE   static inline

Definition at line 48 of file filemap.c.

Function Documentation

◆ action_to_str()

static const char* action_to_str ( file_action_t  action)
static

Definition at line 413 of file filemap.c.

References FILE_ACTION_COPY, FILE_ACTION_COPY_TAIL, FILE_ACTION_CREATE, FILE_ACTION_NONE, FILE_ACTION_REMOVE, and FILE_ACTION_TRUNCATE.

Referenced by print_filemap().

414 {
415  switch (action)
416  {
417  case FILE_ACTION_NONE:
418  return "NONE";
419  case FILE_ACTION_COPY:
420  return "COPY";
422  return "TRUNCATE";
424  return "COPY_TAIL";
425  case FILE_ACTION_CREATE:
426  return "CREATE";
427  case FILE_ACTION_REMOVE:
428  return "REMOVE";
429 
430  default:
431  return "unknown";
432  }
433 }

◆ calculate_totals()

void calculate_totals ( filemap_t filemap)

Definition at line 439 of file filemap.c.

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

440 {
441  file_entry_t *entry;
442  int i;
443 
444  filemap->total_size = 0;
445  filemap->fetch_size = 0;
446 
447  for (i = 0; i < filemap->nentries; i++)
448  {
449  entry = filemap->entries[i];
450 
451  if (entry->source_type != FILE_TYPE_REGULAR)
452  continue;
453 
454  filemap->total_size += entry->source_size;
455 
456  if (entry->action == FILE_ACTION_COPY)
457  {
458  filemap->fetch_size += entry->source_size;
459  continue;
460  }
461 
462  if (entry->action == FILE_ACTION_COPY_TAIL)
463  filemap->fetch_size += (entry->source_size - entry->target_size);
464 
465  if (entry->target_pages_to_overwrite.bitmapsize > 0)
466  {
468  BlockNumber blk;
469 
471  while (datapagemap_next(iter, &blk))
472  filemap->fetch_size += BLCKSZ;
473 
474  pg_free(iter);
475  }
476  }
477 }
uint32 BlockNumber
Definition: block.h:31
uint64 fetch_size
Definition: filemap.h:93
size_t target_size
Definition: filemap.h:61
bool datapagemap_next(datapagemap_iterator_t *iter, BlockNumber *blkno)
Definition: datapagemap.c:87
file_action_t action
Definition: filemap.h:81
file_type_t source_type
Definition: filemap.h:74
size_t source_size
Definition: filemap.h:75
uint64 total_size
Definition: filemap.h:92
datapagemap_t target_pages_to_overwrite
Definition: filemap.h:68
int bitmapsize
Definition: datapagemap.h:18
datapagemap_iterator_t * datapagemap_iterate(datapagemap_t *map)
Definition: datapagemap.c:75
void pg_free(void *ptr)
Definition: fe_memutils.c:105
int nentries
Definition: filemap.h:95
int i
Definition: filemap.h:49
file_entry_t * entries[FLEXIBLE_ARRAY_MEMBER]
Definition: filemap.h:96

◆ check_file_excluded()

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

Definition at line 349 of file filemap.c.

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

Referenced by decide_file_action().

350 {
351  char localpath[MAXPGPATH];
352  int excludeIdx;
353  const char *filename;
354 
355  /*
356  * Skip all temporary files, .../pgsql_tmp/... and .../pgsql_tmp.*
357  */
358  if (strstr(path, "/" PG_TEMP_FILE_PREFIX) != NULL ||
359  strstr(path, "/" PG_TEMP_FILES_DIR "/") != NULL)
360  {
361  return true;
362  }
363 
364  /* check individual files... */
365  for (excludeIdx = 0; excludeFiles[excludeIdx].name != NULL; excludeIdx++)
366  {
367  int cmplen = strlen(excludeFiles[excludeIdx].name);
368 
369  filename = last_dir_separator(path);
370  if (filename == NULL)
371  filename = path;
372  else
373  filename++;
374 
375  if (!excludeFiles[excludeIdx].match_prefix)
376  cmplen++;
377  if (strncmp(filename, excludeFiles[excludeIdx].name, cmplen) == 0)
378  {
379  if (is_source)
380  pg_log_debug("entry \"%s\" excluded from source file list",
381  path);
382  else
383  pg_log_debug("entry \"%s\" excluded from target file list",
384  path);
385  return true;
386  }
387  }
388 
389  /*
390  * ... And check some directories. Note that this includes any contents
391  * within the directories themselves.
392  */
393  for (excludeIdx = 0; excludeDirContents[excludeIdx] != NULL; excludeIdx++)
394  {
395  snprintf(localpath, sizeof(localpath), "%s/",
396  excludeDirContents[excludeIdx]);
397  if (strstr(path, localpath) == path)
398  {
399  if (is_source)
400  pg_log_debug("entry \"%s\" excluded from source file list",
401  path);
402  else
403  pg_log_debug("entry \"%s\" excluded from target file list",
404  path);
405  return true;
406  }
407  }
408 
409  return false;
410 }
#define PG_TEMP_FILES_DIR
Definition: pg_checksums.c:62
#define PG_TEMP_FILE_PREFIX
Definition: pg_checksums.c:63
#define pg_log_debug(...)
Definition: logging.h:92
#define MAXPGPATH
static const struct exclude_list_item excludeFiles[]
Definition: filemap.c:130
char * last_dir_separator(const char *filename)
Definition: path.c:138
const char * name
Definition: encode.c:561
const char * name
Definition: basebackup.c:141
static char * filename
Definition: pg_dumpall.c:92
static const char * excludeDirContents[]
Definition: filemap.c:88
#define snprintf
Definition: port.h:216

◆ datasegpath()

static char * datasegpath ( RelFileNode  rnode,
ForkNumber  forknum,
BlockNumber  segno 
)
static

Definition at line 593 of file filemap.c.

References pfree(), psprintf(), and relpathperm.

Referenced by isRelDataFile(), and process_target_wal_block_change().

594 {
595  char *path;
596  char *segpath;
597 
598  path = relpathperm(rnode, forknum);
599  if (segno > 0)
600  {
601  segpath = psprintf("%s.%u", path, segno);
602  pfree(path);
603  return segpath;
604  }
605  else
606  return path;
607 }
#define relpathperm(rnode, forknum)
Definition: relpath.h:83
char * psprintf(const char *fmt,...)
Definition: psprintf.c:46
void pfree(void *pointer)
Definition: mcxt.c:1169

◆ decide_file_action()

static file_action_t decide_file_action ( file_entry_t entry)
static

Definition at line 640 of file filemap.c.

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, file_entry_t::path, pg_fatal, 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, and file_entry_t::target_type.

Referenced by decide_file_actions().

641 {
642  const char *path = entry->path;
643 
644  /*
645  * Don't touch the control file. It is handled specially, after copying
646  * all the other files.
647  */
648  if (strcmp(path, "global/pg_control") == 0)
649  return FILE_ACTION_NONE;
650 
651  /*
652  * Remove all files matching the exclusion filters in the target.
653  */
654  if (check_file_excluded(path, true))
655  {
656  if (entry->target_exists)
657  return FILE_ACTION_REMOVE;
658  else
659  return FILE_ACTION_NONE;
660  }
661 
662  /*
663  * Handle cases where the file is missing from one of the systems.
664  */
665  if (!entry->target_exists && entry->source_exists)
666  {
667  /*
668  * File exists in source, but not in target. Copy it in toto. (If it's
669  * a relation data file, WAL replay after rewinding should re-create
670  * it anyway. But there's no harm in copying it now.)
671  */
672  switch (entry->source_type)
673  {
674  case FILE_TYPE_DIRECTORY:
675  case FILE_TYPE_SYMLINK:
676  return FILE_ACTION_CREATE;
677  case FILE_TYPE_REGULAR:
678  return FILE_ACTION_COPY;
679  case FILE_TYPE_UNDEFINED:
680  pg_fatal("unknown file type for \"%s\"", entry->path);
681  break;
682  }
683  }
684  else if (entry->target_exists && !entry->source_exists)
685  {
686  /* File exists in target, but not source. Remove it. */
687  return FILE_ACTION_REMOVE;
688  }
689  else if (!entry->target_exists && !entry->source_exists)
690  {
691  /*
692  * Doesn't exist in either server. Why does it have an entry in the
693  * first place??
694  */
695  Assert(false);
696  return FILE_ACTION_NONE;
697  }
698 
699  /*
700  * Otherwise, the file exists on both systems
701  */
702  Assert(entry->target_exists && entry->source_exists);
703 
704  if (entry->source_type != entry->target_type)
705  {
706  /* But it's a different kind of object. Strange.. */
707  pg_fatal("file \"%s\" is of different type in source and target", entry->path);
708  }
709 
710  /*
711  * PG_VERSION files should be identical on both systems, but avoid
712  * overwriting them for paranoia.
713  */
714  if (pg_str_endswith(entry->path, "PG_VERSION"))
715  return FILE_ACTION_NONE;
716 
717  switch (entry->source_type)
718  {
719  case FILE_TYPE_DIRECTORY:
720  return FILE_ACTION_NONE;
721 
722  case FILE_TYPE_SYMLINK:
723 
724  /*
725  * XXX: Should we check if it points to the same target?
726  */
727  return FILE_ACTION_NONE;
728 
729  case FILE_TYPE_REGULAR:
730  if (!entry->isrelfile)
731  {
732  /*
733  * It's a non-data file that we have no special processing
734  * for. Copy it in toto.
735  */
736  return FILE_ACTION_COPY;
737  }
738  else
739  {
740  /*
741  * It's a data file that exists in both systems.
742  *
743  * If it's larger in target, we can truncate it. There will
744  * also be a WAL record of the truncation in the source
745  * system, so WAL replay would eventually truncate the target
746  * too, but we might as well do it now.
747  *
748  * If it's smaller in the target, it means that it has been
749  * truncated in the target, or enlarged in the source, or
750  * both. If it was truncated in the target, we need to copy
751  * the missing tail from the source system. If it was enlarged
752  * in the source system, there will be WAL records in the
753  * source system for the new blocks, so we wouldn't need to
754  * copy them here. But we don't know which scenario we're
755  * dealing with, and there's no harm in copying the missing
756  * blocks now, so do it now.
757  *
758  * If it's the same size, do nothing here. Any blocks modified
759  * in the target will be copied based on parsing the target
760  * system's WAL, and any blocks modified in the source will be
761  * updated after rewinding, when the source system's WAL is
762  * replayed.
763  */
764  if (entry->target_size < entry->source_size)
765  return FILE_ACTION_COPY_TAIL;
766  else if (entry->target_size > entry->source_size)
767  return FILE_ACTION_TRUNCATE;
768  else
769  return FILE_ACTION_NONE;
770  }
771  break;
772 
773  case FILE_TYPE_UNDEFINED:
774  pg_fatal("unknown file type for \"%s\"", path);
775  break;
776  }
777 
778  /* unreachable */
779  pg_fatal("could not decide what to do with file \"%s\"", path);
780 }
bool pg_str_endswith(const char *str, const char *end)
Definition: string.c:31
#define pg_fatal(...)
Definition: pg_rewind.h:37
static bool check_file_excluded(const char *path, bool is_source)
Definition: filemap.c:349
size_t target_size
Definition: filemap.h:61
bool isrelfile
Definition: filemap.h:54
file_type_t target_type
Definition: filemap.h:60
bool target_exists
Definition: filemap.h:59
file_type_t source_type
Definition: filemap.h:74
size_t source_size
Definition: filemap.h:75
const char * path
Definition: filemap.h:53
#define Assert(condition)
Definition: c.h:804
bool source_exists
Definition: filemap.h:73

◆ decide_file_actions()

filemap_t* decide_file_actions ( void  )

Definition at line 789 of file filemap.c.

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

Referenced by main().

790 {
791  int i;
792  filehash_iterator it;
793  file_entry_t *entry;
794  filemap_t *filemap;
795 
796  filehash_start_iterate(filehash, &it);
797  while ((entry = filehash_iterate(filehash, &it)) != NULL)
798  {
799  entry->action = decide_file_action(entry);
800  }
801 
802  /*
803  * Turn the hash table into an array, and sort in the order that the
804  * actions should be performed.
805  */
806  filemap = pg_malloc(offsetof(filemap_t, entries) +
807  filehash->members * sizeof(file_entry_t *));
808  filemap->nentries = filehash->members;
809  filehash_start_iterate(filehash, &it);
810  i = 0;
811  while ((entry = filehash_iterate(filehash, &it)) != NULL)
812  {
813  filemap->entries[i++] = entry;
814  }
815 
816  qsort(&filemap->entries, filemap->nentries, sizeof(file_entry_t *),
818 
819  return filemap;
820 }
static int final_filemap_cmp(const void *a, const void *b)
Definition: filemap.c:620
void * pg_malloc(size_t size)
Definition: fe_memutils.c:47
static file_action_t decide_file_action(file_entry_t *entry)
Definition: filemap.c:640
file_action_t action
Definition: filemap.h:81
static filehash_hash * filehash
Definition: filemap.c:56
int nentries
Definition: filemap.h:95
int i
Definition: filemap.h:49
file_entry_t * entries[FLEXIBLE_ARRAY_MEMBER]
Definition: filemap.h:96
#define qsort(a, b, c, d)
Definition: port.h:504
#define offsetof(type, field)
Definition: c.h:727

◆ filehash_init()

void filehash_init ( void  )

Definition at line 169 of file filemap.c.

References filehash, and FILEHASH_INITIAL_SIZE.

Referenced by main().

170 {
171  filehash = filehash_create(FILEHASH_INITIAL_SIZE, NULL);
172 }
static filehash_hash * filehash
Definition: filemap.c:56
#define FILEHASH_INITIAL_SIZE
Definition: filemap.c:54

◆ final_filemap_cmp()

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

Definition at line 620 of file filemap.c.

References file_entry_t::action, fa(), fb(), FILE_ACTION_REMOVE, and file_entry_t::path.

Referenced by decide_file_actions().

621 {
622  file_entry_t *fa = *((file_entry_t **) a);
623  file_entry_t *fb = *((file_entry_t **) b);
624 
625  if (fa->action > fb->action)
626  return 1;
627  if (fa->action < fb->action)
628  return -1;
629 
630  if (fa->action == FILE_ACTION_REMOVE)
631  return strcmp(fb->path, fa->path);
632  else
633  return strcmp(fa->path, fb->path);
634 }
static int fa(void)
Definition: preproc-init.c:85
static int fb(int x)
Definition: preproc-init.c:92
file_action_t action
Definition: filemap.h:81
const char * path
Definition: filemap.h:53
Definition: filemap.h:49

◆ hash_string_pointer()

static uint32 hash_string_pointer ( const char *  s)
static

Definition at line 827 of file filemap.c.

References hash_bytes().

828 {
829  unsigned char *ss = (unsigned char *) s;
830 
831  return hash_bytes(ss, strlen(s));
832 }
uint32 hash_bytes(const unsigned char *k, int keylen)
Definition: hashfn.c:146

◆ insert_filehash_entry()

static file_entry_t * insert_filehash_entry ( const char *  path)
static

Definition at line 176 of file filemap.c.

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

177 {
178  file_entry_t *entry;
179  bool found;
180 
181  entry = filehash_insert(filehash, path, &found);
182  if (!found)
183  {
184  entry->path = pg_strdup(path);
185  entry->isrelfile = isRelDataFile(path);
186 
187  entry->target_exists = false;
189  entry->target_size = 0;
190  entry->target_link_target = NULL;
191  entry->target_pages_to_overwrite.bitmap = NULL;
193 
194  entry->source_exists = false;
196  entry->source_size = 0;
197  entry->source_link_target = NULL;
198 
199  entry->action = FILE_ACTION_UNDECIDED;
200  }
201 
202  return entry;
203 }
char * bitmap
Definition: datapagemap.h:17
size_t target_size
Definition: filemap.h:61
bool isrelfile
Definition: filemap.h:54
char * source_link_target
Definition: filemap.h:76
file_type_t target_type
Definition: filemap.h:60
file_action_t action
Definition: filemap.h:81
bool target_exists
Definition: filemap.h:59
file_type_t source_type
Definition: filemap.h:74
size_t source_size
Definition: filemap.h:75
char * pg_strdup(const char *in)
Definition: fe_memutils.c:85
const char * path
Definition: filemap.h:53
static filehash_hash * filehash
Definition: filemap.c:56
datapagemap_t target_pages_to_overwrite
Definition: filemap.h:68
int bitmapsize
Definition: datapagemap.h:18
char * target_link_target
Definition: filemap.h:62
static bool isRelDataFile(const char *path)
Definition: filemap.c:510
Definition: filemap.h:49
bool source_exists
Definition: filemap.h:73

◆ isRelDataFile()

static bool isRelDataFile ( const char *  path)
static

Definition at line 510 of file filemap.c.

References datasegpath(), RelFileNode::dbNode, InvalidOid, MAIN_FORKNUM, pfree(), RelFileNode::relNode, RelFileNode::spcNode, and TABLESPACE_VERSION_DIRECTORY.

Referenced by insert_filehash_entry(), and process_source_file().

511 {
512  RelFileNode rnode;
513  unsigned int segNo;
514  int nmatch;
515  bool matched;
516 
517  /*----
518  * Relation data files can be in one of the following directories:
519  *
520  * global/
521  * shared relations
522  *
523  * base/<db oid>/
524  * regular relations, default tablespace
525  *
526  * pg_tblspc/<tblspc oid>/<tblspc version>/
527  * within a non-default tablespace (the name of the directory
528  * depends on version)
529  *
530  * And the relation data files themselves have a filename like:
531  *
532  * <oid>.<segment number>
533  *
534  *----
535  */
536  rnode.spcNode = InvalidOid;
537  rnode.dbNode = InvalidOid;
538  rnode.relNode = InvalidOid;
539  segNo = 0;
540  matched = false;
541 
542  nmatch = sscanf(path, "global/%u.%u", &rnode.relNode, &segNo);
543  if (nmatch == 1 || nmatch == 2)
544  {
545  rnode.spcNode = GLOBALTABLESPACE_OID;
546  rnode.dbNode = 0;
547  matched = true;
548  }
549  else
550  {
551  nmatch = sscanf(path, "base/%u/%u.%u",
552  &rnode.dbNode, &rnode.relNode, &segNo);
553  if (nmatch == 2 || nmatch == 3)
554  {
555  rnode.spcNode = DEFAULTTABLESPACE_OID;
556  matched = true;
557  }
558  else
559  {
560  nmatch = sscanf(path, "pg_tblspc/%u/" TABLESPACE_VERSION_DIRECTORY "/%u/%u.%u",
561  &rnode.spcNode, &rnode.dbNode, &rnode.relNode,
562  &segNo);
563  if (nmatch == 3 || nmatch == 4)
564  matched = true;
565  }
566  }
567 
568  /*
569  * The sscanf tests above can match files that have extra characters at
570  * the end. To eliminate such cases, cross-check that GetRelationPath
571  * creates the exact same filename, when passed the RelFileNode
572  * information we extracted from the filename.
573  */
574  if (matched)
575  {
576  char *check_path = datasegpath(rnode, MAIN_FORKNUM, segNo);
577 
578  if (strcmp(check_path, path) != 0)
579  matched = false;
580 
581  pfree(check_path);
582  }
583 
584  return matched;
585 }
static char * datasegpath(RelFileNode rnode, ForkNumber forknum, BlockNumber segno)
Definition: filemap.c:593
void pfree(void *pointer)
Definition: mcxt.c:1169
#define TABLESPACE_VERSION_DIRECTORY
Definition: relpath.h:26
#define InvalidOid
Definition: postgres_ext.h:36

◆ lookup_filehash_entry()

static file_entry_t * lookup_filehash_entry ( const char *  path)
static

Definition at line 206 of file filemap.c.

References filehash.

Referenced by process_target_wal_block_change().

207 {
208  return filehash_lookup(filehash, path);
209 }
static filehash_hash * filehash
Definition: filemap.c:56

◆ print_filemap()

void print_filemap ( filemap_t filemap)

Definition at line 480 of file filemap.c.

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

481 {
482  file_entry_t *entry;
483  int i;
484 
485  for (i = 0; i < filemap->nentries; i++)
486  {
487  entry = filemap->entries[i];
488  if (entry->action != FILE_ACTION_NONE ||
490  {
491  pg_log_debug("%s (%s)", entry->path,
492  action_to_str(entry->action));
493 
494  if (entry->target_pages_to_overwrite.bitmapsize > 0)
496  }
497  }
498  fflush(stdout);
499 }
#define pg_log_debug(...)
Definition: logging.h:92
file_action_t action
Definition: filemap.h:81
static const char * action_to_str(file_action_t action)
Definition: filemap.c:413
const char * path
Definition: filemap.h:53
datapagemap_t target_pages_to_overwrite
Definition: filemap.h:68
void datapagemap_print(datapagemap_t *map)
Definition: datapagemap.c:117
int bitmapsize
Definition: datapagemap.h:18
int nentries
Definition: filemap.h:95
int i
Definition: filemap.h:49
file_entry_t * entries[FLEXIBLE_ARRAY_MEMBER]
Definition: filemap.h:96

◆ process_source_file()

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

Definition at line 219 of file filemap.c.

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 generate_unaccent_rules::type.

Referenced by libpq_traverse_files(), local_traverse_files(), and main().

221 {
222  file_entry_t *entry;
223 
224  /*
225  * Pretend that pg_wal is a directory, even if it's really a symlink. We
226  * don't want to mess with the symlink itself, nor complain if it's a
227  * symlink in source but not in target or vice versa.
228  */
229  if (strcmp(path, "pg_wal") == 0 && type == FILE_TYPE_SYMLINK)
231 
232  /*
233  * sanity check: a filename that looks like a data file better be a
234  * regular file
235  */
236  if (type != FILE_TYPE_REGULAR && isRelDataFile(path))
237  pg_fatal("data file \"%s\" in source is not a regular file", path);
238 
239  /* Remember this source file */
240  entry = insert_filehash_entry(path);
241  if (entry->source_exists)
242  pg_fatal("duplicate source file \"%s\"", path);
243  entry->source_exists = true;
244  entry->source_type = type;
245  entry->source_size = size;
246  entry->source_link_target = link_target ? pg_strdup(link_target) : NULL;
247 }
static file_entry_t * insert_filehash_entry(const char *path)
Definition: filemap.c:176
#define pg_fatal(...)
Definition: pg_rewind.h:37
char * source_link_target
Definition: filemap.h:76
file_type_t source_type
Definition: filemap.h:74
size_t source_size
Definition: filemap.h:75
char * pg_strdup(const char *in)
Definition: fe_memutils.c:85
static bool isRelDataFile(const char *path)
Definition: filemap.c:510
Definition: filemap.h:49
bool source_exists
Definition: filemap.h:73

◆ process_target_file()

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

Definition at line 255 of file filemap.c.

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 generate_unaccent_rules::type.

Referenced by main().

257 {
258  file_entry_t *entry;
259 
260  /*
261  * Do not apply any exclusion filters here. This has advantage to remove
262  * from the target data folder all paths which have been filtered out from
263  * the source data folder when processing the source files.
264  */
265 
266  /*
267  * Like in process_source_file, pretend that pg_wal is always a directory.
268  */
269  if (strcmp(path, "pg_wal") == 0 && type == FILE_TYPE_SYMLINK)
271 
272  /* Remember this target file */
273  entry = insert_filehash_entry(path);
274  if (entry->target_exists)
275  pg_fatal("duplicate source file \"%s\"", path);
276  entry->target_exists = true;
277  entry->target_type = type;
278  entry->target_size = size;
279  entry->target_link_target = link_target ? pg_strdup(link_target) : NULL;
280 }
static file_entry_t * insert_filehash_entry(const char *path)
Definition: filemap.c:176
#define pg_fatal(...)
Definition: pg_rewind.h:37
size_t target_size
Definition: filemap.h:61
file_type_t target_type
Definition: filemap.h:60
bool target_exists
Definition: filemap.h:59
char * pg_strdup(const char *in)
Definition: fe_memutils.c:85
char * target_link_target
Definition: filemap.h:62
Definition: filemap.h:49

◆ process_target_wal_block_change()

void process_target_wal_block_change ( ForkNumber  forknum,
RelFileNode  rnode,
BlockNumber  blkno 
)

Definition at line 292 of file filemap.c.

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

294 {
295  char *path;
296  file_entry_t *entry;
297  BlockNumber blkno_inseg;
298  int segno;
299 
300  segno = blkno / RELSEG_SIZE;
301  blkno_inseg = blkno % RELSEG_SIZE;
302 
303  path = datasegpath(rnode, forknum, segno);
304  entry = lookup_filehash_entry(path);
305  pfree(path);
306 
307  /*
308  * If the block still exists in both systems, remember it. Otherwise we
309  * can safely ignore it.
310  *
311  * If the block is beyond the EOF in the source system, or the file
312  * doesn't exist in the source at all, we're going to truncate/remove it
313  * away from the target anyway. Likewise, if it doesn't exist in the
314  * target anymore, we will copy it over with the "tail" from the source
315  * system, anyway.
316  *
317  * It is possible to find WAL for a file that doesn't exist on either
318  * system anymore. It means that the relation was dropped later in the
319  * target system, and independently on the source system too, or that it
320  * was created and dropped in the target system and it never existed in
321  * the source. Either way, we can safely ignore it.
322  */
323  if (entry)
324  {
325  Assert(entry->isrelfile);
326 
327  if (entry->target_exists)
328  {
329  if (entry->target_type != FILE_TYPE_REGULAR)
330  pg_fatal("unexpected page modification for non-regular file \"%s\"",
331  entry->path);
332 
333  if (entry->source_exists)
334  {
335  off_t end_offset;
336 
337  end_offset = (blkno_inseg + 1) * BLCKSZ;
338  if (end_offset <= entry->source_size && end_offset <= entry->target_size)
339  datapagemap_add(&entry->target_pages_to_overwrite, blkno_inseg);
340  }
341  }
342  }
343 }
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:206
#define pg_fatal(...)
Definition: pg_rewind.h:37
uint32 BlockNumber
Definition: block.h:31
static char * datasegpath(RelFileNode rnode, ForkNumber forknum, BlockNumber segno)
Definition: filemap.c:593
bool isrelfile
Definition: filemap.h:54
void pfree(void *pointer)
Definition: mcxt.c:1169
file_type_t target_type
Definition: filemap.h:60
bool target_exists
Definition: filemap.h:59
const char * path
Definition: filemap.h:53
datapagemap_t target_pages_to_overwrite
Definition: filemap.h:68
#define Assert(condition)
Definition: c.h:804
Definition: filemap.h:49
bool source_exists
Definition: filemap.h:73

Variable Documentation

◆ excludeDirContents

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

Definition at line 88 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 130 of file filemap.c.

◆ filehash

filehash_hash* filehash
static