@@ -80,7 +80,7 @@ static void backup_cleanup(bool fatal, void *userdata);
8080
8181static void * backup_files (void * arg );
8282
83- static void do_backup_instance (PGconn * backup_conn , PGNodeInfo * nodeInfo );
83+ static void do_backup_instance (PGconn * backup_conn , PGNodeInfo * nodeInfo , bool no_sync );
8484
8585static void pg_start_backup (const char * label , bool smooth , pgBackup * backup ,
8686 PGNodeInfo * nodeInfo , PGconn * backup_conn , PGconn * master_conn );
@@ -129,7 +129,7 @@ backup_stopbackup_callback(bool fatal, void *userdata)
129129 * Move files from 'pgdata' to a subdirectory in 'backup_path'.
130130 */
131131static void
132- do_backup_instance (PGconn * backup_conn , PGNodeInfo * nodeInfo )
132+ do_backup_instance (PGconn * backup_conn , PGNodeInfo * nodeInfo , bool no_sync )
133133{
134134 int i ;
135135 char database_path [MAXPGPATH ];
@@ -155,6 +155,7 @@ do_backup_instance(PGconn *backup_conn, PGNodeInfo *nodeInfo)
155155
156156 /* for fancy reporting */
157157 time_t start_time , end_time ;
158+ char pretty_time [20 ];
158159 char pretty_bytes [20 ];
159160
160161 elog (LOG , "Database backup start" );
@@ -452,7 +453,7 @@ do_backup_instance(PGconn *backup_conn, PGNodeInfo *nodeInfo)
452453 parray_qsort (backup_files_list , pgFileCompareSize );
453454 /* Sort the array for binary search */
454455 if (prev_backup_filelist )
455- parray_qsort (prev_backup_filelist , pgFileComparePathWithExternal );
456+ parray_qsort (prev_backup_filelist , pgFileCompareRelPathWithExternal );
456457
457458 /* write initial backup_content.control file and update backup.control */
458459 write_backup_filelist (& current , backup_files_list ,
@@ -485,6 +486,7 @@ do_backup_instance(PGconn *backup_conn, PGNodeInfo *nodeInfo)
485486 /* Run threads */
486487 thread_interrupted = false;
487488 elog (INFO , "Start transferring data files" );
489+ time (& start_time );
488490 for (i = 0 ; i < num_threads ; i ++ )
489491 {
490492 backup_files_arg * arg = & (threads_args [i ]);
@@ -500,10 +502,16 @@ do_backup_instance(PGconn *backup_conn, PGNodeInfo *nodeInfo)
500502 if (threads_args [i ].ret == 1 )
501503 backup_isok = false;
502504 }
505+
506+ time (& end_time );
507+ pretty_time_interval (difftime (end_time , start_time ),
508+ pretty_time , lengthof (pretty_time ));
503509 if (backup_isok )
504- elog (INFO , "Data files are transferred" );
510+ elog (INFO , "Data files are transferred, time elapsed: %s" ,
511+ pretty_time );
505512 else
506- elog (ERROR , "Data files transferring failed" );
513+ elog (ERROR , "Data files transferring failed, time elapsed: %s" ,
514+ pretty_time );
507515
508516 /* Remove disappeared during backup files from backup_list */
509517 for (i = 0 ; i < parray_num (backup_files_list ); i ++ )
@@ -589,7 +597,8 @@ do_backup_instance(PGconn *backup_conn, PGNodeInfo *nodeInfo)
589597 {
590598 char * ptr = file -> path ;
591599
592- file -> path = pstrdup (GetRelativePath (ptr , database_path ));
600+ file -> path = pgut_strdup (GetRelativePath (ptr , database_path ));
601+ file -> rel_path = pgut_strdup (file -> path );
593602 free (ptr );
594603 }
595604 }
@@ -613,6 +622,48 @@ do_backup_instance(PGconn *backup_conn, PGNodeInfo *nodeInfo)
613622 /* update backup control file to update size info */
614623 write_backup (& current );
615624
625+ /* Sync all copied files unless '--no-sync' flag is used */
626+ if (no_sync )
627+ elog (WARNING , "Backup files are not synced to disk" );
628+ else
629+ {
630+ elog (INFO , "Syncing backup files to disk" );
631+ time (& start_time );
632+
633+ for (i = 0 ; i < parray_num (backup_files_list ); i ++ )
634+ {
635+ char to_fullpath [MAXPGPATH ];
636+ pgFile * file = (pgFile * ) parray_get (backup_files_list , i );
637+
638+ /* TODO: sync directory ? */
639+ if (S_ISDIR (file -> mode ))
640+ continue ;
641+
642+ if (file -> write_size <= 0 )
643+ continue ;
644+
645+ /* construct fullpath */
646+ if (file -> external_dir_num == 0 )
647+ join_path_components (to_fullpath , database_path , file -> rel_path );
648+ else
649+ {
650+ char external_dst [MAXPGPATH ];
651+
652+ makeExternalDirPathByNum (external_dst , external_prefix ,
653+ file -> external_dir_num );
654+ join_path_components (to_fullpath , external_dst , file -> rel_path );
655+ }
656+
657+ if (fio_sync (to_fullpath , FIO_BACKUP_HOST ) != 0 )
658+ elog (ERROR , "Failed to sync file \"%s\": %s" , to_fullpath , strerror (errno ));
659+ }
660+
661+ time (& end_time );
662+ pretty_time_interval (difftime (end_time , start_time ),
663+ pretty_time , lengthof (pretty_time ));
664+ elog (INFO , "Backup files are synced, time elapsed: %s" , pretty_time );
665+ }
666+
616667 /* clean external directories list */
617668 if (external_dirs )
618669 free_dir_list (external_dirs );
@@ -696,7 +747,7 @@ pgdata_basic_setup(ConnectionOptions conn_opt, PGNodeInfo *nodeInfo)
696747 */
697748int
698749do_backup (time_t start_time , bool no_validate ,
699- pgSetBackupParams * set_backup_params )
750+ pgSetBackupParams * set_backup_params , bool no_sync )
700751{
701752 PGconn * backup_conn = NULL ;
702753 PGNodeInfo nodeInfo ;
@@ -795,7 +846,7 @@ do_backup(time_t start_time, bool no_validate,
795846 elog (ERROR , "Options for connection to master must be provided to perform backup from replica" );
796847
797848 /* backup data */
798- do_backup_instance (backup_conn , & nodeInfo );
849+ do_backup_instance (backup_conn , & nodeInfo , no_sync );
799850 pgut_atexit_pop (backup_cleanup , NULL );
800851
801852 /* compute size of wal files of this backup stored in the archive */
@@ -1928,18 +1979,24 @@ static void *
19281979backup_files (void * arg )
19291980{
19301981 int i ;
1931- backup_files_arg * arguments = ( backup_files_arg * ) arg ;
1932- int n_backup_files_list = parray_num ( arguments -> files_list ) ;
1982+ char from_fullpath [ MAXPGPATH ] ;
1983+ char to_fullpath [ MAXPGPATH ] ;
19331984 static time_t prev_time ;
19341985
1986+ backup_files_arg * arguments = (backup_files_arg * ) arg ;
1987+ int n_backup_files_list = parray_num (arguments -> files_list );
1988+
19351989 prev_time = current .start_time ;
19361990
19371991 /* backup a file */
19381992 for (i = 0 ; i < n_backup_files_list ; i ++ )
19391993 {
1940- int ret ;
1941- struct stat buf ;
1942- pgFile * file = (pgFile * ) parray_get (arguments -> files_list , i );
1994+ pgFile * file = (pgFile * ) parray_get (arguments -> files_list , i );
1995+ pgFile * prev_file = NULL ;
1996+
1997+ /* We have already copied all directories */
1998+ if (S_ISDIR (file -> mode ))
1999+ continue ;
19432000
19442001 if (arguments -> thread_num == 1 )
19452002 {
@@ -1957,147 +2014,91 @@ backup_files(void *arg)
19572014
19582015 if (!pg_atomic_test_set_flag (& file -> lock ))
19592016 continue ;
1960- elog (VERBOSE , "Copying file: \"%s\"" , file -> path );
19612017
19622018 /* check for interrupt */
19632019 if (interrupted || thread_interrupted )
19642020 elog (ERROR , "interrupted during backup" );
19652021
19662022 if (progress )
19672023 elog (INFO , "Progress: (%d/%d). Process file \"%s\"" ,
1968- i + 1 , n_backup_files_list , file -> path );
2024+ i + 1 , n_backup_files_list , file -> rel_path );
19692025
1970- /* stat file to check its current state */
1971- ret = fio_stat (file -> path , & buf , true, FIO_DB_HOST );
1972- if (ret == -1 )
2026+ /* Handle zero sized files */
2027+ if (file -> size == 0 )
19732028 {
1974- if (errno == ENOENT )
1975- {
1976- /*
1977- * If file is not found, this is not en error.
1978- * It could have been deleted by concurrent postgres transaction.
1979- */
1980- file -> write_size = FILE_NOT_FOUND ;
1981- elog (LOG , "File \"%s\" is not found" , file -> path );
1982- continue ;
1983- }
1984- else
1985- {
1986- elog (ERROR ,
1987- "can't stat file to backup \"%s\": %s" ,
1988- file -> path , strerror (errno ));
1989- }
1990- }
1991-
1992- /* We have already copied all directories */
1993- if (S_ISDIR (buf .st_mode ))
2029+ file -> write_size = 0 ;
19942030 continue ;
2031+ }
19952032
1996- if (S_ISREG (buf .st_mode ))
2033+ /* construct destination filepath */
2034+ if (file -> external_dir_num == 0 )
2035+ {
2036+ join_path_components (from_fullpath , arguments -> from_root , file -> rel_path );
2037+ join_path_components (to_fullpath , arguments -> to_root , file -> rel_path );
2038+ }
2039+ else
19972040 {
1998- pgFile * * prev_file = NULL ;
1999- char * external_path = NULL ;
2041+ char external_dst [MAXPGPATH ];
2042+ char * external_path = parray_get (arguments -> external_dirs ,
2043+ file -> external_dir_num - 1 );
20002044
2001- if ( file -> external_dir_num )
2002- external_path = parray_get ( arguments -> external_dirs ,
2003- file -> external_dir_num - 1 );
2045+ makeExternalDirPathByNum ( external_dst ,
2046+ arguments -> external_prefix ,
2047+ file -> external_dir_num );
20042048
2005- /* Check that file exist in previous backup */
2006- if (current .backup_mode != BACKUP_MODE_FULL )
2007- {
2008- char * relative ;
2009- pgFile key ;
2010-
2011- relative = GetRelativePath (file -> path , file -> external_dir_num ?
2012- external_path : arguments -> from_root );
2013- key .path = relative ;
2014- key .external_dir_num = file -> external_dir_num ;
2015-
2016- prev_file = (pgFile * * ) parray_bsearch (arguments -> prev_filelist ,
2017- & key , pgFileComparePathWithExternal );
2018- if (prev_file )
2019- /* File exists in previous backup */
2020- file -> exists_in_prev = true;
2021- }
2049+ join_path_components (to_fullpath , external_dst , file -> rel_path );
2050+ join_path_components (from_fullpath , external_path , file -> rel_path );
2051+ }
20222052
2023- /* copy the file into backup */
2024- if (file -> is_datafile && !file -> is_cfs )
2025- {
2026- char to_path [MAXPGPATH ];
2027-
2028- join_path_components (to_path , arguments -> to_root ,
2029- file -> path + strlen (arguments -> from_root ) + 1 );
2030-
2031- if (current .backup_mode != BACKUP_MODE_FULL )
2032- file -> n_blocks = file -> size /BLCKSZ ;
2033-
2034- /* backup block by block if datafile AND not compressed by cfs*/
2035- if (!backup_data_file (arguments , to_path , file ,
2036- arguments -> prev_start_lsn ,
2037- current .backup_mode ,
2038- instance_config .compress_alg ,
2039- instance_config .compress_level ,
2040- arguments -> nodeInfo -> checksum_version ,
2041- arguments -> nodeInfo -> ptrack_version_num ,
2042- arguments -> nodeInfo -> ptrack_schema ,
2043- true))
2044- {
2045- /* disappeared file not to be confused with 'not changed' */
2046- if (file -> write_size != FILE_NOT_FOUND )
2047- file -> write_size = BYTES_INVALID ;
2048- elog (VERBOSE , "File \"%s\" was not copied to backup" , file -> path );
2049- continue ;
2050- }
2051- }
2052- else if (!file -> external_dir_num &&
2053- strcmp (file -> name , "pg_control" ) == 0 )
2054- copy_pgcontrol_file (arguments -> from_root , FIO_DB_HOST ,
2055- arguments -> to_root , FIO_BACKUP_HOST ,
2056- file );
2057- else
2058- {
2059- const char * dst ;
2060- bool skip = false;
2061- char external_dst [MAXPGPATH ];
2053+ /* Encountered some strange beast */
2054+ if (!S_ISREG (file -> mode ))
2055+ elog (WARNING , "Unexpected type %d of file \"%s\", skipping" ,
2056+ file -> mode , from_fullpath );
20622057
2063- /* If non-data file has not changed since last backup... */
2064- if (prev_file && file -> exists_in_prev &&
2065- buf .st_mtime < current .parent_backup )
2066- {
2067- file -> crc = pgFileGetCRC (file -> path , true, false,
2068- & file -> read_size , FIO_DB_HOST );
2069- file -> write_size = file -> read_size ;
2070- /* ...and checksum is the same... */
2071- if (EQ_TRADITIONAL_CRC32 (file -> crc , (* prev_file )-> crc ))
2072- skip = true; /* ...skip copying file. */
2073- }
2074- /* Set file paths */
2075- if (file -> external_dir_num )
2076- {
2077- makeExternalDirPathByNum (external_dst ,
2078- arguments -> external_prefix ,
2079- file -> external_dir_num );
2080- dst = external_dst ;
2081- }
2082- else
2083- dst = arguments -> to_root ;
2084- if (skip ||
2085- !copy_file (FIO_DB_HOST , dst , FIO_BACKUP_HOST , file , true))
2086- {
2087- /* disappeared file not to be confused with 'not changed' */
2088- if (file -> write_size != FILE_NOT_FOUND )
2089- file -> write_size = BYTES_INVALID ;
2090- elog (VERBOSE , "File \"%s\" was not copied to backup" ,
2091- file -> path );
2092- continue ;
2093- }
2058+ /* Check that file exist in previous backup */
2059+ if (current .backup_mode != BACKUP_MODE_FULL )
2060+ {
2061+ pgFile * * prev_file_tmp = NULL ;
2062+ prev_file_tmp = (pgFile * * ) parray_bsearch (arguments -> prev_filelist ,
2063+ file , pgFileCompareRelPathWithExternal );
2064+ if (prev_file_tmp )
2065+ {
2066+ /* File exists in previous backup */
2067+ file -> exists_in_prev = true;
2068+ prev_file = * prev_file_tmp ;
20942069 }
2070+ }
20952071
2096- elog (VERBOSE , "File \"%s\". Copied " INT64_FORMAT " bytes" ,
2097- file -> path , file -> write_size );
2072+ /* backup file */
2073+ if (file -> is_datafile && !file -> is_cfs )
2074+ {
2075+ backup_data_file (& (arguments -> conn_arg ), file , from_fullpath , to_fullpath ,
2076+ arguments -> prev_start_lsn ,
2077+ current .backup_mode ,
2078+ instance_config .compress_alg ,
2079+ instance_config .compress_level ,
2080+ arguments -> nodeInfo -> checksum_version ,
2081+ arguments -> nodeInfo -> ptrack_version_num ,
2082+ arguments -> nodeInfo -> ptrack_schema ,
2083+ true);
20982084 }
20992085 else
2100- elog (WARNING , "unexpected file type %d" , buf .st_mode );
2086+ {
2087+ backup_non_data_file (file , prev_file , from_fullpath , to_fullpath ,
2088+ current .backup_mode , current .parent_backup , true);
2089+ }
2090+
2091+ if (file -> write_size == FILE_NOT_FOUND )
2092+ continue ;
2093+
2094+ if (file -> write_size == BYTES_INVALID )
2095+ {
2096+ elog (VERBOSE , "Skipping the unchanged file: \"%s\"" , from_fullpath );
2097+ continue ;
2098+ }
2099+
2100+ elog (VERBOSE , "File \"%s\". Copied " INT64_FORMAT " bytes" ,
2101+ from_fullpath , file -> write_size );
21012102 }
21022103
21032104 /* ssh connection to longer needed */
0 commit comments