Coverage Report

Created: 2026-08-13 23:35

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
be/src/cloud/cloud_cumulative_compaction_binlog_policy.cpp
Line
Count
Source
1
// Licensed to the Apache Software Foundation (ASF) under one
2
// or more contributor license agreements.  See the NOTICE file
3
// distributed with this work for additional information
4
// regarding copyright ownership.  The ASF licenses this file
5
// to you under the Apache License, Version 2.0 (the
6
// "License"); you may not use this file except in compliance
7
// with the License.  You may obtain a copy of the License at
8
//
9
//   http://www.apache.org/licenses/LICENSE-2.0
10
//
11
// Unless required by applicable law or agreed to in writing,
12
// software distributed under the License is distributed on an
13
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14
// KIND, either express or implied.  See the License for the
15
// specific language governing permissions and limitations
16
// under the License.
17
18
#include "cloud/cloud_cumulative_compaction_binlog_policy.h"
19
20
#include "cloud/cloud_tablet.h"
21
#include "common/config.h"
22
#include "storage/compaction/cumulative_compaction_binlog_policy.h"
23
#include "storage/tablet/tablet.h"
24
#include "util/time.h"
25
26
namespace doris {
27
28
bool CloudBinlogCumulativeCompactionPolicy::is_compaction_enough(
29
2
        const RowsetMetaSharedPtr& rowset_meta) const {
30
2
    if (rowset_meta->compaction_level() !=
31
2
        BinlogCumulativeCompactionPolicy::kBinlogCompactionMaxLevel - 1) {
32
0
        return false;
33
0
    }
34
2
    if (rowset_meta->start_version() == 0) {
35
0
        return true;
36
0
    }
37
2
    return rowset_meta->data_disk_size() >=
38
2
                   config::binlog_compaction_goal_size_mbytes * 1024 * 1024 ||
39
2
           rowset_meta->get_compaction_score() >= config::binlog_compaction_file_count_threshold;
40
2
}
41
42
int64_t CloudBinlogCumulativeCompactionPolicy::new_cumulative_point(
43
        CloudTablet* tablet, const RowsetSharedPtr& output_rowset, Version& last_delete_version,
44
3
        int64_t last_cumulative_point) {
45
3
    if (output_rowset->num_segments() == 0 || !is_compaction_enough(output_rowset->rowset_meta())) {
46
2
        return last_cumulative_point;
47
2
    }
48
1
    return output_rowset->end_version() + 1;
49
3
}
50
51
int64_t CloudBinlogCumulativeCompactionPolicy::get_compaction_level(
52
        CloudTablet* tablet, const std::vector<RowsetSharedPtr>& input_rowsets,
53
0
        RowsetSharedPtr output_rowset) {
54
0
    DCHECK(!input_rowsets.empty()) << "tablet=" << tablet->tablet_id();
55
0
    int64_t first_level = input_rowsets.front()->rowset_meta()->compaction_level();
56
0
    for (size_t i = 1; i < input_rowsets.size(); ++i) {
57
0
        DCHECK_EQ(first_level, input_rowsets[i]->rowset_meta()->compaction_level())
58
0
                << "tablet=" << tablet->tablet_id();
59
0
        DCHECK_EQ(input_rowsets[i]->start_version(), input_rowsets[i - 1]->end_version() + 1)
60
0
                << "tablet=" << tablet->tablet_id();
61
0
    }
62
63
0
    if (first_level == BinlogCumulativeCompactionPolicy::kBinlogCompactionMaxLevel - 1) {
64
0
        return first_level;
65
0
    }
66
0
    return first_level + 1;
67
0
}
68
69
uint32_t CloudBinlogCumulativeCompactionPolicy::calc_binlog_compaction_level_score(
70
        CloudTablet* tablet, const std::vector<RowsetSharedPtr>& candidate_rowsets,
71
15
        int8_t level) const {
72
15
    uint32_t score = 0;
73
15
    const int64_t point = tablet->cumulative_layer_point();
74
45
    for (const auto& rs : candidate_rowsets) {
75
45
        auto rs_meta = rs->rowset_meta();
76
45
        if (rs_meta->compaction_level() != level) {
77
30
            continue;
78
30
        }
79
15
        if (level == BinlogCumulativeCompactionPolicy::kBinlogCompactionMaxLevel - 1 &&
80
15
            point != Tablet::K_INVALID_CUMULATIVE_POINT && rs_meta->end_version() < point) {
81
2
            score += 1;
82
2
            continue;
83
2
        }
84
13
        score += rs_meta->get_compaction_score();
85
13
    }
86
15
    return score;
87
15
}
88
89
uint32_t CloudBinlogCumulativeCompactionPolicy::calc_binlog_compaction_score(
90
        CloudTablet* tablet, const std::vector<RowsetSharedPtr>& candidate_rowsets,
91
5
        int8_t* compaction_level) const {
92
5
    uint32_t max_score = 0;
93
5
    int8_t max_level = -1;
94
20
    for (int8_t level = 0; level < BinlogCumulativeCompactionPolicy::kBinlogCompactionMaxLevel;
95
15
         ++level) {
96
15
        uint32_t score = calc_binlog_compaction_level_score(tablet, candidate_rowsets, level);
97
15
        if (score > max_score) {
98
6
            max_score = score;
99
6
            max_level = level;
100
6
        }
101
15
    }
102
5
    if (compaction_level != nullptr) {
103
5
        *compaction_level = max_level;
104
5
    }
105
5
    return max_score;
106
5
}
107
108
void CloudBinlogCumulativeCompactionPolicy::filter_new_visible_rowsets(
109
        const std::vector<RowsetSharedPtr>& candidate_rowsets,
110
5
        std::vector<RowsetSharedPtr>* output_rowsets) const {
111
5
    output_rowsets->clear();
112
5
    int64_t now = UnixSeconds();
113
5
    int64_t max_processable_old_version = 0;
114
5
    bool filter_new_rowset =
115
5
            candidate_rowsets.size() <= config::binlog_compaction_file_count_threshold;
116
18
    for (const auto& rs : candidate_rowsets) {
117
18
        if (filter_new_rowset && rs->rowset_meta()->is_singleton_delta() &&
118
18
            rs->rowset_meta()->newest_write_timestamp() +
119
6
                            config::binlog_compaction_wait_timesec_after_visible >
120
6
                    now) {
121
3
            continue;
122
3
        }
123
15
        max_processable_old_version = std::max(max_processable_old_version, rs->end_version());
124
15
    }
125
126
5
    output_rowsets->reserve(candidate_rowsets.size());
127
18
    for (const auto& rs : candidate_rowsets) {
128
18
        if (rs->start_version() <= max_processable_old_version) {
129
15
            output_rowsets->push_back(rs);
130
15
        }
131
18
    }
132
5
}
133
134
int64_t CloudBinlogCumulativeCompactionPolicy::pick_input_rowsets(
135
        CloudTablet* tablet, const std::vector<RowsetSharedPtr>& candidate_rowsets,
136
        const int64_t max_compaction_score, const int64_t min_compaction_score,
137
        std::vector<RowsetSharedPtr>* input_rowsets, Version* last_delete_version,
138
5
        size_t* compaction_score, bool allow_delete) {
139
5
    std::vector<RowsetSharedPtr> filtered_rowsets;
140
5
    filter_new_visible_rowsets(candidate_rowsets, &filtered_rowsets);
141
142
5
    int8_t compaction_level = -1;
143
5
    calc_binlog_compaction_score(tablet, filtered_rowsets, &compaction_level);
144
5
    if (compaction_level < 0) {
145
0
        *compaction_score = 0;
146
0
        return 0;
147
0
    }
148
149
5
    std::vector<RowsetSharedPtr> level_rowsets;
150
5
    level_rowsets.reserve(filtered_rowsets.size());
151
15
    for (const auto& rs : filtered_rowsets) {
152
15
        if (rs->rowset_meta()->compaction_level() != compaction_level) {
153
2
            continue;
154
2
        }
155
13
        if (!level_rowsets.empty() &&
156
13
            rs->start_version() != level_rowsets.back()->end_version() + 1) {
157
0
            LOG(WARNING) << "rowset is non-continuous in the same compaction_level "
158
0
                            "of binlog compaction. tablet="
159
0
                         << tablet->tablet_id()
160
0
                         << ", compaction_level=" << static_cast<int>(compaction_level)
161
0
                         << ", prev_version=" << level_rowsets.back()->version()
162
0
                         << ", next_version=" << rs->version();
163
0
            *compaction_score = 0;
164
0
            return 0;
165
0
        }
166
13
        level_rowsets.push_back(rs);
167
13
    }
168
169
5
    std::vector<RowsetSharedPtr> remaining_rowsets;
170
5
    remaining_rowsets.reserve(level_rowsets.size());
171
5
    const int64_t point = tablet->cumulative_layer_point();
172
13
    for (const auto& rs : level_rowsets) {
173
13
        if (compaction_level == BinlogCumulativeCompactionPolicy::kBinlogCompactionMaxLevel - 1 &&
174
13
            point != Tablet::K_INVALID_CUMULATIVE_POINT && rs->end_version() < point) {
175
2
            continue;
176
2
        }
177
11
        remaining_rowsets.push_back(rs);
178
11
    }
179
180
5
    std::vector<RowsetSharedPtr> picked_rowsets;
181
5
    picked_rowsets.reserve(remaining_rowsets.size());
182
5
    int transient_size = 0;
183
5
    int64_t total_size = 0;
184
5
    int64_t picked_score = 0;
185
11
    for (const auto& rs : remaining_rowsets) {
186
11
        if (transient_size >= max_compaction_score) {
187
0
            break;
188
0
        }
189
11
        picked_rowsets.push_back(rs);
190
11
        ++transient_size;
191
11
        total_size += rs->data_disk_size();
192
11
        picked_score += rs->rowset_meta()->get_compaction_score();
193
11
    }
194
195
5
    bool can_do_binlog_compaction =
196
5
            total_size >= config::binlog_compaction_goal_size_mbytes * 1024 * 1024 ||
197
5
            picked_score >= config::binlog_compaction_file_count_threshold ||
198
5
            (UnixMillis() - tablet->last_cumu_compaction_success_time()) / 1000 >=
199
1
                    config::binlog_compaction_time_threshold_seconds;
200
5
    if (transient_size < 2) {
201
1
        can_do_binlog_compaction = false;
202
1
    }
203
5
    if (can_do_binlog_compaction) {
204
4
        input_rowsets->swap(picked_rowsets);
205
4
        *compaction_score = picked_score;
206
4
        return transient_size;
207
4
    }
208
209
1
    input_rowsets->clear();
210
1
    *compaction_score = 0;
211
1
    return 0;
212
5
}
213
214
} // namespace doris