19
19
20
20
#include "libpq/pqsignal.h"
21
21
#include "pgut/pgut-port.h"
22
+ #include "storage/bufpage.h"
23
+ #include "datapagemap.h"
22
24
23
25
/* wait 10 sec until WAL archive complete */
24
26
#define TIMEOUT_ARCHIVE 10
@@ -44,6 +46,7 @@ static void pg_stop_backup(pgBackup *backup);
44
46
static bool pg_is_standby (void );
45
47
static void get_lsn (PGresult * res ,XLogRecPtr * lsn );
46
48
static void get_xid (PGresult * res ,uint32 * xid );
49
+ static void pg_ptrack_clear (void );
47
50
48
51
static void add_files (parray * files ,const char * root ,bool add_root ,bool is_pgdata );
49
52
static void create_file_list (parray * files ,
@@ -52,6 +55,7 @@ static void create_file_list(parray *files,
52
55
const char * prefix ,
53
56
bool is_append );
54
57
static void wait_for_archive (pgBackup * backup ,const char * sql );
58
+ static void make_pagemap_from_ptrack (parray * files );
55
59
56
60
/*
57
61
* Take a backup of database and return the list of files backed up.
@@ -96,7 +100,8 @@ do_backup_database(parray *backup_list, pgBackupOption bkupopt)
96
100
* In differential backup mode, check if there is an already-validated
97
101
* full backup on current timeline.
98
102
*/
99
- if (current .backup_mode == BACKUP_MODE_DIFF_PAGE )
103
+ if (current .backup_mode == BACKUP_MODE_DIFF_PAGE ||
104
+ current .backup_mode == BACKUP_MODE_DIFF_PTRACK )
100
105
{
101
106
pgBackup * prev_backup ;
102
107
@@ -156,7 +161,8 @@ do_backup_database(parray *backup_list, pgBackupOption bkupopt)
156
161
* To take differential backup, the file list of the last completed database
157
162
* backup is needed.
158
163
*/
159
- if (current .backup_mode == BACKUP_MODE_DIFF_PAGE )
164
+ if (current .backup_mode == BACKUP_MODE_DIFF_PAGE ||
165
+ current .backup_mode == BACKUP_MODE_DIFF_PTRACK )
160
166
{
161
167
/* find last completed database backup */
162
168
prev_backup = catalog_get_last_data_backup (backup_list ,current .tli );
@@ -209,15 +215,24 @@ do_backup_database(parray *backup_list, pgBackupOption bkupopt)
209
215
current .start_lsn );
210
216
}
211
217
218
+ if (current .backup_mode == BACKUP_MODE_DIFF_PTRACK )
219
+ {
220
+ parray_qsort (backup_files_list ,pgFileComparePathDesc );
221
+ make_pagemap_from_ptrack (backup_files_list );
222
+ }
223
+
212
224
backup_files (pgdata ,path ,backup_files_list ,prev_files ,lsn ,NULL );
213
225
214
- /* notify end of backup */
226
+ /* Clear ptrack files after backup */
227
+ if (current .backup_mode == BACKUP_MODE_DIFF_PTRACK )
228
+ pg_ptrack_clear ();
229
+ /* Notify end of backup */
215
230
pg_stop_backup (& current );
216
231
217
- /*create file list */
232
+ /*Create file list */
218
233
create_file_list (backup_files_list ,pgdata ,DATABASE_FILE_LIST ,NULL , false);
219
234
220
- /*print summary of size of backup mode files */
235
+ /*Print summary of size of backup mode files */
221
236
for (i = 0 ;i < parray_num (backup_files_list );i ++ )
222
237
{
223
238
pgFile * file = (pgFile * )parray_get (backup_files_list ,i );
@@ -228,7 +243,8 @@ do_backup_database(parray *backup_list, pgBackupOption bkupopt)
228
243
* amount of data written counts while for an differential
229
244
* backup only the data read counts.
230
245
*/
231
- if (current .backup_mode == BACKUP_MODE_DIFF_PAGE )
246
+ if (current .backup_mode == BACKUP_MODE_DIFF_PAGE ||
247
+ current .backup_mode == BACKUP_MODE_DIFF_PTRACK )
232
248
current .data_bytes += file -> read_size ;
233
249
else if (current .backup_mode == BACKUP_MODE_FULL )
234
250
current .data_bytes += file -> size ;
@@ -332,7 +348,8 @@ do_backup(pgBackupOption bkupopt)
332
348
333
349
/* Database data */
334
350
if (current .backup_mode == BACKUP_MODE_FULL ||
335
- current .backup_mode == BACKUP_MODE_DIFF_PAGE )
351
+ current .backup_mode == BACKUP_MODE_DIFF_PAGE ||
352
+ current .backup_mode == BACKUP_MODE_DIFF_PTRACK )
336
353
total_read += current .data_bytes ;
337
354
338
355
if (total_read == 0 )
@@ -435,6 +452,17 @@ pg_start_backup(const char *label, bool smooth, pgBackup *backup)
435
452
disconnect ();
436
453
}
437
454
455
+ static void
456
+ pg_ptrack_clear (void )
457
+ {
458
+ PGresult * res ;
459
+
460
+ reconnect ();
461
+ res = execute ("select pg_ptrack_clear()" ,0 ,NULL );
462
+ PQclear (res );
463
+ disconnect ();
464
+ }
465
+
438
466
static void
439
467
wait_for_archive (pgBackup * backup ,const char * sql )
440
468
{
@@ -806,6 +834,7 @@ add_files(parray *files, const char *root, bool add_root, bool is_pgdata)
806
834
pgFile * file = (pgFile * )parray_get (list_file ,i );
807
835
char * relative ;
808
836
char * fname ;
837
+ int path_len ;
809
838
810
839
/* data file must be a regular file */
811
840
if (!S_ISREG (file -> mode ))
@@ -819,6 +848,27 @@ add_files(parray *files, const char *root, bool add_root, bool is_pgdata)
819
848
!path_is_prefix_of_path ("pg_tblspc" ,relative ))
820
849
continue ;
821
850
851
+ path_len = strlen (file -> path );
852
+ if (path_len > 6 && strncmp (file -> path + (path_len - 6 ),"ptrack" ,6 )== 0 )
853
+ {
854
+ pgFile tmp_file ;
855
+ pgFile * search_file ;
856
+ //elog(WARNING, "Remove ptrack file from backup %s", file->path);
857
+ tmp_file .path = pg_strdup (file -> path );
858
+ tmp_file .path [path_len - 7 ]= '\0' ;
859
+ search_file = * (pgFile * * )parray_bsearch (list_file ,& tmp_file ,pgFileComparePath );
860
+ if (search_file != NULL )
861
+ {
862
+ //elog(WARNING, "Finded main fork for ptrak:%s", search_file->path);
863
+ search_file -> ptrack_path = pg_strdup (file -> path );
864
+ }
865
+ free (tmp_file .path );
866
+ pgFileFree (file );
867
+ parray_remove (list_file ,i );
868
+ i -- ;
869
+ continue ;
870
+ }
871
+
822
872
/* name of data file start with digit */
823
873
fname = last_dir_separator (relative );
824
874
if (fname == NULL )
@@ -927,3 +977,42 @@ process_block_change(ForkNumber forknum, RelFileNode rnode, BlockNumber blkno)
927
977
pg_free (path );
928
978
pg_free (rel_path );
929
979
}
980
+
981
+ void make_pagemap_from_ptrack (parray * files )
982
+ {
983
+ int i ;
984
+ for (i = 0 ;i < parray_num (files );i ++ )
985
+ {
986
+ pgFile * p = (pgFile * )parray_get (files ,i );
987
+ if (p -> ptrack_path != NULL )
988
+ {
989
+ DataPage page ;
990
+ int i ;
991
+ struct stat st ;
992
+ FILE * ptrack_file = fopen (p -> ptrack_path ,"r" );
993
+ if (ptrack_file == NULL )
994
+ {
995
+ elog (ERROR ,"cannot open ptrack file \"%s\": %s" ,p -> ptrack_path ,
996
+ strerror (errno ));
997
+ }
998
+
999
+ elog (LOG ,"Start copy bitmap from ptrack:%s" ,p -> ptrack_path );
1000
+ fstat (fileno (ptrack_file ),& st );
1001
+ p -> pagemap .bitmapsize = st .st_size - (st .st_size /BLCKSZ )* MAXALIGN (SizeOfPageHeaderData );
1002
+ p -> pagemap .bitmap = pg_malloc (p -> pagemap .bitmapsize );
1003
+ while (fread (page .data ,BLCKSZ ,1 ,ptrack_file )== BLCKSZ )
1004
+ {
1005
+ char * map = PageGetContents (page .data );
1006
+ memcpy (p -> pagemap .bitmap ,map ,BLCKSZ - MAXALIGN (SizeOfPageHeaderData ));
1007
+ }
1008
+ fclose (ptrack_file );
1009
+ for (i = 0 ;i < p -> pagemap .bitmapsize ;i ++ )
1010
+ if (p -> pagemap .bitmap [i ]!= 0 )
1011
+ gotoend_loop ;
1012
+
1013
+ pg_free (p -> pagemap .bitmap );
1014
+ p -> pagemap .bitmapsize = 0 ;
1015
+ }
1016
+ end_loop :;
1017
+ }
1018
+ }