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