1919
2020#include "libpq/pqsignal.h"
2121#include "pgut/pgut-port.h"
22+ #include "storage/bufpage.h"
23+ #include "datapagemap.h"
2224
2325/* wait 10 sec until WAL archive complete */
2426#define TIMEOUT_ARCHIVE 10
@@ -44,6 +46,7 @@ static void pg_stop_backup(pgBackup *backup);
4446static bool pg_is_standby (void );
4547static void get_lsn (PGresult * res ,XLogRecPtr * lsn );
4648static void get_xid (PGresult * res ,uint32 * xid );
49+ static void pg_ptrack_clear (void );
4750
4851static void add_files (parray * files ,const char * root ,bool add_root ,bool is_pgdata );
4952static void create_file_list (parray * files ,
@@ -52,6 +55,7 @@ static void create_file_list(parray *files,
5255const char * prefix ,
5356bool is_append );
5457static void wait_for_archive (pgBackup * backup ,const char * sql );
58+ static void make_pagemap_from_ptrack (parray * files );
5559
5660/*
5761 * 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)
96100 * In differential backup mode, check if there is an already-validated
97101 * full backup on current timeline.
98102 */
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 )
100105{
101106pgBackup * prev_backup ;
102107
@@ -156,7 +161,8 @@ do_backup_database(parray *backup_list, pgBackupOption bkupopt)
156161 * To take differential backup, the file list of the last completed database
157162 * backup is needed.
158163 */
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 )
160166{
161167/* find last completed database backup */
162168prev_backup = catalog_get_last_data_backup (backup_list ,current .tli );
@@ -209,15 +215,24 @@ do_backup_database(parray *backup_list, pgBackupOption bkupopt)
209215current .start_lsn );
210216}
211217
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+
212224backup_files (pgdata ,path ,backup_files_list ,prev_files ,lsn ,NULL );
213225
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 */
215230pg_stop_backup (& current );
216231
217- /*create file list */
232+ /*Create file list */
218233create_file_list (backup_files_list ,pgdata ,DATABASE_FILE_LIST ,NULL , false);
219234
220- /*print summary of size of backup mode files */
235+ /*Print summary of size of backup mode files */
221236for (i = 0 ;i < parray_num (backup_files_list );i ++ )
222237{
223238pgFile * file = (pgFile * )parray_get (backup_files_list ,i );
@@ -228,7 +243,8 @@ do_backup_database(parray *backup_list, pgBackupOption bkupopt)
228243 * amount of data written counts while for an differential
229244 * backup only the data read counts.
230245 */
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 )
232248current .data_bytes += file -> read_size ;
233249else if (current .backup_mode == BACKUP_MODE_FULL )
234250current .data_bytes += file -> size ;
@@ -332,7 +348,8 @@ do_backup(pgBackupOption bkupopt)
332348
333349/* Database data */
334350if (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 )
336353total_read += current .data_bytes ;
337354
338355if (total_read == 0 )
@@ -435,6 +452,17 @@ pg_start_backup(const char *label, bool smooth, pgBackup *backup)
435452disconnect ();
436453}
437454
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+
438466static void
439467wait_for_archive (pgBackup * backup ,const char * sql )
440468{
@@ -806,6 +834,7 @@ add_files(parray *files, const char *root, bool add_root, bool is_pgdata)
806834pgFile * file = (pgFile * )parray_get (list_file ,i );
807835char * relative ;
808836char * fname ;
837+ int path_len ;
809838
810839/* data file must be a regular file */
811840if (!S_ISREG (file -> mode ))
@@ -819,6 +848,27 @@ add_files(parray *files, const char *root, bool add_root, bool is_pgdata)
819848!path_is_prefix_of_path ("pg_tblspc" ,relative ))
820849continue ;
821850
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+
822872/* name of data file start with digit */
823873fname = last_dir_separator (relative );
824874if (fname == NULL )
@@ -927,3 +977,42 @@ process_block_change(ForkNumber forknum, RelFileNode rnode, BlockNumber blkno)
927977pg_free (path );
928978pg_free (rel_path );
929979}
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+ }