@@ -82,27 +82,31 @@ def get_backup_file_name(backup_format: BackupFormat):
8282 return backup_format .get_file_name ('backup' )
8383
8484
85- copy_file_range_supported = hasattr (os , " copy_file_range" )
86- COW_COPY_BUFFER_SIZE = 2 ** 30 # 1GB / need int, may overflow, so cannot copy files larger than 2GB in a single pass
85+ COPY_FILE_RANGE_SUPPORTED = hasattr (os , ' copy_file_range' )
86+ COPY_FILE_RANGE_BUFFER_SIZE = 2 ** 30 # 1GiB
8787
88- #copy using "Copy On Write"
89- def _cpcow (src_path : str , dst_path : str ):
90- if not copy_file_range_supported or not config .copy_on_write :
88+
89+ def copy_file_fast (src_path : str , dst_path : str ) -> str :
90+ """
91+ A ``shutil.copy2`` alternative that uses ``os.copy_file_range`` whenever possible
92+
93+ ``os.copy_file_range`` may support copy-on-write, which is much faster than regular copy
94+ """
95+ if not COPY_FILE_RANGE_SUPPORTED or not config .enable_copy_file_range :
9196 return shutil .copy2 (src_path , dst_path )
9297
93- if os .path .isdir (dst_path ):
98+ if os .path .isdir (dst_path ): # ref: shutil.copy2
9499 dst_path = os .path .join (dst_path , os .path .basename (src_path ))
95100
96101 try :
97- with open (src_path ,'rb' ) as fsrc , open (dst_path ,'wb+' ) as fdst :
98- while os .copy_file_range (fsrc .fileno (), fdst .fileno (), COW_COPY_BUFFER_SIZE ):
102+ with open (src_path , 'rb' ) as f_src , open (dst_path , 'wb+' ) as f_dst :
103+ while os .copy_file_range (f_src .fileno (), f_dst .fileno (), COPY_FILE_RANGE_BUFFER_SIZE ):
99104 pass
100-
101105 except Exception as e :
102- server_inst .logger .warning (str ( e ) + str ( src_path ) + "->" + str ( dst_path ) + ",Retry with other functions" )
106+ server_inst .logger .warning ('copy_file_range {} -> {} failed ({}), retrying with shutil.copy' . format ( src_path , dst_path , e ) )
103107 shutil .copy (src_path , dst_path )
104108
105- shutil .copystat (src_path , dst_path ) # copy2
109+ shutil .copystat (src_path , dst_path ) # ref: shutil.copy2
106110 return dst_path
107111
108112
@@ -126,12 +130,12 @@ def copy_worlds(src: str, dst: str, intent: CopyWorldIntent, *, backup_format: O
126130
127131 server_inst .logger .info ('copying {} -> {}' .format (src_path , dst_path ))
128132 if os .path .isdir (src_path ):
129- shutil .copytree (src_path , dst_path , ignore = lambda path , files : set (filter (config .is_file_ignored , files )), copy_function = _cpcow )
133+ shutil .copytree (src_path , dst_path , ignore = lambda path , files : set (filter (config .is_file_ignored , files )), copy_function = copy_file_fast )
130134 elif os .path .isfile (src_path ):
131135 dst_dir = os .path .dirname (dst_path )
132136 if not os .path .isdir (dst_dir ):
133137 os .makedirs (dst_dir )
134- _cpcow (src_path , dst_path )
138+ copy_file_fast (src_path , dst_path )
135139 else :
136140 server_inst .logger .warning ('{} does not exist while copying ({} -> {})' .format (src_path , src_path , dst_path ))
137141 elif backup_format in [BackupFormat .tar , BackupFormat .tar_gz , BackupFormat .tar_xz ]:
0 commit comments