113113#include < thread>
114114#include < unordered_set>
115115#include < filesystem>
116+ #include < utility>
116117
117118#include < fmt/format.h>
118119#include < Poco/Logger.h>
@@ -154,6 +155,10 @@ namespace ProfileEvents
154155 extern const Event LoadedDataPartsMicroseconds;
155156 extern const Event RestorePartsSkippedFiles;
156157 extern const Event RestorePartsSkippedBytes;
158+ extern const Event PartsExports;
159+ extern const Event PartsExportTotalMilliseconds;
160+ extern const Event PartsExportFailures;
161+ extern const Event PartsExportDuplicated;
157162}
158163
159164namespace CurrentMetrics
@@ -198,6 +203,8 @@ namespace Setting
198203 extern const SettingsUInt64 merge_tree_storage_snapshot_sleep_ms;
199204 extern const SettingsBool allow_experimental_export_merge_tree_part;
200205 extern const SettingsUInt64 min_bytes_to_use_direct_io;
206+ extern const SettingsBool export_merge_tree_part_overwrite_file_if_exists;
207+ extern const SettingsBool output_format_parallel_formatting;
201208}
202209
203210namespace MergeTreeSetting
@@ -310,6 +317,7 @@ namespace ErrorCodes
310317 extern const int CANNOT_FORGET_PARTITION;
311318 extern const int DATA_TYPE_CANNOT_BE_USED_IN_KEY;
312319 extern const int UNKNOWN_TABLE;
320+ extern const int FILE_ALREADY_EXISTS;
313321}
314322
315323static void checkSuspiciousIndices (const ASTFunction * index_function)
@@ -5932,9 +5940,15 @@ void MergeTreeData::exportPartToTable(const PartitionCommand & command, ContextP
59325940 part_name, getStorageID ().getFullTableName ());
59335941
59345942 {
5943+ MergeTreeExportManifest manifest (
5944+ dest_storage->getStorageID (),
5945+ part,
5946+ query_context->getSettingsRef ()[Setting::export_merge_tree_part_overwrite_file_if_exists],
5947+ query_context->getSettingsRef ()[Setting::output_format_parallel_formatting]);
5948+
59355949 std::lock_guard lock (export_manifests_mutex);
59365950
5937- if (!export_manifests.emplace (dest_storage-> getStorageID (), part ).second )
5951+ if (!export_manifests.emplace (std::move (manifest) ).second )
59385952 {
59395953 throw Exception (ErrorCodes::ABORTED, " Data part '{}' is already being exported to table '{}'" ,
59405954 part_name, dest_storage->getStorageID ().getFullTableName ());
@@ -5948,19 +5962,6 @@ void MergeTreeData::exportPartToTableImpl(
59485962 const MergeTreeExportManifest & manifest,
59495963 ContextPtr local_context)
59505964{
5951- auto exports_list_entry = getContext ()->getExportsList ().insert (
5952- getStorageID (),
5953- manifest.destination_storage_id ,
5954- manifest.data_part ->getBytesOnDisk (),
5955- manifest.data_part ->name ,
5956- manifest.data_part ->rows_count ,
5957- manifest.data_part ->getBytesOnDisk (),
5958- manifest.data_part ->getBytesUncompressedOnDisk (),
5959- manifest.create_time ,
5960- local_context);
5961-
5962- ThreadGroupSwitcher switcher ((*exports_list_entry)->thread_group , " " );
5963-
59645965 auto metadata_snapshot = getInMemoryMetadataPtr ();
59655966 Names columns_to_read = metadata_snapshot->getColumns ().getNamesOfPhysical ();
59665967 StorageSnapshotPtr storage_snapshot = getStorageSnapshot (metadata_snapshot, local_context);
@@ -5987,16 +5988,29 @@ void MergeTreeData::exportPartToTableImpl(
59875988 throw Exception (ErrorCodes::UNKNOWN_TABLE, " Failed to reconstruct destination storage: {}" , destination_storage_id_name);
59885989 }
59895990
5990- auto sink = destination_storage->import (
5991- manifest.data_part ->name ,
5992- block_with_partition_values,
5993- local_context);
5991+ SinkToStoragePtr sink;
5992+ std::string destination_file_path;
59945993
5995- // / Most likely the file has already been imported, so we can just return
5996- if (!sink)
5994+ try
59975995 {
5998- std::lock_guard inner_lock (export_manifests_mutex);
5996+ auto context_copy = Context::createCopy (local_context);
5997+ context_copy->setSetting (" output_format_parallel_formatting" , manifest.parallel_formatting );
59995998
5999+ sink = destination_storage->import (
6000+ manifest.data_part ->name ,
6001+ block_with_partition_values,
6002+ destination_file_path,
6003+ manifest.overwrite_file_if_exists ,
6004+ context_copy);
6005+ }
6006+ catch (const Exception & e)
6007+ {
6008+ if (e.code () == ErrorCodes::FILE_ALREADY_EXISTS)
6009+ {
6010+ ProfileEvents::increment (ProfileEvents::PartsExportDuplicated);
6011+ }
6012+
6013+ std::lock_guard inner_lock (export_manifests_mutex);
60006014 export_manifests.erase (manifest);
60016015 return ;
60026016 }
@@ -6037,6 +6051,20 @@ void MergeTreeData::exportPartToTableImpl(
60376051 local_context,
60386052 getLogger (" ExportPartition" ));
60396053
6054+ auto exports_list_entry = getContext ()->getExportsList ().insert (
6055+ getStorageID (),
6056+ manifest.destination_storage_id ,
6057+ manifest.data_part ->getBytesOnDisk (),
6058+ manifest.data_part ->name ,
6059+ destination_file_path,
6060+ manifest.data_part ->rows_count ,
6061+ manifest.data_part ->getBytesOnDisk (),
6062+ manifest.data_part ->getBytesUncompressedOnDisk (),
6063+ manifest.create_time ,
6064+ local_context);
6065+
6066+ ThreadGroupSwitcher switcher ((*exports_list_entry)->thread_group , " " );
6067+
60406068 QueryPlanOptimizationSettings optimization_settings (local_context);
60416069 auto pipeline_settings = BuildQueryPipelineSettings (local_context);
60426070 auto builder = plan_for_part.buildQueryPipeline (optimization_settings, pipeline_settings);
@@ -6070,10 +6098,15 @@ void MergeTreeData::exportPartToTableImpl(
60706098 exports_list_entry.get ());
60716099
60726100 export_manifests.erase (manifest);
6101+
6102+ ProfileEvents::increment (ProfileEvents::PartsExports);
6103+ ProfileEvents::increment (ProfileEvents::PartsExportTotalMilliseconds, static_cast <UInt64>((*exports_list_entry)->elapsed * 1000 ));
60736104 }
6074- catch (const Exception & )
6105+ catch (... )
60756106 {
6076- tryLogCurrentException (__PRETTY_FUNCTION__, " Exception is in export part task" );
6107+ tryLogCurrentException (__PRETTY_FUNCTION__, fmt::format (" while exporting the part {}. User should retry." , manifest.data_part ->name ));
6108+
6109+ ProfileEvents::increment (ProfileEvents::PartsExportFailures);
60776110
60786111 std::lock_guard inner_lock (export_manifests_mutex);
60796112 writePartLog (
@@ -8751,6 +8784,7 @@ try
87518784 part_log_elem.rows_read = (*exports_entry)->rows_read ;
87528785 part_log_elem.bytes_read_uncompressed = (*exports_entry)->bytes_read_uncompressed ;
87538786 part_log_elem.peak_memory_usage = (*exports_entry)->getPeakMemoryUsage ();
8787+ part_log_elem.path_on_disk = (*exports_entry)->destination_file_path ;
87548788 }
87558789
87568790 if (profile_counters)
0 commit comments