@@ -153,6 +153,10 @@ do_backup_instance(PGconn *backup_conn, PGNodeInfo *nodeInfo, bool no_sync)
153153 PGconn * master_conn = NULL ;
154154 PGconn * pg_startbackup_conn = NULL ;
155155
156+ /* used for multitimeline incremental backup */
157+ parray * tli_list = NULL ;
158+
159+
156160 /* for fancy reporting */
157161 time_t start_time , end_time ;
158162 char pretty_time [20 ];
@@ -181,17 +185,43 @@ do_backup_instance(PGconn *backup_conn, PGNodeInfo *nodeInfo, bool no_sync)
181185 current .backup_mode == BACKUP_MODE_DIFF_PTRACK ||
182186 current .backup_mode == BACKUP_MODE_DIFF_DELTA )
183187 {
184- char prev_backup_filelist_path [MAXPGPATH ];
185-
186188 /* get list of backups already taken */
187189 backup_list = catalog_get_backup_list (instance_name , INVALID_BACKUP_ID );
188190
189191 prev_backup = catalog_get_last_data_backup (backup_list , current .tli , current .start_time );
190192 if (prev_backup == NULL )
191- elog (ERROR , "Valid backup on current timeline %X is not found. "
192- "Create new FULL backup before an incremental one." ,
193+ {
194+ /* try to setup multi-timeline backup chain */
195+ elog (WARNING , "Valid backup on current timeline %u is not found, "
196+ "try to look up on previous timelines" ,
193197 current .tli );
194198
199+ tli_list = catalog_get_timelines (& instance_config );
200+
201+ if (parray_num (tli_list ) == 0 )
202+ elog (WARNING , "Cannot find valid backup on previous timelines, "
203+ "WAL archive is not available" );
204+ else
205+ {
206+ prev_backup = get_multi_timeline_parent (backup_list , tli_list , current .tli ,
207+ current .start_time , & instance_config );
208+
209+ if (prev_backup == NULL )
210+ elog (WARNING , "Cannot find valid backup on previous timelines" );
211+ }
212+
213+ /* failed to find suitable parent, error out */
214+ if (!prev_backup )
215+ elog (ERROR , "Create new full backup before an incremental one" );
216+ }
217+ }
218+
219+ if (prev_backup )
220+ {
221+ char prev_backup_filelist_path [MAXPGPATH ];
222+
223+ elog (INFO , "Parent backup: %s" , base36enc (prev_backup -> start_time ));
224+
195225 join_path_components (prev_backup_filelist_path , prev_backup -> root_dir ,
196226 DATABASE_FILE_LIST );
197227 /* Files of previous backup needed by DELTA backup */
@@ -378,8 +408,10 @@ do_backup_instance(PGconn *backup_conn, PGNodeInfo *nodeInfo, bool no_sync)
378408 if (current .backup_mode == BACKUP_MODE_DIFF_PAGE ||
379409 current .backup_mode == BACKUP_MODE_DIFF_PTRACK )
380410 {
381- elog (INFO , "Compiling pagemap of changed blocks" );
411+ bool pagemap_isok = true;
412+
382413 time (& start_time );
414+ elog (INFO , "Extracting pagemap of changed blocks" );
383415
384416 if (current .backup_mode == BACKUP_MODE_DIFF_PAGE )
385417 {
@@ -388,8 +420,9 @@ do_backup_instance(PGconn *backup_conn, PGNodeInfo *nodeInfo, bool no_sync)
388420 * reading WAL segments present in archives up to the point
389421 * where this backup has started.
390422 */
391- extractPageMap (arclog_path , current .tli , instance_config .xlog_seg_size ,
392- prev_backup -> start_lsn , current .start_lsn );
423+ pagemap_isok = extractPageMap (arclog_path , instance_config .xlog_seg_size ,
424+ prev_backup -> start_lsn , prev_backup -> tli ,
425+ current .start_lsn , current .tli , tli_list );
393426 }
394427 else if (current .backup_mode == BACKUP_MODE_DIFF_PTRACK )
395428 {
@@ -407,8 +440,14 @@ do_backup_instance(PGconn *backup_conn, PGNodeInfo *nodeInfo, bool no_sync)
407440 }
408441
409442 time (& end_time );
410- elog (INFO , "Pagemap compiled, time elapsed %.0f sec" ,
411- difftime (end_time , start_time ));
443+
444+ /* TODO: add ms precision */
445+ if (pagemap_isok )
446+ elog (INFO , "Pagemap successfully extracted, time elapsed %.0f sec" ,
447+ difftime (end_time , start_time ));
448+ else
449+ elog (ERROR , "Pagemap extraction failed, time elasped: %.0f sec" ,
450+ difftime (end_time , start_time ));
412451 }
413452
414453 /*
@@ -667,6 +706,15 @@ do_backup_instance(PGconn *backup_conn, PGNodeInfo *nodeInfo, bool no_sync)
667706 elog (INFO , "Backup files are synced, time elapsed: %s" , pretty_time );
668707 }
669708
709+ /* be paranoid about instance been from the past */
710+ if (current .backup_mode != BACKUP_MODE_FULL &&
711+ current .stop_lsn < prev_backup -> stop_lsn )
712+ elog (ERROR , "Current backup STOP LSN %X/%X is lower than STOP LSN %X/%X of previous backup %s. "
713+ "It may indicate that we are trying to backup PostgreSQL instance from the past." ,
714+ (uint32 ) (current .stop_lsn >> 32 ), (uint32 ) (current .stop_lsn ),
715+ (uint32 ) (prev_backup -> stop_lsn >> 32 ), (uint32 ) (prev_backup -> stop_lsn ),
716+ base36enc (prev_backup -> stop_lsn ));
717+
670718 /* clean external directories list */
671719 if (external_dirs )
672720 free_dir_list (external_dirs );
@@ -678,6 +726,12 @@ do_backup_instance(PGconn *backup_conn, PGNodeInfo *nodeInfo, bool no_sync)
678726 parray_free (backup_list );
679727 }
680728
729+ if (tli_list )
730+ {
731+ parray_walk (tli_list , timelineInfoFree );
732+ parray_free (tli_list );
733+ }
734+
681735 parray_walk (backup_files_list , pgFileFree );
682736 parray_free (backup_files_list );
683737 backup_files_list = NULL ;
0 commit comments