|
15 | 15 | // specific language governing permissions and limitations |
16 | 16 | // under the License. |
17 | 17 |
|
| 18 | +#include "cloud/cloud_cumulative_compaction_policy.h" |
| 19 | + |
18 | 20 | #include <gen_cpp/AgentService_types.h> |
19 | 21 | #include <gen_cpp/olap_file.pb.h> |
20 | 22 | #include <gtest/gtest-message.h> |
21 | 23 | #include <gtest/gtest-test-part.h> |
22 | 24 | #include <gtest/gtest.h> |
23 | 25 |
|
24 | 26 | #include "cloud/cloud_storage_engine.h" |
| 27 | +#include "cloud/config.h" |
| 28 | +#include "common/config.h" |
25 | 29 | #include "gtest/gtest_pred_impl.h" |
26 | 30 | #include "json2pb/json_to_pb.h" |
27 | 31 | #include "olap/olap_common.h" |
@@ -146,4 +150,122 @@ TEST_F(TestCloudSizeBasedCumulativeCompactionPolicy, new_cumulative_point) { |
146 | 150 | Version version(1, 1); |
147 | 151 | EXPECT_EQ(policy.new_cumulative_point(&_tablet, output_rowset, version, 2), 6); |
148 | 152 | } |
| 153 | + |
| 154 | +// Test case: Empty rowset compaction with skip_trim |
| 155 | +TEST_F(TestCloudSizeBasedCumulativeCompactionPolicy, pick_input_rowsets_empty_rowset_compaction) { |
| 156 | + // Save original config values |
| 157 | + bool orig_enable_empty_rowset_compaction = config::enable_empty_rowset_compaction; |
| 158 | + int32_t orig_empty_rowset_compaction_min_count = config::empty_rowset_compaction_min_count; |
| 159 | + double orig_empty_rowset_compaction_min_ratio = config::empty_rowset_compaction_min_ratio; |
| 160 | + |
| 161 | + // Enable empty rowset compaction |
| 162 | + config::enable_empty_rowset_compaction = true; |
| 163 | + config::empty_rowset_compaction_min_count = 5; |
| 164 | + config::empty_rowset_compaction_min_ratio = 0.5; |
| 165 | + |
| 166 | + CloudTablet _tablet(_engine, _tablet_meta); |
| 167 | + _tablet._base_size = 1024L * 1024 * 1024; // 1GB base |
| 168 | + |
| 169 | + // Create candidate rowsets: 2 normal + 150 empty rowsets |
| 170 | + // This tests that skip_trim = true for empty rowset compaction |
| 171 | + std::vector<RowsetSharedPtr> candidate_rowsets; |
| 172 | + |
| 173 | + // 2 normal rowsets |
| 174 | + for (int i = 0; i < 2; i++) { |
| 175 | + auto rowset = create_rowset(Version(i + 2, i + 2), 1, true, 1024 * 1024); // 1MB |
| 176 | + candidate_rowsets.push_back(rowset); |
| 177 | + } |
| 178 | + |
| 179 | + // 150 empty rowsets (consecutive) |
| 180 | + for (int i = 0; i < 150; i++) { |
| 181 | + auto rowset = create_rowset(Version(i + 4, i + 4), 0, false, 0); // empty |
| 182 | + candidate_rowsets.push_back(rowset); |
| 183 | + } |
| 184 | + |
| 185 | + std::vector<RowsetSharedPtr> input_rowsets; |
| 186 | + Version last_delete_version {-1, -1}; |
| 187 | + size_t compaction_score = 0; |
| 188 | + |
| 189 | + CloudSizeBasedCumulativeCompactionPolicy policy; |
| 190 | + // max=100, but empty rowset compaction should return 150 (skip_trim = true) |
| 191 | + policy.pick_input_rowsets(&_tablet, candidate_rowsets, 100, 50, &input_rowsets, |
| 192 | + &last_delete_version, &compaction_score, true); |
| 193 | + |
| 194 | + // Empty rowset compaction should return all 150 empty rowsets |
| 195 | + // skip_trim = true, so no trimming even though score > max |
| 196 | + EXPECT_EQ(150, input_rowsets.size()); |
| 197 | + EXPECT_EQ(150, compaction_score); |
| 198 | + |
| 199 | + // Verify all returned rowsets are empty |
| 200 | + for (const auto& rs : input_rowsets) { |
| 201 | + EXPECT_EQ(0, rs->num_segments()); |
| 202 | + } |
| 203 | + |
| 204 | + // Restore original config values |
| 205 | + config::enable_empty_rowset_compaction = orig_enable_empty_rowset_compaction; |
| 206 | + config::empty_rowset_compaction_min_count = orig_empty_rowset_compaction_min_count; |
| 207 | + config::empty_rowset_compaction_min_ratio = orig_empty_rowset_compaction_min_ratio; |
| 208 | +} |
| 209 | + |
| 210 | +// Test case: prioritize_query_perf_in_compaction for non-DUP_KEYS table |
| 211 | +// This tests the branch: rs_begin == end && prioritize_query_perf && keys_type != DUP_KEYS |
| 212 | +TEST_F(TestCloudSizeBasedCumulativeCompactionPolicy, pick_input_rowsets_prioritize_query_perf) { |
| 213 | + // Save original config value |
| 214 | + bool orig_prioritize_query_perf = config::prioritize_query_perf_in_compaction; |
| 215 | + |
| 216 | + // Enable prioritize_query_perf_in_compaction |
| 217 | + config::prioritize_query_perf_in_compaction = true; |
| 218 | + |
| 219 | + // Create tablet with UNIQUE keys (not DUP_KEYS) |
| 220 | + TTabletSchema schema; |
| 221 | + schema.keys_type = TKeysType::UNIQUE_KEYS; |
| 222 | + TabletMetaSharedPtr tablet_meta(new TabletMeta(1, 2, 15673, 15674, 4, 5, schema, 6, {{7, 8}}, |
| 223 | + UniqueId(9, 10), TTabletType::TABLET_TYPE_DISK, |
| 224 | + TCompressionType::LZ4F)); |
| 225 | + |
| 226 | + CloudTablet _tablet(_engine, tablet_meta); |
| 227 | + // Use large base_size to get large promotion_size, ensuring total_size < promotion_size |
| 228 | + // so we don't trigger promotion_size early return and can reach level_size logic |
| 229 | + _tablet._base_size = 20L * 1024 * 1024 * 1024; // 20GB base, promotion_size ~= 1GB |
| 230 | + |
| 231 | + // Create candidate rowsets that will ALL be removed by level_size |
| 232 | + // Key: each rowset's level > remain_level after removal |
| 233 | + std::vector<RowsetSharedPtr> candidate_rowsets; |
| 234 | + |
| 235 | + // 3 rowsets with decreasing sizes, all will be removed by level_size: |
| 236 | + // - 40MB: level(40)=32, remain=35, level(35)=32, 32>32? NO... need adjustment |
| 237 | + // Let's use sizes that guarantee all removal: |
| 238 | + // - 50MB: level(50)=32, after remove remain=25, level(25)=16, 32>16 -> remove |
| 239 | + // - 20MB: level(20)=16, after remove remain=5, level(5)=4, 16>4 -> remove |
| 240 | + // - 5MB: level(5)=4, after remove remain=0, level(0)=0, 4>0 -> remove |
| 241 | + auto rowset1 = create_rowset(Version(2, 2), 30, true, 50L * 1024 * 1024); // 50MB, score=30 |
| 242 | + auto rowset2 = create_rowset(Version(3, 3), 20, true, 20L * 1024 * 1024); // 20MB, score=20 |
| 243 | + auto rowset3 = create_rowset(Version(4, 4), 10, true, 5L * 1024 * 1024); // 5MB, score=10 |
| 244 | + candidate_rowsets.push_back(rowset1); |
| 245 | + candidate_rowsets.push_back(rowset2); |
| 246 | + candidate_rowsets.push_back(rowset3); |
| 247 | + |
| 248 | + // total_size = 75MB < promotion_size (~1GB), enters level_size logic |
| 249 | + // All 3 rowsets will be removed by level_size -> rs_begin == end |
| 250 | + // With prioritize_query_perf=true and UNIQUE_KEYS, should return all candidates |
| 251 | + |
| 252 | + std::vector<RowsetSharedPtr> input_rowsets; |
| 253 | + Version last_delete_version {-1, -1}; |
| 254 | + size_t compaction_score = 0; |
| 255 | + |
| 256 | + CloudSizeBasedCumulativeCompactionPolicy policy; |
| 257 | + policy.pick_input_rowsets(&_tablet, candidate_rowsets, 100, 5, &input_rowsets, |
| 258 | + &last_delete_version, &compaction_score, true); |
| 259 | + |
| 260 | + // With prioritize_query_perf enabled for non-DUP_KEYS table, |
| 261 | + // when all rowsets are removed by level_size, should return all candidates |
| 262 | + // (before DEFER trim) |
| 263 | + // Total score = 60, max = 100, so no trimming needed |
| 264 | + EXPECT_EQ(3, input_rowsets.size()); |
| 265 | + EXPECT_EQ(60, compaction_score); |
| 266 | + |
| 267 | + // Restore original config value |
| 268 | + config::prioritize_query_perf_in_compaction = orig_prioritize_query_perf; |
| 269 | +} |
| 270 | + |
149 | 271 | } // namespace doris |
0 commit comments