@@ -28,6 +28,9 @@ static int server_version = 0;
28
28
29
29
static bool in_backup = false;/* TODO: more robust logic */
30
30
31
+ /* list of files contained in backup */
32
+ parray * backup_files_list ;
33
+
31
34
/*
32
35
* Backup routines
33
36
*/
@@ -48,6 +51,7 @@ static void create_file_list(parray *files,
48
51
const char * subdir ,
49
52
const char * prefix ,
50
53
bool is_append );
54
+ static void wait_for_archive (pgBackup * backup ,const char * sql );
51
55
52
56
/*
53
57
* Take a backup of database and return the list of files backed up.
@@ -56,7 +60,6 @@ static parray *
56
60
do_backup_database (parray * backup_list ,pgBackupOption bkupopt )
57
61
{
58
62
int i ;
59
- parray * files ;/* backup file list from non-snapshot */
60
63
parray * prev_files = NULL ;/* file list of previous database backup */
61
64
FILE * fp ;
62
65
char path [MAXPGPATH ];
@@ -68,6 +71,7 @@ do_backup_database(parray *backup_list, pgBackupOption bkupopt)
68
71
69
72
/* repack the options */
70
73
bool smooth_checkpoint = bkupopt .smooth_checkpoint ;
74
+ pgBackup * prev_backup = NULL ;
71
75
72
76
/* Block backup operations on a standby */
73
77
if (pg_is_standby ())
@@ -78,6 +82,9 @@ do_backup_database(parray *backup_list, pgBackupOption bkupopt)
78
82
/* Initialize size summary */
79
83
current .data_bytes = 0 ;
80
84
85
+ /* do some checks on the node */
86
+ sanityChecks ();
87
+
81
88
/*
82
89
* Obtain current timeline by scanning control file, theh LSN
83
90
* obtained at output of pg_start_backup or pg_stop_backup does
@@ -123,8 +130,8 @@ do_backup_database(parray *backup_list, pgBackupOption bkupopt)
123
130
* List directories and symbolic links with the physical path to make
124
131
* mkdirs.sh, then sort them in order of path. Omit $PGDATA.
125
132
*/
126
- files = parray_new ();
127
- dir_list_file (files ,pgdata ,NULL , false, false);
133
+ backup_files_list = parray_new ();
134
+ dir_list_file (backup_files_list ,pgdata ,NULL , false, false);
128
135
129
136
if (!check )
130
137
{
@@ -133,26 +140,24 @@ do_backup_database(parray *backup_list, pgBackupOption bkupopt)
133
140
if (fp == NULL )
134
141
elog (ERROR_SYSTEM ,"can't open make directory script \"%s\": %s" ,
135
142
path ,strerror (errno ));
136
- dir_print_mkdirs_sh (fp ,files ,pgdata );
143
+ dir_print_mkdirs_sh (fp ,backup_files_list ,pgdata );
137
144
fclose (fp );
138
145
if (chmod (path ,DIR_PERMISSION )== -1 )
139
146
elog (ERROR_SYSTEM ,"can't change mode of \"%s\": %s" ,path ,
140
147
strerror (errno ));
141
148
}
142
149
143
150
/* clear directory list */
144
- parray_walk (files ,pgFileFree );
145
- parray_free (files );
146
- files = NULL ;
151
+ parray_walk (backup_files_list ,pgFileFree );
152
+ parray_free (backup_files_list );
153
+ backup_files_list = NULL ;
147
154
148
155
/*
149
156
* To take differential backup, the file list of the last completed database
150
157
* backup is needed.
151
158
*/
152
159
if (current .backup_mode == BACKUP_MODE_DIFF_PAGE )
153
160
{
154
- pgBackup * prev_backup ;
155
-
156
161
/* find last completed database backup */
157
162
prev_backup = catalog_get_last_data_backup (backup_list ,current .tli );
158
163
pgBackupGetPath (prev_backup ,prev_file_txt ,lengthof (prev_file_txt ),
@@ -167,26 +172,55 @@ do_backup_database(parray *backup_list, pgBackupOption bkupopt)
167
172
(uint32 ) (* lsn >>32 ), (uint32 )* lsn );
168
173
}
169
174
170
- /* initialize backup listfrom non-snapshot */
171
- files = parray_new ();
175
+ /* initialize backup list */
176
+ backup_files_list = parray_new ();
172
177
173
178
/* list files with the logical path. omit $PGDATA */
174
- add_files (files ,pgdata , false, true);
179
+ add_files (backup_files_list ,pgdata , false, true);
175
180
176
181
/* backup files */
177
182
pgBackupGetPath (& current ,path ,lengthof (path ),DATABASE_DIR );
178
- backup_files (pgdata ,path ,files ,prev_files ,lsn ,NULL );
183
+
184
+ /*
185
+ * Build page mapping in differential mode. When using this mode, the
186
+ * list of blocks to be taken is known by scanning the WAL segments
187
+ * present in archives up to the point where start backup has begun.
188
+ * However, normally this segment is not yet available in the archives,
189
+ * leading to failures when building the page map. Hence before doing
190
+ * anything and in order to ensure that all the segments needed for the
191
+ * scan are here, for a switch of the last segment with pg_switch_xlog.
192
+ */
193
+ if (current .backup_mode == BACKUP_MODE_DIFF_PAGE )
194
+ {
195
+ /* Enforce archiving of last segment and wait for it to be here */
196
+ wait_for_archive (& current ,"SELECT * FROM pg_switch_xlog()" );
197
+
198
+ /* Now build the page map */
199
+ parray_qsort (backup_files_list ,pgFileComparePathDesc );
200
+ elog (LOG ,"extractPageMap" );
201
+ elog (LOG ,"current_tli:%X" ,current .tli );
202
+ elog (LOG ,"prev_backup->start_lsn: %X/%X" ,
203
+ (uint32 ) (prev_backup -> start_lsn >>32 ),
204
+ (uint32 ) (prev_backup -> start_lsn ));
205
+ elog (LOG ,"current.start_lsn: %X/%X" ,
206
+ (uint32 ) (current .start_lsn >>32 ),
207
+ (uint32 ) (current .start_lsn ));
208
+ extractPageMap (arclog_path ,prev_backup -> start_lsn ,current .tli ,
209
+ current .start_lsn );
210
+ }
211
+
212
+ backup_files (pgdata ,path ,backup_files_list ,prev_files ,lsn ,NULL );
179
213
180
214
/* notify end of backup */
181
215
pg_stop_backup (& current );
182
216
183
217
/* create file list */
184
- create_file_list (files ,pgdata ,DATABASE_FILE_LIST ,NULL , false);
218
+ create_file_list (backup_files_list ,pgdata ,DATABASE_FILE_LIST ,NULL , false);
185
219
186
220
/* print summary of size of backup mode files */
187
- for (i = 0 ;i < parray_num (files );i ++ )
221
+ for (i = 0 ;i < parray_num (backup_files_list );i ++ )
188
222
{
189
- pgFile * file = (pgFile * )parray_get (files ,i );
223
+ pgFile * file = (pgFile * )parray_get (backup_files_list ,i );
190
224
if (!S_ISREG (file -> mode ))
191
225
continue ;
192
226
/*
@@ -204,7 +238,7 @@ do_backup_database(parray *backup_list, pgBackupOption bkupopt)
204
238
current .data_bytes );
205
239
elog (LOG ,"========================================" );
206
240
207
- return files ;
241
+ return backup_files_list ;
208
242
}
209
243
210
244
@@ -654,7 +688,6 @@ backup_files(const char *from_root,
654
688
}
655
689
else
656
690
{
657
- elog (LOG ,"\n" );
658
691
elog (ERROR_SYSTEM ,
659
692
"can't stat backup mode. \"%s\": %s" ,
660
693
file -> path ,strerror (errno ));
@@ -825,3 +858,72 @@ create_file_list(parray *files,
825
858
fclose (fp );
826
859
}
827
860
}
861
+
862
+ /*
863
+ * A helper function to create the path of a relation file and segment.
864
+ *
865
+ * The returned path is palloc'd
866
+ */
867
+ static char *
868
+ datasegpath (RelFileNode rnode ,ForkNumber forknum ,BlockNumber segno )
869
+ {
870
+ char * path ;
871
+ char * segpath ;
872
+
873
+ path = relpathperm (rnode ,forknum );
874
+ if (segno > 0 )
875
+ {
876
+ segpath = psprintf ("%s.%u" ,path ,segno );
877
+ pfree (path );
878
+ return segpath ;
879
+ }
880
+ else
881
+ return path ;
882
+ }
883
+
884
+ /*
885
+ * This routine gets called while reading WAL segments from the WAL archive,
886
+ * for every block that have changed in the target system. It makes note of
887
+ * all the changed blocks in the pagemap of the file and adds them in the
888
+ * things to track for the backup.
889
+ */
890
+ void
891
+ process_block_change (ForkNumber forknum ,RelFileNode rnode ,BlockNumber blkno )
892
+ {
893
+ char * path ;
894
+ char * rel_path ;
895
+ BlockNumber blkno_inseg ;
896
+ int segno ;
897
+ pgFile * file_item = NULL ;
898
+ int j ;
899
+
900
+ segno = blkno /RELSEG_SIZE ;
901
+ blkno_inseg = blkno %RELSEG_SIZE ;
902
+
903
+ rel_path = datasegpath (rnode ,forknum ,segno );
904
+ path = pg_malloc (strlen (rel_path )+ strlen (pgdata )+ 2 );
905
+ sprintf (path ,"%s/%s" ,pgdata ,rel_path );
906
+
907
+ for (j = 0 ;j < parray_num (backup_files_list );j ++ )
908
+ {
909
+ pgFile * p = (pgFile * )parray_get (backup_files_list ,j );
910
+
911
+ if (strcmp (p -> path ,path )== 0 )
912
+ {
913
+ file_item = p ;
914
+ break ;
915
+ }
916
+ }
917
+
918
+ /*
919
+ * If we don't have any record of this file in the file map, it means
920
+ * that it's a relation that did not have much activity since the last
921
+ * backup. We can safely ignore it. If it is a new relation file, the
922
+ * backup would simply copy it as-is.
923
+ */
924
+ if (file_item )
925
+ datapagemap_add (& file_item -> pagemap ,blkno_inseg );
926
+
927
+ pg_free (path );
928
+ pg_free (rel_path );
929
+ }