]>
Commit | Line | Data |
---|---|---|
494da23a | 1 | // Copyright (c) 2018-present, Facebook, Inc. All rights reserved. |
11fdf7f2 TL |
2 | // This source code is licensed under both the GPLv2 (found in the |
3 | // COPYING file in the root directory) and Apache 2.0 License | |
4 | // (found in the LICENSE.Apache file in the root directory). | |
7c673cae | 5 | |
494da23a TL |
6 | #include "db/range_del_aggregator.h" |
7 | ||
8 | #include <memory> | |
9 | #include <string> | |
10 | #include <vector> | |
7c673cae FG |
11 | |
12 | #include "db/db_test_util.h" | |
494da23a TL |
13 | #include "db/dbformat.h" |
14 | #include "db/range_tombstone_fragmenter.h" | |
f67539c2 | 15 | #include "test_util/testutil.h" |
1e59de90 | 16 | #include "util/vector_iterator.h" |
7c673cae | 17 | |
f67539c2 | 18 | namespace ROCKSDB_NAMESPACE { |
7c673cae FG |
19 | |
20 | class RangeDelAggregatorTest : public testing::Test {}; | |
21 | ||
22 | namespace { | |
23 | ||
11fdf7f2 TL |
24 | static auto bytewise_icmp = InternalKeyComparator(BytewiseComparator()); |
25 | ||
494da23a TL |
26 | std::unique_ptr<InternalIterator> MakeRangeDelIter( |
27 | const std::vector<RangeTombstone>& range_dels) { | |
11fdf7f2 TL |
28 | std::vector<std::string> keys, values; |
29 | for (const auto& range_del : range_dels) { | |
30 | auto key_and_value = range_del.Serialize(); | |
31 | keys.push_back(key_and_value.first.Encode().ToString()); | |
32 | values.push_back(key_and_value.second.ToString()); | |
33 | } | |
1e59de90 TL |
34 | return std::unique_ptr<VectorIterator>( |
35 | new VectorIterator(keys, values, &bytewise_icmp)); | |
11fdf7f2 TL |
36 | } |
37 | ||
494da23a TL |
38 | std::vector<std::unique_ptr<FragmentedRangeTombstoneList>> |
39 | MakeFragmentedTombstoneLists( | |
40 | const std::vector<std::vector<RangeTombstone>>& range_dels_list) { | |
41 | std::vector<std::unique_ptr<FragmentedRangeTombstoneList>> fragment_lists; | |
42 | for (const auto& range_dels : range_dels_list) { | |
43 | auto range_del_iter = MakeRangeDelIter(range_dels); | |
44 | fragment_lists.emplace_back(new FragmentedRangeTombstoneList( | |
45 | std::move(range_del_iter), bytewise_icmp)); | |
46 | } | |
47 | return fragment_lists; | |
11fdf7f2 TL |
48 | } |
49 | ||
494da23a TL |
50 | struct TruncatedIterScanTestCase { |
51 | ParsedInternalKey start; | |
52 | ParsedInternalKey end; | |
53 | SequenceNumber seq; | |
54 | }; | |
55 | ||
56 | struct TruncatedIterSeekTestCase { | |
57 | Slice target; | |
58 | ParsedInternalKey start; | |
59 | ParsedInternalKey end; | |
60 | SequenceNumber seq; | |
61 | bool invalid; | |
62 | }; | |
63 | ||
64 | struct ShouldDeleteTestCase { | |
65 | ParsedInternalKey lookup_key; | |
66 | bool result; | |
67 | }; | |
68 | ||
69 | struct IsRangeOverlappedTestCase { | |
70 | Slice start; | |
71 | Slice end; | |
72 | bool result; | |
73 | }; | |
74 | ||
75 | ParsedInternalKey UncutEndpoint(const Slice& s) { | |
76 | return ParsedInternalKey(s, kMaxSequenceNumber, kTypeRangeDeletion); | |
77 | } | |
78 | ||
1e59de90 TL |
79 | ParsedInternalKey InternalValue(const Slice& key, SequenceNumber seq, |
80 | ValueType type = kTypeValue) { | |
81 | return ParsedInternalKey(key, seq, type); | |
494da23a TL |
82 | } |
83 | ||
84 | void VerifyIterator( | |
85 | TruncatedRangeDelIterator* iter, const InternalKeyComparator& icmp, | |
86 | const std::vector<TruncatedIterScanTestCase>& expected_range_dels) { | |
87 | // Test forward iteration. | |
88 | iter->SeekToFirst(); | |
89 | for (size_t i = 0; i < expected_range_dels.size(); i++, iter->Next()) { | |
90 | ASSERT_TRUE(iter->Valid()); | |
91 | EXPECT_EQ(0, icmp.Compare(iter->start_key(), expected_range_dels[i].start)); | |
92 | EXPECT_EQ(0, icmp.Compare(iter->end_key(), expected_range_dels[i].end)); | |
93 | EXPECT_EQ(expected_range_dels[i].seq, iter->seq()); | |
94 | } | |
95 | EXPECT_FALSE(iter->Valid()); | |
96 | ||
97 | // Test reverse iteration. | |
98 | iter->SeekToLast(); | |
99 | std::vector<TruncatedIterScanTestCase> reverse_expected_range_dels( | |
100 | expected_range_dels.rbegin(), expected_range_dels.rend()); | |
101 | for (size_t i = 0; i < reverse_expected_range_dels.size(); | |
102 | i++, iter->Prev()) { | |
103 | ASSERT_TRUE(iter->Valid()); | |
104 | EXPECT_EQ(0, icmp.Compare(iter->start_key(), | |
105 | reverse_expected_range_dels[i].start)); | |
106 | EXPECT_EQ( | |
107 | 0, icmp.Compare(iter->end_key(), reverse_expected_range_dels[i].end)); | |
108 | EXPECT_EQ(reverse_expected_range_dels[i].seq, iter->seq()); | |
11fdf7f2 | 109 | } |
494da23a | 110 | EXPECT_FALSE(iter->Valid()); |
11fdf7f2 TL |
111 | } |
112 | ||
494da23a TL |
113 | void VerifySeek(TruncatedRangeDelIterator* iter, |
114 | const InternalKeyComparator& icmp, | |
115 | const std::vector<TruncatedIterSeekTestCase>& test_cases) { | |
116 | for (const auto& test_case : test_cases) { | |
117 | iter->Seek(test_case.target); | |
118 | if (test_case.invalid) { | |
119 | ASSERT_FALSE(iter->Valid()); | |
120 | } else { | |
121 | ASSERT_TRUE(iter->Valid()); | |
122 | EXPECT_EQ(0, icmp.Compare(iter->start_key(), test_case.start)); | |
123 | EXPECT_EQ(0, icmp.Compare(iter->end_key(), test_case.end)); | |
124 | EXPECT_EQ(test_case.seq, iter->seq()); | |
7c673cae FG |
125 | } |
126 | } | |
494da23a | 127 | } |
11fdf7f2 | 128 | |
494da23a TL |
129 | void VerifySeekForPrev( |
130 | TruncatedRangeDelIterator* iter, const InternalKeyComparator& icmp, | |
131 | const std::vector<TruncatedIterSeekTestCase>& test_cases) { | |
132 | for (const auto& test_case : test_cases) { | |
133 | iter->SeekForPrev(test_case.target); | |
134 | if (test_case.invalid) { | |
135 | ASSERT_FALSE(iter->Valid()); | |
11fdf7f2 | 136 | } else { |
494da23a TL |
137 | ASSERT_TRUE(iter->Valid()); |
138 | EXPECT_EQ(0, icmp.Compare(iter->start_key(), test_case.start)); | |
139 | EXPECT_EQ(0, icmp.Compare(iter->end_key(), test_case.end)); | |
140 | EXPECT_EQ(test_case.seq, iter->seq()); | |
11fdf7f2 TL |
141 | } |
142 | } | |
7c673cae FG |
143 | } |
144 | ||
494da23a TL |
145 | void VerifyShouldDelete(RangeDelAggregator* range_del_agg, |
146 | const std::vector<ShouldDeleteTestCase>& test_cases) { | |
147 | for (const auto& test_case : test_cases) { | |
148 | EXPECT_EQ( | |
149 | test_case.result, | |
150 | range_del_agg->ShouldDelete( | |
151 | test_case.lookup_key, RangeDelPositioningMode::kForwardTraversal)); | |
152 | } | |
153 | for (auto it = test_cases.rbegin(); it != test_cases.rend(); ++it) { | |
154 | const auto& test_case = *it; | |
155 | EXPECT_EQ( | |
156 | test_case.result, | |
157 | range_del_agg->ShouldDelete( | |
158 | test_case.lookup_key, RangeDelPositioningMode::kBackwardTraversal)); | |
159 | } | |
7c673cae FG |
160 | } |
161 | ||
494da23a TL |
162 | void VerifyIsRangeOverlapped( |
163 | ReadRangeDelAggregator* range_del_agg, | |
164 | const std::vector<IsRangeOverlappedTestCase>& test_cases) { | |
165 | for (const auto& test_case : test_cases) { | |
166 | EXPECT_EQ(test_case.result, | |
167 | range_del_agg->IsRangeOverlapped(test_case.start, test_case.end)); | |
168 | } | |
7c673cae FG |
169 | } |
170 | ||
494da23a TL |
171 | void CheckIterPosition(const RangeTombstone& tombstone, |
172 | const FragmentedRangeTombstoneIterator* iter) { | |
173 | // Test InternalIterator interface. | |
174 | EXPECT_EQ(tombstone.start_key_, ExtractUserKey(iter->key())); | |
175 | EXPECT_EQ(tombstone.end_key_, iter->value()); | |
176 | EXPECT_EQ(tombstone.seq_, iter->seq()); | |
177 | ||
178 | // Test FragmentedRangeTombstoneIterator interface. | |
179 | EXPECT_EQ(tombstone.start_key_, iter->start_key()); | |
180 | EXPECT_EQ(tombstone.end_key_, iter->end_key()); | |
181 | EXPECT_EQ(tombstone.seq_, GetInternalKeySeqno(iter->key())); | |
7c673cae FG |
182 | } |
183 | ||
494da23a TL |
184 | void VerifyFragmentedRangeDels( |
185 | FragmentedRangeTombstoneIterator* iter, | |
186 | const std::vector<RangeTombstone>& expected_tombstones) { | |
187 | iter->SeekToFirst(); | |
188 | for (size_t i = 0; i < expected_tombstones.size(); i++, iter->Next()) { | |
189 | ASSERT_TRUE(iter->Valid()); | |
190 | CheckIterPosition(expected_tombstones[i], iter); | |
191 | } | |
192 | EXPECT_FALSE(iter->Valid()); | |
7c673cae FG |
193 | } |
194 | ||
1e59de90 | 195 | } // anonymous namespace |
11fdf7f2 | 196 | |
494da23a TL |
197 | TEST_F(RangeDelAggregatorTest, EmptyTruncatedIter) { |
198 | auto range_del_iter = MakeRangeDelIter({}); | |
199 | FragmentedRangeTombstoneList fragment_list(std::move(range_del_iter), | |
200 | bytewise_icmp); | |
201 | std::unique_ptr<FragmentedRangeTombstoneIterator> input_iter( | |
202 | new FragmentedRangeTombstoneIterator(&fragment_list, bytewise_icmp, | |
203 | kMaxSequenceNumber)); | |
7c673cae | 204 | |
494da23a TL |
205 | TruncatedRangeDelIterator iter(std::move(input_iter), &bytewise_icmp, nullptr, |
206 | nullptr); | |
7c673cae | 207 | |
494da23a TL |
208 | iter.SeekToFirst(); |
209 | ASSERT_FALSE(iter.Valid()); | |
7c673cae | 210 | |
494da23a TL |
211 | iter.SeekToLast(); |
212 | ASSERT_FALSE(iter.Valid()); | |
7c673cae FG |
213 | } |
214 | ||
494da23a TL |
215 | TEST_F(RangeDelAggregatorTest, UntruncatedIter) { |
216 | auto range_del_iter = | |
217 | MakeRangeDelIter({{"a", "e", 10}, {"e", "g", 8}, {"j", "n", 4}}); | |
218 | FragmentedRangeTombstoneList fragment_list(std::move(range_del_iter), | |
219 | bytewise_icmp); | |
220 | std::unique_ptr<FragmentedRangeTombstoneIterator> input_iter( | |
221 | new FragmentedRangeTombstoneIterator(&fragment_list, bytewise_icmp, | |
222 | kMaxSequenceNumber)); | |
223 | ||
224 | TruncatedRangeDelIterator iter(std::move(input_iter), &bytewise_icmp, nullptr, | |
225 | nullptr); | |
226 | ||
227 | VerifyIterator(&iter, bytewise_icmp, | |
228 | {{UncutEndpoint("a"), UncutEndpoint("e"), 10}, | |
229 | {UncutEndpoint("e"), UncutEndpoint("g"), 8}, | |
230 | {UncutEndpoint("j"), UncutEndpoint("n"), 4}}); | |
231 | ||
232 | VerifySeek( | |
233 | &iter, bytewise_icmp, | |
234 | {{"d", UncutEndpoint("a"), UncutEndpoint("e"), 10}, | |
235 | {"e", UncutEndpoint("e"), UncutEndpoint("g"), 8}, | |
236 | {"ia", UncutEndpoint("j"), UncutEndpoint("n"), 4}, | |
237 | {"n", UncutEndpoint(""), UncutEndpoint(""), 0, true /* invalid */}, | |
238 | {"", UncutEndpoint("a"), UncutEndpoint("e"), 10}}); | |
239 | ||
240 | VerifySeekForPrev( | |
241 | &iter, bytewise_icmp, | |
242 | {{"d", UncutEndpoint("a"), UncutEndpoint("e"), 10}, | |
243 | {"e", UncutEndpoint("e"), UncutEndpoint("g"), 8}, | |
244 | {"ia", UncutEndpoint("e"), UncutEndpoint("g"), 8}, | |
245 | {"n", UncutEndpoint("j"), UncutEndpoint("n"), 4}, | |
246 | {"", UncutEndpoint(""), UncutEndpoint(""), 0, true /* invalid */}}); | |
7c673cae FG |
247 | } |
248 | ||
494da23a TL |
249 | TEST_F(RangeDelAggregatorTest, UntruncatedIterWithSnapshot) { |
250 | auto range_del_iter = | |
251 | MakeRangeDelIter({{"a", "e", 10}, {"e", "g", 8}, {"j", "n", 4}}); | |
252 | FragmentedRangeTombstoneList fragment_list(std::move(range_del_iter), | |
253 | bytewise_icmp); | |
254 | std::unique_ptr<FragmentedRangeTombstoneIterator> input_iter( | |
255 | new FragmentedRangeTombstoneIterator(&fragment_list, bytewise_icmp, | |
256 | 9 /* snapshot */)); | |
257 | ||
258 | TruncatedRangeDelIterator iter(std::move(input_iter), &bytewise_icmp, nullptr, | |
259 | nullptr); | |
260 | ||
261 | VerifyIterator(&iter, bytewise_icmp, | |
262 | {{UncutEndpoint("e"), UncutEndpoint("g"), 8}, | |
263 | {UncutEndpoint("j"), UncutEndpoint("n"), 4}}); | |
264 | ||
265 | VerifySeek( | |
266 | &iter, bytewise_icmp, | |
267 | {{"d", UncutEndpoint("e"), UncutEndpoint("g"), 8}, | |
268 | {"e", UncutEndpoint("e"), UncutEndpoint("g"), 8}, | |
269 | {"ia", UncutEndpoint("j"), UncutEndpoint("n"), 4}, | |
270 | {"n", UncutEndpoint(""), UncutEndpoint(""), 0, true /* invalid */}, | |
271 | {"", UncutEndpoint("e"), UncutEndpoint("g"), 8}}); | |
272 | ||
273 | VerifySeekForPrev( | |
274 | &iter, bytewise_icmp, | |
275 | {{"d", UncutEndpoint(""), UncutEndpoint(""), 0, true /* invalid */}, | |
276 | {"e", UncutEndpoint("e"), UncutEndpoint("g"), 8}, | |
277 | {"ia", UncutEndpoint("e"), UncutEndpoint("g"), 8}, | |
278 | {"n", UncutEndpoint("j"), UncutEndpoint("n"), 4}, | |
279 | {"", UncutEndpoint(""), UncutEndpoint(""), 0, true /* invalid */}}); | |
11fdf7f2 TL |
280 | } |
281 | ||
494da23a TL |
282 | TEST_F(RangeDelAggregatorTest, TruncatedIterPartiallyCutTombstones) { |
283 | auto range_del_iter = | |
284 | MakeRangeDelIter({{"a", "e", 10}, {"e", "g", 8}, {"j", "n", 4}}); | |
285 | FragmentedRangeTombstoneList fragment_list(std::move(range_del_iter), | |
286 | bytewise_icmp); | |
287 | std::unique_ptr<FragmentedRangeTombstoneIterator> input_iter( | |
288 | new FragmentedRangeTombstoneIterator(&fragment_list, bytewise_icmp, | |
289 | kMaxSequenceNumber)); | |
290 | ||
291 | InternalKey smallest("d", 7, kTypeValue); | |
292 | InternalKey largest("m", 9, kTypeValue); | |
293 | TruncatedRangeDelIterator iter(std::move(input_iter), &bytewise_icmp, | |
294 | &smallest, &largest); | |
295 | ||
1e59de90 TL |
296 | VerifyIterator( |
297 | &iter, bytewise_icmp, | |
298 | {{InternalValue("d", 7), UncutEndpoint("e"), 10}, | |
299 | {UncutEndpoint("e"), UncutEndpoint("g"), 8}, | |
300 | {UncutEndpoint("j"), InternalValue("m", 8, kValueTypeForSeek), 4}}); | |
494da23a TL |
301 | |
302 | VerifySeek( | |
303 | &iter, bytewise_icmp, | |
304 | {{"d", InternalValue("d", 7), UncutEndpoint("e"), 10}, | |
305 | {"e", UncutEndpoint("e"), UncutEndpoint("g"), 8}, | |
1e59de90 TL |
306 | {"ia", UncutEndpoint("j"), InternalValue("m", 8, kValueTypeForSeek), 4, |
307 | false /* invalid */}, | |
494da23a TL |
308 | {"n", UncutEndpoint(""), UncutEndpoint(""), 0, true /* invalid */}, |
309 | {"", InternalValue("d", 7), UncutEndpoint("e"), 10}}); | |
310 | ||
311 | VerifySeekForPrev( | |
312 | &iter, bytewise_icmp, | |
313 | {{"d", InternalValue("d", 7), UncutEndpoint("e"), 10}, | |
314 | {"e", UncutEndpoint("e"), UncutEndpoint("g"), 8}, | |
315 | {"ia", UncutEndpoint("e"), UncutEndpoint("g"), 8}, | |
1e59de90 TL |
316 | {"n", UncutEndpoint("j"), InternalValue("m", 8, kValueTypeForSeek), 4, |
317 | false /* invalid */}, | |
494da23a | 318 | {"", UncutEndpoint(""), UncutEndpoint(""), 0, true /* invalid */}}); |
11fdf7f2 TL |
319 | } |
320 | ||
494da23a TL |
321 | TEST_F(RangeDelAggregatorTest, TruncatedIterFullyCutTombstones) { |
322 | auto range_del_iter = | |
323 | MakeRangeDelIter({{"a", "e", 10}, {"e", "g", 8}, {"j", "n", 4}}); | |
324 | FragmentedRangeTombstoneList fragment_list(std::move(range_del_iter), | |
325 | bytewise_icmp); | |
326 | std::unique_ptr<FragmentedRangeTombstoneIterator> input_iter( | |
327 | new FragmentedRangeTombstoneIterator(&fragment_list, bytewise_icmp, | |
328 | kMaxSequenceNumber)); | |
329 | ||
330 | InternalKey smallest("f", 7, kTypeValue); | |
331 | InternalKey largest("i", 9, kTypeValue); | |
332 | TruncatedRangeDelIterator iter(std::move(input_iter), &bytewise_icmp, | |
333 | &smallest, &largest); | |
334 | ||
335 | VerifyIterator(&iter, bytewise_icmp, | |
336 | {{InternalValue("f", 7), UncutEndpoint("g"), 8}}); | |
337 | ||
338 | VerifySeek( | |
339 | &iter, bytewise_icmp, | |
340 | {{"d", InternalValue("f", 7), UncutEndpoint("g"), 8}, | |
341 | {"f", InternalValue("f", 7), UncutEndpoint("g"), 8}, | |
342 | {"j", UncutEndpoint(""), UncutEndpoint(""), 0, true /* invalid */}}); | |
343 | ||
344 | VerifySeekForPrev( | |
345 | &iter, bytewise_icmp, | |
346 | {{"d", UncutEndpoint(""), UncutEndpoint(""), 0, true /* invalid */}, | |
347 | {"f", InternalValue("f", 7), UncutEndpoint("g"), 8}, | |
348 | {"j", InternalValue("f", 7), UncutEndpoint("g"), 8}}); | |
11fdf7f2 TL |
349 | } |
350 | ||
494da23a TL |
351 | TEST_F(RangeDelAggregatorTest, SingleIterInAggregator) { |
352 | auto range_del_iter = MakeRangeDelIter({{"a", "e", 10}, {"c", "g", 8}}); | |
353 | FragmentedRangeTombstoneList fragment_list(std::move(range_del_iter), | |
354 | bytewise_icmp); | |
355 | std::unique_ptr<FragmentedRangeTombstoneIterator> input_iter( | |
356 | new FragmentedRangeTombstoneIterator(&fragment_list, bytewise_icmp, | |
357 | kMaxSequenceNumber)); | |
358 | ||
359 | ReadRangeDelAggregator range_del_agg(&bytewise_icmp, kMaxSequenceNumber); | |
360 | range_del_agg.AddTombstones(std::move(input_iter)); | |
361 | ||
362 | VerifyShouldDelete(&range_del_agg, {{InternalValue("a", 19), false}, | |
363 | {InternalValue("b", 9), true}, | |
364 | {InternalValue("d", 9), true}, | |
365 | {InternalValue("e", 7), true}, | |
366 | {InternalValue("g", 7), false}}); | |
367 | ||
368 | VerifyIsRangeOverlapped(&range_del_agg, {{"", "_", false}, | |
369 | {"_", "a", true}, | |
370 | {"a", "c", true}, | |
371 | {"d", "f", true}, | |
372 | {"g", "l", false}}); | |
11fdf7f2 TL |
373 | } |
374 | ||
494da23a TL |
375 | TEST_F(RangeDelAggregatorTest, MultipleItersInAggregator) { |
376 | auto fragment_lists = MakeFragmentedTombstoneLists( | |
377 | {{{"a", "e", 10}, {"c", "g", 8}}, | |
378 | {{"a", "b", 20}, {"h", "i", 25}, {"ii", "j", 15}}}); | |
379 | ||
380 | ReadRangeDelAggregator range_del_agg(&bytewise_icmp, kMaxSequenceNumber); | |
381 | for (const auto& fragment_list : fragment_lists) { | |
382 | std::unique_ptr<FragmentedRangeTombstoneIterator> input_iter( | |
383 | new FragmentedRangeTombstoneIterator(fragment_list.get(), bytewise_icmp, | |
384 | kMaxSequenceNumber)); | |
385 | range_del_agg.AddTombstones(std::move(input_iter)); | |
386 | } | |
387 | ||
388 | VerifyShouldDelete(&range_del_agg, {{InternalValue("a", 19), true}, | |
389 | {InternalValue("b", 19), false}, | |
390 | {InternalValue("b", 9), true}, | |
391 | {InternalValue("d", 9), true}, | |
392 | {InternalValue("e", 7), true}, | |
393 | {InternalValue("g", 7), false}, | |
394 | {InternalValue("h", 24), true}, | |
395 | {InternalValue("i", 24), false}, | |
396 | {InternalValue("ii", 14), true}, | |
397 | {InternalValue("j", 14), false}}); | |
398 | ||
399 | VerifyIsRangeOverlapped(&range_del_agg, {{"", "_", false}, | |
400 | {"_", "a", true}, | |
401 | {"a", "c", true}, | |
402 | {"d", "f", true}, | |
403 | {"g", "l", true}, | |
404 | {"x", "y", false}}); | |
7c673cae FG |
405 | } |
406 | ||
494da23a TL |
407 | TEST_F(RangeDelAggregatorTest, MultipleItersInAggregatorWithUpperBound) { |
408 | auto fragment_lists = MakeFragmentedTombstoneLists( | |
409 | {{{"a", "e", 10}, {"c", "g", 8}}, | |
410 | {{"a", "b", 20}, {"h", "i", 25}, {"ii", "j", 15}}}); | |
411 | ||
412 | ReadRangeDelAggregator range_del_agg(&bytewise_icmp, 19); | |
413 | for (const auto& fragment_list : fragment_lists) { | |
414 | std::unique_ptr<FragmentedRangeTombstoneIterator> input_iter( | |
415 | new FragmentedRangeTombstoneIterator(fragment_list.get(), bytewise_icmp, | |
416 | 19 /* snapshot */)); | |
417 | range_del_agg.AddTombstones(std::move(input_iter)); | |
418 | } | |
419 | ||
420 | VerifyShouldDelete(&range_del_agg, {{InternalValue("a", 19), false}, | |
421 | {InternalValue("a", 9), true}, | |
422 | {InternalValue("b", 9), true}, | |
423 | {InternalValue("d", 9), true}, | |
424 | {InternalValue("e", 7), true}, | |
425 | {InternalValue("g", 7), false}, | |
426 | {InternalValue("h", 24), false}, | |
427 | {InternalValue("i", 24), false}, | |
428 | {InternalValue("ii", 14), true}, | |
429 | {InternalValue("j", 14), false}}); | |
430 | ||
431 | VerifyIsRangeOverlapped(&range_del_agg, {{"", "_", false}, | |
432 | {"_", "a", true}, | |
433 | {"a", "c", true}, | |
434 | {"d", "f", true}, | |
435 | {"g", "l", true}, | |
436 | {"x", "y", false}}); | |
7c673cae FG |
437 | } |
438 | ||
494da23a TL |
439 | TEST_F(RangeDelAggregatorTest, MultipleTruncatedItersInAggregator) { |
440 | auto fragment_lists = MakeFragmentedTombstoneLists( | |
441 | {{{"a", "z", 10}}, {{"a", "z", 10}}, {{"a", "z", 10}}}); | |
442 | std::vector<std::pair<InternalKey, InternalKey>> iter_bounds = { | |
443 | {InternalKey("a", 4, kTypeValue), | |
444 | InternalKey("m", kMaxSequenceNumber, kTypeRangeDeletion)}, | |
445 | {InternalKey("m", 20, kTypeValue), | |
446 | InternalKey("x", kMaxSequenceNumber, kTypeRangeDeletion)}, | |
447 | {InternalKey("x", 5, kTypeValue), InternalKey("zz", 30, kTypeValue)}}; | |
448 | ||
449 | ReadRangeDelAggregator range_del_agg(&bytewise_icmp, 19); | |
450 | for (size_t i = 0; i < fragment_lists.size(); i++) { | |
451 | const auto& fragment_list = fragment_lists[i]; | |
452 | const auto& bounds = iter_bounds[i]; | |
453 | std::unique_ptr<FragmentedRangeTombstoneIterator> input_iter( | |
454 | new FragmentedRangeTombstoneIterator(fragment_list.get(), bytewise_icmp, | |
455 | 19 /* snapshot */)); | |
456 | range_del_agg.AddTombstones(std::move(input_iter), &bounds.first, | |
457 | &bounds.second); | |
458 | } | |
459 | ||
460 | VerifyShouldDelete(&range_del_agg, {{InternalValue("a", 10), false}, | |
461 | {InternalValue("a", 9), false}, | |
462 | {InternalValue("a", 4), true}, | |
463 | {InternalValue("m", 10), false}, | |
464 | {InternalValue("m", 9), true}, | |
465 | {InternalValue("x", 10), false}, | |
466 | {InternalValue("x", 9), false}, | |
467 | {InternalValue("x", 5), true}, | |
468 | {InternalValue("z", 9), false}}); | |
469 | ||
470 | VerifyIsRangeOverlapped(&range_del_agg, {{"", "_", false}, | |
471 | {"_", "a", true}, | |
472 | {"a", "n", true}, | |
473 | {"l", "x", true}, | |
474 | {"w", "z", true}, | |
475 | {"zzz", "zz", false}, | |
476 | {"zz", "zzz", false}}); | |
7c673cae FG |
477 | } |
478 | ||
494da23a TL |
479 | TEST_F(RangeDelAggregatorTest, MultipleTruncatedItersInAggregatorSameLevel) { |
480 | auto fragment_lists = MakeFragmentedTombstoneLists( | |
481 | {{{"a", "z", 10}}, {{"a", "z", 10}}, {{"a", "z", 10}}}); | |
482 | std::vector<std::pair<InternalKey, InternalKey>> iter_bounds = { | |
483 | {InternalKey("a", 4, kTypeValue), | |
484 | InternalKey("m", kMaxSequenceNumber, kTypeRangeDeletion)}, | |
485 | {InternalKey("m", 20, kTypeValue), | |
486 | InternalKey("x", kMaxSequenceNumber, kTypeRangeDeletion)}, | |
487 | {InternalKey("x", 5, kTypeValue), InternalKey("zz", 30, kTypeValue)}}; | |
488 | ||
489 | ReadRangeDelAggregator range_del_agg(&bytewise_icmp, 19); | |
490 | ||
491 | auto add_iter_to_agg = [&](size_t i) { | |
492 | std::unique_ptr<FragmentedRangeTombstoneIterator> input_iter( | |
493 | new FragmentedRangeTombstoneIterator(fragment_lists[i].get(), | |
494 | bytewise_icmp, 19 /* snapshot */)); | |
495 | range_del_agg.AddTombstones(std::move(input_iter), &iter_bounds[i].first, | |
496 | &iter_bounds[i].second); | |
497 | }; | |
498 | ||
499 | add_iter_to_agg(0); | |
500 | VerifyShouldDelete(&range_del_agg, {{InternalValue("a", 10), false}, | |
501 | {InternalValue("a", 9), false}, | |
502 | {InternalValue("a", 4), true}}); | |
503 | ||
504 | add_iter_to_agg(1); | |
505 | VerifyShouldDelete(&range_del_agg, {{InternalValue("m", 10), false}, | |
506 | {InternalValue("m", 9), true}}); | |
507 | ||
508 | add_iter_to_agg(2); | |
509 | VerifyShouldDelete(&range_del_agg, {{InternalValue("x", 10), false}, | |
510 | {InternalValue("x", 9), false}, | |
511 | {InternalValue("x", 5), true}, | |
512 | {InternalValue("z", 9), false}}); | |
513 | ||
514 | VerifyIsRangeOverlapped(&range_del_agg, {{"", "_", false}, | |
515 | {"_", "a", true}, | |
516 | {"a", "n", true}, | |
517 | {"l", "x", true}, | |
518 | {"w", "z", true}, | |
519 | {"zzz", "zz", false}, | |
520 | {"zz", "zzz", false}}); | |
7c673cae FG |
521 | } |
522 | ||
494da23a TL |
523 | TEST_F(RangeDelAggregatorTest, CompactionAggregatorNoSnapshots) { |
524 | auto fragment_lists = MakeFragmentedTombstoneLists( | |
525 | {{{"a", "e", 10}, {"c", "g", 8}}, | |
526 | {{"a", "b", 20}, {"h", "i", 25}, {"ii", "j", 15}}}); | |
527 | ||
528 | std::vector<SequenceNumber> snapshots; | |
529 | CompactionRangeDelAggregator range_del_agg(&bytewise_icmp, snapshots); | |
530 | for (const auto& fragment_list : fragment_lists) { | |
531 | std::unique_ptr<FragmentedRangeTombstoneIterator> input_iter( | |
532 | new FragmentedRangeTombstoneIterator(fragment_list.get(), bytewise_icmp, | |
533 | kMaxSequenceNumber)); | |
534 | range_del_agg.AddTombstones(std::move(input_iter)); | |
535 | } | |
536 | ||
537 | VerifyShouldDelete(&range_del_agg, {{InternalValue("a", 19), true}, | |
538 | {InternalValue("b", 19), false}, | |
539 | {InternalValue("b", 9), true}, | |
540 | {InternalValue("d", 9), true}, | |
541 | {InternalValue("e", 7), true}, | |
542 | {InternalValue("g", 7), false}, | |
543 | {InternalValue("h", 24), true}, | |
544 | {InternalValue("i", 24), false}, | |
545 | {InternalValue("ii", 14), true}, | |
546 | {InternalValue("j", 14), false}}); | |
547 | ||
548 | auto range_del_compaction_iter = range_del_agg.NewIterator(); | |
549 | VerifyFragmentedRangeDels(range_del_compaction_iter.get(), {{"a", "b", 20}, | |
550 | {"b", "c", 10}, | |
551 | {"c", "e", 10}, | |
552 | {"e", "g", 8}, | |
553 | {"h", "i", 25}, | |
554 | {"ii", "j", 15}}); | |
11fdf7f2 TL |
555 | } |
556 | ||
494da23a TL |
557 | TEST_F(RangeDelAggregatorTest, CompactionAggregatorWithSnapshots) { |
558 | auto fragment_lists = MakeFragmentedTombstoneLists( | |
559 | {{{"a", "e", 10}, {"c", "g", 8}}, | |
560 | {{"a", "b", 20}, {"h", "i", 25}, {"ii", "j", 15}}}); | |
561 | ||
562 | std::vector<SequenceNumber> snapshots{9, 19}; | |
563 | CompactionRangeDelAggregator range_del_agg(&bytewise_icmp, snapshots); | |
564 | for (const auto& fragment_list : fragment_lists) { | |
565 | std::unique_ptr<FragmentedRangeTombstoneIterator> input_iter( | |
566 | new FragmentedRangeTombstoneIterator(fragment_list.get(), bytewise_icmp, | |
567 | kMaxSequenceNumber)); | |
568 | range_del_agg.AddTombstones(std::move(input_iter)); | |
11fdf7f2 | 569 | } |
494da23a TL |
570 | |
571 | VerifyShouldDelete( | |
572 | &range_del_agg, | |
573 | { | |
574 | {InternalValue("a", 19), false}, // [10, 19] | |
575 | {InternalValue("a", 9), false}, // [0, 9] | |
576 | {InternalValue("b", 9), false}, // [0, 9] | |
577 | {InternalValue("d", 9), false}, // [0, 9] | |
578 | {InternalValue("d", 7), true}, // [0, 9] | |
579 | {InternalValue("e", 7), true}, // [0, 9] | |
580 | {InternalValue("g", 7), false}, // [0, 9] | |
581 | {InternalValue("h", 24), true}, // [20, kMaxSequenceNumber] | |
582 | {InternalValue("i", 24), false}, // [20, kMaxSequenceNumber] | |
583 | {InternalValue("ii", 14), true}, // [10, 19] | |
584 | {InternalValue("j", 14), false} // [10, 19] | |
585 | }); | |
586 | ||
587 | auto range_del_compaction_iter = range_del_agg.NewIterator(); | |
588 | VerifyFragmentedRangeDels(range_del_compaction_iter.get(), {{"a", "b", 20}, | |
589 | {"a", "b", 10}, | |
590 | {"b", "c", 10}, | |
591 | {"c", "e", 10}, | |
592 | {"c", "e", 8}, | |
593 | {"e", "g", 8}, | |
594 | {"h", "i", 25}, | |
595 | {"ii", "j", 15}}); | |
11fdf7f2 TL |
596 | } |
597 | ||
494da23a TL |
598 | TEST_F(RangeDelAggregatorTest, CompactionAggregatorEmptyIteratorLeft) { |
599 | auto fragment_lists = MakeFragmentedTombstoneLists( | |
600 | {{{"a", "e", 10}, {"c", "g", 8}}, | |
601 | {{"a", "b", 20}, {"h", "i", 25}, {"ii", "j", 15}}}); | |
602 | ||
603 | std::vector<SequenceNumber> snapshots{9, 19}; | |
604 | CompactionRangeDelAggregator range_del_agg(&bytewise_icmp, snapshots); | |
605 | for (const auto& fragment_list : fragment_lists) { | |
606 | std::unique_ptr<FragmentedRangeTombstoneIterator> input_iter( | |
607 | new FragmentedRangeTombstoneIterator(fragment_list.get(), bytewise_icmp, | |
608 | kMaxSequenceNumber)); | |
609 | range_del_agg.AddTombstones(std::move(input_iter)); | |
11fdf7f2 | 610 | } |
494da23a TL |
611 | |
612 | Slice start("_"); | |
613 | Slice end("__"); | |
11fdf7f2 TL |
614 | } |
615 | ||
494da23a TL |
616 | TEST_F(RangeDelAggregatorTest, CompactionAggregatorEmptyIteratorRight) { |
617 | auto fragment_lists = MakeFragmentedTombstoneLists( | |
618 | {{{"a", "e", 10}, {"c", "g", 8}}, | |
619 | {{"a", "b", 20}, {"h", "i", 25}, {"ii", "j", 15}}}); | |
620 | ||
621 | std::vector<SequenceNumber> snapshots{9, 19}; | |
622 | CompactionRangeDelAggregator range_del_agg(&bytewise_icmp, snapshots); | |
623 | for (const auto& fragment_list : fragment_lists) { | |
624 | std::unique_ptr<FragmentedRangeTombstoneIterator> input_iter( | |
625 | new FragmentedRangeTombstoneIterator(fragment_list.get(), bytewise_icmp, | |
626 | kMaxSequenceNumber)); | |
627 | range_del_agg.AddTombstones(std::move(input_iter)); | |
628 | } | |
629 | ||
630 | Slice start("p"); | |
631 | Slice end("q"); | |
632 | auto range_del_compaction_iter1 = | |
633 | range_del_agg.NewIterator(&start, &end, false /* end_key_inclusive */); | |
634 | VerifyFragmentedRangeDels(range_del_compaction_iter1.get(), {}); | |
635 | ||
636 | auto range_del_compaction_iter2 = | |
637 | range_del_agg.NewIterator(&start, &end, true /* end_key_inclusive */); | |
638 | VerifyFragmentedRangeDels(range_del_compaction_iter2.get(), {}); | |
11fdf7f2 TL |
639 | } |
640 | ||
494da23a TL |
641 | TEST_F(RangeDelAggregatorTest, CompactionAggregatorBoundedIterator) { |
642 | auto fragment_lists = MakeFragmentedTombstoneLists( | |
643 | {{{"a", "e", 10}, {"c", "g", 8}}, | |
644 | {{"a", "b", 20}, {"h", "i", 25}, {"ii", "j", 15}}}); | |
645 | ||
646 | std::vector<SequenceNumber> snapshots{9, 19}; | |
647 | CompactionRangeDelAggregator range_del_agg(&bytewise_icmp, snapshots); | |
648 | for (const auto& fragment_list : fragment_lists) { | |
649 | std::unique_ptr<FragmentedRangeTombstoneIterator> input_iter( | |
650 | new FragmentedRangeTombstoneIterator(fragment_list.get(), bytewise_icmp, | |
651 | kMaxSequenceNumber)); | |
652 | range_del_agg.AddTombstones(std::move(input_iter)); | |
653 | } | |
654 | ||
655 | Slice start("bb"); | |
656 | Slice end("e"); | |
657 | auto range_del_compaction_iter1 = | |
658 | range_del_agg.NewIterator(&start, &end, false /* end_key_inclusive */); | |
659 | VerifyFragmentedRangeDels(range_del_compaction_iter1.get(), | |
660 | {{"a", "c", 10}, {"c", "e", 10}, {"c", "e", 8}}); | |
661 | ||
662 | auto range_del_compaction_iter2 = | |
663 | range_del_agg.NewIterator(&start, &end, true /* end_key_inclusive */); | |
664 | VerifyFragmentedRangeDels( | |
665 | range_del_compaction_iter2.get(), | |
666 | {{"a", "c", 10}, {"c", "e", 10}, {"c", "e", 8}, {"e", "g", 8}}); | |
11fdf7f2 TL |
667 | } |
668 | ||
494da23a TL |
669 | TEST_F(RangeDelAggregatorTest, |
670 | CompactionAggregatorBoundedIteratorExtraFragments) { | |
671 | auto fragment_lists = MakeFragmentedTombstoneLists( | |
672 | {{{"a", "d", 10}, {"c", "g", 8}}, | |
673 | {{"b", "c", 20}, {"d", "f", 30}, {"h", "i", 25}, {"ii", "j", 15}}}); | |
674 | ||
675 | std::vector<SequenceNumber> snapshots{9, 19}; | |
676 | CompactionRangeDelAggregator range_del_agg(&bytewise_icmp, snapshots); | |
677 | for (const auto& fragment_list : fragment_lists) { | |
678 | std::unique_ptr<FragmentedRangeTombstoneIterator> input_iter( | |
679 | new FragmentedRangeTombstoneIterator(fragment_list.get(), bytewise_icmp, | |
680 | kMaxSequenceNumber)); | |
681 | range_del_agg.AddTombstones(std::move(input_iter)); | |
682 | } | |
683 | ||
684 | Slice start("bb"); | |
685 | Slice end("e"); | |
686 | auto range_del_compaction_iter1 = | |
687 | range_del_agg.NewIterator(&start, &end, false /* end_key_inclusive */); | |
688 | VerifyFragmentedRangeDels(range_del_compaction_iter1.get(), {{"a", "b", 10}, | |
689 | {"b", "c", 20}, | |
690 | {"b", "c", 10}, | |
691 | {"c", "d", 10}, | |
692 | {"c", "d", 8}, | |
693 | {"d", "f", 30}, | |
694 | {"d", "f", 8}, | |
695 | {"f", "g", 8}}); | |
696 | ||
697 | auto range_del_compaction_iter2 = | |
698 | range_del_agg.NewIterator(&start, &end, true /* end_key_inclusive */); | |
699 | VerifyFragmentedRangeDels(range_del_compaction_iter2.get(), {{"a", "b", 10}, | |
700 | {"b", "c", 20}, | |
701 | {"b", "c", 10}, | |
702 | {"c", "d", 10}, | |
703 | {"c", "d", 8}, | |
704 | {"d", "f", 30}, | |
705 | {"d", "f", 8}, | |
706 | {"f", "g", 8}}); | |
7c673cae FG |
707 | } |
708 | ||
f67539c2 | 709 | } // namespace ROCKSDB_NAMESPACE |
7c673cae FG |
710 | |
711 | int main(int argc, char** argv) { | |
1e59de90 | 712 | ROCKSDB_NAMESPACE::port::InstallStackTraceHandler(); |
7c673cae FG |
713 | ::testing::InitGoogleTest(&argc, argv); |
714 | return RUN_ALL_TESTS(); | |
715 | } |