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