PostgreSQL Source Code: src/bin/pg_rewind/filemap.c Source File (original) (raw)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
25
26#include <sys/stat.h>
28
30#include "catalog/pg_tablespace_d.h"
37
38
39
40
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
53
54#define FILEHASH_INITIAL_SIZE 1000
55
57
61
64
65
66
67
69{
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
85
86#define KEEPWAL_INITIAL_SIZE 1000
87
88
89static keepwal_hash *keepwal = NULL;
91
93
95
96
97
98
99
100
101
103{
104 const char *name;
106};
107
108
109
110
111
112
113
114
115
116
118{
119
120
121
122
123 "pg_stat_tmp",
124
125
126
127
128
129
130 "pg_replslot",
131
132
133 "pg_dynshmem",
134
135
136 "pg_notify",
137
138
139
140
141
142 "pg_serial",
143
144
145 "pg_snapshots",
146
147
148 "pg_subtrans",
149
150
151 NULL
152};
153
154
155
156
157
159{
160
161 {"postgresql.auto.conf.tmp", false},
162
163
164 {"current_logfiles.tmp", false},
165
166
167
168 {"pg_internal.init", true},
169
170
171
172
173
174
175 {"backup_label", false},
176 {"tablespace_map", false},
177
178
179
180
181
182
183
184 {"backup_manifest", false},
185
186 {"postmaster.pid", false},
187 {"postmaster.opts", false},
188
189
190 {NULL, false}
191};
192
193
194
195
196void
198{
200}
201
202
205{
207 bool found;
208
209 entry = filehash_insert(filehash, path, &found);
210 if (!found)
211 {
214
221
226
228 }
229
230 return entry;
231}
232
235{
236 return filehash_lookup(filehash, path);
237}
238
239
240
241
242void
244{
245
247}
248
249
250void
252{
254 bool found;
255
256
258
259 entry = keepwal_insert(keepwal, path, &found);
260
261 if (!found)
263}
264
265
266static bool
268{
269 return keepwal_lookup(keepwal, path) != NULL;
270}
271
272
273
274
275
276
277
278
279void
281 const char *link_target)
282{
284
285
286
287
288
289
292
293
294
295
296
298 pg_fatal("data file \"%s\" in source is not a regular file", path);
299
300
303 pg_fatal("duplicate source file \"%s\"", path);
308}
309
310
311
312
313
314
315void
317 const char *link_target)
318{
320
321
322
323
324
325
326
327
328
329
332
333
336 pg_fatal("duplicate source file \"%s\"", path);
341}
342
343
344
345
346
347
348
349
350
351
352void
355{
356 char *path;
359 int segno;
360
361 segno = blkno / RELSEG_SIZE;
362 blkno_inseg = blkno % RELSEG_SIZE;
363
364 path = datasegpath(rlocator, forknum, segno);
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384 if (entry)
385 {
387
389 {
391 pg_fatal("unexpected page modification for non-regular file \"%s\"",
392 entry->path);
393
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)
401 }
402 }
403 }
404}
405
406
407
408
409static bool
411{
413 int excludeIdx;
415
416
417
418
421 {
422 return true;
423 }
424
425
426 for (excludeIdx = 0; excludeFiles[excludeIdx].name != NULL; excludeIdx++)
427 {
429
433 else
435
437 cmplen++;
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
452
453
454 for (excludeIdx = 0; excludeDirContents[excludeIdx] != NULL; excludeIdx++)
455 {
456 snprintf(localpath, sizeof(localpath), "%s/",
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{
477 {
479 return "NONE";
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
498
499void
501{
503 int i;
504
507
509 {
511
513 continue;
514
516
518 {
520 continue;
521 }
522
525
527 {
530
534
536 }
537 }
538}
539
540void
542{
544 int i;
545
547 {
549
553 {
556
559 }
560 }
562}
563
564
565
566
569{
571 unsigned int segNo;
572 int nmatch;
574
575
576 if (strncmp("pg_wal/", path, 7) == 0)
577 {
578 const char *filename = path + 7;
579
582 else
584 }
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
615 segNo = 0;
617
618 nmatch = sscanf(path, "global/%u.%u", &rlocator.relNumber, &segNo);
619 if (nmatch == 1 || nmatch == 2)
620 {
621 rlocator.spcOid = GLOBALTABLESPACE_OID;
622 rlocator.dbOid = 0;
624 }
625 else
626 {
627 nmatch = sscanf(path, "base/%u/%u.%u",
629 if (nmatch == 2 || nmatch == 3)
630 {
631 rlocator.spcOid = DEFAULTTABLESPACE_OID;
633 }
634 else
635 {
638 &segNo);
639 if (nmatch == 3 || nmatch == 4)
641 }
642 }
643
644
645
646
647
648
649
651 {
653
654 if (strcmp(check_path, path) != 0)
656
657 pfree(check_path);
658 }
659
660 return result;
661}
662
663
664
665
666
667
668static char *
670{
672 char *segpath;
673
675 if (segno > 0)
676 {
677 segpath = psprintf("%s.%u", path.str, segno);
678 return segpath;
679 }
680 else
682}
683
684
685
686
687
688
689
690
691
692
693
694static int
696{
699
700 if (fa->action > fb->action)
701 return 1;
702 if (fa->action < fb->action)
703 return -1;
704
706 return strcmp(fb->path, fa->path);
707 else
708 return strcmp(fa->path, fb->path);
709}
710
711
712
713
714
715
716
717
720 size_t source_size, size_t target_size)
721{
724
725
727
728
729
730
731
732
733
734
735
736
737
738 if (file_segno < last_common_segno &&
739 source_size == target_size)
741
743}
744
745
746
747
750{
751 const char *path = entry->path;
752
753
754
755
756
759
760
761 if (strstr(path, ".DS_Store") != NULL)
763
764
765
766
768 {
771 else
773 }
774
775
776
777
779 {
780
781
782
783
784
786 {
793 pg_fatal("unknown file type for \"%s\"", entry->path);
794 break;
795 }
796 }
798 {
799
800
801
802
804 {
805 pg_log_debug("Not removing file \"%s\" because it is required for recovery", path);
807 }
809 }
811 {
812
813
814
815
818 }
819
820
821
822
824
826 {
827
828 pg_fatal("file \"%s\" is of different type in source and target", entry->path);
829 }
830
831
832
833
834
837
839 {
842
844
845
846
847
849
852 {
853
855
858 else
859 filename++;
860
864 }
866 {
867
868
869
870
872 }
873 else
874 {
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
903 else
905 }
906 break;
907
909 pg_fatal("unknown file type for \"%s\"", path);
910 break;
911 }
912
913
914 pg_fatal("could not decide what to do with file \"%s\"", path);
915}
916
917
918
919
920
921
922
925{
926 int i;
927 filehash_iterator it;
930
931 filehash_start_iterate(filehash, &it);
932 while ((entry = filehash_iterate(filehash, &it)) != NULL)
933 {
935 }
936
937
938
939
940
944 filehash_start_iterate(filehash, &it);
945 i = 0;
946 while ((entry = filehash_iterate(filehash, &it)) != NULL)
947 {
948 filemap->entries[i++] = entry;
949 }
950
953
954 return filemap;
955}
bool datapagemap_next(datapagemap_iterator_t *iter, BlockNumber *blkno)
void datapagemap_print(datapagemap_t *map)
datapagemap_iterator_t * datapagemap_iterate(datapagemap_t *map)
void datapagemap_add(datapagemap_t *map, BlockNumber blkno)
void * pg_malloc(size_t size)
char * pg_strdup(const char *in)
#define PG_TEMP_FILES_DIR
#define PG_TEMP_FILE_PREFIX
static const struct exclude_list_item excludeFiles[]
struct keepwal_entry keepwal_entry
static bool keepwal_entry_exists(const char *path)
static const char * action_to_str(file_action_t action)
void process_source_file(const char *path, file_type_t type, size_t size, const char *link_target)
static const char *const excludeDirContents[]
void print_filemap(filemap_t *filemap)
static char * datasegpath(RelFileLocator rlocator, ForkNumber forknum, BlockNumber segno)
static file_action_t decide_file_action(file_entry_t *entry, XLogSegNo last_common_segno)
static filehash_hash * filehash
void process_target_file(const char *path, file_type_t type, size_t size, const char *link_target)
void process_target_wal_block_change(ForkNumber forknum, RelFileLocator rlocator, BlockNumber blkno)
void keepwal_add_entry(const char *path)
static file_action_t decide_wal_file_action(const char *fname, XLogSegNo last_common_segno, size_t source_size, size_t target_size)
static keepwal_hash * keepwal
static file_entry_t * lookup_filehash_entry(const char *path)
#define KEEPWAL_INITIAL_SIZE
static file_entry_t * insert_filehash_entry(const char *path)
static bool check_file_excluded(const char *path, bool is_source)
#define FILEHASH_INITIAL_SIZE
static int final_filemap_cmp(const void *a, const void *b)
void calculate_totals(filemap_t *filemap)
filemap_t * decide_file_actions(XLogSegNo last_common_segno)
static file_content_type_t getFileContentType(const char *path)
@ FILE_CONTENT_TYPE_OTHER
@ FILE_CONTENT_TYPE_RELATION
Assert(PointerIsAligned(start, uint64))
#define pg_log_debug(...)
char * pstrdup(const char *in)
void pfree(void *pointer)
char * last_dir_separator(const char *filename)
#define qsort(a, b, c, d)
char * psprintf(const char *fmt,...)
#define InvalidRelFileNumber
#define relpathperm(rlocator, forknum)
#define TABLESPACE_VERSION_DIRECTORY
bool pg_str_endswith(const char *str, const char *end)
char str[REL_PATH_STR_MAXLEN+1]
datapagemap_t target_pages_to_overwrite
char * source_link_target
file_content_type_t content_type
char * target_link_target
file_entry_t * entries[FLEXIBLE_ARRAY_MEMBER]
#define XLOG_CONTROL_FILE
static bool IsXLogFileName(const char *fname)
static void XLogFromFileName(const char *fname, TimeLineID *tli, XLogSegNo *logSegNo, int wal_segsz_bytes)