1 //  Copyright (c) 2011-present, Facebook, Inc.  All rights reserved.
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).
5 
6 #include "db/compaction/compaction_iterator.h"
7 
8 #include <string>
9 #include <vector>
10 
11 #include "db/dbformat.h"
12 #include "port/port.h"
13 #include "test_util/testharness.h"
14 #include "test_util/testutil.h"
15 #include "util/string_util.h"
16 #include "util/vector_iterator.h"
17 #include "utilities/merge_operators.h"
18 
19 namespace ROCKSDB_NAMESPACE {
20 
21 // Expects no merging attempts.
22 class NoMergingMergeOp : public MergeOperator {
23  public:
FullMergeV2(const MergeOperationInput &,MergeOperationOutput *) const24   bool FullMergeV2(const MergeOperationInput& /*merge_in*/,
25                    MergeOperationOutput* /*merge_out*/) const override {
26     ADD_FAILURE();
27     return false;
28   }
PartialMergeMulti(const Slice &,const std::deque<Slice> &,std::string *,Logger *) const29   bool PartialMergeMulti(const Slice& /*key*/,
30                          const std::deque<Slice>& /*operand_list*/,
31                          std::string* /*new_value*/,
32                          Logger* /*logger*/) const override {
33     ADD_FAILURE();
34     return false;
35   }
Name() const36   const char* Name() const override {
37     return "CompactionIteratorTest NoMergingMergeOp";
38   }
39 };
40 
41 // Compaction filter that gets stuck when it sees a particular key,
42 // then gets unstuck when told to.
43 // Always returns Decision::kRemove.
44 class StallingFilter : public CompactionFilter {
45  public:
FilterV2(int,const Slice & key,ValueType,const Slice &,std::string *,std::string *) const46   Decision FilterV2(int /*level*/, const Slice& key, ValueType /*type*/,
47                     const Slice& /*existing_value*/, std::string* /*new_value*/,
48                     std::string* /*skip_until*/) const override {
49     int k = std::atoi(key.ToString().c_str());
50     last_seen.store(k);
51     while (k >= stall_at.load()) {
52       std::this_thread::yield();
53     }
54     return Decision::kRemove;
55   }
56 
Name() const57   const char* Name() const override {
58     return "CompactionIteratorTest StallingFilter";
59   }
60 
61   // Wait until the filter sees a key >= k and stalls at that key.
62   // If `exact`, asserts that the seen key is equal to k.
WaitForStall(int k,bool exact=true)63   void WaitForStall(int k, bool exact = true) {
64     stall_at.store(k);
65     while (last_seen.load() < k) {
66       std::this_thread::yield();
67     }
68     if (exact) {
69       EXPECT_EQ(k, last_seen.load());
70     }
71   }
72 
73   // Filter will stall on key >= stall_at. Advance stall_at to unstall.
74   mutable std::atomic<int> stall_at{0};
75   // Last key the filter was called with.
76   mutable std::atomic<int> last_seen{0};
77 };
78 
79 // Compaction filter that filter out all keys.
80 class FilterAllKeysCompactionFilter : public CompactionFilter {
81  public:
FilterV2(int,const Slice &,ValueType,const Slice &,std::string *,std::string *) const82   Decision FilterV2(int /*level*/, const Slice& /*key*/, ValueType /*type*/,
83                     const Slice& /*existing_value*/, std::string* /*new_value*/,
84                     std::string* /*skip_until*/) const override {
85     return Decision::kRemove;
86   }
87 
Name() const88   const char* Name() const override { return "AllKeysCompactionFilter"; }
89 };
90 
91 class LoggingForwardVectorIterator : public VectorIterator {
92  public:
93   struct Action {
94     enum class Type {
95       SEEK_TO_FIRST,
96       SEEK,
97       NEXT,
98     };
99 
100     Type type;
101     std::string arg;
102 
ActionROCKSDB_NAMESPACE::LoggingForwardVectorIterator::Action103     explicit Action(Type _type, std::string _arg = "")
104         : type(_type), arg(_arg) {}
105 
operator ==ROCKSDB_NAMESPACE::LoggingForwardVectorIterator::Action106     bool operator==(const Action& rhs) const {
107       return std::tie(type, arg) == std::tie(rhs.type, rhs.arg);
108     }
109   };
110 
LoggingForwardVectorIterator(const std::vector<std::string> & keys,const std::vector<std::string> & values)111   LoggingForwardVectorIterator(const std::vector<std::string>& keys,
112                                const std::vector<std::string>& values)
113       : VectorIterator(keys, values) {
114     current_ = keys_.size();
115   }
116 
SeekToFirst()117   void SeekToFirst() override {
118     log.emplace_back(Action::Type::SEEK_TO_FIRST);
119     VectorIterator::SeekToFirst();
120   }
SeekToLast()121   void SeekToLast() override { assert(false); }
122 
Seek(const Slice & target)123   void Seek(const Slice& target) override {
124     log.emplace_back(Action::Type::SEEK, target.ToString());
125     VectorIterator::Seek(target);
126   }
127 
SeekForPrev(const Slice &)128   void SeekForPrev(const Slice& /*target*/) override { assert(false); }
129 
Next()130   void Next() override {
131     assert(Valid());
132     log.emplace_back(Action::Type::NEXT);
133     VectorIterator::Next();
134   }
Prev()135   void Prev() override { assert(false); }
136 
key() const137   Slice key() const override {
138     assert(Valid());
139     return VectorIterator::key();
140   }
value() const141   Slice value() const override {
142     assert(Valid());
143     return VectorIterator::value();
144   }
145 
146   std::vector<Action> log;
147 };
148 
149 class FakeCompaction : public CompactionIterator::CompactionProxy {
150  public:
level() const151   int level() const override { return 0; }
152 
KeyNotExistsBeyondOutputLevel(const Slice &,std::vector<size_t> *) const153   bool KeyNotExistsBeyondOutputLevel(
154       const Slice& /*user_key*/,
155       std::vector<size_t>* /*level_ptrs*/) const override {
156     return is_bottommost_level || key_not_exists_beyond_output_level;
157   }
158 
bottommost_level() const159   bool bottommost_level() const override { return is_bottommost_level; }
160 
number_levels() const161   int number_levels() const override { return 1; }
162 
GetLargestUserKey() const163   Slice GetLargestUserKey() const override {
164     return "\xff\xff\xff\xff\xff\xff\xff\xff\xff";
165   }
166 
allow_ingest_behind() const167   bool allow_ingest_behind() const override { return is_allow_ingest_behind; }
168 
preserve_deletes() const169   bool preserve_deletes() const override { return false; }
170 
enable_blob_garbage_collection() const171   bool enable_blob_garbage_collection() const override { return false; }
172 
blob_garbage_collection_age_cutoff() const173   double blob_garbage_collection_age_cutoff() const override { return 0.0; }
174 
input_version() const175   Version* input_version() const override { return nullptr; }
176 
DoesInputReferenceBlobFiles() const177   bool DoesInputReferenceBlobFiles() const override { return false; }
178 
real_compaction() const179   const Compaction* real_compaction() const override { return nullptr; }
180 
181   bool key_not_exists_beyond_output_level = false;
182 
183   bool is_bottommost_level = false;
184 
185   bool is_allow_ingest_behind = false;
186 };
187 
188 // A simplified snapshot checker which assumes each snapshot has a global
189 // last visible sequence.
190 class TestSnapshotChecker : public SnapshotChecker {
191  public:
TestSnapshotChecker(SequenceNumber last_committed_sequence,const std::unordered_map<SequenceNumber,SequenceNumber> & snapshots={{}})192   explicit TestSnapshotChecker(
193       SequenceNumber last_committed_sequence,
194       const std::unordered_map<SequenceNumber, SequenceNumber>& snapshots = {{}})
195       : last_committed_sequence_(last_committed_sequence),
196         snapshots_(snapshots) {}
197 
CheckInSnapshot(SequenceNumber seq,SequenceNumber snapshot_seq) const198   SnapshotCheckerResult CheckInSnapshot(
199       SequenceNumber seq, SequenceNumber snapshot_seq) const override {
200     if (snapshot_seq == kMaxSequenceNumber) {
201       return seq <= last_committed_sequence_
202                  ? SnapshotCheckerResult::kInSnapshot
203                  : SnapshotCheckerResult::kNotInSnapshot;
204     }
205     assert(snapshots_.count(snapshot_seq) > 0);
206     return seq <= snapshots_.at(snapshot_seq)
207                ? SnapshotCheckerResult::kInSnapshot
208                : SnapshotCheckerResult::kNotInSnapshot;
209   }
210 
211  private:
212   SequenceNumber last_committed_sequence_;
213   // A map of valid snapshot to last visible sequence to the snapshot.
214   std::unordered_map<SequenceNumber, SequenceNumber> snapshots_;
215 };
216 
217 // Test param:
218 //   bool: whether to pass snapshot_checker to compaction iterator.
219 class CompactionIteratorTest : public testing::TestWithParam<bool> {
220  public:
CompactionIteratorTest()221   CompactionIteratorTest()
222       : cmp_(BytewiseComparator()), icmp_(cmp_), snapshots_({}) {}
223 
CompactionIteratorTest(const Comparator * ucmp)224   explicit CompactionIteratorTest(const Comparator* ucmp)
225       : cmp_(ucmp), icmp_(cmp_), snapshots_({}) {}
226 
InitIterators(const std::vector<std::string> & ks,const std::vector<std::string> & vs,const std::vector<std::string> & range_del_ks,const std::vector<std::string> & range_del_vs,SequenceNumber last_sequence,SequenceNumber last_committed_sequence=kMaxSequenceNumber,MergeOperator * merge_op=nullptr,CompactionFilter * filter=nullptr,bool bottommost_level=false,SequenceNumber earliest_write_conflict_snapshot=kMaxSequenceNumber,bool key_not_exists_beyond_output_level=false,const std::string * full_history_ts_low=nullptr)227   void InitIterators(
228       const std::vector<std::string>& ks, const std::vector<std::string>& vs,
229       const std::vector<std::string>& range_del_ks,
230       const std::vector<std::string>& range_del_vs,
231       SequenceNumber last_sequence,
232       SequenceNumber last_committed_sequence = kMaxSequenceNumber,
233       MergeOperator* merge_op = nullptr, CompactionFilter* filter = nullptr,
234       bool bottommost_level = false,
235       SequenceNumber earliest_write_conflict_snapshot = kMaxSequenceNumber,
236       bool key_not_exists_beyond_output_level = false,
237       const std::string* full_history_ts_low = nullptr) {
238     std::unique_ptr<InternalIterator> unfragmented_range_del_iter(
239         new VectorIterator(range_del_ks, range_del_vs, &icmp_));
240     auto tombstone_list = std::make_shared<FragmentedRangeTombstoneList>(
241         std::move(unfragmented_range_del_iter), icmp_);
242     std::unique_ptr<FragmentedRangeTombstoneIterator> range_del_iter(
243         new FragmentedRangeTombstoneIterator(tombstone_list, icmp_,
244                                              kMaxSequenceNumber));
245     range_del_agg_.reset(new CompactionRangeDelAggregator(&icmp_, snapshots_));
246     range_del_agg_->AddTombstones(std::move(range_del_iter));
247 
248     std::unique_ptr<CompactionIterator::CompactionProxy> compaction;
249     if (filter || bottommost_level || key_not_exists_beyond_output_level) {
250       compaction_proxy_ = new FakeCompaction();
251       compaction_proxy_->is_bottommost_level = bottommost_level;
252       compaction_proxy_->is_allow_ingest_behind = AllowIngestBehind();
253       compaction_proxy_->key_not_exists_beyond_output_level =
254           key_not_exists_beyond_output_level;
255       compaction.reset(compaction_proxy_);
256     }
257     bool use_snapshot_checker = UseSnapshotChecker() || GetParam();
258     if (use_snapshot_checker || last_committed_sequence < kMaxSequenceNumber) {
259       snapshot_checker_.reset(
260           new TestSnapshotChecker(last_committed_sequence, snapshot_map_));
261     }
262     merge_helper_.reset(
263         new MergeHelper(Env::Default(), cmp_, merge_op, filter, nullptr, false,
264                         0 /*latest_snapshot*/, snapshot_checker_.get(),
265                         0 /*level*/, nullptr /*statistics*/, &shutting_down_));
266 
267     if (c_iter_) {
268       // Since iter_ is still used in ~CompactionIterator(), we call
269       // ~CompactionIterator() first.
270       c_iter_.reset();
271     }
272     iter_.reset(new LoggingForwardVectorIterator(ks, vs));
273     iter_->SeekToFirst();
274     c_iter_.reset(new CompactionIterator(
275         iter_.get(), cmp_, merge_helper_.get(), last_sequence, &snapshots_,
276         earliest_write_conflict_snapshot, snapshot_checker_.get(),
277         Env::Default(), false /* report_detailed_time */, false,
278         range_del_agg_.get(), nullptr /* blob_file_builder */,
279         true /*allow_data_in_errors*/, std::move(compaction), filter,
280         &shutting_down_, /*preserve_deletes_seqnum=*/0,
281         /*manual_compaction_paused=*/nullptr,
282         /*manual_compaction_canceled=*/nullptr, /*info_log=*/nullptr,
283         full_history_ts_low));
284   }
285 
AddSnapshot(SequenceNumber snapshot,SequenceNumber last_visible_seq=kMaxSequenceNumber)286   void AddSnapshot(SequenceNumber snapshot,
287                    SequenceNumber last_visible_seq = kMaxSequenceNumber) {
288     snapshots_.push_back(snapshot);
289     snapshot_map_[snapshot] = last_visible_seq;
290   }
291 
UseSnapshotChecker() const292   virtual bool UseSnapshotChecker() const { return false; }
293 
AllowIngestBehind() const294   virtual bool AllowIngestBehind() const { return false; }
295 
RunTest(const std::vector<std::string> & input_keys,const std::vector<std::string> & input_values,const std::vector<std::string> & expected_keys,const std::vector<std::string> & expected_values,SequenceNumber last_committed_seq=kMaxSequenceNumber,MergeOperator * merge_operator=nullptr,CompactionFilter * compaction_filter=nullptr,bool bottommost_level=false,SequenceNumber earliest_write_conflict_snapshot=kMaxSequenceNumber,bool key_not_exists_beyond_output_level=false,const std::string * full_history_ts_low=nullptr)296   void RunTest(
297       const std::vector<std::string>& input_keys,
298       const std::vector<std::string>& input_values,
299       const std::vector<std::string>& expected_keys,
300       const std::vector<std::string>& expected_values,
301       SequenceNumber last_committed_seq = kMaxSequenceNumber,
302       MergeOperator* merge_operator = nullptr,
303       CompactionFilter* compaction_filter = nullptr,
304       bool bottommost_level = false,
305       SequenceNumber earliest_write_conflict_snapshot = kMaxSequenceNumber,
306       bool key_not_exists_beyond_output_level = false,
307       const std::string* full_history_ts_low = nullptr) {
308     InitIterators(input_keys, input_values, {}, {}, kMaxSequenceNumber,
309                   last_committed_seq, merge_operator, compaction_filter,
310                   bottommost_level, earliest_write_conflict_snapshot,
311                   key_not_exists_beyond_output_level, full_history_ts_low);
312     c_iter_->SeekToFirst();
313     for (size_t i = 0; i < expected_keys.size(); i++) {
314       std::string info = "i = " + ToString(i);
315       ASSERT_TRUE(c_iter_->Valid()) << info;
316       ASSERT_OK(c_iter_->status()) << info;
317       ASSERT_EQ(expected_keys[i], c_iter_->key().ToString()) << info;
318       ASSERT_EQ(expected_values[i], c_iter_->value().ToString()) << info;
319       c_iter_->Next();
320     }
321     ASSERT_OK(c_iter_->status());
322     ASSERT_FALSE(c_iter_->Valid());
323   }
324 
ClearSnapshots()325   void ClearSnapshots() {
326     snapshots_.clear();
327     snapshot_map_.clear();
328   }
329 
330   const Comparator* cmp_;
331   const InternalKeyComparator icmp_;
332   std::vector<SequenceNumber> snapshots_;
333   // A map of valid snapshot to last visible sequence to the snapshot.
334   std::unordered_map<SequenceNumber, SequenceNumber> snapshot_map_;
335   std::unique_ptr<MergeHelper> merge_helper_;
336   std::unique_ptr<LoggingForwardVectorIterator> iter_;
337   std::unique_ptr<CompactionIterator> c_iter_;
338   std::unique_ptr<CompactionRangeDelAggregator> range_del_agg_;
339   std::unique_ptr<SnapshotChecker> snapshot_checker_;
340   std::atomic<bool> shutting_down_{false};
341   FakeCompaction* compaction_proxy_;
342 };
343 
344 // It is possible that the output of the compaction iterator is empty even if
345 // the input is not.
TEST_P(CompactionIteratorTest,EmptyResult)346 TEST_P(CompactionIteratorTest, EmptyResult) {
347   InitIterators({test::KeyStr("a", 5, kTypeSingleDeletion),
348                  test::KeyStr("a", 3, kTypeValue)},
349                 {"", "val"}, {}, {}, 5);
350   c_iter_->SeekToFirst();
351   ASSERT_OK(c_iter_->status());
352   ASSERT_FALSE(c_iter_->Valid());
353 }
354 
355 // If there is a corruption after a single deletion, the corrupted key should
356 // be preserved.
TEST_P(CompactionIteratorTest,CorruptionAfterSingleDeletion)357 TEST_P(CompactionIteratorTest, CorruptionAfterSingleDeletion) {
358   InitIterators({test::KeyStr("a", 5, kTypeSingleDeletion),
359                  test::KeyStr("a", 3, kTypeValue, true),
360                  test::KeyStr("b", 10, kTypeValue)},
361                 {"", "val", "val2"}, {}, {}, 10);
362   c_iter_->SeekToFirst();
363   ASSERT_TRUE(c_iter_->Valid());
364   ASSERT_EQ(test::KeyStr("a", 5, kTypeSingleDeletion),
365             c_iter_->key().ToString());
366   c_iter_->Next();
367   ASSERT_TRUE(c_iter_->Valid());
368   ASSERT_EQ(test::KeyStr("a", 3, kTypeValue, true), c_iter_->key().ToString());
369   c_iter_->Next();
370   ASSERT_TRUE(c_iter_->Valid());
371   ASSERT_EQ(test::KeyStr("b", 10, kTypeValue), c_iter_->key().ToString());
372   c_iter_->Next();
373   ASSERT_OK(c_iter_->status());
374   ASSERT_FALSE(c_iter_->Valid());
375 }
376 
TEST_P(CompactionIteratorTest,SimpleRangeDeletion)377 TEST_P(CompactionIteratorTest, SimpleRangeDeletion) {
378   InitIterators({test::KeyStr("morning", 5, kTypeValue),
379                  test::KeyStr("morning", 2, kTypeValue),
380                  test::KeyStr("night", 3, kTypeValue)},
381                 {"zao", "zao", "wan"},
382                 {test::KeyStr("ma", 4, kTypeRangeDeletion)}, {"mz"}, 5);
383   c_iter_->SeekToFirst();
384   ASSERT_TRUE(c_iter_->Valid());
385   ASSERT_EQ(test::KeyStr("morning", 5, kTypeValue), c_iter_->key().ToString());
386   c_iter_->Next();
387   ASSERT_TRUE(c_iter_->Valid());
388   ASSERT_EQ(test::KeyStr("night", 3, kTypeValue), c_iter_->key().ToString());
389   c_iter_->Next();
390   ASSERT_OK(c_iter_->status());
391   ASSERT_FALSE(c_iter_->Valid());
392 }
393 
TEST_P(CompactionIteratorTest,RangeDeletionWithSnapshots)394 TEST_P(CompactionIteratorTest, RangeDeletionWithSnapshots) {
395   AddSnapshot(10);
396   std::vector<std::string> ks1;
397   ks1.push_back(test::KeyStr("ma", 28, kTypeRangeDeletion));
398   std::vector<std::string> vs1{"mz"};
399   std::vector<std::string> ks2{test::KeyStr("morning", 15, kTypeValue),
400                                test::KeyStr("morning", 5, kTypeValue),
401                                test::KeyStr("night", 40, kTypeValue),
402                                test::KeyStr("night", 20, kTypeValue)};
403   std::vector<std::string> vs2{"zao 15", "zao 5", "wan 40", "wan 20"};
404   InitIterators(ks2, vs2, ks1, vs1, 40);
405   c_iter_->SeekToFirst();
406   ASSERT_TRUE(c_iter_->Valid());
407   ASSERT_EQ(test::KeyStr("morning", 5, kTypeValue), c_iter_->key().ToString());
408   c_iter_->Next();
409   ASSERT_TRUE(c_iter_->Valid());
410   ASSERT_EQ(test::KeyStr("night", 40, kTypeValue), c_iter_->key().ToString());
411   c_iter_->Next();
412   ASSERT_OK(c_iter_->status());
413   ASSERT_FALSE(c_iter_->Valid());
414 }
415 
TEST_P(CompactionIteratorTest,CompactionFilterSkipUntil)416 TEST_P(CompactionIteratorTest, CompactionFilterSkipUntil) {
417   class Filter : public CompactionFilter {
418     Decision FilterV2(int /*level*/, const Slice& key, ValueType t,
419                       const Slice& existing_value, std::string* /*new_value*/,
420                       std::string* skip_until) const override {
421       std::string k = key.ToString();
422       std::string v = existing_value.ToString();
423       // See InitIterators() call below for the sequence of keys and their
424       // filtering decisions. Here we closely assert that compaction filter is
425       // called with the expected keys and only them, and with the right values.
426       if (k == "a") {
427         EXPECT_EQ(ValueType::kValue, t);
428         EXPECT_EQ("av50", v);
429         return Decision::kKeep;
430       }
431       if (k == "b") {
432         EXPECT_EQ(ValueType::kValue, t);
433         EXPECT_EQ("bv60", v);
434         *skip_until = "d+";
435         return Decision::kRemoveAndSkipUntil;
436       }
437       if (k == "e") {
438         EXPECT_EQ(ValueType::kMergeOperand, t);
439         EXPECT_EQ("em71", v);
440         return Decision::kKeep;
441       }
442       if (k == "f") {
443         if (v == "fm65") {
444           EXPECT_EQ(ValueType::kMergeOperand, t);
445           *skip_until = "f";
446         } else {
447           EXPECT_EQ("fm30", v);
448           EXPECT_EQ(ValueType::kMergeOperand, t);
449           *skip_until = "g+";
450         }
451         return Decision::kRemoveAndSkipUntil;
452       }
453       if (k == "h") {
454         EXPECT_EQ(ValueType::kValue, t);
455         EXPECT_EQ("hv91", v);
456         return Decision::kKeep;
457       }
458       if (k == "i") {
459         EXPECT_EQ(ValueType::kMergeOperand, t);
460         EXPECT_EQ("im95", v);
461         *skip_until = "z";
462         return Decision::kRemoveAndSkipUntil;
463       }
464       ADD_FAILURE();
465       return Decision::kKeep;
466     }
467 
468     const char* Name() const override {
469       return "CompactionIteratorTest.CompactionFilterSkipUntil::Filter";
470     }
471   };
472 
473   NoMergingMergeOp merge_op;
474   Filter filter;
475   InitIterators(
476       {test::KeyStr("a", 50, kTypeValue),  // keep
477        test::KeyStr("a", 45, kTypeMerge),
478        test::KeyStr("b", 60, kTypeValue),  // skip to "d+"
479        test::KeyStr("b", 40, kTypeValue), test::KeyStr("c", 35, kTypeValue),
480        test::KeyStr("d", 70, kTypeMerge),
481        test::KeyStr("e", 71, kTypeMerge),  // keep
482        test::KeyStr("f", 65, kTypeMerge),  // skip to "f", aka keep
483        test::KeyStr("f", 30, kTypeMerge),  // skip to "g+"
484        test::KeyStr("f", 25, kTypeValue), test::KeyStr("g", 90, kTypeValue),
485        test::KeyStr("h", 91, kTypeValue),  // keep
486        test::KeyStr("i", 95, kTypeMerge),  // skip to "z"
487        test::KeyStr("j", 99, kTypeValue)},
488       {"av50", "am45", "bv60", "bv40", "cv35", "dm70", "em71", "fm65", "fm30",
489        "fv25", "gv90", "hv91", "im95", "jv99"},
490       {}, {}, kMaxSequenceNumber, kMaxSequenceNumber, &merge_op, &filter);
491 
492   // Compaction should output just "a", "e" and "h" keys.
493   c_iter_->SeekToFirst();
494   ASSERT_TRUE(c_iter_->Valid());
495   ASSERT_EQ(test::KeyStr("a", 50, kTypeValue), c_iter_->key().ToString());
496   ASSERT_EQ("av50", c_iter_->value().ToString());
497   c_iter_->Next();
498   ASSERT_TRUE(c_iter_->Valid());
499   ASSERT_EQ(test::KeyStr("e", 71, kTypeMerge), c_iter_->key().ToString());
500   ASSERT_EQ("em71", c_iter_->value().ToString());
501   c_iter_->Next();
502   ASSERT_TRUE(c_iter_->Valid());
503   ASSERT_EQ(test::KeyStr("h", 91, kTypeValue), c_iter_->key().ToString());
504   ASSERT_EQ("hv91", c_iter_->value().ToString());
505   c_iter_->Next();
506   ASSERT_OK(c_iter_->status());
507   ASSERT_FALSE(c_iter_->Valid());
508 
509   // Check that the compaction iterator did the correct sequence of calls on
510   // the underlying iterator.
511   using A = LoggingForwardVectorIterator::Action;
512   using T = A::Type;
513   std::vector<A> expected_actions = {
514       A(T::SEEK_TO_FIRST),
515       A(T::NEXT),
516       A(T::NEXT),
517       A(T::SEEK, test::KeyStr("d+", kMaxSequenceNumber, kValueTypeForSeek)),
518       A(T::NEXT),
519       A(T::NEXT),
520       A(T::SEEK, test::KeyStr("g+", kMaxSequenceNumber, kValueTypeForSeek)),
521       A(T::NEXT),
522       A(T::SEEK, test::KeyStr("z", kMaxSequenceNumber, kValueTypeForSeek))};
523   ASSERT_EQ(expected_actions, iter_->log);
524 }
525 
TEST_P(CompactionIteratorTest,ShuttingDownInFilter)526 TEST_P(CompactionIteratorTest, ShuttingDownInFilter) {
527   NoMergingMergeOp merge_op;
528   StallingFilter filter;
529   InitIterators(
530       {test::KeyStr("1", 1, kTypeValue), test::KeyStr("2", 2, kTypeValue),
531        test::KeyStr("3", 3, kTypeValue), test::KeyStr("4", 4, kTypeValue)},
532       {"v1", "v2", "v3", "v4"}, {}, {}, kMaxSequenceNumber, kMaxSequenceNumber,
533       &merge_op, &filter);
534   // Don't leave tombstones (kTypeDeletion) for filtered keys.
535   compaction_proxy_->key_not_exists_beyond_output_level = true;
536 
537   std::atomic<bool> seek_done{false};
538   ROCKSDB_NAMESPACE::port::Thread compaction_thread([&] {
539     c_iter_->SeekToFirst();
540     EXPECT_FALSE(c_iter_->Valid());
541     EXPECT_TRUE(c_iter_->status().IsShutdownInProgress());
542     seek_done.store(true);
543   });
544 
545   // Let key 1 through.
546   filter.WaitForStall(1);
547 
548   // Shutdown during compaction filter call for key 2.
549   filter.WaitForStall(2);
550   shutting_down_.store(true);
551   EXPECT_FALSE(seek_done.load());
552 
553   // Unstall filter and wait for SeekToFirst() to return.
554   filter.stall_at.store(3);
555   compaction_thread.join();
556   assert(seek_done.load());
557 
558   // Check that filter was never called again.
559   EXPECT_EQ(2, filter.last_seen.load());
560 }
561 
562 // Same as ShuttingDownInFilter, but shutdown happens during filter call for
563 // a merge operand, not for a value.
TEST_P(CompactionIteratorTest,ShuttingDownInMerge)564 TEST_P(CompactionIteratorTest, ShuttingDownInMerge) {
565   NoMergingMergeOp merge_op;
566   StallingFilter filter;
567   InitIterators(
568       {test::KeyStr("1", 1, kTypeValue), test::KeyStr("2", 2, kTypeMerge),
569        test::KeyStr("3", 3, kTypeMerge), test::KeyStr("4", 4, kTypeValue)},
570       {"v1", "v2", "v3", "v4"}, {}, {}, kMaxSequenceNumber, kMaxSequenceNumber,
571       &merge_op, &filter);
572   compaction_proxy_->key_not_exists_beyond_output_level = true;
573 
574   std::atomic<bool> seek_done{false};
575   ROCKSDB_NAMESPACE::port::Thread compaction_thread([&] {
576     c_iter_->SeekToFirst();
577     ASSERT_FALSE(c_iter_->Valid());
578     ASSERT_TRUE(c_iter_->status().IsShutdownInProgress());
579     seek_done.store(true);
580   });
581 
582   // Let key 1 through.
583   filter.WaitForStall(1);
584 
585   // Shutdown during compaction filter call for key 2.
586   filter.WaitForStall(2);
587   shutting_down_.store(true);
588   EXPECT_FALSE(seek_done.load());
589 
590   // Unstall filter and wait for SeekToFirst() to return.
591   filter.stall_at.store(3);
592   compaction_thread.join();
593   assert(seek_done.load());
594 
595   // Check that filter was never called again.
596   EXPECT_EQ(2, filter.last_seen.load());
597 }
598 
TEST_P(CompactionIteratorTest,SingleMergeOperand)599 TEST_P(CompactionIteratorTest, SingleMergeOperand) {
600   class Filter : public CompactionFilter {
601     Decision FilterV2(int /*level*/, const Slice& key, ValueType t,
602                       const Slice& existing_value, std::string* /*new_value*/,
603                       std::string* /*skip_until*/) const override {
604       std::string k = key.ToString();
605       std::string v = existing_value.ToString();
606 
607       // See InitIterators() call below for the sequence of keys and their
608       // filtering decisions. Here we closely assert that compaction filter is
609       // called with the expected keys and only them, and with the right values.
610       if (k == "a") {
611         EXPECT_EQ(ValueType::kMergeOperand, t);
612         EXPECT_EQ("av1", v);
613         return Decision::kKeep;
614       } else if (k == "b") {
615         EXPECT_EQ(ValueType::kMergeOperand, t);
616         return Decision::kKeep;
617       } else if (k == "c") {
618         return Decision::kKeep;
619       }
620 
621       ADD_FAILURE();
622       return Decision::kKeep;
623     }
624 
625     const char* Name() const override {
626       return "CompactionIteratorTest.SingleMergeOperand::Filter";
627     }
628   };
629 
630   class SingleMergeOp : public MergeOperator {
631    public:
632     bool FullMergeV2(const MergeOperationInput& merge_in,
633                      MergeOperationOutput* merge_out) const override {
634       // See InitIterators() call below for why "c" is the only key for which
635       // FullMergeV2 should be called.
636       EXPECT_EQ("c", merge_in.key.ToString());
637 
638       std::string temp_value;
639       if (merge_in.existing_value != nullptr) {
640         temp_value = merge_in.existing_value->ToString();
641       }
642 
643       for (auto& operand : merge_in.operand_list) {
644         temp_value.append(operand.ToString());
645       }
646       merge_out->new_value = temp_value;
647 
648       return true;
649     }
650 
651     bool PartialMergeMulti(const Slice& key,
652                            const std::deque<Slice>& operand_list,
653                            std::string* new_value,
654                            Logger* /*logger*/) const override {
655       std::string string_key = key.ToString();
656       EXPECT_TRUE(string_key == "a" || string_key == "b");
657 
658       if (string_key == "a") {
659         EXPECT_EQ(1, operand_list.size());
660       } else if (string_key == "b") {
661         EXPECT_EQ(2, operand_list.size());
662       }
663 
664       std::string temp_value;
665       for (auto& operand : operand_list) {
666         temp_value.append(operand.ToString());
667       }
668       swap(temp_value, *new_value);
669 
670       return true;
671     }
672 
673     const char* Name() const override {
674       return "CompactionIteratorTest SingleMergeOp";
675     }
676 
677     bool AllowSingleOperand() const override { return true; }
678   };
679 
680   SingleMergeOp merge_op;
681   Filter filter;
682   InitIterators(
683       // a should invoke PartialMergeMulti with a single merge operand.
684       {test::KeyStr("a", 50, kTypeMerge),
685        // b should invoke PartialMergeMulti with two operands.
686        test::KeyStr("b", 70, kTypeMerge), test::KeyStr("b", 60, kTypeMerge),
687        // c should invoke FullMerge due to kTypeValue at the beginning.
688        test::KeyStr("c", 90, kTypeMerge), test::KeyStr("c", 80, kTypeValue)},
689       {"av1", "bv2", "bv1", "cv2", "cv1"}, {}, {}, kMaxSequenceNumber,
690       kMaxSequenceNumber, &merge_op, &filter);
691 
692   c_iter_->SeekToFirst();
693   ASSERT_TRUE(c_iter_->Valid());
694   ASSERT_EQ(test::KeyStr("a", 50, kTypeMerge), c_iter_->key().ToString());
695   ASSERT_EQ("av1", c_iter_->value().ToString());
696   c_iter_->Next();
697   ASSERT_TRUE(c_iter_->Valid());
698   ASSERT_EQ("bv1bv2", c_iter_->value().ToString());
699   c_iter_->Next();
700   ASSERT_OK(c_iter_->status());
701   ASSERT_EQ("cv1cv2", c_iter_->value().ToString());
702 }
703 
704 // In bottommost level, values earlier than earliest snapshot can be output
705 // with sequence = 0.
TEST_P(CompactionIteratorTest,ZeroOutSequenceAtBottomLevel)706 TEST_P(CompactionIteratorTest, ZeroOutSequenceAtBottomLevel) {
707   AddSnapshot(1);
708   RunTest({test::KeyStr("a", 1, kTypeValue), test::KeyStr("b", 2, kTypeValue)},
709           {"v1", "v2"},
710           {test::KeyStr("a", 0, kTypeValue), test::KeyStr("b", 2, kTypeValue)},
711           {"v1", "v2"}, kMaxSequenceNumber /*last_committed_seq*/,
712           nullptr /*merge_operator*/, nullptr /*compaction_filter*/,
713           true /*bottommost_level*/);
714 }
715 
716 // In bottommost level, deletions earlier than earliest snapshot can be removed
717 // permanently.
TEST_P(CompactionIteratorTest,RemoveDeletionAtBottomLevel)718 TEST_P(CompactionIteratorTest, RemoveDeletionAtBottomLevel) {
719   AddSnapshot(1);
720   RunTest(
721       {test::KeyStr("a", 1, kTypeDeletion), test::KeyStr("b", 3, kTypeDeletion),
722        test::KeyStr("b", 1, kTypeValue)},
723       {"", "", ""},
724       {test::KeyStr("b", 3, kTypeDeletion), test::KeyStr("b", 0, kTypeValue)},
725       {"", ""}, kMaxSequenceNumber /*last_committed_seq*/,
726       nullptr /*merge_operator*/, nullptr /*compaction_filter*/,
727       true /*bottommost_level*/);
728 }
729 
730 // In bottommost level, single deletions earlier than earliest snapshot can be
731 // removed permanently.
TEST_P(CompactionIteratorTest,RemoveSingleDeletionAtBottomLevel)732 TEST_P(CompactionIteratorTest, RemoveSingleDeletionAtBottomLevel) {
733   AddSnapshot(1);
734   RunTest({test::KeyStr("a", 1, kTypeSingleDeletion),
735            test::KeyStr("b", 2, kTypeSingleDeletion)},
736           {"", ""}, {test::KeyStr("b", 2, kTypeSingleDeletion)}, {""},
737           kMaxSequenceNumber /*last_committed_seq*/, nullptr /*merge_operator*/,
738           nullptr /*compaction_filter*/, true /*bottommost_level*/);
739 }
740 
TEST_P(CompactionIteratorTest,ConvertToPutAtBottom)741 TEST_P(CompactionIteratorTest, ConvertToPutAtBottom) {
742   std::shared_ptr<MergeOperator> merge_op =
743       MergeOperators::CreateStringAppendOperator();
744   RunTest({test::KeyStr("a", 4, kTypeMerge), test::KeyStr("a", 3, kTypeMerge),
745            test::KeyStr("a", 2, kTypeMerge), test::KeyStr("b", 1, kTypeValue)},
746           {"a4", "a3", "a2", "b1"},
747           {test::KeyStr("a", 0, kTypeValue), test::KeyStr("b", 0, kTypeValue)},
748           {"a2,a3,a4", "b1"}, kMaxSequenceNumber /*last_committed_seq*/,
749           merge_op.get(), nullptr /*compaction_filter*/,
750           true /*bottomost_level*/);
751 }
752 
753 INSTANTIATE_TEST_CASE_P(CompactionIteratorTestInstance, CompactionIteratorTest,
754                         testing::Values(true, false));
755 
756 // Tests how CompactionIterator work together with SnapshotChecker.
757 class CompactionIteratorWithSnapshotCheckerTest
758     : public CompactionIteratorTest {
759  public:
UseSnapshotChecker() const760   bool UseSnapshotChecker() const override { return true; }
761 };
762 
763 // Uncommitted keys (keys with seq > last_committed_seq) should be output as-is
764 // while committed version of these keys should get compacted as usual.
765 
TEST_F(CompactionIteratorWithSnapshotCheckerTest,PreserveUncommittedKeys_Value)766 TEST_F(CompactionIteratorWithSnapshotCheckerTest,
767        PreserveUncommittedKeys_Value) {
768   RunTest(
769       {test::KeyStr("foo", 3, kTypeValue), test::KeyStr("foo", 2, kTypeValue),
770        test::KeyStr("foo", 1, kTypeValue)},
771       {"v3", "v2", "v1"},
772       {test::KeyStr("foo", 3, kTypeValue), test::KeyStr("foo", 2, kTypeValue)},
773       {"v3", "v2"}, 2 /*last_committed_seq*/);
774 }
775 
TEST_F(CompactionIteratorWithSnapshotCheckerTest,PreserveUncommittedKeys_Deletion)776 TEST_F(CompactionIteratorWithSnapshotCheckerTest,
777        PreserveUncommittedKeys_Deletion) {
778   RunTest({test::KeyStr("foo", 2, kTypeDeletion),
779            test::KeyStr("foo", 1, kTypeValue)},
780           {"", "v1"},
781           {test::KeyStr("foo", 2, kTypeDeletion),
782            test::KeyStr("foo", 1, kTypeValue)},
783           {"", "v1"}, 1 /*last_committed_seq*/);
784 }
785 
TEST_F(CompactionIteratorWithSnapshotCheckerTest,PreserveUncommittedKeys_Merge)786 TEST_F(CompactionIteratorWithSnapshotCheckerTest,
787        PreserveUncommittedKeys_Merge) {
788   auto merge_op = MergeOperators::CreateStringAppendOperator();
789   RunTest(
790       {test::KeyStr("foo", 3, kTypeMerge), test::KeyStr("foo", 2, kTypeMerge),
791        test::KeyStr("foo", 1, kTypeValue)},
792       {"v3", "v2", "v1"},
793       {test::KeyStr("foo", 3, kTypeMerge), test::KeyStr("foo", 2, kTypeValue)},
794       {"v3", "v1,v2"}, 2 /*last_committed_seq*/, merge_op.get());
795 }
796 
TEST_F(CompactionIteratorWithSnapshotCheckerTest,PreserveUncommittedKeys_SingleDelete)797 TEST_F(CompactionIteratorWithSnapshotCheckerTest,
798        PreserveUncommittedKeys_SingleDelete) {
799   RunTest({test::KeyStr("foo", 2, kTypeSingleDeletion),
800            test::KeyStr("foo", 1, kTypeValue)},
801           {"", "v1"},
802           {test::KeyStr("foo", 2, kTypeSingleDeletion),
803            test::KeyStr("foo", 1, kTypeValue)},
804           {"", "v1"}, 1 /*last_committed_seq*/);
805 }
806 
TEST_F(CompactionIteratorWithSnapshotCheckerTest,PreserveUncommittedKeys_BlobIndex)807 TEST_F(CompactionIteratorWithSnapshotCheckerTest,
808        PreserveUncommittedKeys_BlobIndex) {
809   RunTest({test::KeyStr("foo", 3, kTypeBlobIndex),
810            test::KeyStr("foo", 2, kTypeBlobIndex),
811            test::KeyStr("foo", 1, kTypeBlobIndex)},
812           {"v3", "v2", "v1"},
813           {test::KeyStr("foo", 3, kTypeBlobIndex),
814            test::KeyStr("foo", 2, kTypeBlobIndex)},
815           {"v3", "v2"}, 2 /*last_committed_seq*/);
816 }
817 
818 // Test compaction iterator dedup keys visible to the same snapshot.
819 
TEST_F(CompactionIteratorWithSnapshotCheckerTest,DedupSameSnapshot_Value)820 TEST_F(CompactionIteratorWithSnapshotCheckerTest, DedupSameSnapshot_Value) {
821   AddSnapshot(2, 1);
822   RunTest(
823       {test::KeyStr("foo", 4, kTypeValue), test::KeyStr("foo", 3, kTypeValue),
824        test::KeyStr("foo", 2, kTypeValue), test::KeyStr("foo", 1, kTypeValue)},
825       {"v4", "v3", "v2", "v1"},
826       {test::KeyStr("foo", 4, kTypeValue), test::KeyStr("foo", 3, kTypeValue),
827        test::KeyStr("foo", 1, kTypeValue)},
828       {"v4", "v3", "v1"}, 3 /*last_committed_seq*/);
829 }
830 
TEST_F(CompactionIteratorWithSnapshotCheckerTest,DedupSameSnapshot_Deletion)831 TEST_F(CompactionIteratorWithSnapshotCheckerTest, DedupSameSnapshot_Deletion) {
832   AddSnapshot(2, 1);
833   RunTest(
834       {test::KeyStr("foo", 4, kTypeValue),
835        test::KeyStr("foo", 3, kTypeDeletion),
836        test::KeyStr("foo", 2, kTypeValue), test::KeyStr("foo", 1, kTypeValue)},
837       {"v4", "", "v2", "v1"},
838       {test::KeyStr("foo", 4, kTypeValue),
839        test::KeyStr("foo", 3, kTypeDeletion),
840        test::KeyStr("foo", 1, kTypeValue)},
841       {"v4", "", "v1"}, 3 /*last_committed_seq*/);
842 }
843 
TEST_F(CompactionIteratorWithSnapshotCheckerTest,DedupSameSnapshot_Merge)844 TEST_F(CompactionIteratorWithSnapshotCheckerTest, DedupSameSnapshot_Merge) {
845   AddSnapshot(2, 1);
846   AddSnapshot(4, 3);
847   auto merge_op = MergeOperators::CreateStringAppendOperator();
848   RunTest(
849       {test::KeyStr("foo", 5, kTypeMerge), test::KeyStr("foo", 4, kTypeMerge),
850        test::KeyStr("foo", 3, kTypeMerge), test::KeyStr("foo", 2, kTypeMerge),
851        test::KeyStr("foo", 1, kTypeValue)},
852       {"v5", "v4", "v3", "v2", "v1"},
853       {test::KeyStr("foo", 5, kTypeMerge), test::KeyStr("foo", 4, kTypeMerge),
854        test::KeyStr("foo", 3, kTypeMerge), test::KeyStr("foo", 1, kTypeValue)},
855       {"v5", "v4", "v2,v3", "v1"}, 4 /*last_committed_seq*/, merge_op.get());
856 }
857 
TEST_F(CompactionIteratorWithSnapshotCheckerTest,DedupSameSnapshot_SingleDeletion)858 TEST_F(CompactionIteratorWithSnapshotCheckerTest,
859        DedupSameSnapshot_SingleDeletion) {
860   AddSnapshot(2, 1);
861   RunTest(
862       {test::KeyStr("foo", 4, kTypeValue),
863        test::KeyStr("foo", 3, kTypeSingleDeletion),
864        test::KeyStr("foo", 2, kTypeValue), test::KeyStr("foo", 1, kTypeValue)},
865       {"v4", "", "v2", "v1"},
866       {test::KeyStr("foo", 4, kTypeValue), test::KeyStr("foo", 1, kTypeValue)},
867       {"v4", "v1"}, 3 /*last_committed_seq*/);
868 }
869 
TEST_F(CompactionIteratorWithSnapshotCheckerTest,DedupSameSnapshot_BlobIndex)870 TEST_F(CompactionIteratorWithSnapshotCheckerTest, DedupSameSnapshot_BlobIndex) {
871   AddSnapshot(2, 1);
872   RunTest({test::KeyStr("foo", 4, kTypeBlobIndex),
873            test::KeyStr("foo", 3, kTypeBlobIndex),
874            test::KeyStr("foo", 2, kTypeBlobIndex),
875            test::KeyStr("foo", 1, kTypeBlobIndex)},
876           {"v4", "v3", "v2", "v1"},
877           {test::KeyStr("foo", 4, kTypeBlobIndex),
878            test::KeyStr("foo", 3, kTypeBlobIndex),
879            test::KeyStr("foo", 1, kTypeBlobIndex)},
880           {"v4", "v3", "v1"}, 3 /*last_committed_seq*/);
881 }
882 
883 // At bottom level, sequence numbers can be zero out, and deletions can be
884 // removed, but only when they are visible to earliest snapshot.
885 
TEST_F(CompactionIteratorWithSnapshotCheckerTest,NotZeroOutSequenceIfNotVisibleToEarliestSnapshot)886 TEST_F(CompactionIteratorWithSnapshotCheckerTest,
887        NotZeroOutSequenceIfNotVisibleToEarliestSnapshot) {
888   AddSnapshot(2, 1);
889   RunTest({test::KeyStr("a", 1, kTypeValue), test::KeyStr("b", 2, kTypeValue),
890            test::KeyStr("c", 3, kTypeValue)},
891           {"v1", "v2", "v3"},
892           {test::KeyStr("a", 0, kTypeValue), test::KeyStr("b", 2, kTypeValue),
893            test::KeyStr("c", 3, kTypeValue)},
894           {"v1", "v2", "v3"}, kMaxSequenceNumber /*last_committed_seq*/,
895           nullptr /*merge_operator*/, nullptr /*compaction_filter*/,
896           true /*bottommost_level*/);
897 }
898 
TEST_F(CompactionIteratorWithSnapshotCheckerTest,NotRemoveDeletionIfNotVisibleToEarliestSnapshot)899 TEST_F(CompactionIteratorWithSnapshotCheckerTest,
900        NotRemoveDeletionIfNotVisibleToEarliestSnapshot) {
901   AddSnapshot(2, 1);
902   RunTest(
903       {test::KeyStr("a", 1, kTypeDeletion), test::KeyStr("b", 2, kTypeDeletion),
904        test::KeyStr("c", 3, kTypeDeletion)},
905       {"", "", ""}, {}, {"", ""}, kMaxSequenceNumber /*last_committed_seq*/,
906       nullptr /*merge_operator*/, nullptr /*compaction_filter*/,
907       true /*bottommost_level*/);
908 }
909 
TEST_F(CompactionIteratorWithSnapshotCheckerTest,NotRemoveDeletionIfValuePresentToEarlierSnapshot)910 TEST_F(CompactionIteratorWithSnapshotCheckerTest,
911        NotRemoveDeletionIfValuePresentToEarlierSnapshot) {
912   AddSnapshot(2,1);
913   RunTest({test::KeyStr("a", 4, kTypeDeletion),
914            test::KeyStr("a", 1, kTypeValue), test::KeyStr("b", 3, kTypeValue)},
915           {"", "", ""},
916           {test::KeyStr("a", 4, kTypeDeletion),
917            test::KeyStr("a", 0, kTypeValue), test::KeyStr("b", 3, kTypeValue)},
918           {"", "", ""}, kMaxSequenceNumber /*last_committed_seq*/,
919           nullptr /*merge_operator*/, nullptr /*compaction_filter*/,
920           true /*bottommost_level*/);
921 }
922 
TEST_F(CompactionIteratorWithSnapshotCheckerTest,NotRemoveSingleDeletionIfNotVisibleToEarliestSnapshot)923 TEST_F(CompactionIteratorWithSnapshotCheckerTest,
924        NotRemoveSingleDeletionIfNotVisibleToEarliestSnapshot) {
925   AddSnapshot(2, 1);
926   RunTest({test::KeyStr("a", 1, kTypeSingleDeletion),
927            test::KeyStr("b", 2, kTypeSingleDeletion),
928            test::KeyStr("c", 3, kTypeSingleDeletion)},
929           {"", "", ""},
930           {test::KeyStr("b", 2, kTypeSingleDeletion),
931            test::KeyStr("c", 3, kTypeSingleDeletion)},
932           {"", ""}, kMaxSequenceNumber /*last_committed_seq*/,
933           nullptr /*merge_operator*/, nullptr /*compaction_filter*/,
934           true /*bottommost_level*/);
935 }
936 
937 // Single delete should not cancel out values that not visible to the
938 // same set of snapshots
TEST_F(CompactionIteratorWithSnapshotCheckerTest,SingleDeleteAcrossSnapshotBoundary)939 TEST_F(CompactionIteratorWithSnapshotCheckerTest,
940        SingleDeleteAcrossSnapshotBoundary) {
941   AddSnapshot(2, 1);
942   RunTest({test::KeyStr("a", 2, kTypeSingleDeletion),
943            test::KeyStr("a", 1, kTypeValue)},
944           {"", "v1"},
945           {test::KeyStr("a", 2, kTypeSingleDeletion),
946            test::KeyStr("a", 1, kTypeValue)},
947           {"", "v1"}, 2 /*last_committed_seq*/);
948 }
949 
950 // Single delete should be kept in case it is not visible to the
951 // earliest write conflict snapshot. If a single delete is kept for this reason,
952 // corresponding value can be trimmed to save space.
TEST_F(CompactionIteratorWithSnapshotCheckerTest,KeepSingleDeletionForWriteConflictChecking)953 TEST_F(CompactionIteratorWithSnapshotCheckerTest,
954        KeepSingleDeletionForWriteConflictChecking) {
955   AddSnapshot(2, 0);
956   RunTest({test::KeyStr("a", 2, kTypeSingleDeletion),
957            test::KeyStr("a", 1, kTypeValue)},
958           {"", "v1"},
959           {test::KeyStr("a", 2, kTypeSingleDeletion),
960            test::KeyStr("a", 1, kTypeValue)},
961           {"", ""}, 2 /*last_committed_seq*/, nullptr /*merge_operator*/,
962           nullptr /*compaction_filter*/, false /*bottommost_level*/,
963           2 /*earliest_write_conflict_snapshot*/);
964 }
965 
966 // Same as above but with a blob index. In addition to the value getting
967 // trimmed, the type of the KV is changed to kTypeValue.
TEST_F(CompactionIteratorWithSnapshotCheckerTest,KeepSingleDeletionForWriteConflictChecking_BlobIndex)968 TEST_F(CompactionIteratorWithSnapshotCheckerTest,
969        KeepSingleDeletionForWriteConflictChecking_BlobIndex) {
970   AddSnapshot(2, 0);
971   RunTest({test::KeyStr("a", 2, kTypeSingleDeletion),
972            test::KeyStr("a", 1, kTypeBlobIndex)},
973           {"", "fake_blob_index"},
974           {test::KeyStr("a", 2, kTypeSingleDeletion),
975            test::KeyStr("a", 1, kTypeValue)},
976           {"", ""}, 2 /*last_committed_seq*/, nullptr /*merge_operator*/,
977           nullptr /*compaction_filter*/, false /*bottommost_level*/,
978           2 /*earliest_write_conflict_snapshot*/);
979 }
980 
981 // Compaction filter should keep uncommitted key as-is, and
982 //   * Convert the latest value to deletion, and/or
983 //   * if latest value is a merge, apply filter to all subsequent merges.
984 
TEST_F(CompactionIteratorWithSnapshotCheckerTest,CompactionFilter_Value)985 TEST_F(CompactionIteratorWithSnapshotCheckerTest, CompactionFilter_Value) {
986   std::unique_ptr<CompactionFilter> compaction_filter(
987       new FilterAllKeysCompactionFilter());
988   RunTest(
989       {test::KeyStr("a", 2, kTypeValue), test::KeyStr("a", 1, kTypeValue),
990        test::KeyStr("b", 3, kTypeValue), test::KeyStr("c", 1, kTypeValue)},
991       {"v2", "v1", "v3", "v4"},
992       {test::KeyStr("a", 2, kTypeValue), test::KeyStr("a", 1, kTypeDeletion),
993        test::KeyStr("b", 3, kTypeValue), test::KeyStr("c", 1, kTypeDeletion)},
994       {"v2", "", "v3", ""}, 1 /*last_committed_seq*/,
995       nullptr /*merge_operator*/, compaction_filter.get());
996 }
997 
TEST_F(CompactionIteratorWithSnapshotCheckerTest,CompactionFilter_Deletion)998 TEST_F(CompactionIteratorWithSnapshotCheckerTest, CompactionFilter_Deletion) {
999   std::unique_ptr<CompactionFilter> compaction_filter(
1000       new FilterAllKeysCompactionFilter());
1001   RunTest(
1002       {test::KeyStr("a", 2, kTypeDeletion), test::KeyStr("a", 1, kTypeValue)},
1003       {"", "v1"},
1004       {test::KeyStr("a", 2, kTypeDeletion),
1005        test::KeyStr("a", 1, kTypeDeletion)},
1006       {"", ""}, 1 /*last_committed_seq*/, nullptr /*merge_operator*/,
1007       compaction_filter.get());
1008 }
1009 
TEST_F(CompactionIteratorWithSnapshotCheckerTest,CompactionFilter_PartialMerge)1010 TEST_F(CompactionIteratorWithSnapshotCheckerTest,
1011        CompactionFilter_PartialMerge) {
1012   std::shared_ptr<MergeOperator> merge_op =
1013       MergeOperators::CreateStringAppendOperator();
1014   std::unique_ptr<CompactionFilter> compaction_filter(
1015       new FilterAllKeysCompactionFilter());
1016   RunTest({test::KeyStr("a", 3, kTypeMerge), test::KeyStr("a", 2, kTypeMerge),
1017            test::KeyStr("a", 1, kTypeMerge)},
1018           {"v3", "v2", "v1"}, {test::KeyStr("a", 3, kTypeMerge)}, {"v3"},
1019           2 /*last_committed_seq*/, merge_op.get(), compaction_filter.get());
1020 }
1021 
TEST_F(CompactionIteratorWithSnapshotCheckerTest,CompactionFilter_FullMerge)1022 TEST_F(CompactionIteratorWithSnapshotCheckerTest, CompactionFilter_FullMerge) {
1023   std::shared_ptr<MergeOperator> merge_op =
1024       MergeOperators::CreateStringAppendOperator();
1025   std::unique_ptr<CompactionFilter> compaction_filter(
1026       new FilterAllKeysCompactionFilter());
1027   RunTest(
1028       {test::KeyStr("a", 3, kTypeMerge), test::KeyStr("a", 2, kTypeMerge),
1029        test::KeyStr("a", 1, kTypeValue)},
1030       {"v3", "v2", "v1"},
1031       {test::KeyStr("a", 3, kTypeMerge), test::KeyStr("a", 1, kTypeDeletion)},
1032       {"v3", ""}, 2 /*last_committed_seq*/, merge_op.get(),
1033       compaction_filter.get());
1034 }
1035 
1036 // Tests how CompactionIterator work together with AllowIngestBehind.
1037 class CompactionIteratorWithAllowIngestBehindTest
1038     : public CompactionIteratorTest {
1039  public:
AllowIngestBehind() const1040   bool AllowIngestBehind() const override { return true; }
1041 };
1042 
1043 // When allow_ingest_behind is set, compaction iterator is not targeting
1044 // the bottommost level since there is no guarantee there won't be further
1045 // data ingested under the compaction output in future.
TEST_P(CompactionIteratorWithAllowIngestBehindTest,NoConvertToPutAtBottom)1046 TEST_P(CompactionIteratorWithAllowIngestBehindTest, NoConvertToPutAtBottom) {
1047   std::shared_ptr<MergeOperator> merge_op =
1048       MergeOperators::CreateStringAppendOperator();
1049   RunTest({test::KeyStr("a", 4, kTypeMerge), test::KeyStr("a", 3, kTypeMerge),
1050            test::KeyStr("a", 2, kTypeMerge), test::KeyStr("b", 1, kTypeValue)},
1051           {"a4", "a3", "a2", "b1"},
1052           {test::KeyStr("a", 4, kTypeMerge), test::KeyStr("b", 1, kTypeValue)},
1053           {"a2,a3,a4", "b1"}, kMaxSequenceNumber /*last_committed_seq*/,
1054           merge_op.get(), nullptr /*compaction_filter*/,
1055           true /*bottomost_level*/);
1056 }
1057 
TEST_P(CompactionIteratorWithAllowIngestBehindTest,MergeToPutIfEncounteredPutAtBottom)1058 TEST_P(CompactionIteratorWithAllowIngestBehindTest,
1059        MergeToPutIfEncounteredPutAtBottom) {
1060   std::shared_ptr<MergeOperator> merge_op =
1061       MergeOperators::CreateStringAppendOperator();
1062   RunTest({test::KeyStr("a", 4, kTypeMerge), test::KeyStr("a", 3, kTypeMerge),
1063            test::KeyStr("a", 2, kTypeValue), test::KeyStr("b", 1, kTypeValue)},
1064           {"a4", "a3", "a2", "b1"},
1065           {test::KeyStr("a", 4, kTypeValue), test::KeyStr("b", 1, kTypeValue)},
1066           {"a2,a3,a4", "b1"}, kMaxSequenceNumber /*last_committed_seq*/,
1067           merge_op.get(), nullptr /*compaction_filter*/,
1068           true /*bottomost_level*/);
1069 }
1070 
1071 INSTANTIATE_TEST_CASE_P(CompactionIteratorWithAllowIngestBehindTestInstance,
1072                         CompactionIteratorWithAllowIngestBehindTest,
1073                         testing::Values(true, false));
1074 
1075 class CompactionIteratorTsGcTest : public CompactionIteratorTest {
1076  public:
CompactionIteratorTsGcTest()1077   CompactionIteratorTsGcTest()
1078       : CompactionIteratorTest(test::ComparatorWithU64Ts()) {}
1079 };
1080 
TEST_P(CompactionIteratorTsGcTest,NoKeyEligibleForGC)1081 TEST_P(CompactionIteratorTsGcTest, NoKeyEligibleForGC) {
1082   constexpr char user_key[][2] = {{'a', '\0'}, {'b', '\0'}};
1083   const std::vector<std::string> input_keys = {
1084       test::KeyStr(/*ts=*/103, user_key[0], /*seq=*/4, kTypeValue),
1085       test::KeyStr(/*ts=*/102, user_key[0], /*seq=*/3,
1086                    kTypeDeletionWithTimestamp),
1087       test::KeyStr(/*ts=*/104, user_key[1], /*seq=*/5, kTypeValue)};
1088   const std::vector<std::string> input_values = {"a3", "", "b2"};
1089   std::string full_history_ts_low;
1090   // All keys' timestamps are newer than or equal to 102, thus none of them
1091   // will be eligible for GC.
1092   PutFixed64(&full_history_ts_low, 102);
1093   const std::vector<std::string>& expected_keys = input_keys;
1094   const std::vector<std::string>& expected_values = input_values;
1095   const std::vector<std::pair<bool, bool>> params = {
1096       {false, false}, {false, true}, {true, true}};
1097   for (const std::pair<bool, bool>& param : params) {
1098     const bool bottommost_level = param.first;
1099     const bool key_not_exists_beyond_output_level = param.second;
1100     RunTest(input_keys, input_values, expected_keys, expected_values,
1101             /*last_committed_seq=*/kMaxSequenceNumber,
1102             /*merge_operator=*/nullptr, /*compaction_filter=*/nullptr,
1103             bottommost_level,
1104             /*earliest_write_conflict_snapshot=*/kMaxSequenceNumber,
1105             key_not_exists_beyond_output_level, &full_history_ts_low);
1106   }
1107 }
1108 
TEST_P(CompactionIteratorTsGcTest,AllKeysOlderThanThreshold)1109 TEST_P(CompactionIteratorTsGcTest, AllKeysOlderThanThreshold) {
1110   constexpr char user_key[][2] = {{'a', '\0'}, {'b', '\0'}};
1111   const std::vector<std::string> input_keys = {
1112       test::KeyStr(/*ts=*/103, user_key[0], /*seq=*/4,
1113                    kTypeDeletionWithTimestamp),
1114       test::KeyStr(/*ts=*/102, user_key[0], /*seq=*/3, kTypeValue),
1115       test::KeyStr(/*ts=*/101, user_key[0], /*seq=*/2, kTypeValue),
1116       test::KeyStr(/*ts=*/104, user_key[1], /*seq=*/5, kTypeValue)};
1117   const std::vector<std::string> input_values = {"", "a2", "a1", "b5"};
1118   std::string full_history_ts_low;
1119   PutFixed64(&full_history_ts_low, std::numeric_limits<uint64_t>::max());
1120   {
1121     // With a snapshot at seq 3, both the deletion marker and the key at 3 must
1122     // be preserved.
1123     AddSnapshot(3);
1124     const std::vector<std::string> expected_keys = {
1125         input_keys[0], input_keys[1], input_keys[3]};
1126     const std::vector<std::string> expected_values = {"", "a2", "b5"};
1127     RunTest(input_keys, input_values, expected_keys, expected_values,
1128             /*last_committed_seq=*/kMaxSequenceNumber,
1129             /*merge_operator=*/nullptr, /*compaction_filter=*/nullptr,
1130             /*bottommost_level=*/false,
1131             /*earliest_write_conflict_snapshot=*/kMaxSequenceNumber,
1132             /*key_not_exists_beyond_output_level=*/false, &full_history_ts_low);
1133     ClearSnapshots();
1134   }
1135   {
1136     // No snapshot, the deletion marker should be preserved because the user
1137     // key may appear beyond output level.
1138     const std::vector<std::string> expected_keys = {input_keys[0],
1139                                                     input_keys[3]};
1140     const std::vector<std::string> expected_values = {"", "b5"};
1141     RunTest(input_keys, input_values, expected_keys, expected_values,
1142             /*last_committed_seq=*/kMaxSequenceNumber,
1143             /*merge_operator=*/nullptr, /*compaction_filter=*/nullptr,
1144             /*bottommost_level=*/false,
1145             /*earliest_write_conflict_snapshot=*/kMaxSequenceNumber,
1146             /*key_not_exists_beyond_output_level=*/false, &full_history_ts_low);
1147   }
1148   {
1149     // No snapshot, the deletion marker can be dropped because the user key
1150     // does not appear in higher levels.
1151     const std::vector<std::string> expected_keys = {input_keys[3]};
1152     const std::vector<std::string> expected_values = {"b5"};
1153     RunTest(input_keys, input_values, expected_keys, expected_values,
1154             /*last_committed_seq=*/kMaxSequenceNumber,
1155             /*merge_operator=*/nullptr, /*compaction_filter=*/nullptr,
1156             /*bottommost_level=*/false,
1157             /*earliest_write_conflict_snapshot=*/kMaxSequenceNumber,
1158             /*key_not_exists_beyond_output_level=*/true, &full_history_ts_low);
1159   }
1160 }
1161 
TEST_P(CompactionIteratorTsGcTest,NewHidesOldSameSnapshot)1162 TEST_P(CompactionIteratorTsGcTest, NewHidesOldSameSnapshot) {
1163   constexpr char user_key[] = "a";
1164   const std::vector<std::string> input_keys = {
1165       test::KeyStr(/*ts=*/103, user_key, /*seq=*/4, kTypeDeletionWithTimestamp),
1166       test::KeyStr(/*ts=*/102, user_key, /*seq=*/3, kTypeValue),
1167       test::KeyStr(/*ts=*/101, user_key, /*seq=*/2, kTypeValue),
1168       test::KeyStr(/*ts=*/100, user_key, /*seq=*/1, kTypeValue)};
1169   const std::vector<std::string> input_values = {"", "a2", "a1", "a0"};
1170   {
1171     std::string full_history_ts_low;
1172     // Keys whose timestamps larger than or equal to 102 will be preserved.
1173     PutFixed64(&full_history_ts_low, 102);
1174     const std::vector<std::string> expected_keys = {input_keys[0],
1175                                                     input_keys[1]};
1176     const std::vector<std::string> expected_values = {"", "a2"};
1177     RunTest(input_keys, input_values, expected_keys, expected_values,
1178             /*last_committed_seq=*/kMaxSequenceNumber,
1179             /*merge_operator=*/nullptr, /*compaction_filter=*/nullptr,
1180             /*bottommost_level=*/false,
1181             /*earliest_write_conflict_snapshot=*/kMaxSequenceNumber,
1182             /*key_not_exists_beyond_output_level=*/false, &full_history_ts_low);
1183   }
1184 }
1185 
TEST_P(CompactionIteratorTsGcTest,DropTombstones)1186 TEST_P(CompactionIteratorTsGcTest, DropTombstones) {
1187   constexpr char user_key[] = "a";
1188   const std::vector<std::string> input_keys = {
1189       test::KeyStr(/*ts=*/103, user_key, /*seq=*/4, kTypeDeletionWithTimestamp),
1190       test::KeyStr(/*ts=*/102, user_key, /*seq=*/3, kTypeValue),
1191       test::KeyStr(/*ts=*/101, user_key, /*seq=*/2, kTypeDeletionWithTimestamp),
1192       test::KeyStr(/*ts=*/100, user_key, /*seq=*/1, kTypeValue)};
1193   const std::vector<std::string> input_values = {"", "a2", "", "a0"};
1194   const std::vector<std::string> expected_keys = {input_keys[0], input_keys[1]};
1195   const std::vector<std::string> expected_values = {"", "a2"};
1196 
1197   // Take a snapshot at seq 2.
1198   AddSnapshot(2);
1199 
1200   {
1201     // Non-bottommost level, but key does not exist beyond output level.
1202     std::string full_history_ts_low;
1203     PutFixed64(&full_history_ts_low, 102);
1204     RunTest(input_keys, input_values, expected_keys, expected_values,
1205             /*last_committed_sequence=*/kMaxSequenceNumber,
1206             /*merge_op=*/nullptr, /*compaction_filter=*/nullptr,
1207             /*bottommost_level=*/false,
1208             /*earliest_write_conflict_snapshot=*/kMaxSequenceNumber,
1209             /*key_not_exists_beyond_output_level=*/true, &full_history_ts_low);
1210   }
1211   {
1212     // Bottommost level
1213     std::string full_history_ts_low;
1214     PutFixed64(&full_history_ts_low, 102);
1215     RunTest(input_keys, input_values, expected_keys, expected_values,
1216             /*last_committed_seq=*/kMaxSequenceNumber,
1217             /*merge_operator=*/nullptr, /*compaction_filter=*/nullptr,
1218             /*bottommost_level=*/true,
1219             /*earliest_write_conflict_snapshot=*/kMaxSequenceNumber,
1220             /*key_not_exists_beyond_output_level=*/false, &full_history_ts_low);
1221   }
1222 }
1223 
TEST_P(CompactionIteratorTsGcTest,RewriteTs)1224 TEST_P(CompactionIteratorTsGcTest, RewriteTs) {
1225   constexpr char user_key[] = "a";
1226   const std::vector<std::string> input_keys = {
1227       test::KeyStr(/*ts=*/103, user_key, /*seq=*/4, kTypeDeletionWithTimestamp),
1228       test::KeyStr(/*ts=*/102, user_key, /*seq=*/3, kTypeValue),
1229       test::KeyStr(/*ts=*/101, user_key, /*seq=*/2, kTypeDeletionWithTimestamp),
1230       test::KeyStr(/*ts=*/100, user_key, /*seq=*/1, kTypeValue)};
1231   const std::vector<std::string> input_values = {"", "a2", "", "a0"};
1232   const std::vector<std::string> expected_keys = {
1233       input_keys[0], input_keys[1], input_keys[2],
1234       test::KeyStr(/*ts=*/0, user_key, /*seq=*/0, kTypeValue)};
1235   const std::vector<std::string> expected_values = {"", "a2", "", "a0"};
1236 
1237   AddSnapshot(1);
1238   AddSnapshot(2);
1239 
1240   {
1241     // Bottommost level and need to rewrite both ts and seq.
1242     std::string full_history_ts_low;
1243     PutFixed64(&full_history_ts_low, 102);
1244     RunTest(input_keys, input_values, expected_keys, expected_values,
1245             /*last_committed_seq=*/kMaxSequenceNumber,
1246             /*merge_operator=*/nullptr, /*compaction_filter=*/nullptr,
1247             /*bottommost_level=*/true,
1248             /*earliest_write_conflict_snapshot=*/kMaxSequenceNumber,
1249             /*key_not_exists_beyond_output_level=*/true, &full_history_ts_low);
1250   }
1251 }
1252 
TEST_P(CompactionIteratorTsGcTest,SingleDeleteNoKeyEligibleForGC)1253 TEST_P(CompactionIteratorTsGcTest, SingleDeleteNoKeyEligibleForGC) {
1254   constexpr char user_key[][2] = {{'a', '\0'}, {'b', '\0'}};
1255   const std::vector<std::string> input_keys = {
1256       test::KeyStr(/*ts=*/104, user_key[0], /*seq=*/4, kTypeSingleDeletion),
1257       test::KeyStr(/*ts=*/103, user_key[0], /*seq=*/3, kTypeValue),
1258       test::KeyStr(/*ts=*/102, user_key[1], /*seq=*/2, kTypeValue)};
1259   const std::vector<std::string> input_values = {"", "a3", "b2"};
1260   std::string full_history_ts_low;
1261   // All keys' timestamps are newer than or equal to 102, thus none of them
1262   // will be eligible for GC.
1263   PutFixed64(&full_history_ts_low, 102);
1264   const std::vector<std::string>& expected_keys = input_keys;
1265   const std::vector<std::string>& expected_values = input_values;
1266   const std::vector<std::pair<bool, bool>> params = {
1267       {false, false}, {false, true}, {true, true}};
1268   for (const std::pair<bool, bool>& param : params) {
1269     const bool bottommost_level = param.first;
1270     const bool key_not_exists_beyond_output_level = param.second;
1271     RunTest(input_keys, input_values, expected_keys, expected_values,
1272             /*last_committed_seq=*/kMaxSequenceNumber,
1273             /*merge_operator=*/nullptr, /*compaction_filter=*/nullptr,
1274             bottommost_level,
1275             /*earliest_write_conflict_snapshot=*/kMaxSequenceNumber,
1276             key_not_exists_beyond_output_level, &full_history_ts_low);
1277   }
1278 }
1279 
TEST_P(CompactionIteratorTsGcTest,SingleDeleteDropTombstones)1280 TEST_P(CompactionIteratorTsGcTest, SingleDeleteDropTombstones) {
1281   constexpr char user_key[] = "a";
1282   const std::vector<std::string> input_keys = {
1283       test::KeyStr(/*ts=*/103, user_key, /*seq=*/4, kTypeSingleDeletion),
1284       test::KeyStr(/*ts=*/102, user_key, /*seq=*/3, kTypeValue),
1285       test::KeyStr(/*ts=*/101, user_key, /*seq=*/2, kTypeSingleDeletion),
1286       test::KeyStr(/*ts=*/100, user_key, /*seq=*/1, kTypeValue)};
1287   const std::vector<std::string> input_values = {"", "a2", "", "a0"};
1288   const std::vector<std::string> expected_keys = {input_keys[0], input_keys[1]};
1289   const std::vector<std::string> expected_values = {"", "a2"};
1290 
1291   // Take a snapshot at seq 2.
1292   AddSnapshot(2);
1293   {
1294     const std::vector<std::pair<bool, bool>> params = {
1295         {false, false}, {false, true}, {true, true}};
1296     for (const std::pair<bool, bool>& param : params) {
1297       const bool bottommost_level = param.first;
1298       const bool key_not_exists_beyond_output_level = param.second;
1299       std::string full_history_ts_low;
1300       PutFixed64(&full_history_ts_low, 102);
1301       RunTest(input_keys, input_values, expected_keys, expected_values,
1302               /*last_committed_seq=*/kMaxSequenceNumber,
1303               /*merge_operator=*/nullptr, /*compaction_filter=*/nullptr,
1304               bottommost_level,
1305               /*earliest_write_conflict_snapshot=*/kMaxSequenceNumber,
1306               key_not_exists_beyond_output_level, &full_history_ts_low);
1307     }
1308   }
1309 }
1310 
TEST_P(CompactionIteratorTsGcTest,SingleDeleteAllKeysOlderThanThreshold)1311 TEST_P(CompactionIteratorTsGcTest, SingleDeleteAllKeysOlderThanThreshold) {
1312   constexpr char user_key[][2] = {{'a', '\0'}, {'b', '\0'}};
1313   const std::vector<std::string> input_keys = {
1314       test::KeyStr(/*ts=*/103, user_key[0], /*seq=*/4, kTypeSingleDeletion),
1315       test::KeyStr(/*ts=*/102, user_key[0], /*seq=*/3, kTypeValue),
1316       test::KeyStr(/*ts=*/104, user_key[1], /*seq=*/5, kTypeValue)};
1317   const std::vector<std::string> input_values = {"", "a2", "b5"};
1318   std::string full_history_ts_low;
1319   PutFixed64(&full_history_ts_low, std::numeric_limits<uint64_t>::max());
1320   {
1321     // With a snapshot at seq 3, both the deletion marker and the key at 3 must
1322     // be preserved.
1323     AddSnapshot(3);
1324     const std::vector<std::string> expected_keys = {
1325         input_keys[0], input_keys[1], input_keys[2]};
1326     const std::vector<std::string> expected_values = {"", "a2", "b5"};
1327     RunTest(input_keys, input_values, expected_keys, expected_values,
1328             /*last_committed_seq=*/kMaxSequenceNumber,
1329             /*merge_operator=*/nullptr, /*compaction_filter=*/nullptr,
1330             /*bottommost_level=*/false,
1331             /*earliest_write_conflict_snapshot=*/kMaxSequenceNumber,
1332             /*key_not_exists_beyond_output_level=*/false, &full_history_ts_low);
1333     ClearSnapshots();
1334   }
1335   {
1336     // No snapshot.
1337     const std::vector<std::string> expected_keys = {input_keys[2]};
1338     const std::vector<std::string> expected_values = {"b5"};
1339     RunTest(input_keys, input_values, expected_keys, expected_values,
1340             /*last_committed_seq=*/kMaxSequenceNumber,
1341             /*merge_operator=*/nullptr, /*compaction_filter=*/nullptr,
1342             /*bottommost_level=*/false,
1343             /*earliest_write_conflict_snapshot=*/kMaxSequenceNumber,
1344             /*key_not_exists_beyond_output_level=*/false, &full_history_ts_low);
1345   }
1346 }
1347 
1348 INSTANTIATE_TEST_CASE_P(CompactionIteratorTsGcTestInstance,
1349                         CompactionIteratorTsGcTest,
1350                         testing::Values(true, false));
1351 
1352 }  // namespace ROCKSDB_NAMESPACE
1353 
main(int argc,char ** argv)1354 int main(int argc, char** argv) {
1355   ::testing::InitGoogleTest(&argc, argv);
1356   return RUN_ALL_TESTS();
1357 }
1358