PostgreSQL Source Code  git master
filemap.c
Go to the documentation of this file.
1 /*-------------------------------------------------------------------------
2  *
3  * filemap.c
4  * A data structure for keeping track of files that have changed.
5  *
6  * This source file contains the logic to decide what to do with different
7  * kinds of files, and the data structure to support it. Before modifying
8  * anything, pg_rewind collects information about all the files and their
9  * attributes in the target and source data directories. It also scans the
10  * WAL log in the target, and collects information about data blocks that
11  * were changed. All this information is stored in a hash table, using the
12  * file path relative to the root of the data directory as the key.
13  *
14  * After collecting all the information required, the decide_file_actions()
15  * function scans the hash table and decides what action needs to be taken
16  * for each file. Finally, it sorts the array to the final order that the
17  * actions should be executed in.
18  *
19  * Copyright (c) 2013-2024, PostgreSQL Global Development Group
20  *
21  *-------------------------------------------------------------------------
22  */
23 
24 #include "postgres_fe.h"
25 
26 #include <sys/stat.h>
27 #include <unistd.h>
28 
29 #include "catalog/pg_tablespace_d.h"
30 #include "common/file_utils.h"
31 #include "common/hashfn_unstable.h"
32 #include "common/string.h"
33 #include "datapagemap.h"
34 #include "filemap.h"
35 #include "pg_rewind.h"
36 
37 /*
38  * Define a hash table which we can use to store information about the files
39  * appearing in source and target systems.
40  */
41 #define SH_PREFIX filehash
42 #define SH_ELEMENT_TYPE file_entry_t
43 #define SH_KEY_TYPE const char *
44 #define SH_KEY path
45 #define SH_HASH_KEY(tb, key) hash_string(key)
46 #define SH_EQUAL(tb, a, b) (strcmp(a, b) == 0)
47 #define SH_SCOPE static inline
48 #define SH_RAW_ALLOCATOR pg_malloc0
49 #define SH_DECLARE
50 #define SH_DEFINE
51 #include "lib/simplehash.h"
52 
53 #define FILEHASH_INITIAL_SIZE 1000
54 
55 static filehash_hash *filehash;
56 
57 static bool isRelDataFile(const char *path);
58 static char *datasegpath(RelFileLocator rlocator, ForkNumber forknum,
59  BlockNumber segno);
60 
61 static file_entry_t *insert_filehash_entry(const char *path);
62 static file_entry_t *lookup_filehash_entry(const char *path);
63 static int final_filemap_cmp(const void *a, const void *b);
64 static bool check_file_excluded(const char *path, bool is_source);
65 
66 /*
67  * Definition of one element part of an exclusion list, used to exclude
68  * contents when rewinding. "name" is the name of the file or path to
69  * check for exclusion. If "match_prefix" is true, any items matching
70  * the name as prefix are excluded.
71  */
72 struct exclude_list_item
73 {
74  const char *name;
75  bool match_prefix;
76 };
77 
78 /*
79  * The contents of these directories are removed or recreated during server
80  * start so they are not included in data processed by pg_rewind.
81  *
82  * Note: those lists should be kept in sync with what basebackup.c provides.
83  * Some of the values, contrary to what basebackup.c uses, are hardcoded as
84  * they are defined in backend-only headers. So this list is maintained
85  * with a best effort in mind.
86  */
87 static const char *const excludeDirContents[] =
88 {
89  /*
90  * Skip temporary statistics files. PG_STAT_TMP_DIR must be skipped
91  * because extensions like pg_stat_statements store data there.
92  */
93  "pg_stat_tmp", /* defined as PG_STAT_TMP_DIR */
94 
95  /*
96  * It is generally not useful to backup the contents of this directory
97  * even if the intention is to restore to another primary. See backup.sgml
98  * for a more detailed description.
99  */
100  "pg_replslot", /* defined as PG_REPLSLOT_DIR */
101 
102  /* Contents removed on startup, see dsm_cleanup_for_mmap(). */
103  "pg_dynshmem", /* defined as PG_DYNSHMEM_DIR */
104 
105  /* Contents removed on startup, see AsyncShmemInit(). */
106  "pg_notify",
107 
108  /*
109  * Old contents are loaded for possible debugging but are not required for
110  * normal operation, see SerialInit().
111  */
112  "pg_serial",
113 
114  /* Contents removed on startup, see DeleteAllExportedSnapshotFiles(). */
115  "pg_snapshots",
116 
117  /* Contents zeroed on startup, see StartupSUBTRANS(). */
118  "pg_subtrans",
119 
120  /* end of list */
121  NULL
122 };
123 
124 /*
125  * List of files excluded from filemap processing. Files are excluded
126  * if their prefix match.
127  */
128 static const struct exclude_list_item excludeFiles[] =
129 {
130  /* Skip auto conf temporary file. */
131  {"postgresql.auto.conf.tmp", false}, /* defined as PG_AUTOCONF_FILENAME */
132 
133  /* Skip current log file temporary file */
134  {"current_logfiles.tmp", false}, /* defined as
135  * LOG_METAINFO_DATAFILE_TMP */
136 
137  /* Skip relation cache because it is rebuilt on startup */
138  {"pg_internal.init", true}, /* defined as RELCACHE_INIT_FILENAME */
139 
140  /*
141  * If there is a backup_label or tablespace_map file, it indicates that a
142  * recovery failed and this cluster probably can't be rewound, but exclude
143  * them anyway if they are found.
144  */
145  {"backup_label", false}, /* defined as BACKUP_LABEL_FILE */
146  {"tablespace_map", false}, /* defined as TABLESPACE_MAP */
147 
148  /*
149  * If there's a backup_manifest, it belongs to a backup that was used to
150  * start this server. It is *not* correct for this backup. Our
151  * backup_manifest is injected into the backup separately if users want
152  * it.
153  */
154  {"backup_manifest", false},
155 
156  {"postmaster.pid", false},
157  {"postmaster.opts", false},
158 
159  /* end of list */
160  {NULL, false}
161 };
162 
163 /*
164  * Initialize the hash table for the file map.
165  */
166 void
168 {
169  filehash = filehash_create(FILEHASH_INITIAL_SIZE, NULL);
170 }
171 
172 /* Look up entry for 'path', creating a new one if it doesn't exist */
173 static file_entry_t *
174 insert_filehash_entry(const char *path)
175 {
176  file_entry_t *entry;
177  bool found;
178 
179  entry = filehash_insert(filehash, path, &found);
180  if (!found)
181  {
182  entry->path = pg_strdup(path);
183  entry->isrelfile = isRelDataFile(path);
184 
185  entry->target_exists = false;
187  entry->target_size = 0;
188  entry->target_link_target = NULL;
189  entry->target_pages_to_overwrite.bitmap = NULL;
191 
192  entry->source_exists = false;
194  entry->source_size = 0;
195  entry->source_link_target = NULL;
196 
197  entry->action = FILE_ACTION_UNDECIDED;
198  }
199 
200  return entry;
201 }
202 
203 static file_entry_t *
204 lookup_filehash_entry(const char *path)
205 {
206  return filehash_lookup(filehash, path);
207 }
208 
209 /*
210  * Callback for processing source file list.
211  *
212  * This is called once for every file in the source server. We record the
213  * type and size of the file, so that decide_file_action() can later decide what
214  * to do with it.
215  */
216 void
217 process_source_file(const char *path, file_type_t type, size_t size,
218  const char *link_target)
219 {
220  file_entry_t *entry;
221 
222  /*
223  * Pretend that pg_wal is a directory, even if it's really a symlink. We
224  * don't want to mess with the symlink itself, nor complain if it's a
225  * symlink in source but not in target or vice versa.
226  */
227  if (strcmp(path, "pg_wal") == 0 && type == FILE_TYPE_SYMLINK)
229 
230  /*
231  * sanity check: a filename that looks like a data file better be a
232  * regular file
233  */
234  if (type != FILE_TYPE_REGULAR && isRelDataFile(path))
235  pg_fatal("data file \"%s\" in source is not a regular file", path);
236 
237  /* Remember this source file */
238  entry = insert_filehash_entry(path);
239  if (entry->source_exists)
240  pg_fatal("duplicate source file \"%s\"", path);
241  entry->source_exists = true;
242  entry->source_type = type;
243  entry->source_size = size;
244  entry->source_link_target = link_target ? pg_strdup(link_target) : NULL;
245 }
246 
247 /*
248  * Callback for processing target file list.
249  *
250  * Record the type and size of the file, like process_source_file() does.
251  */
252 void
253 process_target_file(const char *path, file_type_t type, size_t size,
254  const char *link_target)
255 {
256  file_entry_t *entry;
257 
258  /*
259  * Do not apply any exclusion filters here. This has advantage to remove
260  * from the target data folder all paths which have been filtered out from
261  * the source data folder when processing the source files.
262  */
263 
264  /*
265  * Like in process_source_file, pretend that pg_wal is always a directory.
266  */
267  if (strcmp(path, "pg_wal") == 0 && type == FILE_TYPE_SYMLINK)
269 
270  /* Remember this target file */
271  entry = insert_filehash_entry(path);
272  if (entry->target_exists)
273  pg_fatal("duplicate source file \"%s\"", path);
274  entry->target_exists = true;
275  entry->target_type = type;
276  entry->target_size = size;
277  entry->target_link_target = link_target ? pg_strdup(link_target) : NULL;
278 }
279 
280 /*
281  * This callback gets called while we read the WAL in the target, for every
282  * block that has changed in the target system. It decides if the given
283  * 'blkno' in the target relfile needs to be overwritten from the source, and
284  * if so, records it in 'target_pages_to_overwrite' bitmap.
285  *
286  * NOTE: All the files on both systems must have already been added to the
287  * hash table!
288  */
289 void
291  BlockNumber blkno)
292 {
293  char *path;
294  file_entry_t *entry;
295  BlockNumber blkno_inseg;
296  int segno;
297 
298  segno = blkno / RELSEG_SIZE;
299  blkno_inseg = blkno % RELSEG_SIZE;
300 
301  path = datasegpath(rlocator, forknum, segno);
302  entry = lookup_filehash_entry(path);
303  pfree(path);
304 
305  /*
306  * If the block still exists in both systems, remember it. Otherwise we
307  * can safely ignore it.
308  *
309  * If the block is beyond the EOF in the source system, or the file
310  * doesn't exist in the source at all, we're going to truncate/remove it
311  * away from the target anyway. Likewise, if it doesn't exist in the
312  * target anymore, we will copy it over with the "tail" from the source
313  * system, anyway.
314  *
315  * It is possible to find WAL for a file that doesn't exist on either
316  * system anymore. It means that the relation was dropped later in the
317  * target system, and independently on the source system too, or that it
318  * was created and dropped in the target system and it never existed in
319  * the source. Either way, we can safely ignore it.
320  */
321  if (entry)
322  {
323  Assert(entry->isrelfile);
324 
325  if (entry->target_exists)
326  {
327  if (entry->target_type != FILE_TYPE_REGULAR)
328  pg_fatal("unexpected page modification for non-regular file \"%s\"",
329  entry->path);
330 
331  if (entry->source_exists)
332  {
333  off_t end_offset;
334 
335  end_offset = (blkno_inseg + 1) * BLCKSZ;
336  if (end_offset <= entry->source_size && end_offset <= entry->target_size)
337  datapagemap_add(&entry->target_pages_to_overwrite, blkno_inseg);
338  }
339  }
340  }
341 }
342 
343 /*
344  * Is this the path of file that pg_rewind can skip copying?
345  */
346 static bool
347 check_file_excluded(const char *path, bool is_source)
348 {
349  char localpath[MAXPGPATH];
350  int excludeIdx;
351  const char *filename;
352 
353  /*
354  * Skip all temporary files, .../pgsql_tmp/... and .../pgsql_tmp.*
355  */
356  if (strstr(path, "/" PG_TEMP_FILE_PREFIX) != NULL ||
357  strstr(path, "/" PG_TEMP_FILES_DIR "/") != NULL)
358  {
359  return true;
360  }
361 
362  /* check individual files... */
363  for (excludeIdx = 0; excludeFiles[excludeIdx].name != NULL; excludeIdx++)
364  {
365  int cmplen = strlen(excludeFiles[excludeIdx].name);
366 
368  if (filename == NULL)
369  filename = path;
370  else
371  filename++;
372 
373  if (!excludeFiles[excludeIdx].match_prefix)
374  cmplen++;
375  if (strncmp(filename, excludeFiles[excludeIdx].name, cmplen) == 0)
376  {
377  if (is_source)
378  pg_log_debug("entry \"%s\" excluded from source file list",
379  path);
380  else
381  pg_log_debug("entry \"%s\" excluded from target file list",
382  path);
383  return true;
384  }
385  }
386 
387  /*
388  * ... And check some directories. Note that this includes any contents
389  * within the directories themselves.
390  */
391  for (excludeIdx = 0; excludeDirContents[excludeIdx] != NULL; excludeIdx++)
392  {
393  snprintf(localpath, sizeof(localpath), "%s/",
394  excludeDirContents[excludeIdx]);
395  if (strstr(path, localpath) == path)
396  {
397  if (is_source)
398  pg_log_debug("entry \"%s\" excluded from source file list",
399  path);
400  else
401  pg_log_debug("entry \"%s\" excluded from target file list",
402  path);
403  return true;
404  }
405  }
406 
407  return false;
408 }
409 
410 static const char *
412 {
413  switch (action)
414  {
415  case FILE_ACTION_NONE:
416  return "NONE";
417  case FILE_ACTION_COPY:
418  return "COPY";
420  return "TRUNCATE";
422  return "COPY_TAIL";
423  case FILE_ACTION_CREATE:
424  return "CREATE";
425  case FILE_ACTION_REMOVE:
426  return "REMOVE";
427 
428  default:
429  return "unknown";
430  }
431 }
432 
433 /*
434  * Calculate the totals needed for progress reports.
435  */
436 void
438 {
439  file_entry_t *entry;
440  int i;
441 
442  filemap->total_size = 0;
443  filemap->fetch_size = 0;
444 
445  for (i = 0; i < filemap->nentries; i++)
446  {
447  entry = filemap->entries[i];
448 
449  if (entry->source_type != FILE_TYPE_REGULAR)
450  continue;
451 
452  filemap->total_size += entry->source_size;
453 
454  if (entry->action == FILE_ACTION_COPY)
455  {
456  filemap->fetch_size += entry->source_size;
457  continue;
458  }
459 
460  if (entry->action == FILE_ACTION_COPY_TAIL)
461  filemap->fetch_size += (entry->source_size - entry->target_size);
462 
463  if (entry->target_pages_to_overwrite.bitmapsize > 0)
464  {
466  BlockNumber blk;
467 
469  while (datapagemap_next(iter, &blk))
470  filemap->fetch_size += BLCKSZ;
471 
472  pg_free(iter);
473  }
474  }
475 }
476 
477 void
479 {
480  file_entry_t *entry;
481  int i;
482 
483  for (i = 0; i < filemap->nentries; i++)
484  {
485  entry = filemap->entries[i];
486  if (entry->action != FILE_ACTION_NONE ||
488  {
489  pg_log_debug("%s (%s)", entry->path,
490  action_to_str(entry->action));
491 
492  if (entry->target_pages_to_overwrite.bitmapsize > 0)
494  }
495  }
496  fflush(stdout);
497 }
498 
499 /*
500  * Does it look like a relation data file?
501  *
502  * For our purposes, only files belonging to the main fork are considered
503  * relation files. Other forks are always copied in toto, because we cannot
504  * reliably track changes to them, because WAL only contains block references
505  * for the main fork.
506  */
507 static bool
508 isRelDataFile(const char *path)
509 {
510  RelFileLocator rlocator;
511  unsigned int segNo;
512  int nmatch;
513  bool matched;
514 
515  /*----
516  * Relation data files can be in one of the following directories:
517  *
518  * global/
519  * shared relations
520  *
521  * base/<db oid>/
522  * regular relations, default tablespace
523  *
524  * pg_tblspc/<tblspc oid>/<tblspc version>/
525  * within a non-default tablespace (the name of the directory
526  * depends on version)
527  *
528  * And the relation data files themselves have a filename like:
529  *
530  * <oid>.<segment number>
531  *
532  *----
533  */
534  rlocator.spcOid = InvalidOid;
535  rlocator.dbOid = InvalidOid;
536  rlocator.relNumber = InvalidRelFileNumber;
537  segNo = 0;
538  matched = false;
539 
540  nmatch = sscanf(path, "global/%u.%u", &rlocator.relNumber, &segNo);
541  if (nmatch == 1 || nmatch == 2)
542  {
543  rlocator.spcOid = GLOBALTABLESPACE_OID;
544  rlocator.dbOid = 0;
545  matched = true;
546  }
547  else
548  {
549  nmatch = sscanf(path, "base/%u/%u.%u",
550  &rlocator.dbOid, &rlocator.relNumber, &segNo);
551  if (nmatch == 2 || nmatch == 3)
552  {
553  rlocator.spcOid = DEFAULTTABLESPACE_OID;
554  matched = true;
555  }
556  else
557  {
558  nmatch = sscanf(path, "pg_tblspc/%u/" TABLESPACE_VERSION_DIRECTORY "/%u/%u.%u",
559  &rlocator.spcOid, &rlocator.dbOid, &rlocator.relNumber,
560  &segNo);
561  if (nmatch == 3 || nmatch == 4)
562  matched = true;
563  }
564  }
565 
566  /*
567  * The sscanf tests above can match files that have extra characters at
568  * the end. To eliminate such cases, cross-check that GetRelationPath
569  * creates the exact same filename, when passed the RelFileLocator
570  * information we extracted from the filename.
571  */
572  if (matched)
573  {
574  char *check_path = datasegpath(rlocator, MAIN_FORKNUM, segNo);
575 
576  if (strcmp(check_path, path) != 0)
577  matched = false;
578 
579  pfree(check_path);
580  }
581 
582  return matched;
583 }
584 
585 /*
586  * A helper function to create the path of a relation file and segment.
587  *
588  * The returned path is palloc'd
589  */
590 static char *
592 {
593  char *path;
594  char *segpath;
595 
596  path = relpathperm(rlocator, forknum);
597  if (segno > 0)
598  {
599  segpath = psprintf("%s.%u", path, segno);
600  pfree(path);
601  return segpath;
602  }
603  else
604  return path;
605 }
606 
607 /*
608  * In the final stage, the filemap is sorted so that removals come last.
609  * From disk space usage point of view, it would be better to do removals
610  * first, but for now, safety first. If a whole directory is deleted, all
611  * files and subdirectories inside it need to removed first. On creation,
612  * parent directory needs to be created before files and directories inside
613  * it. To achieve that, the file_action_t enum is ordered so that we can
614  * just sort on that first. Furthermore, sort REMOVE entries in reverse
615  * path order, so that "foo/bar" subdirectory is removed before "foo".
616  */
617 static int
618 final_filemap_cmp(const void *a, const void *b)
619 {
620  file_entry_t *fa = *((file_entry_t **) a);
621  file_entry_t *fb = *((file_entry_t **) b);
622 
623  if (fa->action > fb->action)
624  return 1;
625  if (fa->action < fb->action)
626  return -1;
627 
628  if (fa->action == FILE_ACTION_REMOVE)
629  return strcmp(fb->path, fa->path);
630  else
631  return strcmp(fa->path, fb->path);
632 }
633 
634 /*
635  * Decide what action to perform to a file.
636  */
637 static file_action_t
639 {
640  const char *path = entry->path;
641 
642  /*
643  * Don't touch the control file. It is handled specially, after copying
644  * all the other files.
645  */
646  if (strcmp(path, "global/pg_control") == 0)
647  return FILE_ACTION_NONE;
648 
649  /* Skip macOS system files */
650  if (strstr(path, ".DS_Store") != NULL)
651  return FILE_ACTION_NONE;
652 
653  /*
654  * Remove all files matching the exclusion filters in the target.
655  */
656  if (check_file_excluded(path, true))
657  {
658  if (entry->target_exists)
659  return FILE_ACTION_REMOVE;
660  else
661  return FILE_ACTION_NONE;
662  }
663 
664  /*
665  * Handle cases where the file is missing from one of the systems.
666  */
667  if (!entry->target_exists && entry->source_exists)
668  {
669  /*
670  * File exists in source, but not in target. Copy it in toto. (If it's
671  * a relation data file, WAL replay after rewinding should re-create
672  * it anyway. But there's no harm in copying it now.)
673  */
674  switch (entry->source_type)
675  {
676  case FILE_TYPE_DIRECTORY:
677  case FILE_TYPE_SYMLINK:
678  return FILE_ACTION_CREATE;
679  case FILE_TYPE_REGULAR:
680  return FILE_ACTION_COPY;
681  case FILE_TYPE_UNDEFINED:
682  pg_fatal("unknown file type for \"%s\"", entry->path);
683  break;
684  }
685  }
686  else if (entry->target_exists && !entry->source_exists)
687  {
688  /* File exists in target, but not source. Remove it. */
689  return FILE_ACTION_REMOVE;
690  }
691  else if (!entry->target_exists && !entry->source_exists)
692  {
693  /*
694  * Doesn't exist in either server. Why does it have an entry in the
695  * first place??
696  */
697  Assert(false);
698  return FILE_ACTION_NONE;
699  }
700 
701  /*
702  * Otherwise, the file exists on both systems
703  */
704  Assert(entry->target_exists && entry->source_exists);
705 
706  if (entry->source_type != entry->target_type)
707  {
708  /* But it's a different kind of object. Strange.. */
709  pg_fatal("file \"%s\" is of different type in source and target", entry->path);
710  }
711 
712  /*
713  * PG_VERSION files should be identical on both systems, but avoid
714  * overwriting them for paranoia.
715  */
716  if (pg_str_endswith(entry->path, "PG_VERSION"))
717  return FILE_ACTION_NONE;
718 
719  switch (entry->source_type)
720  {
721  case FILE_TYPE_DIRECTORY:
722  return FILE_ACTION_NONE;
723 
724  case FILE_TYPE_SYMLINK:
725 
726  /*
727  * XXX: Should we check if it points to the same target?
728  */
729  return FILE_ACTION_NONE;
730 
731  case FILE_TYPE_REGULAR:
732  if (!entry->isrelfile)
733  {
734  /*
735  * It's a non-data file that we have no special processing
736  * for. Copy it in toto.
737  */
738  return FILE_ACTION_COPY;
739  }
740  else
741  {
742  /*
743  * It's a data file that exists in both systems.
744  *
745  * If it's larger in target, we can truncate it. There will
746  * also be a WAL record of the truncation in the source
747  * system, so WAL replay would eventually truncate the target
748  * too, but we might as well do it now.
749  *
750  * If it's smaller in the target, it means that it has been
751  * truncated in the target, or enlarged in the source, or
752  * both. If it was truncated in the target, we need to copy
753  * the missing tail from the source system. If it was enlarged
754  * in the source system, there will be WAL records in the
755  * source system for the new blocks, so we wouldn't need to
756  * copy them here. But we don't know which scenario we're
757  * dealing with, and there's no harm in copying the missing
758  * blocks now, so do it now.
759  *
760  * If it's the same size, do nothing here. Any blocks modified
761  * in the target will be copied based on parsing the target
762  * system's WAL, and any blocks modified in the source will be
763  * updated after rewinding, when the source system's WAL is
764  * replayed.
765  */
766  if (entry->target_size < entry->source_size)
767  return FILE_ACTION_COPY_TAIL;
768  else if (entry->target_size > entry->source_size)
769  return FILE_ACTION_TRUNCATE;
770  else
771  return FILE_ACTION_NONE;
772  }
773  break;
774 
775  case FILE_TYPE_UNDEFINED:
776  pg_fatal("unknown file type for \"%s\"", path);
777  break;
778  }
779 
780  /* unreachable */
781  pg_fatal("could not decide what to do with file \"%s\"", path);
782 }
783 
784 /*
785  * Decide what to do with each file.
786  *
787  * Returns a 'filemap' with the entries in the order that their actions
788  * should be executed.
789  */
790 filemap_t *
792 {
793  int i;
794  filehash_iterator it;
795  file_entry_t *entry;
796  filemap_t *filemap;
797 
798  filehash_start_iterate(filehash, &it);
799  while ((entry = filehash_iterate(filehash, &it)) != NULL)
800  {
801  entry->action = decide_file_action(entry);
802  }
803 
804  /*
805  * Turn the hash table into an array, and sort in the order that the
806  * actions should be performed.
807  */
808  filemap = pg_malloc(offsetof(filemap_t, entries) +
809  filehash->members * sizeof(file_entry_t *));
810  filemap->nentries = filehash->members;
811  filehash_start_iterate(filehash, &it);
812  i = 0;
813  while ((entry = filehash_iterate(filehash, &it)) != NULL)
814  {
815  filemap->entries[i++] = entry;
816  }
817 
818  qsort(&filemap->entries, filemap->nentries, sizeof(file_entry_t *),
820 
821  return filemap;
822 }
uint32 BlockNumber
Definition: block.h:31
#define Assert(condition)
Definition: c.h:861
bool datapagemap_next(datapagemap_iterator_t *iter, BlockNumber *blkno)
Definition: datapagemap.c:87
void datapagemap_print(datapagemap_t *map)
Definition: datapagemap.c:117
void datapagemap_add(datapagemap_t *map, BlockNumber blkno)
Definition: datapagemap.c:32
datapagemap_iterator_t * datapagemap_iterate(datapagemap_t *map)
Definition: datapagemap.c:75
char * pg_strdup(const char *in)
Definition: fe_memutils.c:85
void pg_free(void *ptr)
Definition: fe_memutils.c:105
void * pg_malloc(size_t size)
Definition: fe_memutils.c:47
#define PG_TEMP_FILES_DIR
Definition: file_utils.h:62
#define PG_TEMP_FILE_PREFIX
Definition: file_utils.h:63
static const struct exclude_list_item excludeFiles[]
Definition: filemap.c:128
static bool isRelDataFile(const char *path)
Definition: filemap.c:508
void filehash_init(void)
Definition: filemap.c:167
void process_source_file(const char *path, file_type_t type, size_t size, const char *link_target)
Definition: filemap.c:217
static const char *const excludeDirContents[]
Definition: filemap.c:87
static const char * action_to_str(file_action_t action)
Definition: filemap.c:411
void print_filemap(filemap_t *filemap)
Definition: filemap.c:478
static char * datasegpath(RelFileLocator rlocator, ForkNumber forknum, BlockNumber segno)
Definition: filemap.c:591
static filehash_hash * filehash
Definition: filemap.c:55
void process_target_file(const char *path, file_type_t type, size_t size, const char *link_target)
Definition: filemap.c:253
void process_target_wal_block_change(ForkNumber forknum, RelFileLocator rlocator, BlockNumber blkno)
Definition: filemap.c:290
filemap_t * decide_file_actions(void)
Definition: filemap.c:791
static file_action_t decide_file_action(file_entry_t *entry)
Definition: filemap.c:638
static file_entry_t * lookup_filehash_entry(const char *path)
Definition: filemap.c:204
static file_entry_t * insert_filehash_entry(const char *path)
Definition: filemap.c:174
static bool check_file_excluded(const char *path, bool is_source)
Definition: filemap.c:347
#define FILEHASH_INITIAL_SIZE
Definition: filemap.c:53
static int final_filemap_cmp(const void *a, const void *b)
Definition: filemap.c:618
void calculate_totals(filemap_t *filemap)
Definition: filemap.c:437
file_action_t
Definition: filemap.h:17
@ 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_UNDECIDED
Definition: filemap.h:18
@ FILE_ACTION_TRUNCATE
Definition: filemap.h:26
@ FILE_ACTION_CREATE
Definition: filemap.h:20
file_type_t
Definition: filemap.h:31
@ FILE_TYPE_UNDEFINED
Definition: filemap.h:32
@ FILE_TYPE_REGULAR
Definition: filemap.h:34
@ FILE_TYPE_SYMLINK
Definition: filemap.h:36
@ FILE_TYPE_DIRECTORY
Definition: filemap.h:35
int b
Definition: isn.c:70
int a
Definition: isn.c:69
int i
Definition: isn.c:73
static void const char fflush(stdout)
#define pg_log_debug(...)
Definition: logging.h:133
void pfree(void *pointer)
Definition: mcxt.c:1521
#define pg_fatal(...)
#define MAXPGPATH
static char * filename
Definition: pg_dumpall.c:119
char * last_dir_separator(const char *filename)
Definition: path.c:140
#define snprintf
Definition: port.h:238
#define qsort(a, b, c, d)
Definition: port.h:447
#define InvalidOid
Definition: postgres_ext.h:36
static int fa(void)
Definition: preproc-init.c:85
static int fb(int x)
Definition: preproc-init.c:92
char * psprintf(const char *fmt,...)
Definition: psprintf.c:46
ForkNumber
Definition: relpath.h:56
@ MAIN_FORKNUM
Definition: relpath.h:58
#define InvalidRelFileNumber
Definition: relpath.h:26
#define relpathperm(rlocator, forknum)
Definition: relpath.h:98
#define TABLESPACE_VERSION_DIRECTORY
Definition: relpath.h:33
static pg_noinline void Size size
Definition: slab.c:607
bool pg_str_endswith(const char *str, const char *end)
Definition: string.c:32
RelFileNumber relNumber
int bitmapsize
Definition: datapagemap.h:18
char * bitmap
Definition: datapagemap.h:17
const char * name
Definition: basebackup.c:140
Definition: filemap.h:50
datapagemap_t target_pages_to_overwrite
Definition: filemap.h:68
const char * path
Definition: filemap.h:53
size_t source_size
Definition: filemap.h:75
bool source_exists
Definition: filemap.h:73
bool target_exists
Definition: filemap.h:59
char * source_link_target
Definition: filemap.h:76
file_type_t source_type
Definition: filemap.h:74
char * target_link_target
Definition: filemap.h:62
size_t target_size
Definition: filemap.h:61
file_action_t action
Definition: filemap.h:81
file_type_t target_type
Definition: filemap.h:60
bool isrelfile
Definition: filemap.h:54
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
const char * type
const char * name