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