| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173 |
- // Copyright (c) Meta Platforms, Inc. and affiliates.
- // This source code is licensed under both the GPLv2 (found in the
- // COPYING file in the root directory) and Apache 2.0 License
- // (found in the LICENSE.Apache file in the root directory).
- #include "db/db_test_util.h"
- #include "rocksdb/attribute_groups.h"
- namespace ROCKSDB_NAMESPACE {
- class CoalescingIteratorTest : public DBTestBase {
- public:
- CoalescingIteratorTest()
- : DBTestBase("coalescing_iterator_test", /*env_do_fsync=*/true) {}
- // Verify Iteration of CoalescingIterator
- // by SeekToFirst() + Next() and SeekToLast() + Prev()
- void VerifyCoalescingIterator(const std::vector<ColumnFamilyHandle*>& cfhs,
- const std::vector<Slice>& expected_keys,
- const std::vector<Slice>& expected_values,
- const std::optional<std::vector<WideColumns>>&
- expected_wide_columns = std::nullopt,
- const Slice* lower_bound = nullptr,
- const Slice* upper_bound = nullptr,
- bool allow_unprepared_value = false) {
- const size_t num_keys = expected_keys.size();
- ReadOptions read_options;
- read_options.iterate_lower_bound = lower_bound;
- read_options.iterate_upper_bound = upper_bound;
- read_options.allow_unprepared_value = allow_unprepared_value;
- std::unique_ptr<Iterator> iter =
- db_->NewCoalescingIterator(read_options, cfhs);
- auto check_iter_entry = [&](size_t idx) {
- ASSERT_EQ(iter->key(), expected_keys[idx]);
- if (allow_unprepared_value) {
- ASSERT_TRUE(iter->value().empty());
- ASSERT_TRUE(iter->PrepareValue());
- ASSERT_TRUE(iter->Valid());
- }
- ASSERT_EQ(iter->value(), expected_values[idx]);
- if (expected_wide_columns.has_value()) {
- ASSERT_EQ(iter->columns(), expected_wide_columns.value()[idx]);
- }
- };
- {
- size_t i = 0;
- for (iter->SeekToFirst(); iter->Valid(); iter->Next()) {
- check_iter_entry(i);
- ++i;
- }
- ASSERT_EQ(num_keys, i);
- ASSERT_OK(iter->status());
- }
- {
- size_t i = 0;
- for (iter->SeekToLast(); iter->Valid(); iter->Prev()) {
- check_iter_entry(num_keys - 1 - i);
- ++i;
- }
- ASSERT_EQ(num_keys, i);
- ASSERT_OK(iter->status());
- }
- }
- void VerifyExpectedKeys(ColumnFamilyHandle* cfh,
- const std::vector<Slice>& expected_keys) {
- std::unique_ptr<Iterator> iter(db_->NewIterator(ReadOptions(), cfh));
- size_t i = 0;
- for (iter->SeekToFirst(); iter->Valid(); iter->Next()) {
- ASSERT_EQ(iter->key(), expected_keys[i]);
- ++i;
- }
- ASSERT_EQ(i, expected_keys.size());
- ASSERT_OK(iter->status());
- }
- };
- TEST_F(CoalescingIteratorTest, InvalidArguments) {
- Options options = GetDefaultOptions();
- {
- CreateAndReopenWithCF({"cf_1", "cf_2", "cf_3"}, options);
- // Invalid - No CF is provided
- std::unique_ptr<Iterator> iter_with_no_cf =
- db_->NewCoalescingIterator(ReadOptions(), {});
- ASSERT_NOK(iter_with_no_cf->status());
- ASSERT_TRUE(iter_with_no_cf->status().IsInvalidArgument());
- }
- }
- TEST_F(CoalescingIteratorTest, SimpleValues) {
- Options options = GetDefaultOptions();
- {
- // Case 1: Unique key per CF
- CreateAndReopenWithCF({"cf_1", "cf_2", "cf_3"}, options);
- ASSERT_OK(Put(0, "key_1", "key_1_cf_0_val"));
- ASSERT_OK(Put(1, "key_2", "key_2_cf_1_val"));
- ASSERT_OK(Put(2, "key_3", "key_3_cf_2_val"));
- ASSERT_OK(Put(3, "key_4", "key_4_cf_3_val"));
- std::vector<Slice> expected_keys = {"key_1", "key_2", "key_3", "key_4"};
- std::vector<Slice> expected_values = {"key_1_cf_0_val", "key_2_cf_1_val",
- "key_3_cf_2_val", "key_4_cf_3_val"};
- // Test for iteration over CF default->1->2->3
- std::vector<ColumnFamilyHandle*> cfhs_order_0_1_2_3 = {
- handles_[0], handles_[1], handles_[2], handles_[3]};
- VerifyCoalescingIterator(cfhs_order_0_1_2_3, expected_keys,
- expected_values);
- // Test for iteration over CF 3->1->default_cf->2
- std::vector<ColumnFamilyHandle*> cfhs_order_3_1_0_2 = {
- handles_[3], handles_[1], handles_[0], handles_[2]};
- // Iteration order and the return values should be the same since keys are
- // unique per CF
- VerifyCoalescingIterator(cfhs_order_3_1_0_2, expected_keys,
- expected_values);
- // Verify Seek()
- {
- std::unique_ptr<Iterator> iter =
- db_->NewCoalescingIterator(ReadOptions(), cfhs_order_0_1_2_3);
- iter->Seek("");
- ASSERT_EQ(IterStatus(iter.get()), "key_1->key_1_cf_0_val");
- iter->Seek("key_1");
- ASSERT_EQ(IterStatus(iter.get()), "key_1->key_1_cf_0_val");
- iter->Seek("key_2");
- ASSERT_EQ(IterStatus(iter.get()), "key_2->key_2_cf_1_val");
- iter->Next();
- ASSERT_EQ(IterStatus(iter.get()), "key_3->key_3_cf_2_val");
- iter->Seek("key_x");
- ASSERT_EQ(IterStatus(iter.get()), "(invalid)");
- }
- // Verify SeekForPrev()
- {
- std::unique_ptr<Iterator> iter =
- db_->NewCoalescingIterator(ReadOptions(), cfhs_order_0_1_2_3);
- iter->SeekForPrev("");
- ASSERT_EQ(IterStatus(iter.get()), "(invalid)");
- iter->SeekForPrev("key_1");
- ASSERT_EQ(IterStatus(iter.get()), "key_1->key_1_cf_0_val");
- iter->Next();
- ASSERT_EQ(IterStatus(iter.get()), "key_2->key_2_cf_1_val");
- iter->SeekForPrev("key_x");
- ASSERT_EQ(IterStatus(iter.get()), "key_4->key_4_cf_3_val");
- iter->Prev();
- ASSERT_EQ(IterStatus(iter.get()), "key_3->key_3_cf_2_val");
- iter->Next();
- ASSERT_EQ(IterStatus(iter.get()), "key_4->key_4_cf_3_val");
- iter->Next();
- ASSERT_EQ(IterStatus(iter.get()), "(invalid)");
- }
- }
- {
- // Case 2: Same key in multiple CFs
- options = CurrentOptions(options);
- DestroyAndReopen(options);
- CreateAndReopenWithCF({"cf_1", "cf_2", "cf_3"}, options);
- ASSERT_OK(Put(0, "key_1", "key_1_cf_0_val"));
- ASSERT_OK(Put(3, "key_1", "key_1_cf_3_val"));
- ASSERT_OK(Put(1, "key_2", "key_2_cf_1_val"));
- ASSERT_OK(Put(2, "key_2", "key_2_cf_2_val"));
- ASSERT_OK(Put(0, "key_3", "key_3_cf_0_val"));
- ASSERT_OK(Put(1, "key_3", "key_3_cf_1_val"));
- ASSERT_OK(Put(3, "key_3", "key_3_cf_3_val"));
- std::vector<Slice> expected_keys = {"key_1", "key_2", "key_3"};
- // Test for iteration over CFs default->1->2->3
- std::vector<ColumnFamilyHandle*> cfhs_order_0_1_2_3 = {
- handles_[0], handles_[1], handles_[2], handles_[3]};
- std::vector<Slice> expected_values = {"key_1_cf_3_val", "key_2_cf_2_val",
- "key_3_cf_3_val"};
- VerifyCoalescingIterator(cfhs_order_0_1_2_3, expected_keys,
- expected_values);
- // Test for iteration over CFs 3->2->default_cf->1
- std::vector<ColumnFamilyHandle*> cfhs_order_3_2_0_1 = {
- handles_[3], handles_[2], handles_[0], handles_[1]};
- expected_values = {"key_1_cf_0_val", "key_2_cf_1_val", "key_3_cf_1_val"};
- VerifyCoalescingIterator(cfhs_order_3_2_0_1, expected_keys,
- expected_values);
- // Verify Seek()
- {
- std::unique_ptr<Iterator> iter =
- db_->NewCoalescingIterator(ReadOptions(), cfhs_order_3_2_0_1);
- iter->Seek("");
- ASSERT_EQ(IterStatus(iter.get()), "key_1->key_1_cf_0_val");
- iter->Seek("key_1");
- ASSERT_EQ(IterStatus(iter.get()), "key_1->key_1_cf_0_val");
- iter->Seek("key_2");
- ASSERT_EQ(IterStatus(iter.get()), "key_2->key_2_cf_1_val");
- iter->Next();
- ASSERT_EQ(IterStatus(iter.get()), "key_3->key_3_cf_1_val");
- iter->Seek("key_x");
- ASSERT_EQ(IterStatus(iter.get()), "(invalid)");
- }
- // Verify SeekForPrev()
- {
- std::unique_ptr<Iterator> iter =
- db_->NewCoalescingIterator(ReadOptions(), cfhs_order_3_2_0_1);
- iter->SeekForPrev("");
- ASSERT_EQ(IterStatus(iter.get()), "(invalid)");
- iter->SeekForPrev("key_1");
- ASSERT_EQ(IterStatus(iter.get()), "key_1->key_1_cf_0_val");
- iter->Next();
- ASSERT_EQ(IterStatus(iter.get()), "key_2->key_2_cf_1_val");
- iter->SeekForPrev("key_x");
- ASSERT_EQ(IterStatus(iter.get()), "key_3->key_3_cf_1_val");
- iter->Next();
- ASSERT_EQ(IterStatus(iter.get()), "(invalid)");
- }
- }
- }
- TEST_F(CoalescingIteratorTest, LowerAndUpperBounds) {
- Options options = GetDefaultOptions();
- {
- // Case 1: Unique key per CF
- CreateAndReopenWithCF({"cf_1", "cf_2", "cf_3"}, options);
- ASSERT_OK(Put(0, "key_1", "key_1_cf_0_val"));
- ASSERT_OK(Put(1, "key_2", "key_2_cf_1_val"));
- ASSERT_OK(Put(2, "key_3", "key_3_cf_2_val"));
- ASSERT_OK(Put(3, "key_4", "key_4_cf_3_val"));
- std::vector<ColumnFamilyHandle*> cfhs_order_0_1_2_3 = {
- handles_[0], handles_[1], handles_[2], handles_[3]};
- // with lower_bound
- {
- // lower_bound is inclusive
- Slice lb = Slice("key_2");
- std::vector<Slice> expected_keys = {"key_2", "key_3", "key_4"};
- std::vector<Slice> expected_values = {"key_2_cf_1_val", "key_3_cf_2_val",
- "key_4_cf_3_val"};
- VerifyCoalescingIterator(cfhs_order_0_1_2_3, expected_keys,
- expected_values, std::nullopt, &lb);
- }
- // with upper_bound
- {
- // upper_bound is exclusive
- Slice ub = Slice("key_3");
- std::vector<Slice> expected_keys = {"key_1", "key_2"};
- std::vector<Slice> expected_values = {"key_1_cf_0_val", "key_2_cf_1_val"};
- VerifyCoalescingIterator(cfhs_order_0_1_2_3, expected_keys,
- expected_values, std::nullopt, nullptr, &ub);
- }
- // with lower and upper bound
- {
- Slice lb = Slice("key_2");
- Slice ub = Slice("key_4");
- std::vector<Slice> expected_keys = {"key_2", "key_3"};
- std::vector<Slice> expected_values = {"key_2_cf_1_val", "key_3_cf_2_val"};
- VerifyCoalescingIterator(cfhs_order_0_1_2_3, expected_keys,
- expected_values, std::nullopt, &lb, &ub);
- }
- {
- Slice lb = Slice("key_2");
- Slice ub = Slice("key_4");
- ReadOptions read_options;
- read_options.iterate_lower_bound = &lb;
- read_options.iterate_upper_bound = &ub;
- // Verify Seek() with bounds
- {
- std::unique_ptr<Iterator> iter =
- db_->NewCoalescingIterator(read_options, cfhs_order_0_1_2_3);
- iter->Seek("");
- ASSERT_EQ(IterStatus(iter.get()), "key_2->key_2_cf_1_val");
- iter->Next();
- ASSERT_EQ(IterStatus(iter.get()), "key_3->key_3_cf_2_val");
- iter->Seek("key_x");
- ASSERT_EQ(IterStatus(iter.get()), "(invalid)");
- }
- // Verify SeekForPrev() with bounds
- {
- std::unique_ptr<Iterator> iter =
- db_->NewCoalescingIterator(read_options, cfhs_order_0_1_2_3);
- iter->SeekForPrev("");
- ASSERT_EQ(IterStatus(iter.get()), "(invalid)");
- iter->SeekForPrev("key_1");
- ASSERT_EQ(IterStatus(iter.get()), "(invalid)");
- iter->SeekForPrev("key_2");
- ASSERT_EQ(IterStatus(iter.get()), "key_2->key_2_cf_1_val");
- iter->Next();
- ASSERT_EQ(IterStatus(iter.get()), "key_3->key_3_cf_2_val");
- iter->SeekForPrev("key_x");
- ASSERT_EQ(IterStatus(iter.get()), "key_3->key_3_cf_2_val");
- iter->Prev();
- ASSERT_EQ(IterStatus(iter.get()), "key_2->key_2_cf_1_val");
- iter->Next();
- ASSERT_EQ(IterStatus(iter.get()), "key_3->key_3_cf_2_val");
- iter->Next();
- ASSERT_EQ(IterStatus(iter.get()), "(invalid)");
- }
- }
- }
- {
- // Case 2: Same key in multiple CFs
- options = CurrentOptions(options);
- DestroyAndReopen(options);
- CreateAndReopenWithCF({"cf_1", "cf_2", "cf_3"}, options);
- ASSERT_OK(Put(0, "key_1", "key_1_cf_0_val"));
- ASSERT_OK(Put(3, "key_1", "key_1_cf_3_val"));
- ASSERT_OK(Put(1, "key_2", "key_2_cf_1_val"));
- ASSERT_OK(Put(2, "key_2", "key_2_cf_2_val"));
- ASSERT_OK(Put(0, "key_3", "key_3_cf_0_val"));
- ASSERT_OK(Put(1, "key_3", "key_3_cf_1_val"));
- ASSERT_OK(Put(3, "key_3", "key_3_cf_3_val"));
- // Test for iteration over CFs default->1->2->3
- std::vector<ColumnFamilyHandle*> cfhs_order_0_1_2_3 = {
- handles_[0], handles_[1], handles_[2], handles_[3]};
- // with lower_bound
- {
- // lower_bound is inclusive
- Slice lb = Slice("key_2");
- std::vector<Slice> expected_keys = {"key_2", "key_3"};
- std::vector<Slice> expected_values = {"key_2_cf_2_val", "key_3_cf_3_val"};
- VerifyCoalescingIterator(cfhs_order_0_1_2_3, expected_keys,
- expected_values, std::nullopt, &lb);
- }
- // with upper_bound
- {
- // upper_bound is exclusive
- Slice ub = Slice("key_3");
- std::vector<Slice> expected_keys = {"key_1", "key_2"};
- std::vector<Slice> expected_values = {"key_1_cf_3_val", "key_2_cf_2_val"};
- VerifyCoalescingIterator(cfhs_order_0_1_2_3, expected_keys,
- expected_values, std::nullopt, nullptr, &ub);
- }
- // with lower and upper bound
- {
- Slice lb = Slice("key_2");
- Slice ub = Slice("key_3");
- std::vector<Slice> expected_keys = {"key_2"};
- std::vector<Slice> expected_values = {"key_2_cf_2_val"};
- VerifyCoalescingIterator(cfhs_order_0_1_2_3, expected_keys,
- expected_values, std::nullopt, &lb, &ub);
- }
- // Test for iteration over CFs 3->2->default_cf->1
- std::vector<ColumnFamilyHandle*> cfhs_order_3_2_0_1 = {
- handles_[3], handles_[2], handles_[0], handles_[1]};
- {
- // lower_bound is inclusive
- Slice lb = Slice("key_2");
- std::vector<Slice> expected_keys = {"key_2", "key_3"};
- std::vector<Slice> expected_values = {"key_2_cf_1_val", "key_3_cf_1_val"};
- VerifyCoalescingIterator(cfhs_order_3_2_0_1, expected_keys,
- expected_values, std::nullopt, &lb);
- }
- // with upper_bound
- {
- // upper_bound is exclusive
- Slice ub = Slice("key_3");
- std::vector<Slice> expected_keys = {"key_1", "key_2"};
- std::vector<Slice> expected_values = {"key_1_cf_0_val", "key_2_cf_1_val"};
- VerifyCoalescingIterator(cfhs_order_3_2_0_1, expected_keys,
- expected_values, std::nullopt, nullptr, &ub);
- }
- // with lower and upper bound
- {
- Slice lb = Slice("key_2");
- Slice ub = Slice("key_3");
- std::vector<Slice> expected_keys = {"key_2"};
- std::vector<Slice> expected_values = {"key_2_cf_1_val"};
- VerifyCoalescingIterator(cfhs_order_3_2_0_1, expected_keys,
- expected_values, std::nullopt, &lb, &ub);
- }
- {
- Slice lb = Slice("key_2");
- Slice ub = Slice("key_3");
- ReadOptions read_options;
- read_options.iterate_lower_bound = &lb;
- read_options.iterate_upper_bound = &ub;
- // Verify Seek() with bounds
- {
- std::unique_ptr<Iterator> iter =
- db_->NewCoalescingIterator(read_options, cfhs_order_3_2_0_1);
- iter->Seek("");
- ASSERT_EQ(IterStatus(iter.get()), "key_2->key_2_cf_1_val");
- iter->Next();
- ASSERT_EQ(IterStatus(iter.get()), "(invalid)");
- iter->Seek("key_x");
- ASSERT_EQ(IterStatus(iter.get()), "(invalid)");
- }
- // Verify SeekForPrev() with bounds
- {
- std::unique_ptr<Iterator> iter =
- db_->NewCoalescingIterator(read_options, cfhs_order_3_2_0_1);
- iter->SeekForPrev("");
- ASSERT_EQ(IterStatus(iter.get()), "(invalid)");
- iter->SeekForPrev("key_1");
- ASSERT_EQ(IterStatus(iter.get()), "(invalid)");
- iter->SeekForPrev("key_2");
- ASSERT_EQ(IterStatus(iter.get()), "key_2->key_2_cf_1_val");
- iter->SeekForPrev("key_x");
- ASSERT_EQ(IterStatus(iter.get()), "key_2->key_2_cf_1_val");
- iter->Next();
- ASSERT_EQ(IterStatus(iter.get()), "(invalid)");
- }
- }
- }
- }
- TEST_F(CoalescingIteratorTest, ConsistentViewExplicitSnapshot) {
- Options options = GetDefaultOptions();
- options.atomic_flush = true;
- CreateAndReopenWithCF({"cf_1", "cf_2", "cf_3"}, options);
- for (int i = 0; i < 4; ++i) {
- ASSERT_OK(Put(i, "cf" + std::to_string(i) + "_key",
- "cf" + std::to_string(i) + "_val"));
- }
- ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->LoadDependency(
- {{"DBImpl::BGWorkFlush:done",
- "DBImpl::MultiCFSnapshot::BeforeCheckingSnapshot"}});
- bool flushed = false;
- ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->SetCallBack(
- "DBImpl::MultiCFSnapshot::AfterRefSV", [&](void* /*arg*/) {
- if (!flushed) {
- for (int i = 0; i < 4; ++i) {
- ASSERT_OK(Put(i, "cf" + std::to_string(i) + "_key",
- "cf" + std::to_string(i) + "_val_new"));
- }
- ASSERT_OK(Flush());
- flushed = true;
- }
- });
- ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->EnableProcessing();
- std::vector<ColumnFamilyHandle*> cfhs_order_0_1_2_3 = {
- handles_[0], handles_[1], handles_[2], handles_[3]};
- ReadOptions read_options;
- const Snapshot* snapshot = db_->GetSnapshot();
- read_options.snapshot = snapshot;
- // Verify Seek()
- {
- std::unique_ptr<Iterator> iter =
- db_->NewCoalescingIterator(read_options, cfhs_order_0_1_2_3);
- iter->Seek("");
- ASSERT_EQ(IterStatus(iter.get()), "cf0_key->cf0_val");
- iter->Next();
- ASSERT_EQ(IterStatus(iter.get()), "cf1_key->cf1_val");
- }
- // Verify SeekForPrev()
- {
- std::unique_ptr<Iterator> iter =
- db_->NewCoalescingIterator(read_options, cfhs_order_0_1_2_3);
- iter->SeekForPrev("");
- ASSERT_EQ(IterStatus(iter.get()), "(invalid)");
- iter->SeekForPrev("cf2_key");
- ASSERT_EQ(IterStatus(iter.get()), "cf2_key->cf2_val");
- iter->Prev();
- ASSERT_EQ(IterStatus(iter.get()), "cf1_key->cf1_val");
- }
- db_->ReleaseSnapshot(snapshot);
- }
- TEST_F(CoalescingIteratorTest, ConsistentViewImplicitSnapshot) {
- Options options = GetDefaultOptions();
- CreateAndReopenWithCF({"cf_1", "cf_2", "cf_3"}, options);
- for (int i = 0; i < 4; ++i) {
- ASSERT_OK(Put(i, "cf" + std::to_string(i) + "_key",
- "cf" + std::to_string(i) + "_val"));
- }
- ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->LoadDependency(
- {{"DBImpl::BGWorkFlush:done",
- "DBImpl::MultiCFSnapshot::BeforeCheckingSnapshot"}});
- bool flushed = false;
- ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->SetCallBack(
- "DBImpl::MultiCFSnapshot::AfterRefSV", [&](void* /*arg*/) {
- if (!flushed) {
- for (int i = 0; i < 4; ++i) {
- ASSERT_OK(Put(i, "cf" + std::to_string(i) + "_key",
- "cf" + std::to_string(i) + "_val_new"));
- }
- ASSERT_OK(Flush(1));
- flushed = true;
- }
- });
- ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->EnableProcessing();
- std::vector<ColumnFamilyHandle*> cfhs_order_0_1_2_3 = {
- handles_[0], handles_[1], handles_[2], handles_[3]};
- // Verify Seek()
- {
- std::unique_ptr<Iterator> iter =
- db_->NewCoalescingIterator(ReadOptions(), cfhs_order_0_1_2_3);
- iter->Seek("cf2_key");
- ASSERT_EQ(IterStatus(iter.get()), "cf2_key->cf2_val_new");
- iter->Next();
- ASSERT_EQ(IterStatus(iter.get()), "cf3_key->cf3_val_new");
- }
- // Verify SeekForPrev()
- {
- std::unique_ptr<Iterator> iter =
- db_->NewCoalescingIterator(ReadOptions(), cfhs_order_0_1_2_3);
- iter->SeekForPrev("");
- ASSERT_EQ(IterStatus(iter.get()), "(invalid)");
- iter->SeekForPrev("cf1_key");
- ASSERT_EQ(IterStatus(iter.get()), "cf1_key->cf1_val_new");
- iter->Prev();
- ASSERT_EQ(IterStatus(iter.get()), "cf0_key->cf0_val_new");
- }
- }
- TEST_F(CoalescingIteratorTest, EmptyCfs) {
- Options options = GetDefaultOptions();
- {
- // Case 1: No keys in any of the CFs
- CreateAndReopenWithCF({"cf_1", "cf_2", "cf_3"}, options);
- std::unique_ptr<Iterator> iter =
- db_->NewCoalescingIterator(ReadOptions(), handles_);
- iter->SeekToFirst();
- ASSERT_EQ(IterStatus(iter.get()), "(invalid)");
- iter->SeekToLast();
- ASSERT_EQ(IterStatus(iter.get()), "(invalid)");
- iter->Seek("foo");
- ASSERT_EQ(IterStatus(iter.get()), "(invalid)");
- iter->SeekForPrev("foo");
- ASSERT_EQ(IterStatus(iter.get()), "(invalid)");
- ASSERT_OK(iter->status());
- }
- {
- // Case 2: A single key exists in only one of the CF. Rest CFs are empty.
- ASSERT_OK(Put(1, "key_1", "key_1_cf_1_val"));
- std::unique_ptr<Iterator> iter =
- db_->NewCoalescingIterator(ReadOptions(), handles_);
- iter->SeekToFirst();
- ASSERT_EQ(IterStatus(iter.get()), "key_1->key_1_cf_1_val");
- iter->Next();
- ASSERT_EQ(IterStatus(iter.get()), "(invalid)");
- iter->SeekToLast();
- ASSERT_EQ(IterStatus(iter.get()), "key_1->key_1_cf_1_val");
- iter->Prev();
- ASSERT_EQ(IterStatus(iter.get()), "(invalid)");
- }
- {
- // Case 3: same key exists in all of the CFs except one (cf_2)
- ASSERT_OK(Put(0, "key_1", "key_1_cf_0_val"));
- ASSERT_OK(Put(3, "key_1", "key_1_cf_3_val"));
- // handles_ are in the order of 0->1->2->3
- std::unique_ptr<Iterator> iter =
- db_->NewCoalescingIterator(ReadOptions(), handles_);
- iter->SeekToFirst();
- ASSERT_EQ(IterStatus(iter.get()), "key_1->key_1_cf_3_val");
- iter->Next();
- ASSERT_EQ(IterStatus(iter.get()), "(invalid)");
- iter->SeekToLast();
- ASSERT_EQ(IterStatus(iter.get()), "key_1->key_1_cf_3_val");
- iter->Prev();
- ASSERT_EQ(IterStatus(iter.get()), "(invalid)");
- }
- }
- TEST_F(CoalescingIteratorTest, WideColumns) {
- // Set up the DB and Column Families
- Options options = GetDefaultOptions();
- CreateAndReopenWithCF({"cf_1", "cf_2", "cf_3"}, options);
- constexpr char key_1[] = "key_1";
- WideColumns key_1_columns_in_cf_2{
- {kDefaultWideColumnName, "cf_2_col_val_0_key_1"},
- {"cf_2_col_name_1", "cf_2_col_val_1_key_1"},
- {"cf_2_col_name_2", "cf_2_col_val_2_key_1"},
- {"cf_overlap_col_name", "cf_2_overlap_value_key_1"}};
- WideColumns key_1_columns_in_cf_3{
- {"cf_3_col_name_1", "cf_3_col_val_1_key_1"},
- {"cf_3_col_name_2", "cf_3_col_val_2_key_1"},
- {"cf_3_col_name_3", "cf_3_col_val_3_key_1"},
- {"cf_overlap_col_name", "cf_3_overlap_value_key_1"}};
- WideColumns key_1_expected_columns_cfh_order_2_3{
- {kDefaultWideColumnName, "cf_2_col_val_0_key_1"},
- {"cf_2_col_name_1", "cf_2_col_val_1_key_1"},
- {"cf_2_col_name_2", "cf_2_col_val_2_key_1"},
- {"cf_3_col_name_1", "cf_3_col_val_1_key_1"},
- {"cf_3_col_name_2", "cf_3_col_val_2_key_1"},
- {"cf_3_col_name_3", "cf_3_col_val_3_key_1"},
- {"cf_overlap_col_name", "cf_3_overlap_value_key_1"}};
- WideColumns key_1_expected_columns_cfh_order_3_2{
- {kDefaultWideColumnName, "cf_2_col_val_0_key_1"},
- {"cf_2_col_name_1", "cf_2_col_val_1_key_1"},
- {"cf_2_col_name_2", "cf_2_col_val_2_key_1"},
- {"cf_3_col_name_1", "cf_3_col_val_1_key_1"},
- {"cf_3_col_name_2", "cf_3_col_val_2_key_1"},
- {"cf_3_col_name_3", "cf_3_col_val_3_key_1"},
- {"cf_overlap_col_name", "cf_2_overlap_value_key_1"}};
- constexpr char key_2[] = "key_2";
- WideColumns key_2_columns_in_cf_1{
- {"cf_overlap_col_name", "cf_1_overlap_value_key_2"}};
- WideColumns key_2_columns_in_cf_2{
- {"cf_2_col_name_1", "cf_2_col_val_1_key_2"},
- {"cf_2_col_name_2", "cf_2_col_val_2_key_2"},
- {"cf_overlap_col_name", "cf_2_overlap_value_key_2"}};
- WideColumns key_2_expected_columns_cfh_order_1_2{
- {"cf_2_col_name_1", "cf_2_col_val_1_key_2"},
- {"cf_2_col_name_2", "cf_2_col_val_2_key_2"},
- {"cf_overlap_col_name", "cf_2_overlap_value_key_2"}};
- WideColumns key_2_expected_columns_cfh_order_2_1{
- {"cf_2_col_name_1", "cf_2_col_val_1_key_2"},
- {"cf_2_col_name_2", "cf_2_col_val_2_key_2"},
- {"cf_overlap_col_name", "cf_1_overlap_value_key_2"}};
- constexpr char key_3[] = "key_3";
- WideColumns key_3_columns_in_cf_1{
- {"cf_1_col_name_1", "cf_1_col_val_1_key_3"}};
- WideColumns key_3_columns_in_cf_3{
- {"cf_3_col_name_1", "cf_3_col_val_1_key_3"}};
- WideColumns key_3_expected_columns{
- {"cf_1_col_name_1", "cf_1_col_val_1_key_3"},
- {"cf_3_col_name_1", "cf_3_col_val_1_key_3"},
- };
- constexpr char key_4[] = "key_4";
- WideColumns key_4_columns_in_cf_0{
- {"cf_0_col_name_1", "cf_0_col_val_1_key_4"}};
- WideColumns key_4_columns_in_cf_2{
- {"cf_2_col_name_1", "cf_2_col_val_1_key_4"}};
- WideColumns key_4_expected_columns{
- {"cf_0_col_name_1", "cf_0_col_val_1_key_4"},
- {"cf_2_col_name_1", "cf_2_col_val_1_key_4"},
- };
- // Use AttributeGroup PutEntity API to insert them together
- AttributeGroups key_1_attribute_groups{
- AttributeGroup(handles_[2], key_1_columns_in_cf_2),
- AttributeGroup(handles_[3], key_1_columns_in_cf_3)};
- AttributeGroups key_2_attribute_groups{
- AttributeGroup(handles_[1], key_2_columns_in_cf_1),
- AttributeGroup(handles_[2], key_2_columns_in_cf_2)};
- AttributeGroups key_3_attribute_groups{
- AttributeGroup(handles_[1], key_3_columns_in_cf_1),
- AttributeGroup(handles_[3], key_3_columns_in_cf_3)};
- AttributeGroups key_4_attribute_groups{
- AttributeGroup(handles_[0], key_4_columns_in_cf_0),
- AttributeGroup(handles_[2], key_4_columns_in_cf_2)};
- ASSERT_OK(db_->PutEntity(WriteOptions(), key_1, key_1_attribute_groups));
- ASSERT_OK(db_->PutEntity(WriteOptions(), key_2, key_2_attribute_groups));
- ASSERT_OK(db_->PutEntity(WriteOptions(), key_3, key_3_attribute_groups));
- ASSERT_OK(db_->PutEntity(WriteOptions(), key_4, key_4_attribute_groups));
- // Keys should be returned in order regardless of cfh order
- std::vector<Slice> expected_keys = {key_1, key_2, key_3, key_4};
- // Since value for kDefaultWideColumnName only exists for key_1, rest will
- // return empty value after coalesced
- std::vector<Slice> expected_values = {"cf_2_col_val_0_key_1", "", "", ""};
- // Test for iteration over CF default->1->2->3
- {
- std::vector<ColumnFamilyHandle*> cfhs_order_0_1_2_3 = {
- handles_[0], handles_[1], handles_[2], handles_[3]};
- // Coalesced columns
- std::vector<WideColumns> expected_wide_columns_0_1_2_3 = {
- key_1_expected_columns_cfh_order_2_3,
- key_2_expected_columns_cfh_order_1_2, key_3_expected_columns,
- key_4_expected_columns};
- VerifyCoalescingIterator(cfhs_order_0_1_2_3, expected_keys, expected_values,
- expected_wide_columns_0_1_2_3);
- }
- // Test for iteration over CF 3->2->default->1
- {
- std::vector<ColumnFamilyHandle*> cfhs_order_3_2_0_1 = {
- handles_[3], handles_[2], handles_[0], handles_[1]};
- // Coalesced columns
- std::vector<WideColumns> expected_wide_columns_3_2_0_1 = {
- key_1_expected_columns_cfh_order_3_2,
- key_2_expected_columns_cfh_order_2_1, key_3_expected_columns,
- key_4_expected_columns};
- VerifyCoalescingIterator(cfhs_order_3_2_0_1, expected_keys, expected_values,
- expected_wide_columns_3_2_0_1);
- }
- }
- TEST_F(CoalescingIteratorTest, DifferentComparatorsInMultiCFs) {
- // This test creates two column families with two different comparators.
- // Attempting to create the CoalescingIterator should fail.
- Options options = GetDefaultOptions();
- options.create_if_missing = true;
- DestroyAndReopen(options);
- options.comparator = BytewiseComparator();
- CreateColumnFamilies({"cf_forward"}, options);
- options.comparator = ReverseBytewiseComparator();
- CreateColumnFamilies({"cf_reverse"}, options);
- ASSERT_OK(Put(0, "key_1", "value_1"));
- ASSERT_OK(Put(0, "key_2", "value_2"));
- ASSERT_OK(Put(0, "key_3", "value_3"));
- ASSERT_OK(Put(1, "key_1", "value_1"));
- ASSERT_OK(Put(1, "key_2", "value_2"));
- ASSERT_OK(Put(1, "key_3", "value_3"));
- VerifyExpectedKeys(handles_[0], {"key_1", "key_2", "key_3"});
- VerifyExpectedKeys(handles_[1], {"key_3", "key_2", "key_1"});
- std::unique_ptr<Iterator> iter =
- db_->NewCoalescingIterator(ReadOptions(), handles_);
- ASSERT_NOK(iter->status());
- ASSERT_TRUE(iter->status().IsInvalidArgument());
- }
- TEST_F(CoalescingIteratorTest, CustomComparatorsInMultiCFs) {
- // This test creates two column families with the same custom test
- // comparators (but instantiated independently). Attempting to create the
- // CoalescingIterator should not fail.
- Options options = GetDefaultOptions();
- options.create_if_missing = true;
- DestroyAndReopen(options);
- static auto comparator_1 =
- std::make_unique<test::SimpleSuffixReverseComparator>(
- test::SimpleSuffixReverseComparator());
- static auto comparator_2 =
- std::make_unique<test::SimpleSuffixReverseComparator>(
- test::SimpleSuffixReverseComparator());
- ASSERT_NE(comparator_1, comparator_2);
- options.comparator = comparator_1.get();
- CreateColumnFamilies({"cf_1"}, options);
- options.comparator = comparator_2.get();
- CreateColumnFamilies({"cf_2"}, options);
- ASSERT_OK(Put(0, "key_001_001", "value_0_3"));
- ASSERT_OK(Put(0, "key_001_002", "value_0_2"));
- ASSERT_OK(Put(0, "key_001_003", "value_0_1"));
- ASSERT_OK(Put(0, "key_002_001", "value_0_6"));
- ASSERT_OK(Put(0, "key_002_002", "value_0_5"));
- ASSERT_OK(Put(0, "key_002_003", "value_0_4"));
- ASSERT_OK(Put(1, "key_001_001", "value_1_3"));
- ASSERT_OK(Put(1, "key_001_002", "value_1_2"));
- ASSERT_OK(Put(1, "key_001_003", "value_1_1"));
- ASSERT_OK(Put(1, "key_003_004", "value_1_6"));
- ASSERT_OK(Put(1, "key_003_005", "value_1_5"));
- ASSERT_OK(Put(1, "key_003_006", "value_1_4"));
- VerifyExpectedKeys(
- handles_[0], {"key_001_003", "key_001_002", "key_001_001", "key_002_003",
- "key_002_002", "key_002_001"});
- VerifyExpectedKeys(
- handles_[1], {"key_001_003", "key_001_002", "key_001_001", "key_003_006",
- "key_003_005", "key_003_004"});
- std::vector<Slice> expected_keys = {
- "key_001_003", "key_001_002", "key_001_001", "key_002_003", "key_002_002",
- "key_002_001", "key_003_006", "key_003_005", "key_003_004"};
- std::vector<Slice> expected_values = {"value_1_1", "value_1_2", "value_1_3",
- "value_0_4", "value_0_5", "value_0_6",
- "value_1_4", "value_1_5", "value_1_6"};
- std::unique_ptr<Iterator> iter =
- db_->NewCoalescingIterator(ReadOptions(), handles_);
- size_t i = 0;
- for (iter->SeekToFirst(); iter->Valid(); iter->Next()) {
- ASSERT_EQ(expected_keys[i], iter->key());
- ASSERT_EQ(expected_values[i], iter->value());
- ++i;
- }
- ASSERT_EQ(expected_keys.size(), i);
- ASSERT_OK(iter->status());
- }
- TEST_F(CoalescingIteratorTest, AllowUnpreparedValue) {
- Options options = GetDefaultOptions();
- options.enable_blob_files = true;
- CreateAndReopenWithCF({"cf_1", "cf_2", "cf_3"}, options);
- ASSERT_OK(Put(0, "key_1", "key_1_cf_0_val"));
- ASSERT_OK(Put(3, "key_1", "key_1_cf_3_val"));
- ASSERT_OK(Put(1, "key_2", "key_2_cf_1_val"));
- ASSERT_OK(Put(2, "key_2", "key_2_cf_2_val"));
- ASSERT_OK(Put(0, "key_3", "key_3_cf_0_val"));
- ASSERT_OK(Put(1, "key_3", "key_3_cf_1_val"));
- ASSERT_OK(Put(3, "key_3", "key_3_cf_3_val"));
- ASSERT_OK(Flush());
- std::vector<ColumnFamilyHandle*> cfhs_order_3_2_0_1{handles_[3], handles_[2],
- handles_[0], handles_[1]};
- std::vector<Slice> expected_keys{"key_1", "key_2", "key_3"};
- std::vector<Slice> expected_values{"key_1_cf_0_val", "key_2_cf_1_val",
- "key_3_cf_1_val"};
- VerifyCoalescingIterator(cfhs_order_3_2_0_1, expected_keys, expected_values,
- /* expected_wide_columns */ std::nullopt,
- /* lower_bound */ nullptr, /* upper_bound */ nullptr,
- /* allow_unprepared_value */ true);
- ReadOptions read_options;
- read_options.allow_unprepared_value = true;
- {
- std::unique_ptr<Iterator> iter =
- db_->NewCoalescingIterator(read_options, cfhs_order_3_2_0_1);
- iter->Seek("");
- ASSERT_EQ(IterStatus(iter.get()), "key_1->");
- ASSERT_TRUE(iter->PrepareValue());
- ASSERT_EQ(IterStatus(iter.get()), "key_1->key_1_cf_0_val");
- iter->Seek("key_1");
- ASSERT_EQ(IterStatus(iter.get()), "key_1->");
- ASSERT_TRUE(iter->PrepareValue());
- ASSERT_EQ(IterStatus(iter.get()), "key_1->key_1_cf_0_val");
- iter->Seek("key_2");
- ASSERT_EQ(IterStatus(iter.get()), "key_2->");
- ASSERT_TRUE(iter->PrepareValue());
- ASSERT_EQ(IterStatus(iter.get()), "key_2->key_2_cf_1_val");
- iter->Next();
- ASSERT_EQ(IterStatus(iter.get()), "key_3->");
- ASSERT_TRUE(iter->PrepareValue());
- ASSERT_EQ(IterStatus(iter.get()), "key_3->key_3_cf_1_val");
- iter->Seek("key_x");
- ASSERT_EQ(IterStatus(iter.get()), "(invalid)");
- }
- {
- std::unique_ptr<Iterator> iter =
- db_->NewCoalescingIterator(read_options, cfhs_order_3_2_0_1);
- iter->SeekForPrev("");
- ASSERT_EQ(IterStatus(iter.get()), "(invalid)");
- iter->SeekForPrev("key_1");
- ASSERT_EQ(IterStatus(iter.get()), "key_1->");
- ASSERT_TRUE(iter->PrepareValue());
- ASSERT_EQ(IterStatus(iter.get()), "key_1->key_1_cf_0_val");
- iter->Next();
- ASSERT_EQ(IterStatus(iter.get()), "key_2->");
- ASSERT_TRUE(iter->PrepareValue());
- ASSERT_EQ(IterStatus(iter.get()), "key_2->key_2_cf_1_val");
- iter->SeekForPrev("key_x");
- ASSERT_EQ(IterStatus(iter.get()), "key_3->");
- ASSERT_TRUE(iter->PrepareValue());
- ASSERT_EQ(IterStatus(iter.get()), "key_3->key_3_cf_1_val");
- iter->Next();
- ASSERT_EQ(IterStatus(iter.get()), "(invalid)");
- }
- }
- TEST_F(CoalescingIteratorTest, AllowUnpreparedValue_Corruption) {
- Options options = GetDefaultOptions();
- options.enable_blob_files = true;
- CreateAndReopenWithCF({"cf_1", "cf_2", "cf_3"}, options);
- ASSERT_OK(Put(0, "key_1", "key_1_cf_0_val"));
- ASSERT_OK(Put(3, "key_1", "key_1_cf_3_val"));
- ASSERT_OK(Put(1, "key_2", "key_2_cf_1_val"));
- ASSERT_OK(Put(2, "key_2", "key_2_cf_2_val"));
- ASSERT_OK(Put(0, "key_3", "key_3_cf_0_val"));
- ASSERT_OK(Put(1, "key_3", "key_3_cf_1_val"));
- ASSERT_OK(Put(3, "key_3", "key_3_cf_3_val"));
- ASSERT_OK(Flush());
- ReadOptions read_options;
- read_options.allow_unprepared_value = true;
- std::vector<ColumnFamilyHandle*> cfhs_order_3_2_0_1{handles_[3], handles_[2],
- handles_[0], handles_[1]};
- std::unique_ptr<Iterator> iter =
- db_->NewCoalescingIterator(read_options, cfhs_order_3_2_0_1);
- iter->SeekToFirst();
- ASSERT_TRUE(iter->Valid());
- ASSERT_OK(iter->status());
- ASSERT_EQ(iter->key(), "key_1");
- ASSERT_TRUE(iter->value().empty());
- SyncPoint::GetInstance()->SetCallBack(
- "BlobFileReader::GetBlob:TamperWithResult", [](void* arg) {
- Slice* const blob_index = static_cast<Slice*>(arg);
- assert(blob_index);
- assert(!blob_index->empty());
- blob_index->remove_prefix(1);
- });
- SyncPoint::GetInstance()->EnableProcessing();
- ASSERT_FALSE(iter->PrepareValue());
- ASSERT_FALSE(iter->Valid());
- ASSERT_TRUE(iter->status().IsCorruption());
- SyncPoint::GetInstance()->DisableProcessing();
- SyncPoint::GetInstance()->ClearAllCallBacks();
- }
- class AttributeGroupIteratorTest : public DBTestBase {
- public:
- AttributeGroupIteratorTest()
- : DBTestBase("attribute_group_iterator_test", /*env_do_fsync=*/true) {}
- void VerifyAttributeGroupIterator(
- const std::vector<ColumnFamilyHandle*>& cfhs,
- const std::vector<Slice>& expected_keys,
- const std::vector<IteratorAttributeGroups>& expected_attribute_groups,
- const Slice* lower_bound = nullptr, const Slice* upper_bound = nullptr,
- bool allow_unprepared_value = false) {
- const size_t num_keys = expected_keys.size();
- ReadOptions read_options;
- read_options.iterate_lower_bound = lower_bound;
- read_options.iterate_upper_bound = upper_bound;
- read_options.allow_unprepared_value = allow_unprepared_value;
- std::unique_ptr<AttributeGroupIterator> iter =
- db_->NewAttributeGroupIterator(read_options, cfhs);
- auto check_iter_entry = [&](size_t idx) {
- ASSERT_EQ(iter->key(), expected_keys[idx]);
- if (allow_unprepared_value) {
- ASSERT_TRUE(iter->attribute_groups().empty());
- ASSERT_TRUE(iter->PrepareValue());
- ASSERT_TRUE(iter->Valid());
- }
- ASSERT_EQ(iter->attribute_groups(), expected_attribute_groups[idx]);
- };
- {
- size_t i = 0;
- for (iter->SeekToFirst(); iter->Valid(); iter->Next()) {
- check_iter_entry(i);
- ++i;
- }
- ASSERT_EQ(i, num_keys);
- ASSERT_OK(iter->status());
- }
- {
- size_t i = 0;
- for (iter->SeekToLast(); iter->Valid(); iter->Prev()) {
- check_iter_entry(num_keys - 1 - i);
- ++i;
- }
- ASSERT_EQ(i, num_keys);
- ASSERT_OK(iter->status());
- }
- }
- };
- TEST_F(AttributeGroupIteratorTest, IterateAttributeGroups) {
- // Set up the DB and Column Families
- Options options = GetDefaultOptions();
- CreateAndReopenWithCF({"cf_1", "cf_2", "cf_3"}, options);
- constexpr char key_1[] = "key_1";
- WideColumns key_1_columns_in_cf_2{
- {kDefaultWideColumnName, "cf_2_col_val_0_key_1"},
- {"cf_2_col_name_1", "cf_2_col_val_1_key_1"},
- {"cf_2_col_name_2", "cf_2_col_val_2_key_1"}};
- WideColumns key_1_columns_in_cf_3{
- {"cf_3_col_name_1", "cf_3_col_val_1_key_1"},
- {"cf_3_col_name_2", "cf_3_col_val_2_key_1"},
- {"cf_3_col_name_3", "cf_3_col_val_3_key_1"}};
- constexpr char key_2[] = "key_2";
- WideColumns key_2_columns_in_cf_1{
- {"cf_1_col_name_1", "cf_1_col_val_1_key_2"}};
- WideColumns key_2_columns_in_cf_2{
- {"cf_2_col_name_1", "cf_2_col_val_1_key_2"},
- {"cf_2_col_name_2", "cf_2_col_val_2_key_2"}};
- constexpr char key_3[] = "key_3";
- WideColumns key_3_columns_in_cf_1{
- {"cf_1_col_name_1", "cf_1_col_val_1_key_3"}};
- WideColumns key_3_columns_in_cf_3{
- {"cf_3_col_name_1", "cf_3_col_val_1_key_3"}};
- constexpr char key_4[] = "key_4";
- WideColumns key_4_columns_in_cf_0{
- {"cf_0_col_name_1", "cf_0_col_val_1_key_4"}};
- WideColumns key_4_columns_in_cf_2{
- {"cf_2_col_name_1", "cf_2_col_val_1_key_4"}};
- AttributeGroups key_1_attribute_groups{
- AttributeGroup(handles_[2], key_1_columns_in_cf_2),
- AttributeGroup(handles_[3], key_1_columns_in_cf_3)};
- AttributeGroups key_2_attribute_groups{
- AttributeGroup(handles_[1], key_2_columns_in_cf_1),
- AttributeGroup(handles_[2], key_2_columns_in_cf_2)};
- AttributeGroups key_3_attribute_groups{
- AttributeGroup(handles_[1], key_3_columns_in_cf_1),
- AttributeGroup(handles_[3], key_3_columns_in_cf_3)};
- AttributeGroups key_4_attribute_groups{
- AttributeGroup(handles_[0], key_4_columns_in_cf_0),
- AttributeGroup(handles_[2], key_4_columns_in_cf_2)};
- ASSERT_OK(db_->PutEntity(WriteOptions(), key_1, key_1_attribute_groups));
- ASSERT_OK(db_->PutEntity(WriteOptions(), key_2, key_2_attribute_groups));
- ASSERT_OK(db_->PutEntity(WriteOptions(), key_3, key_3_attribute_groups));
- ASSERT_OK(db_->PutEntity(WriteOptions(), key_4, key_4_attribute_groups));
- IteratorAttributeGroups key_1_expected_attribute_groups{
- IteratorAttributeGroup(key_1_attribute_groups[0]),
- IteratorAttributeGroup(key_1_attribute_groups[1])};
- IteratorAttributeGroups key_2_expected_attribute_groups{
- IteratorAttributeGroup(key_2_attribute_groups[0]),
- IteratorAttributeGroup(key_2_attribute_groups[1])};
- IteratorAttributeGroups key_3_expected_attribute_groups{
- IteratorAttributeGroup(key_3_attribute_groups[0]),
- IteratorAttributeGroup(key_3_attribute_groups[1])};
- IteratorAttributeGroups key_4_expected_attribute_groups{
- IteratorAttributeGroup(key_4_attribute_groups[0]),
- IteratorAttributeGroup(key_4_attribute_groups[1])};
- // Test for iteration over CF default->1->2->3
- std::vector<ColumnFamilyHandle*> cfhs_order_0_1_2_3 = {
- handles_[0], handles_[1], handles_[2], handles_[3]};
- {
- std::vector<Slice> expected_keys = {key_1, key_2, key_3, key_4};
- std::vector<IteratorAttributeGroups> expected_attribute_groups{
- key_1_expected_attribute_groups, key_2_expected_attribute_groups,
- key_3_expected_attribute_groups, key_4_expected_attribute_groups};
- VerifyAttributeGroupIterator(cfhs_order_0_1_2_3, expected_keys,
- expected_attribute_groups);
- }
- Slice lb = Slice("key_2");
- Slice ub = Slice("key_4");
- // Test for lower bound only
- {
- std::vector<Slice> expected_keys = {key_2, key_3, key_4};
- std::vector<IteratorAttributeGroups> expected_attribute_groups{
- key_2_expected_attribute_groups, key_3_expected_attribute_groups,
- key_4_expected_attribute_groups};
- VerifyAttributeGroupIterator(cfhs_order_0_1_2_3, expected_keys,
- expected_attribute_groups, &lb);
- }
- // Test for upper bound only
- {
- std::vector<Slice> expected_keys = {key_1, key_2, key_3};
- std::vector<IteratorAttributeGroups> expected_attribute_groups{
- key_1_expected_attribute_groups, key_2_expected_attribute_groups,
- key_3_expected_attribute_groups};
- VerifyAttributeGroupIterator(cfhs_order_0_1_2_3, expected_keys,
- expected_attribute_groups, nullptr, &ub);
- }
- // Test for lower and upper bound
- {
- std::vector<Slice> expected_keys = {key_2, key_3};
- std::vector<IteratorAttributeGroups> expected_attribute_groups{
- key_2_expected_attribute_groups, key_3_expected_attribute_groups};
- VerifyAttributeGroupIterator(cfhs_order_0_1_2_3, expected_keys,
- expected_attribute_groups, &lb, &ub);
- }
- }
- TEST_F(AttributeGroupIteratorTest, AllowUnpreparedValue) {
- Options options = GetDefaultOptions();
- CreateAndReopenWithCF({"cf_1", "cf_2", "cf_3"}, options);
- constexpr char key_1[] = "key_1";
- WideColumns key_1_columns_in_cf_2{
- {kDefaultWideColumnName, "cf_2_col_val_0_key_1"},
- {"cf_2_col_name_1", "cf_2_col_val_1_key_1"},
- {"cf_2_col_name_2", "cf_2_col_val_2_key_1"}};
- WideColumns key_1_columns_in_cf_3{
- {"cf_3_col_name_1", "cf_3_col_val_1_key_1"},
- {"cf_3_col_name_2", "cf_3_col_val_2_key_1"},
- {"cf_3_col_name_3", "cf_3_col_val_3_key_1"}};
- constexpr char key_2[] = "key_2";
- WideColumns key_2_columns_in_cf_1{
- {"cf_1_col_name_1", "cf_1_col_val_1_key_2"}};
- WideColumns key_2_columns_in_cf_2{
- {"cf_2_col_name_1", "cf_2_col_val_1_key_2"},
- {"cf_2_col_name_2", "cf_2_col_val_2_key_2"}};
- constexpr char key_3[] = "key_3";
- WideColumns key_3_columns_in_cf_1{
- {"cf_1_col_name_1", "cf_1_col_val_1_key_3"}};
- WideColumns key_3_columns_in_cf_3{
- {"cf_3_col_name_1", "cf_3_col_val_1_key_3"}};
- constexpr char key_4[] = "key_4";
- WideColumns key_4_columns_in_cf_0{
- {"cf_0_col_name_1", "cf_0_col_val_1_key_4"}};
- WideColumns key_4_columns_in_cf_2{
- {"cf_2_col_name_1", "cf_2_col_val_1_key_4"}};
- AttributeGroups key_1_attribute_groups{
- AttributeGroup(handles_[2], key_1_columns_in_cf_2),
- AttributeGroup(handles_[3], key_1_columns_in_cf_3)};
- AttributeGroups key_2_attribute_groups{
- AttributeGroup(handles_[1], key_2_columns_in_cf_1),
- AttributeGroup(handles_[2], key_2_columns_in_cf_2)};
- AttributeGroups key_3_attribute_groups{
- AttributeGroup(handles_[1], key_3_columns_in_cf_1),
- AttributeGroup(handles_[3], key_3_columns_in_cf_3)};
- AttributeGroups key_4_attribute_groups{
- AttributeGroup(handles_[0], key_4_columns_in_cf_0),
- AttributeGroup(handles_[2], key_4_columns_in_cf_2)};
- ASSERT_OK(db_->PutEntity(WriteOptions(), key_1, key_1_attribute_groups));
- ASSERT_OK(db_->PutEntity(WriteOptions(), key_2, key_2_attribute_groups));
- ASSERT_OK(db_->PutEntity(WriteOptions(), key_3, key_3_attribute_groups));
- ASSERT_OK(db_->PutEntity(WriteOptions(), key_4, key_4_attribute_groups));
- IteratorAttributeGroups key_1_expected_attribute_groups{
- IteratorAttributeGroup(key_1_attribute_groups[0]),
- IteratorAttributeGroup(key_1_attribute_groups[1])};
- IteratorAttributeGroups key_2_expected_attribute_groups{
- IteratorAttributeGroup(key_2_attribute_groups[0]),
- IteratorAttributeGroup(key_2_attribute_groups[1])};
- IteratorAttributeGroups key_3_expected_attribute_groups{
- IteratorAttributeGroup(key_3_attribute_groups[0]),
- IteratorAttributeGroup(key_3_attribute_groups[1])};
- IteratorAttributeGroups key_4_expected_attribute_groups{
- IteratorAttributeGroup(key_4_attribute_groups[0]),
- IteratorAttributeGroup(key_4_attribute_groups[1])};
- std::vector<ColumnFamilyHandle*> cfhs_order_0_1_2_3{handles_[0], handles_[1],
- handles_[2], handles_[3]};
- std::vector<Slice> expected_keys{key_1, key_2, key_3, key_4};
- std::vector<IteratorAttributeGroups> expected_attribute_groups{
- key_1_expected_attribute_groups, key_2_expected_attribute_groups,
- key_3_expected_attribute_groups, key_4_expected_attribute_groups};
- VerifyAttributeGroupIterator(
- cfhs_order_0_1_2_3, expected_keys, expected_attribute_groups,
- /* lower_bound */ nullptr, /* upper_bound */ nullptr,
- /* allow_unprepared_value */ true);
- }
- } // namespace ROCKSDB_NAMESPACE
- int main(int argc, char** argv) {
- ROCKSDB_NAMESPACE::port::InstallStackTraceHandler();
- ::testing::InitGoogleTest(&argc, argv);
- return RUN_ALL_TESTS();
- }
|