@@ -39,6 +39,8 @@ typedef struct
3939 int ret ;
4040} restore_files_arg ;
4141
42+ static bool control_downloaded = false;
43+ static ControlFileData instance_control ;
4244
4345static void
4446print_recovery_settings (InstanceState * instanceState , FILE * fp , pgBackup * backup ,
@@ -501,6 +503,9 @@ do_restore_or_validate(InstanceState *instanceState, time_t target_backup_id, pg
501503 if (redo .checksum_version == 0 )
502504 elog (ERROR , "Incremental restore in 'lsn' mode require "
503505 "data_checksums to be enabled in destination data directory" );
506+ if (!control_downloaded )
507+ get_control_file_or_back_file (instance_config .pgdata , FIO_DB_HOST ,
508+ & instance_control );
504509
505510 timelines = read_timeline_history (instanceState -> instance_wal_subdir_path ,
506511 redo .tli , false);
@@ -719,6 +724,10 @@ restore_chain(pgBackup *dest_backup, parray *parent_chain,
719724 parray * pgdata_files = NULL ;
720725 parray * dest_files = NULL ;
721726 parray * external_dirs = NULL ;
727+ pgFile * dest_pg_control_file = NULL ;
728+ char dest_pg_control_fullpath [MAXPGPATH ];
729+ char dest_pg_control_bak_fullpath [MAXPGPATH ];
730+
722731 /* arrays with meta info for multi threaded backup */
723732 pthread_t * threads ;
724733 restore_files_arg * threads_args ;
@@ -922,6 +931,11 @@ restore_chain(pgBackup *dest_backup, parray *parent_chain,
922931 pg_strcasecmp (file -> name , RELMAPPER_FILENAME ) == 0 )
923932 redundant = true;
924933
934+ /* global/pg_control.pbk.bak are always keeped, because it's needed for restart failed incremental restore */
935+ if (file -> external_dir_num == 0 &&
936+ pg_strcasecmp (file -> rel_path , XLOG_CONTROL_BAK_FILE ) == 0 )
937+ redundant = false;
938+
925939 /* do not delete the useful internal directories */
926940 if (S_ISDIR (file -> mode ) && !redundant )
927941 continue ;
@@ -974,6 +988,42 @@ restore_chain(pgBackup *dest_backup, parray *parent_chain,
974988 dest_bytes = dest_backup -> pgdata_bytes ;
975989
976990 pretty_size (dest_bytes , pretty_dest_bytes , lengthof (pretty_dest_bytes ));
991+ /*
992+ * [Issue #313]
993+ * find pg_control file (in already sorted earlier dest_files, see parray_qsort(backup->files...))
994+ * and exclude it from list for future special processing
995+ */
996+ {
997+ int control_file_elem_index ;
998+ pgFile search_key ;
999+ MemSet (& search_key , 0 , sizeof (pgFile ));
1000+ /* pgFileCompareRelPathWithExternal uses only .rel_path and .external_dir_num for comparision */
1001+ search_key .rel_path = XLOG_CONTROL_FILE ;
1002+ search_key .external_dir_num = 0 ;
1003+ control_file_elem_index = parray_bsearch_index (dest_files , & search_key , pgFileCompareRelPathWithExternal );
1004+
1005+ if (control_file_elem_index < 0 )
1006+ elog (ERROR , "File \"%s\" not found in backup %s" , XLOG_CONTROL_FILE , base36enc (dest_backup -> start_time ));
1007+ dest_pg_control_file = (pgFile * ) parray_get (dest_files , control_file_elem_index );
1008+ parray_remove (dest_files , control_file_elem_index );
1009+
1010+ join_path_components (dest_pg_control_fullpath , pgdata_path , XLOG_CONTROL_FILE );
1011+ join_path_components (dest_pg_control_bak_fullpath , pgdata_path , XLOG_CONTROL_BAK_FILE );
1012+ /*
1013+ * rename (if it exist) dest control file before restoring
1014+ * if it doesn't exist, that mean, that we already restoring in a previously failed
1015+ * pgdata, where XLOG_CONTROL_BAK_FILE exist
1016+ */
1017+ if (params -> incremental_mode != INCR_NONE )
1018+ {
1019+ if (fio_access (dest_pg_control_fullpath ,F_OK ,FIO_DB_HOST ) == 0 ){
1020+ if (fio_rename (dest_pg_control_fullpath , dest_pg_control_bak_fullpath , FIO_DB_HOST ) < 0 )
1021+ elog (WARNING , "Cannot rename file \"%s\" to \"%s\": %s" ,
1022+ dest_pg_control_fullpath , dest_pg_control_bak_fullpath , strerror (errno ));
1023+ }
1024+ }
1025+ }
1026+
9771027 elog (INFO , "Start restoring backup files. PGDATA size: %s" , pretty_dest_bytes );
9781028 time (& start_time );
9791029 thread_interrupted = false;
@@ -1014,6 +1064,32 @@ restore_chain(pgBackup *dest_backup, parray *parent_chain,
10141064 total_bytes += threads_args [i ].restored_bytes ;
10151065 }
10161066
1067+ /* [Issue #313] copy pg_control at very end */
1068+ if (restore_isok )
1069+ {
1070+ FILE * out = NULL ;
1071+ elog (progress ? INFO : LOG , "Progress: Restore file \"%s\"" ,
1072+ dest_pg_control_file -> rel_path );
1073+
1074+ out = fio_fopen (dest_pg_control_fullpath , PG_BINARY_R "+" , FIO_DB_HOST );
1075+
1076+ total_bytes += restore_non_data_file (parent_chain ,
1077+ dest_backup ,
1078+ dest_pg_control_file ,
1079+ out ,
1080+ dest_pg_control_fullpath , false);
1081+ fio_fclose (out );
1082+ /* Now backup control file can be deleted */
1083+ if (params -> incremental_mode != INCR_NONE )
1084+ {
1085+ pgFile * dst_control ;
1086+ dst_control = pgFileNew (dest_pg_control_bak_fullpath , XLOG_CONTROL_BAK_FILE ,
1087+ true,0 , FIO_BACKUP_HOST );
1088+ fio_delete (dst_control -> mode , dest_pg_control_bak_fullpath , FIO_LOCAL_HOST );
1089+ pgFileFree (dst_control );
1090+ }
1091+ }
1092+
10171093 time (& end_time );
10181094 pretty_time_interval (difftime (end_time , start_time ),
10191095 pretty_time , lengthof (pretty_time ));
@@ -1098,6 +1174,8 @@ restore_chain(pgBackup *dest_backup, parray *parent_chain,
10981174 parray_free (pgdata_files );
10991175 }
11001176
1177+ if (dest_pg_control_file ) pgFileFree (dest_pg_control_file );
1178+
11011179 for (i = parray_num (parent_chain ) - 1 ; i >= 0 ; i -- )
11021180 {
11031181 pgBackup * backup = (pgBackup * ) parray_get (parent_chain , i );
@@ -2230,7 +2308,10 @@ check_incremental_compatibility(const char *pgdata, uint64 system_identifier,
22302308 */
22312309 elog (LOG , "Trying to read pg_control file in destination directory" );
22322310
2233- system_id_pgdata = get_system_identifier (pgdata , FIO_DB_HOST , false);
2311+ get_control_file_or_back_file (pgdata , FIO_DB_HOST , & instance_control );
2312+ control_downloaded = true;
2313+
2314+ system_id_pgdata = instance_control .system_identifier ;
22342315
22352316 if (system_id_pgdata == instance_config .system_identifier )
22362317 system_id_match = true;
0 commit comments