|
26 | 26 | #include "cloud/config.h" |
27 | 27 | #include "common/config.h" |
28 | 28 | #include "common/logging.h" |
| 29 | +#include "common/metrics/doris_metrics.h" |
29 | 30 | #include "common/status.h" |
30 | 31 | #include "cpp/sync_point.h" |
31 | 32 | #include "service/backend_options.h" |
32 | 33 | #include "storage/compaction/compaction.h" |
33 | 34 | #include "storage/compaction/cumulative_compaction_policy.h" |
34 | 35 | #include "storage/compaction/cumulative_compaction_time_series_policy.h" |
| 36 | +#include "storage/merger.h" |
| 37 | +#include "storage/rowset/rowset_reader.h" |
| 38 | +#include "storage/rowset/rowset_writer.h" |
| 39 | +#include "storage/tablet/tablet_schema.h" |
35 | 40 | #include "util/debug_points.h" |
36 | 41 | #include "util/trace.h" |
37 | 42 | #include "util/uuid_generator.h" |
38 | 43 |
|
39 | 44 | namespace doris { |
40 | 45 | using namespace ErrorCode; |
41 | 46 |
|
| 47 | +namespace cloud { |
| 48 | + |
| 49 | +bool is_single_rowset_compaction_candidate(const RowsetSharedPtr& rowset) { |
| 50 | + return !rowset->rowset_meta()->has_delete_predicate() && |
| 51 | + rowset->rowset_meta()->is_segments_overlapping() && |
| 52 | + rowset->num_segments() >= config::cloud_single_rowset_compaction_min_segments; |
| 53 | +} |
| 54 | + |
| 55 | +bool should_use_single_rowset_grouped_compaction(const std::vector<RowsetSharedPtr>& input_rowsets, |
| 56 | + const TabletSchema& tablet_schema, |
| 57 | + std::string_view compaction_policy) { |
| 58 | + return compaction_policy == CUMULATIVE_SIZE_BASED_POLICY && |
| 59 | + tablet_schema.num_key_columns() > 0 && tablet_schema.cluster_key_uids().empty() && |
| 60 | + config::enable_cloud_single_rowset_compaction && input_rowsets.size() == 1 && |
| 61 | + is_single_rowset_compaction_candidate(input_rowsets.front()); |
| 62 | +} |
| 63 | + |
| 64 | +} // namespace cloud |
| 65 | + |
42 | 66 | bvar::Adder<uint64_t> cumu_output_size("cumu_compaction", "output_size"); |
43 | 67 | bvar::LatencyRecorder g_cu_compaction_hold_delete_bitmap_lock_time_ms( |
44 | 68 | "cu_compaction_hold_delete_bitmap_lock_time_ms"); |
@@ -266,17 +290,19 @@ Status CloudCumulativeCompaction::modify_rowsets() { |
266 | 290 | } |
267 | 291 | auto compaction_policy = cloud_tablet()->tablet_meta()->compaction_policy(); |
268 | 292 | int64_t new_cumulative_point = input_cumulative_point; |
269 | | - if (!_enable_parallel_cumu_compaction && input_tablet_state == TABLET_NOTREADY && |
270 | | - _output_rowset->start_version() > input_cumulative_point) { |
271 | | - // Historical rowsets are absent from a schema-change target until conversion finishes. |
272 | | - DORIS_CHECK_LE(input_cumulative_point, input_alter_version); |
273 | | - DORIS_CHECK_GT(_output_rowset->start_version(), input_alter_version); |
274 | | - } else if (!_enable_parallel_cumu_compaction || |
275 | | - _output_rowset->start_version() == input_cumulative_point) { |
276 | | - new_cumulative_point = |
277 | | - _engine.cumu_compaction_policy(compaction_policy) |
278 | | - ->new_cumulative_point(cloud_tablet(), _output_rowset, _last_delete_version, |
279 | | - input_cumulative_point); |
| 293 | + if (!_single_rowset_compaction_segment_group_size.has_value()) { |
| 294 | + if (!_enable_parallel_cumu_compaction && input_tablet_state == TABLET_NOTREADY && |
| 295 | + _output_rowset->start_version() > input_cumulative_point) { |
| 296 | + // Historical rowsets are absent from a schema-change target until conversion finishes. |
| 297 | + DORIS_CHECK_LE(input_cumulative_point, input_alter_version); |
| 298 | + DORIS_CHECK_GT(_output_rowset->start_version(), input_alter_version); |
| 299 | + } else if (!_enable_parallel_cumu_compaction || |
| 300 | + _output_rowset->start_version() == input_cumulative_point) { |
| 301 | + new_cumulative_point = |
| 302 | + _engine.cumu_compaction_policy(compaction_policy) |
| 303 | + ->new_cumulative_point(cloud_tablet(), _output_rowset, |
| 304 | + _last_delete_version, input_cumulative_point); |
| 305 | + } |
280 | 306 | } |
281 | 307 | // commit compaction job |
282 | 308 | cloud::TabletJobInfoPB job; |
@@ -607,6 +633,7 @@ Status CloudCumulativeCompaction::advance_cumulative_point_before_pick( |
607 | 633 |
|
608 | 634 | Status CloudCumulativeCompaction::pick_rowsets_to_compact() { |
609 | 635 | _input_rowsets.clear(); |
| 636 | + _single_rowset_compaction_segment_group_size.reset(); |
610 | 637 |
|
611 | 638 | int64_t min_conflict_version = _min_conflict_version; |
612 | 639 | int64_t max_conflict_version = _max_conflict_version; |
@@ -645,6 +672,19 @@ Status CloudCumulativeCompaction::pick_rowsets_to_compact() { |
645 | 672 | config::cumulative_compaction_min_deltas, &_input_rowsets, |
646 | 673 | &_last_delete_version, &compaction_score); |
647 | 674 |
|
| 675 | + if (config::enable_cloud_single_rowset_compaction) { |
| 676 | + for (const auto& rowset : _input_rowsets) { |
| 677 | + if (cloud::should_use_single_rowset_grouped_compaction( |
| 678 | + {rowset}, *cloud_tablet()->tablet_schema(), compaction_policy)) { |
| 679 | + auto grouped_input_rowset = rowset; |
| 680 | + _input_rowsets = {std::move(grouped_input_rowset)}; |
| 681 | + _single_rowset_compaction_segment_group_size = |
| 682 | + config::cloud_single_rowset_compaction_segment_group_size; |
| 683 | + return Status::OK(); |
| 684 | + } |
| 685 | + } |
| 686 | + } |
| 687 | + |
648 | 688 | if (_input_rowsets.empty()) { |
649 | 689 | return Status::Error<CUMULATIVE_NO_SUITABLE_VERSION>( |
650 | 690 | "no suitable versions: input rowsets empty"); |
@@ -708,6 +748,88 @@ Status CloudCumulativeCompaction::pick_rowsets_to_compact() { |
708 | 748 | return Status::OK(); |
709 | 749 | } |
710 | 750 |
|
| 751 | +Status CloudCumulativeCompaction::prepare_merge_input_rowsets(MergeInputRowsetsResult* result) { |
| 752 | + if (!_single_rowset_compaction_segment_group_size.has_value()) { |
| 753 | + return Status::OK(); |
| 754 | + } |
| 755 | + |
| 756 | + const int64_t segment_group_size = *_single_rowset_compaction_segment_group_size; |
| 757 | + if (segment_group_size <= 0) { |
| 758 | + return Status::InvalidArgument( |
| 759 | + "cloud_single_rowset_compaction_segment_group_size must be positive, value={}", |
| 760 | + segment_group_size); |
| 761 | + } |
| 762 | + result->is_segment_grouped = true; |
| 763 | + result->segment_group_size = segment_group_size; |
| 764 | + return Status::OK(); |
| 765 | +} |
| 766 | + |
| 767 | +Status CloudCumulativeCompaction::do_merge_input_rowsets( |
| 768 | + const std::vector<RowsetReaderSharedPtr>& input_rs_readers, |
| 769 | + MergeInputRowsetsResult* result) { |
| 770 | + if (!result->is_segment_grouped) { |
| 771 | + return Compaction::do_merge_input_rowsets(input_rs_readers, result); |
| 772 | + } |
| 773 | + |
| 774 | + const int64_t segment_group_size = result->segment_group_size; |
| 775 | + const auto& input_rowset = _input_rowsets.front(); |
| 776 | + const int64_t segment_group_count = |
| 777 | + (input_rowset->num_segments() + segment_group_size - 1) / segment_group_size; |
| 778 | + for (int64_t segment_start = 0; segment_start < input_rowset->num_segments(); |
| 779 | + segment_start += segment_group_size) { |
| 780 | + const int64_t segment_end = |
| 781 | + std::min(segment_start + segment_group_size, input_rowset->num_segments()); |
| 782 | + const int32_t output_segment_start = _output_rs_writer->get_allocated_segment_id(); |
| 783 | + |
| 784 | + RowsetReaderSharedPtr rs_reader; |
| 785 | + RETURN_IF_ERROR(input_rowset->create_reader(&rs_reader)); |
| 786 | + std::vector<RowsetReaderSharedPtr> group_readers; |
| 787 | + group_readers.push_back(std::move(rs_reader)); |
| 788 | + |
| 789 | + Merger::Statistics group_stats; |
| 790 | + group_stats.rowid_conversion = _stats.rowid_conversion; |
| 791 | + RETURN_IF_ERROR(execute_merge(group_readers, segment_end - segment_start, &group_stats, |
| 792 | + std::make_pair(segment_start, segment_end), |
| 793 | + {.total_ranges = segment_group_count, |
| 794 | + .range_index = segment_start / segment_group_size})); |
| 795 | + |
| 796 | + _stats.output_rows += group_stats.output_rows; |
| 797 | + _stats.merged_rows += group_stats.merged_rows; |
| 798 | + _stats.filtered_rows += group_stats.filtered_rows; |
| 799 | + _stats.bytes_read_from_local += group_stats.bytes_read_from_local; |
| 800 | + _stats.bytes_read_from_remote += group_stats.bytes_read_from_remote; |
| 801 | + _stats.cached_bytes_total += group_stats.cached_bytes_total; |
| 802 | + _stats.cloud_local_read_time += group_stats.cloud_local_read_time; |
| 803 | + _stats.cloud_remote_read_time += group_stats.cloud_remote_read_time; |
| 804 | + |
| 805 | + const int32_t output_segment_end = _output_rs_writer->get_allocated_segment_id(); |
| 806 | + const int32_t output_group_size = output_segment_end - output_segment_start; |
| 807 | + if (output_group_size > 0) { |
| 808 | + ++result->output_segment_group_count; |
| 809 | + } |
| 810 | + } |
| 811 | + return Status::OK(); |
| 812 | +} |
| 813 | + |
| 814 | +void CloudCumulativeCompaction::update_output_rowset_after_build( |
| 815 | + const MergeInputRowsetsResult& result) { |
| 816 | + if (!result.is_segment_grouped) { |
| 817 | + return; |
| 818 | + } |
| 819 | + if (result.output_segment_group_count > 1) { |
| 820 | + _output_rowset->rowset_meta()->set_segments_overlap(OVERLAPPING); |
| 821 | + } |
| 822 | + |
| 823 | + const auto& input_rowset = _input_rowsets.front(); |
| 824 | + LOG_INFO("finish single rowset grouped compaction, tablet_id={}, version=[{}-{}]", |
| 825 | + _tablet->tablet_id(), input_rowset->start_version(), input_rowset->end_version()) |
| 826 | + .tag("job_id", _uuid) |
| 827 | + .tag("input_segments", input_rowset->num_segments()) |
| 828 | + .tag("segment_group_size", result.segment_group_size) |
| 829 | + .tag("output_segments", _output_rowset->num_segments()) |
| 830 | + .tag("output_groups", result.output_segment_group_count); |
| 831 | +} |
| 832 | + |
711 | 833 | void CloudCumulativeCompaction::update_cumulative_point(int64_t input_cumulative_point, |
712 | 834 | int64_t output_cumulative_point) { |
713 | 835 | DORIS_CHECK_LT(input_cumulative_point, output_cumulative_point); |
|
0 commit comments