Repository: nifi-minifi-cpp Updated Branches: refs/heads/master 49ed50945 -> d3a13a497
http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/d3a13a49/thirdparty/rocksdb/utilities/ttl/ttl_test.cc ---------------------------------------------------------------------- diff --git a/thirdparty/rocksdb/utilities/ttl/ttl_test.cc b/thirdparty/rocksdb/utilities/ttl/ttl_test.cc deleted file mode 100644 index 586d0ce..0000000 --- a/thirdparty/rocksdb/utilities/ttl/ttl_test.cc +++ /dev/null @@ -1,645 +0,0 @@ -// Copyright (c) 2011 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. - -#ifndef ROCKSDB_LITE - -#include <map> -#include <memory> -#include "rocksdb/compaction_filter.h" -#include "rocksdb/utilities/db_ttl.h" -#include "util/string_util.h" -#include "util/testharness.h" -#ifndef OS_WIN -#include <unistd.h> -#endif - -namespace rocksdb { - -namespace { - -typedef std::map<std::string, std::string> KVMap; - -enum BatchOperation { OP_PUT = 0, OP_DELETE = 1 }; -} - -class SpecialTimeEnv : public EnvWrapper { - public: - explicit SpecialTimeEnv(Env* base) : EnvWrapper(base) { - base->GetCurrentTime(¤t_time_); - } - - void Sleep(int64_t sleep_time) { current_time_ += sleep_time; } - virtual Status GetCurrentTime(int64_t* current_time) override { - *current_time = current_time_; - return Status::OK(); - } - - private: - int64_t current_time_ = 0; -}; - -class TtlTest : public testing::Test { - public: - TtlTest() { - env_.reset(new SpecialTimeEnv(Env::Default())); - dbname_ = test::TmpDir() + "/db_ttl"; - options_.create_if_missing = true; - options_.env = env_.get(); - // ensure that compaction is kicked in to always strip timestamp from kvs - options_.max_compaction_bytes = 1; - // compaction should take place always from level0 for determinism - db_ttl_ = nullptr; - DestroyDB(dbname_, Options()); - } - - ~TtlTest() { - CloseTtl(); - DestroyDB(dbname_, Options()); - } - - // Open database with TTL support when TTL not provided with db_ttl_ pointer - void OpenTtl() { - ASSERT_TRUE(db_ttl_ == - nullptr); // db should be closed before opening again - ASSERT_OK(DBWithTTL::Open(options_, dbname_, &db_ttl_)); - } - - // Open database with TTL support when TTL provided with db_ttl_ pointer - void OpenTtl(int32_t ttl) { - ASSERT_TRUE(db_ttl_ == nullptr); - ASSERT_OK(DBWithTTL::Open(options_, dbname_, &db_ttl_, ttl)); - } - - // Open with TestFilter compaction filter - void OpenTtlWithTestCompaction(int32_t ttl) { - options_.compaction_filter_factory = - std::shared_ptr<CompactionFilterFactory>( - new TestFilterFactory(kSampleSize_, kNewValue_)); - OpenTtl(ttl); - } - - // Open database with TTL support in read_only mode - void OpenReadOnlyTtl(int32_t ttl) { - ASSERT_TRUE(db_ttl_ == nullptr); - ASSERT_OK(DBWithTTL::Open(options_, dbname_, &db_ttl_, ttl, true)); - } - - void CloseTtl() { - delete db_ttl_; - db_ttl_ = nullptr; - } - - // Populates and returns a kv-map - void MakeKVMap(int64_t num_entries) { - kvmap_.clear(); - int digits = 1; - for (int64_t dummy = num_entries; dummy /= 10; ++digits) { - } - int digits_in_i = 1; - for (int64_t i = 0; i < num_entries; i++) { - std::string key = "key"; - std::string value = "value"; - if (i % 10 == 0) { - digits_in_i++; - } - for(int j = digits_in_i; j < digits; j++) { - key.append("0"); - value.append("0"); - } - AppendNumberTo(&key, i); - AppendNumberTo(&value, i); - kvmap_[key] = value; - } - ASSERT_EQ(static_cast<int64_t>(kvmap_.size()), - num_entries); // check all insertions done - } - - // Makes a write-batch with key-vals from kvmap_ and 'Write''s it - void MakePutWriteBatch(const BatchOperation* batch_ops, int64_t num_ops) { - ASSERT_LE(num_ops, static_cast<int64_t>(kvmap_.size())); - static WriteOptions wopts; - static FlushOptions flush_opts; - WriteBatch batch; - kv_it_ = kvmap_.begin(); - for (int64_t i = 0; i < num_ops && kv_it_ != kvmap_.end(); i++, ++kv_it_) { - switch (batch_ops[i]) { - case OP_PUT: - batch.Put(kv_it_->first, kv_it_->second); - break; - case OP_DELETE: - batch.Delete(kv_it_->first); - break; - default: - FAIL(); - } - } - db_ttl_->Write(wopts, &batch); - db_ttl_->Flush(flush_opts); - } - - // Puts num_entries starting from start_pos_map from kvmap_ into the database - void PutValues(int64_t start_pos_map, int64_t num_entries, bool flush = true, - ColumnFamilyHandle* cf = nullptr) { - ASSERT_TRUE(db_ttl_); - ASSERT_LE(start_pos_map + num_entries, static_cast<int64_t>(kvmap_.size())); - static WriteOptions wopts; - static FlushOptions flush_opts; - kv_it_ = kvmap_.begin(); - advance(kv_it_, start_pos_map); - for (int64_t i = 0; kv_it_ != kvmap_.end() && i < num_entries; - i++, ++kv_it_) { - ASSERT_OK(cf == nullptr - ? db_ttl_->Put(wopts, kv_it_->first, kv_it_->second) - : db_ttl_->Put(wopts, cf, kv_it_->first, kv_it_->second)); - } - // Put a mock kv at the end because CompactionFilter doesn't delete last key - ASSERT_OK(cf == nullptr ? db_ttl_->Put(wopts, "keymock", "valuemock") - : db_ttl_->Put(wopts, cf, "keymock", "valuemock")); - if (flush) { - if (cf == nullptr) { - db_ttl_->Flush(flush_opts); - } else { - db_ttl_->Flush(flush_opts, cf); - } - } - } - - // Runs a manual compaction - void ManualCompact(ColumnFamilyHandle* cf = nullptr) { - if (cf == nullptr) { - db_ttl_->CompactRange(CompactRangeOptions(), nullptr, nullptr); - } else { - db_ttl_->CompactRange(CompactRangeOptions(), cf, nullptr, nullptr); - } - } - - // checks the whole kvmap_ to return correct values using KeyMayExist - void SimpleKeyMayExistCheck() { - static ReadOptions ropts; - bool value_found; - std::string val; - for(auto &kv : kvmap_) { - bool ret = db_ttl_->KeyMayExist(ropts, kv.first, &val, &value_found); - if (ret == false || value_found == false) { - fprintf(stderr, "KeyMayExist could not find key=%s in the database but" - " should have\n", kv.first.c_str()); - FAIL(); - } else if (val.compare(kv.second) != 0) { - fprintf(stderr, " value for key=%s present in database is %s but" - " should be %s\n", kv.first.c_str(), val.c_str(), - kv.second.c_str()); - FAIL(); - } - } - } - - // checks the whole kvmap_ to return correct values using MultiGet - void SimpleMultiGetTest() { - static ReadOptions ropts; - std::vector<Slice> keys; - std::vector<std::string> values; - - for (auto& kv : kvmap_) { - keys.emplace_back(kv.first); - } - - auto statuses = db_ttl_->MultiGet(ropts, keys, &values); - size_t i = 0; - for (auto& kv : kvmap_) { - ASSERT_OK(statuses[i]); - ASSERT_EQ(values[i], kv.second); - ++i; - } - } - - // Sleeps for slp_tim then runs a manual compaction - // Checks span starting from st_pos from kvmap_ in the db and - // Gets should return true if check is true and false otherwise - // Also checks that value that we got is the same as inserted; and =kNewValue - // if test_compaction_change is true - void SleepCompactCheck(int slp_tim, int64_t st_pos, int64_t span, - bool check = true, bool test_compaction_change = false, - ColumnFamilyHandle* cf = nullptr) { - ASSERT_TRUE(db_ttl_); - - env_->Sleep(slp_tim); - ManualCompact(cf); - static ReadOptions ropts; - kv_it_ = kvmap_.begin(); - advance(kv_it_, st_pos); - std::string v; - for (int64_t i = 0; kv_it_ != kvmap_.end() && i < span; i++, ++kv_it_) { - Status s = (cf == nullptr) ? db_ttl_->Get(ropts, kv_it_->first, &v) - : db_ttl_->Get(ropts, cf, kv_it_->first, &v); - if (s.ok() != check) { - fprintf(stderr, "key=%s ", kv_it_->first.c_str()); - if (!s.ok()) { - fprintf(stderr, "is absent from db but was expected to be present\n"); - } else { - fprintf(stderr, "is present in db but was expected to be absent\n"); - } - FAIL(); - } else if (s.ok()) { - if (test_compaction_change && v.compare(kNewValue_) != 0) { - fprintf(stderr, " value for key=%s present in database is %s but " - " should be %s\n", kv_it_->first.c_str(), v.c_str(), - kNewValue_.c_str()); - FAIL(); - } else if (!test_compaction_change && v.compare(kv_it_->second) !=0) { - fprintf(stderr, " value for key=%s present in database is %s but " - " should be %s\n", kv_it_->first.c_str(), v.c_str(), - kv_it_->second.c_str()); - FAIL(); - } - } - } - } - - // Similar as SleepCompactCheck but uses TtlIterator to read from db - void SleepCompactCheckIter(int slp, int st_pos, int64_t span, - bool check = true) { - ASSERT_TRUE(db_ttl_); - env_->Sleep(slp); - ManualCompact(); - static ReadOptions ropts; - Iterator *dbiter = db_ttl_->NewIterator(ropts); - kv_it_ = kvmap_.begin(); - advance(kv_it_, st_pos); - - dbiter->Seek(kv_it_->first); - if (!check) { - if (dbiter->Valid()) { - ASSERT_NE(dbiter->value().compare(kv_it_->second), 0); - } - } else { // dbiter should have found out kvmap_[st_pos] - for (int64_t i = st_pos; kv_it_ != kvmap_.end() && i < st_pos + span; - i++, ++kv_it_) { - ASSERT_TRUE(dbiter->Valid()); - ASSERT_EQ(dbiter->value().compare(kv_it_->second), 0); - dbiter->Next(); - } - } - delete dbiter; - } - - class TestFilter : public CompactionFilter { - public: - TestFilter(const int64_t kSampleSize, const std::string& kNewValue) - : kSampleSize_(kSampleSize), - kNewValue_(kNewValue) { - } - - // Works on keys of the form "key<number>" - // Drops key if number at the end of key is in [0, kSampleSize_/3), - // Keeps key if it is in [kSampleSize_/3, 2*kSampleSize_/3), - // Change value if it is in [2*kSampleSize_/3, kSampleSize_) - // Eg. kSampleSize_=6. Drop:key0-1...Keep:key2-3...Change:key4-5... - virtual bool Filter(int level, const Slice& key, - const Slice& value, std::string* new_value, - bool* value_changed) const override { - assert(new_value != nullptr); - - std::string search_str = "0123456789"; - std::string key_string = key.ToString(); - size_t pos = key_string.find_first_of(search_str); - int num_key_end; - if (pos != std::string::npos) { - auto key_substr = key_string.substr(pos, key.size() - pos); -#ifndef CYGWIN - num_key_end = std::stoi(key_substr); -#else - num_key_end = std::strtol(key_substr.c_str(), 0, 10); -#endif - - } else { - return false; // Keep keys not matching the format "key<NUMBER>" - } - - int64_t partition = kSampleSize_ / 3; - if (num_key_end < partition) { - return true; - } else if (num_key_end < partition * 2) { - return false; - } else { - *new_value = kNewValue_; - *value_changed = true; - return false; - } - } - - virtual const char* Name() const override { - return "TestFilter"; - } - - private: - const int64_t kSampleSize_; - const std::string kNewValue_; - }; - - class TestFilterFactory : public CompactionFilterFactory { - public: - TestFilterFactory(const int64_t kSampleSize, const std::string& kNewValue) - : kSampleSize_(kSampleSize), - kNewValue_(kNewValue) { - } - - virtual std::unique_ptr<CompactionFilter> CreateCompactionFilter( - const CompactionFilter::Context& context) override { - return std::unique_ptr<CompactionFilter>( - new TestFilter(kSampleSize_, kNewValue_)); - } - - virtual const char* Name() const override { - return "TestFilterFactory"; - } - - private: - const int64_t kSampleSize_; - const std::string kNewValue_; - }; - - - // Choose carefully so that Put, Gets & Compaction complete in 1 second buffer - static const int64_t kSampleSize_ = 100; - std::string dbname_; - DBWithTTL* db_ttl_; - unique_ptr<SpecialTimeEnv> env_; - - private: - Options options_; - KVMap kvmap_; - KVMap::iterator kv_it_; - const std::string kNewValue_ = "new_value"; - unique_ptr<CompactionFilter> test_comp_filter_; -}; // class TtlTest - -// If TTL is non positive or not provided, the behaviour is TTL = infinity -// This test opens the db 3 times with such default behavior and inserts a -// bunch of kvs each time. All kvs should accumulate in the db till the end -// Partitions the sample-size provided into 3 sets over boundary1 and boundary2 -TEST_F(TtlTest, NoEffect) { - MakeKVMap(kSampleSize_); - int64_t boundary1 = kSampleSize_ / 3; - int64_t boundary2 = 2 * boundary1; - - OpenTtl(); - PutValues(0, boundary1); //T=0: Set1 never deleted - SleepCompactCheck(1, 0, boundary1); //T=1: Set1 still there - CloseTtl(); - - OpenTtl(0); - PutValues(boundary1, boundary2 - boundary1); //T=1: Set2 never deleted - SleepCompactCheck(1, 0, boundary2); //T=2: Sets1 & 2 still there - CloseTtl(); - - OpenTtl(-1); - PutValues(boundary2, kSampleSize_ - boundary2); //T=3: Set3 never deleted - SleepCompactCheck(1, 0, kSampleSize_, true); //T=4: Sets 1,2,3 still there - CloseTtl(); -} - -// Puts a set of values and checks its presence using Get during ttl -TEST_F(TtlTest, PresentDuringTTL) { - MakeKVMap(kSampleSize_); - - OpenTtl(2); // T=0:Open the db with ttl = 2 - PutValues(0, kSampleSize_); // T=0:Insert Set1. Delete at t=2 - SleepCompactCheck(1, 0, kSampleSize_, true); // T=1:Set1 should still be there - CloseTtl(); -} - -// Puts a set of values and checks its absence using Get after ttl -TEST_F(TtlTest, AbsentAfterTTL) { - MakeKVMap(kSampleSize_); - - OpenTtl(1); // T=0:Open the db with ttl = 2 - PutValues(0, kSampleSize_); // T=0:Insert Set1. Delete at t=2 - SleepCompactCheck(2, 0, kSampleSize_, false); // T=2:Set1 should not be there - CloseTtl(); -} - -// Resets the timestamp of a set of kvs by updating them and checks that they -// are not deleted according to the old timestamp -TEST_F(TtlTest, ResetTimestamp) { - MakeKVMap(kSampleSize_); - - OpenTtl(3); - PutValues(0, kSampleSize_); // T=0: Insert Set1. Delete at t=3 - env_->Sleep(2); // T=2 - PutValues(0, kSampleSize_); // T=2: Insert Set1. Delete at t=5 - SleepCompactCheck(2, 0, kSampleSize_); // T=4: Set1 should still be there - CloseTtl(); -} - -// Similar to PresentDuringTTL but uses Iterator -TEST_F(TtlTest, IterPresentDuringTTL) { - MakeKVMap(kSampleSize_); - - OpenTtl(2); - PutValues(0, kSampleSize_); // T=0: Insert. Delete at t=2 - SleepCompactCheckIter(1, 0, kSampleSize_); // T=1: Set should be there - CloseTtl(); -} - -// Similar to AbsentAfterTTL but uses Iterator -TEST_F(TtlTest, IterAbsentAfterTTL) { - MakeKVMap(kSampleSize_); - - OpenTtl(1); - PutValues(0, kSampleSize_); // T=0: Insert. Delete at t=1 - SleepCompactCheckIter(2, 0, kSampleSize_, false); // T=2: Should not be there - CloseTtl(); -} - -// Checks presence while opening the same db more than once with the same ttl -// Note: The second open will open the same db -TEST_F(TtlTest, MultiOpenSamePresent) { - MakeKVMap(kSampleSize_); - - OpenTtl(2); - PutValues(0, kSampleSize_); // T=0: Insert. Delete at t=2 - CloseTtl(); - - OpenTtl(2); // T=0. Delete at t=2 - SleepCompactCheck(1, 0, kSampleSize_); // T=1: Set should be there - CloseTtl(); -} - -// Checks absence while opening the same db more than once with the same ttl -// Note: The second open will open the same db -TEST_F(TtlTest, MultiOpenSameAbsent) { - MakeKVMap(kSampleSize_); - - OpenTtl(1); - PutValues(0, kSampleSize_); // T=0: Insert. Delete at t=1 - CloseTtl(); - - OpenTtl(1); // T=0.Delete at t=1 - SleepCompactCheck(2, 0, kSampleSize_, false); // T=2: Set should not be there - CloseTtl(); -} - -// Checks presence while opening the same db more than once with bigger ttl -TEST_F(TtlTest, MultiOpenDifferent) { - MakeKVMap(kSampleSize_); - - OpenTtl(1); - PutValues(0, kSampleSize_); // T=0: Insert. Delete at t=1 - CloseTtl(); - - OpenTtl(3); // T=0: Set deleted at t=3 - SleepCompactCheck(2, 0, kSampleSize_); // T=2: Set should be there - CloseTtl(); -} - -// Checks presence during ttl in read_only mode -TEST_F(TtlTest, ReadOnlyPresentForever) { - MakeKVMap(kSampleSize_); - - OpenTtl(1); // T=0:Open the db normally - PutValues(0, kSampleSize_); // T=0:Insert Set1. Delete at t=1 - CloseTtl(); - - OpenReadOnlyTtl(1); - SleepCompactCheck(2, 0, kSampleSize_); // T=2:Set1 should still be there - CloseTtl(); -} - -// Checks whether WriteBatch works well with TTL -// Puts all kvs in kvmap_ in a batch and writes first, then deletes first half -TEST_F(TtlTest, WriteBatchTest) { - MakeKVMap(kSampleSize_); - BatchOperation batch_ops[kSampleSize_]; - for (int i = 0; i < kSampleSize_; i++) { - batch_ops[i] = OP_PUT; - } - - OpenTtl(2); - MakePutWriteBatch(batch_ops, kSampleSize_); - for (int i = 0; i < kSampleSize_ / 2; i++) { - batch_ops[i] = OP_DELETE; - } - MakePutWriteBatch(batch_ops, kSampleSize_ / 2); - SleepCompactCheck(0, 0, kSampleSize_ / 2, false); - SleepCompactCheck(0, kSampleSize_ / 2, kSampleSize_ - kSampleSize_ / 2); - CloseTtl(); -} - -// Checks user's compaction filter for correctness with TTL logic -TEST_F(TtlTest, CompactionFilter) { - MakeKVMap(kSampleSize_); - - OpenTtlWithTestCompaction(1); - PutValues(0, kSampleSize_); // T=0:Insert Set1. Delete at t=1 - // T=2: TTL logic takes precedence over TestFilter:-Set1 should not be there - SleepCompactCheck(2, 0, kSampleSize_, false); - CloseTtl(); - - OpenTtlWithTestCompaction(3); - PutValues(0, kSampleSize_); // T=0:Insert Set1. - int64_t partition = kSampleSize_ / 3; - SleepCompactCheck(1, 0, partition, false); // Part dropped - SleepCompactCheck(0, partition, partition); // Part kept - SleepCompactCheck(0, 2 * partition, partition, true, true); // Part changed - CloseTtl(); -} - -// Insert some key-values which KeyMayExist should be able to get and check that -// values returned are fine -TEST_F(TtlTest, KeyMayExist) { - MakeKVMap(kSampleSize_); - - OpenTtl(); - PutValues(0, kSampleSize_, false); - - SimpleKeyMayExistCheck(); - - CloseTtl(); -} - -TEST_F(TtlTest, MultiGetTest) { - MakeKVMap(kSampleSize_); - - OpenTtl(); - PutValues(0, kSampleSize_, false); - - SimpleMultiGetTest(); - - CloseTtl(); -} - -TEST_F(TtlTest, ColumnFamiliesTest) { - DB* db; - Options options; - options.create_if_missing = true; - options.env = env_.get(); - - DB::Open(options, dbname_, &db); - ColumnFamilyHandle* handle; - ASSERT_OK(db->CreateColumnFamily(ColumnFamilyOptions(options), - "ttl_column_family", &handle)); - - delete handle; - delete db; - - std::vector<ColumnFamilyDescriptor> column_families; - column_families.push_back(ColumnFamilyDescriptor( - kDefaultColumnFamilyName, ColumnFamilyOptions(options))); - column_families.push_back(ColumnFamilyDescriptor( - "ttl_column_family", ColumnFamilyOptions(options))); - - std::vector<ColumnFamilyHandle*> handles; - - ASSERT_OK(DBWithTTL::Open(DBOptions(options), dbname_, column_families, - &handles, &db_ttl_, {3, 5}, false)); - ASSERT_EQ(handles.size(), 2U); - ColumnFamilyHandle* new_handle; - ASSERT_OK(db_ttl_->CreateColumnFamilyWithTtl(options, "ttl_column_family_2", - &new_handle, 2)); - handles.push_back(new_handle); - - MakeKVMap(kSampleSize_); - PutValues(0, kSampleSize_, false, handles[0]); - PutValues(0, kSampleSize_, false, handles[1]); - PutValues(0, kSampleSize_, false, handles[2]); - - // everything should be there after 1 second - SleepCompactCheck(1, 0, kSampleSize_, true, false, handles[0]); - SleepCompactCheck(0, 0, kSampleSize_, true, false, handles[1]); - SleepCompactCheck(0, 0, kSampleSize_, true, false, handles[2]); - - // only column family 1 should be alive after 4 seconds - SleepCompactCheck(3, 0, kSampleSize_, false, false, handles[0]); - SleepCompactCheck(0, 0, kSampleSize_, true, false, handles[1]); - SleepCompactCheck(0, 0, kSampleSize_, false, false, handles[2]); - - // nothing should be there after 6 seconds - SleepCompactCheck(2, 0, kSampleSize_, false, false, handles[0]); - SleepCompactCheck(0, 0, kSampleSize_, false, false, handles[1]); - SleepCompactCheck(0, 0, kSampleSize_, false, false, handles[2]); - - for (auto h : handles) { - delete h; - } - delete db_ttl_; - db_ttl_ = nullptr; -} - -} // namespace rocksdb - -// A black-box test for the ttl wrapper around rocksdb -int main(int argc, char** argv) { - ::testing::InitGoogleTest(&argc, argv); - return RUN_ALL_TESTS(); -} - -#else -#include <stdio.h> - -int main(int argc, char** argv) { - fprintf(stderr, "SKIPPED as DBWithTTL is not supported in ROCKSDB_LITE\n"); - return 0; -} - -#endif // !ROCKSDB_LITE http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/d3a13a49/thirdparty/rocksdb/utilities/util_merge_operators_test.cc ---------------------------------------------------------------------- diff --git a/thirdparty/rocksdb/utilities/util_merge_operators_test.cc b/thirdparty/rocksdb/utilities/util_merge_operators_test.cc deleted file mode 100644 index d8b3cfb..0000000 --- a/thirdparty/rocksdb/utilities/util_merge_operators_test.cc +++ /dev/null @@ -1,99 +0,0 @@ -// Copyright (c) 2011-present, Facebook, Inc. All rights reserved. -// 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 "util/testharness.h" -#include "util/testutil.h" -#include "utilities/merge_operators.h" - -namespace rocksdb { - -class UtilMergeOperatorTest : public testing::Test { - public: - UtilMergeOperatorTest() {} - - std::string FullMergeV2(std::string existing_value, - std::vector<std::string> operands, - std::string key = "") { - std::string result; - Slice result_operand(nullptr, 0); - - Slice existing_value_slice(existing_value); - std::vector<Slice> operands_slice(operands.begin(), operands.end()); - - const MergeOperator::MergeOperationInput merge_in( - key, &existing_value_slice, operands_slice, nullptr); - MergeOperator::MergeOperationOutput merge_out(result, result_operand); - merge_operator_->FullMergeV2(merge_in, &merge_out); - - if (result_operand.data()) { - result.assign(result_operand.data(), result_operand.size()); - } - return result; - } - - std::string FullMergeV2(std::vector<std::string> operands, - std::string key = "") { - std::string result; - Slice result_operand(nullptr, 0); - - std::vector<Slice> operands_slice(operands.begin(), operands.end()); - - const MergeOperator::MergeOperationInput merge_in(key, nullptr, - operands_slice, nullptr); - MergeOperator::MergeOperationOutput merge_out(result, result_operand); - merge_operator_->FullMergeV2(merge_in, &merge_out); - - if (result_operand.data()) { - result.assign(result_operand.data(), result_operand.size()); - } - return result; - } - - std::string PartialMerge(std::string left, std::string right, - std::string key = "") { - std::string result; - - merge_operator_->PartialMerge(key, left, right, &result, nullptr); - return result; - } - - std::string PartialMergeMulti(std::deque<std::string> operands, - std::string key = "") { - std::string result; - std::deque<Slice> operands_slice(operands.begin(), operands.end()); - - merge_operator_->PartialMergeMulti(key, operands_slice, &result, nullptr); - return result; - } - - protected: - std::shared_ptr<MergeOperator> merge_operator_; -}; - -TEST_F(UtilMergeOperatorTest, MaxMergeOperator) { - merge_operator_ = MergeOperators::CreateMaxOperator(); - - EXPECT_EQ("B", FullMergeV2("B", {"A"})); - EXPECT_EQ("B", FullMergeV2("A", {"B"})); - EXPECT_EQ("", FullMergeV2({"", "", ""})); - EXPECT_EQ("A", FullMergeV2({"A"})); - EXPECT_EQ("ABC", FullMergeV2({"ABC"})); - EXPECT_EQ("Z", FullMergeV2({"ABC", "Z", "C", "AXX"})); - EXPECT_EQ("ZZZ", FullMergeV2({"ABC", "CC", "Z", "ZZZ"})); - EXPECT_EQ("a", FullMergeV2("a", {"ABC", "CC", "Z", "ZZZ"})); - - EXPECT_EQ("z", PartialMergeMulti({"a", "z", "efqfqwgwew", "aaz", "hhhhh"})); - - EXPECT_EQ("b", PartialMerge("a", "b")); - EXPECT_EQ("z", PartialMerge("z", "azzz")); - EXPECT_EQ("a", PartialMerge("a", "")); -} - -} // namespace rocksdb - -int main(int argc, char** argv) { - ::testing::InitGoogleTest(&argc, argv); - return RUN_ALL_TESTS(); -} http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/d3a13a49/thirdparty/rocksdb/utilities/write_batch_with_index/write_batch_with_index_test.cc ---------------------------------------------------------------------- diff --git a/thirdparty/rocksdb/utilities/write_batch_with_index/write_batch_with_index_test.cc b/thirdparty/rocksdb/utilities/write_batch_with_index/write_batch_with_index_test.cc deleted file mode 100644 index 5b1250a..0000000 --- a/thirdparty/rocksdb/utilities/write_batch_with_index/write_batch_with_index_test.cc +++ /dev/null @@ -1,1805 +0,0 @@ -// Copyright (c) 2011-present, Facebook, Inc. All rights reserved. -// 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). -// -// Copyright (c) 2011 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. - -#ifndef ROCKSDB_LITE - -#include <memory> -#include <map> -#include "db/column_family.h" -#include "port/stack_trace.h" -#include "rocksdb/utilities/write_batch_with_index.h" -#include "util/random.h" -#include "util/string_util.h" -#include "util/testharness.h" -#include "utilities/merge_operators.h" -#include "utilities/merge_operators/string_append/stringappend.h" - -namespace rocksdb { - -namespace { -class ColumnFamilyHandleImplDummy : public ColumnFamilyHandleImpl { - public: - explicit ColumnFamilyHandleImplDummy(int id, const Comparator* comparator) - : ColumnFamilyHandleImpl(nullptr, nullptr, nullptr), - id_(id), - comparator_(comparator) {} - uint32_t GetID() const override { return id_; } - const Comparator* GetComparator() const override { return comparator_; } - - private: - uint32_t id_; - const Comparator* comparator_; -}; - -struct Entry { - std::string key; - std::string value; - WriteType type; -}; - -struct TestHandler : public WriteBatch::Handler { - std::map<uint32_t, std::vector<Entry>> seen; - virtual Status PutCF(uint32_t column_family_id, const Slice& key, - const Slice& value) { - Entry e; - e.key = key.ToString(); - e.value = value.ToString(); - e.type = kPutRecord; - seen[column_family_id].push_back(e); - return Status::OK(); - } - virtual Status MergeCF(uint32_t column_family_id, const Slice& key, - const Slice& value) { - Entry e; - e.key = key.ToString(); - e.value = value.ToString(); - e.type = kMergeRecord; - seen[column_family_id].push_back(e); - return Status::OK(); - } - virtual void LogData(const Slice& blob) {} - virtual Status DeleteCF(uint32_t column_family_id, const Slice& key) { - Entry e; - e.key = key.ToString(); - e.value = ""; - e.type = kDeleteRecord; - seen[column_family_id].push_back(e); - return Status::OK(); - } -}; -} // namespace anonymous - -class WriteBatchWithIndexTest : public testing::Test {}; - -void TestValueAsSecondaryIndexHelper(std::vector<Entry> entries, - WriteBatchWithIndex* batch) { - // In this test, we insert <key, value> to column family `data`, and - // <value, key> to column family `index`. Then iterator them in order - // and seek them by key. - - // Sort entries by key - std::map<std::string, std::vector<Entry*>> data_map; - // Sort entries by value - std::map<std::string, std::vector<Entry*>> index_map; - for (auto& e : entries) { - data_map[e.key].push_back(&e); - index_map[e.value].push_back(&e); - } - - ColumnFamilyHandleImplDummy data(6, BytewiseComparator()); - ColumnFamilyHandleImplDummy index(8, BytewiseComparator()); - for (auto& e : entries) { - if (e.type == kPutRecord) { - batch->Put(&data, e.key, e.value); - batch->Put(&index, e.value, e.key); - } else if (e.type == kMergeRecord) { - batch->Merge(&data, e.key, e.value); - batch->Put(&index, e.value, e.key); - } else { - assert(e.type == kDeleteRecord); - std::unique_ptr<WBWIIterator> iter(batch->NewIterator(&data)); - iter->Seek(e.key); - ASSERT_OK(iter->status()); - auto write_entry = iter->Entry(); - ASSERT_EQ(e.key, write_entry.key.ToString()); - ASSERT_EQ(e.value, write_entry.value.ToString()); - batch->Delete(&data, e.key); - batch->Put(&index, e.value, ""); - } - } - - // Iterator all keys - { - std::unique_ptr<WBWIIterator> iter(batch->NewIterator(&data)); - for (int seek_to_first : {0, 1}) { - if (seek_to_first) { - iter->SeekToFirst(); - } else { - iter->Seek(""); - } - for (auto pair : data_map) { - for (auto v : pair.second) { - ASSERT_OK(iter->status()); - ASSERT_TRUE(iter->Valid()); - auto write_entry = iter->Entry(); - ASSERT_EQ(pair.first, write_entry.key.ToString()); - ASSERT_EQ(v->type, write_entry.type); - if (write_entry.type != kDeleteRecord) { - ASSERT_EQ(v->value, write_entry.value.ToString()); - } - iter->Next(); - } - } - ASSERT_TRUE(!iter->Valid()); - } - iter->SeekToLast(); - for (auto pair = data_map.rbegin(); pair != data_map.rend(); ++pair) { - for (auto v = pair->second.rbegin(); v != pair->second.rend(); v++) { - ASSERT_OK(iter->status()); - ASSERT_TRUE(iter->Valid()); - auto write_entry = iter->Entry(); - ASSERT_EQ(pair->first, write_entry.key.ToString()); - ASSERT_EQ((*v)->type, write_entry.type); - if (write_entry.type != kDeleteRecord) { - ASSERT_EQ((*v)->value, write_entry.value.ToString()); - } - iter->Prev(); - } - } - ASSERT_TRUE(!iter->Valid()); - } - - // Iterator all indexes - { - std::unique_ptr<WBWIIterator> iter(batch->NewIterator(&index)); - for (int seek_to_first : {0, 1}) { - if (seek_to_first) { - iter->SeekToFirst(); - } else { - iter->Seek(""); - } - for (auto pair : index_map) { - for (auto v : pair.second) { - ASSERT_OK(iter->status()); - ASSERT_TRUE(iter->Valid()); - auto write_entry = iter->Entry(); - ASSERT_EQ(pair.first, write_entry.key.ToString()); - if (v->type != kDeleteRecord) { - ASSERT_EQ(v->key, write_entry.value.ToString()); - ASSERT_EQ(v->value, write_entry.key.ToString()); - } - iter->Next(); - } - } - ASSERT_TRUE(!iter->Valid()); - } - - iter->SeekToLast(); - for (auto pair = index_map.rbegin(); pair != index_map.rend(); ++pair) { - for (auto v = pair->second.rbegin(); v != pair->second.rend(); v++) { - ASSERT_OK(iter->status()); - ASSERT_TRUE(iter->Valid()); - auto write_entry = iter->Entry(); - ASSERT_EQ(pair->first, write_entry.key.ToString()); - if ((*v)->type != kDeleteRecord) { - ASSERT_EQ((*v)->key, write_entry.value.ToString()); - ASSERT_EQ((*v)->value, write_entry.key.ToString()); - } - iter->Prev(); - } - } - ASSERT_TRUE(!iter->Valid()); - } - - // Seek to every key - { - std::unique_ptr<WBWIIterator> iter(batch->NewIterator(&data)); - - // Seek the keys one by one in reverse order - for (auto pair = data_map.rbegin(); pair != data_map.rend(); ++pair) { - iter->Seek(pair->first); - ASSERT_OK(iter->status()); - for (auto v : pair->second) { - ASSERT_TRUE(iter->Valid()); - auto write_entry = iter->Entry(); - ASSERT_EQ(pair->first, write_entry.key.ToString()); - ASSERT_EQ(v->type, write_entry.type); - if (write_entry.type != kDeleteRecord) { - ASSERT_EQ(v->value, write_entry.value.ToString()); - } - iter->Next(); - ASSERT_OK(iter->status()); - } - } - } - - // Seek to every index - { - std::unique_ptr<WBWIIterator> iter(batch->NewIterator(&index)); - - // Seek the keys one by one in reverse order - for (auto pair = index_map.rbegin(); pair != index_map.rend(); ++pair) { - iter->Seek(pair->first); - ASSERT_OK(iter->status()); - for (auto v : pair->second) { - ASSERT_TRUE(iter->Valid()); - auto write_entry = iter->Entry(); - ASSERT_EQ(pair->first, write_entry.key.ToString()); - ASSERT_EQ(v->value, write_entry.key.ToString()); - if (v->type != kDeleteRecord) { - ASSERT_EQ(v->key, write_entry.value.ToString()); - } - iter->Next(); - ASSERT_OK(iter->status()); - } - } - } - - // Verify WriteBatch can be iterated - TestHandler handler; - batch->GetWriteBatch()->Iterate(&handler); - - // Verify data column family - { - ASSERT_EQ(entries.size(), handler.seen[data.GetID()].size()); - size_t i = 0; - for (auto e : handler.seen[data.GetID()]) { - auto write_entry = entries[i++]; - ASSERT_EQ(e.type, write_entry.type); - ASSERT_EQ(e.key, write_entry.key); - if (e.type != kDeleteRecord) { - ASSERT_EQ(e.value, write_entry.value); - } - } - } - - // Verify index column family - { - ASSERT_EQ(entries.size(), handler.seen[index.GetID()].size()); - size_t i = 0; - for (auto e : handler.seen[index.GetID()]) { - auto write_entry = entries[i++]; - ASSERT_EQ(e.key, write_entry.value); - if (write_entry.type != kDeleteRecord) { - ASSERT_EQ(e.value, write_entry.key); - } - } - } -} - -TEST_F(WriteBatchWithIndexTest, TestValueAsSecondaryIndex) { - Entry entries[] = { - {"aaa", "0005", kPutRecord}, - {"b", "0002", kPutRecord}, - {"cdd", "0002", kMergeRecord}, - {"aab", "00001", kPutRecord}, - {"cc", "00005", kPutRecord}, - {"cdd", "0002", kPutRecord}, - {"aab", "0003", kPutRecord}, - {"cc", "00005", kDeleteRecord}, - }; - std::vector<Entry> entries_list(entries, entries + 8); - - WriteBatchWithIndex batch(nullptr, 20); - - TestValueAsSecondaryIndexHelper(entries_list, &batch); - - // Clear batch and re-run test with new values - batch.Clear(); - - Entry new_entries[] = { - {"aaa", "0005", kPutRecord}, - {"e", "0002", kPutRecord}, - {"add", "0002", kMergeRecord}, - {"aab", "00001", kPutRecord}, - {"zz", "00005", kPutRecord}, - {"add", "0002", kPutRecord}, - {"aab", "0003", kPutRecord}, - {"zz", "00005", kDeleteRecord}, - }; - - entries_list = std::vector<Entry>(new_entries, new_entries + 8); - - TestValueAsSecondaryIndexHelper(entries_list, &batch); -} - -TEST_F(WriteBatchWithIndexTest, TestComparatorForCF) { - ColumnFamilyHandleImplDummy cf1(6, nullptr); - ColumnFamilyHandleImplDummy reverse_cf(66, ReverseBytewiseComparator()); - ColumnFamilyHandleImplDummy cf2(88, BytewiseComparator()); - WriteBatchWithIndex batch(BytewiseComparator(), 20); - - batch.Put(&cf1, "ddd", ""); - batch.Put(&cf2, "aaa", ""); - batch.Put(&cf2, "eee", ""); - batch.Put(&cf1, "ccc", ""); - batch.Put(&reverse_cf, "a11", ""); - batch.Put(&cf1, "bbb", ""); - - Slice key_slices[] = {"a", "3", "3"}; - Slice value_slice = ""; - batch.Put(&reverse_cf, SliceParts(key_slices, 3), - SliceParts(&value_slice, 1)); - batch.Put(&reverse_cf, "a22", ""); - - { - std::unique_ptr<WBWIIterator> iter(batch.NewIterator(&cf1)); - iter->Seek(""); - ASSERT_OK(iter->status()); - ASSERT_TRUE(iter->Valid()); - ASSERT_EQ("bbb", iter->Entry().key.ToString()); - iter->Next(); - ASSERT_OK(iter->status()); - ASSERT_TRUE(iter->Valid()); - ASSERT_EQ("ccc", iter->Entry().key.ToString()); - iter->Next(); - ASSERT_OK(iter->status()); - ASSERT_TRUE(iter->Valid()); - ASSERT_EQ("ddd", iter->Entry().key.ToString()); - iter->Next(); - ASSERT_OK(iter->status()); - ASSERT_TRUE(!iter->Valid()); - } - - { - std::unique_ptr<WBWIIterator> iter(batch.NewIterator(&cf2)); - iter->Seek(""); - ASSERT_OK(iter->status()); - ASSERT_TRUE(iter->Valid()); - ASSERT_EQ("aaa", iter->Entry().key.ToString()); - iter->Next(); - ASSERT_OK(iter->status()); - ASSERT_TRUE(iter->Valid()); - ASSERT_EQ("eee", iter->Entry().key.ToString()); - iter->Next(); - ASSERT_OK(iter->status()); - ASSERT_TRUE(!iter->Valid()); - } - - { - std::unique_ptr<WBWIIterator> iter(batch.NewIterator(&reverse_cf)); - iter->Seek(""); - ASSERT_OK(iter->status()); - ASSERT_TRUE(!iter->Valid()); - - iter->Seek("z"); - ASSERT_OK(iter->status()); - ASSERT_TRUE(iter->Valid()); - ASSERT_EQ("a33", iter->Entry().key.ToString()); - iter->Next(); - ASSERT_OK(iter->status()); - ASSERT_TRUE(iter->Valid()); - ASSERT_EQ("a22", iter->Entry().key.ToString()); - iter->Next(); - ASSERT_OK(iter->status()); - ASSERT_TRUE(iter->Valid()); - ASSERT_EQ("a11", iter->Entry().key.ToString()); - iter->Next(); - ASSERT_OK(iter->status()); - ASSERT_TRUE(!iter->Valid()); - - iter->Seek("a22"); - ASSERT_OK(iter->status()); - ASSERT_TRUE(iter->Valid()); - ASSERT_EQ("a22", iter->Entry().key.ToString()); - - iter->Seek("a13"); - ASSERT_OK(iter->status()); - ASSERT_TRUE(iter->Valid()); - ASSERT_EQ("a11", iter->Entry().key.ToString()); - } -} - -TEST_F(WriteBatchWithIndexTest, TestOverwriteKey) { - ColumnFamilyHandleImplDummy cf1(6, nullptr); - ColumnFamilyHandleImplDummy reverse_cf(66, ReverseBytewiseComparator()); - ColumnFamilyHandleImplDummy cf2(88, BytewiseComparator()); - WriteBatchWithIndex batch(BytewiseComparator(), 20, true); - - batch.Put(&cf1, "ddd", ""); - batch.Merge(&cf1, "ddd", ""); - batch.Delete(&cf1, "ddd"); - batch.Put(&cf2, "aaa", ""); - batch.Delete(&cf2, "aaa"); - batch.Put(&cf2, "aaa", "aaa"); - batch.Put(&cf2, "eee", "eee"); - batch.Put(&cf1, "ccc", ""); - batch.Put(&reverse_cf, "a11", ""); - batch.Delete(&cf1, "ccc"); - batch.Put(&reverse_cf, "a33", "a33"); - batch.Put(&reverse_cf, "a11", "a11"); - Slice slices[] = {"a", "3", "3"}; - batch.Delete(&reverse_cf, SliceParts(slices, 3)); - - { - std::unique_ptr<WBWIIterator> iter(batch.NewIterator(&cf1)); - iter->Seek(""); - ASSERT_OK(iter->status()); - ASSERT_TRUE(iter->Valid()); - ASSERT_EQ("ccc", iter->Entry().key.ToString()); - ASSERT_TRUE(iter->Entry().type == WriteType::kDeleteRecord); - iter->Next(); - ASSERT_OK(iter->status()); - ASSERT_TRUE(iter->Valid()); - ASSERT_EQ("ddd", iter->Entry().key.ToString()); - ASSERT_TRUE(iter->Entry().type == WriteType::kDeleteRecord); - iter->Next(); - ASSERT_OK(iter->status()); - ASSERT_TRUE(!iter->Valid()); - } - - { - std::unique_ptr<WBWIIterator> iter(batch.NewIterator(&cf2)); - iter->SeekToLast(); - ASSERT_OK(iter->status()); - ASSERT_TRUE(iter->Valid()); - ASSERT_EQ("eee", iter->Entry().key.ToString()); - ASSERT_EQ("eee", iter->Entry().value.ToString()); - iter->Prev(); - ASSERT_OK(iter->status()); - ASSERT_TRUE(iter->Valid()); - ASSERT_EQ("aaa", iter->Entry().key.ToString()); - ASSERT_EQ("aaa", iter->Entry().value.ToString()); - iter->Prev(); - ASSERT_OK(iter->status()); - ASSERT_TRUE(!iter->Valid()); - - iter->SeekToFirst(); - ASSERT_OK(iter->status()); - ASSERT_TRUE(iter->Valid()); - ASSERT_EQ("aaa", iter->Entry().key.ToString()); - ASSERT_EQ("aaa", iter->Entry().value.ToString()); - iter->Next(); - ASSERT_OK(iter->status()); - ASSERT_TRUE(iter->Valid()); - ASSERT_EQ("eee", iter->Entry().key.ToString()); - ASSERT_EQ("eee", iter->Entry().value.ToString()); - iter->Next(); - ASSERT_OK(iter->status()); - ASSERT_TRUE(!iter->Valid()); - } - - { - std::unique_ptr<WBWIIterator> iter(batch.NewIterator(&reverse_cf)); - iter->Seek(""); - ASSERT_OK(iter->status()); - ASSERT_TRUE(!iter->Valid()); - - iter->Seek("z"); - ASSERT_OK(iter->status()); - ASSERT_TRUE(iter->Valid()); - ASSERT_EQ("a33", iter->Entry().key.ToString()); - ASSERT_TRUE(iter->Entry().type == WriteType::kDeleteRecord); - iter->Next(); - ASSERT_OK(iter->status()); - ASSERT_TRUE(iter->Valid()); - ASSERT_EQ("a11", iter->Entry().key.ToString()); - ASSERT_EQ("a11", iter->Entry().value.ToString()); - iter->Next(); - ASSERT_OK(iter->status()); - ASSERT_TRUE(!iter->Valid()); - - iter->SeekToLast(); - ASSERT_TRUE(iter->Valid()); - ASSERT_EQ("a11", iter->Entry().key.ToString()); - ASSERT_EQ("a11", iter->Entry().value.ToString()); - iter->Prev(); - - ASSERT_OK(iter->status()); - ASSERT_TRUE(iter->Valid()); - ASSERT_EQ("a33", iter->Entry().key.ToString()); - ASSERT_TRUE(iter->Entry().type == WriteType::kDeleteRecord); - iter->Prev(); - ASSERT_TRUE(!iter->Valid()); - } -} - -namespace { -typedef std::map<std::string, std::string> KVMap; - -class KVIter : public Iterator { - public: - explicit KVIter(const KVMap* map) : map_(map), iter_(map_->end()) {} - virtual bool Valid() const { return iter_ != map_->end(); } - virtual void SeekToFirst() { iter_ = map_->begin(); } - virtual void SeekToLast() { - if (map_->empty()) { - iter_ = map_->end(); - } else { - iter_ = map_->find(map_->rbegin()->first); - } - } - virtual void Seek(const Slice& k) { iter_ = map_->lower_bound(k.ToString()); } - virtual void SeekForPrev(const Slice& k) { - iter_ = map_->upper_bound(k.ToString()); - Prev(); - } - virtual void Next() { ++iter_; } - virtual void Prev() { - if (iter_ == map_->begin()) { - iter_ = map_->end(); - return; - } - --iter_; - } - - virtual Slice key() const { return iter_->first; } - virtual Slice value() const { return iter_->second; } - virtual Status status() const { return Status::OK(); } - - private: - const KVMap* const map_; - KVMap::const_iterator iter_; -}; - -void AssertIter(Iterator* iter, const std::string& key, - const std::string& value) { - ASSERT_OK(iter->status()); - ASSERT_TRUE(iter->Valid()); - ASSERT_EQ(key, iter->key().ToString()); - ASSERT_EQ(value, iter->value().ToString()); -} - -void AssertItersEqual(Iterator* iter1, Iterator* iter2) { - ASSERT_EQ(iter1->Valid(), iter2->Valid()); - if (iter1->Valid()) { - ASSERT_EQ(iter1->key().ToString(), iter2->key().ToString()); - ASSERT_EQ(iter1->value().ToString(), iter2->value().ToString()); - } -} -} // namespace - -TEST_F(WriteBatchWithIndexTest, TestRandomIteraratorWithBase) { - std::vector<std::string> source_strings = {"a", "b", "c", "d", "e", - "f", "g", "h", "i", "j"}; - for (int rand_seed = 301; rand_seed < 366; rand_seed++) { - Random rnd(rand_seed); - - ColumnFamilyHandleImplDummy cf1(6, BytewiseComparator()); - ColumnFamilyHandleImplDummy cf2(2, BytewiseComparator()); - ColumnFamilyHandleImplDummy cf3(8, BytewiseComparator()); - - WriteBatchWithIndex batch(BytewiseComparator(), 20, true); - - if (rand_seed % 2 == 0) { - batch.Put(&cf2, "zoo", "bar"); - } - if (rand_seed % 4 == 1) { - batch.Put(&cf3, "zoo", "bar"); - } - - KVMap map; - KVMap merged_map; - for (auto key : source_strings) { - std::string value = key + key; - int type = rnd.Uniform(6); - switch (type) { - case 0: - // only base has it - map[key] = value; - merged_map[key] = value; - break; - case 1: - // only delta has it - batch.Put(&cf1, key, value); - map[key] = value; - merged_map[key] = value; - break; - case 2: - // both has it. Delta should win - batch.Put(&cf1, key, value); - map[key] = "wrong_value"; - merged_map[key] = value; - break; - case 3: - // both has it. Delta is delete - batch.Delete(&cf1, key); - map[key] = "wrong_value"; - break; - case 4: - // only delta has it. Delta is delete - batch.Delete(&cf1, key); - map[key] = "wrong_value"; - break; - default: - // Neither iterator has it. - break; - } - } - - std::unique_ptr<Iterator> iter( - batch.NewIteratorWithBase(&cf1, new KVIter(&map))); - std::unique_ptr<Iterator> result_iter(new KVIter(&merged_map)); - - bool is_valid = false; - for (int i = 0; i < 128; i++) { - // Random walk and make sure iter and result_iter returns the - // same key and value - int type = rnd.Uniform(5); - ASSERT_OK(iter->status()); - switch (type) { - case 0: - // Seek to First - iter->SeekToFirst(); - result_iter->SeekToFirst(); - break; - case 1: - // Seek to last - iter->SeekToLast(); - result_iter->SeekToLast(); - break; - case 2: { - // Seek to random key - auto key_idx = rnd.Uniform(static_cast<int>(source_strings.size())); - auto key = source_strings[key_idx]; - iter->Seek(key); - result_iter->Seek(key); - break; - } - case 3: - // Next - if (is_valid) { - iter->Next(); - result_iter->Next(); - } else { - continue; - } - break; - default: - assert(type == 4); - // Prev - if (is_valid) { - iter->Prev(); - result_iter->Prev(); - } else { - continue; - } - break; - } - AssertItersEqual(iter.get(), result_iter.get()); - is_valid = iter->Valid(); - } - } -} - -TEST_F(WriteBatchWithIndexTest, TestIteraratorWithBase) { - ColumnFamilyHandleImplDummy cf1(6, BytewiseComparator()); - ColumnFamilyHandleImplDummy cf2(2, BytewiseComparator()); - WriteBatchWithIndex batch(BytewiseComparator(), 20, true); - - { - KVMap map; - map["a"] = "aa"; - map["c"] = "cc"; - map["e"] = "ee"; - std::unique_ptr<Iterator> iter( - batch.NewIteratorWithBase(&cf1, new KVIter(&map))); - - iter->SeekToFirst(); - AssertIter(iter.get(), "a", "aa"); - iter->Next(); - AssertIter(iter.get(), "c", "cc"); - iter->Next(); - AssertIter(iter.get(), "e", "ee"); - iter->Next(); - ASSERT_OK(iter->status()); - ASSERT_TRUE(!iter->Valid()); - - iter->SeekToLast(); - AssertIter(iter.get(), "e", "ee"); - iter->Prev(); - AssertIter(iter.get(), "c", "cc"); - iter->Prev(); - AssertIter(iter.get(), "a", "aa"); - iter->Prev(); - ASSERT_OK(iter->status()); - ASSERT_TRUE(!iter->Valid()); - - iter->Seek("b"); - AssertIter(iter.get(), "c", "cc"); - - iter->Prev(); - AssertIter(iter.get(), "a", "aa"); - - iter->Seek("a"); - AssertIter(iter.get(), "a", "aa"); - } - - // Test the case that there is one element in the write batch - batch.Put(&cf2, "zoo", "bar"); - batch.Put(&cf1, "a", "aa"); - { - KVMap empty_map; - std::unique_ptr<Iterator> iter( - batch.NewIteratorWithBase(&cf1, new KVIter(&empty_map))); - - iter->SeekToFirst(); - AssertIter(iter.get(), "a", "aa"); - iter->Next(); - ASSERT_OK(iter->status()); - ASSERT_TRUE(!iter->Valid()); - } - - batch.Delete(&cf1, "b"); - batch.Put(&cf1, "c", "cc"); - batch.Put(&cf1, "d", "dd"); - batch.Delete(&cf1, "e"); - - { - KVMap map; - map["b"] = ""; - map["cc"] = "cccc"; - map["f"] = "ff"; - std::unique_ptr<Iterator> iter( - batch.NewIteratorWithBase(&cf1, new KVIter(&map))); - - iter->SeekToFirst(); - AssertIter(iter.get(), "a", "aa"); - iter->Next(); - AssertIter(iter.get(), "c", "cc"); - iter->Next(); - AssertIter(iter.get(), "cc", "cccc"); - iter->Next(); - AssertIter(iter.get(), "d", "dd"); - iter->Next(); - AssertIter(iter.get(), "f", "ff"); - iter->Next(); - ASSERT_OK(iter->status()); - ASSERT_TRUE(!iter->Valid()); - - iter->SeekToLast(); - AssertIter(iter.get(), "f", "ff"); - iter->Prev(); - AssertIter(iter.get(), "d", "dd"); - iter->Prev(); - AssertIter(iter.get(), "cc", "cccc"); - iter->Prev(); - AssertIter(iter.get(), "c", "cc"); - iter->Next(); - AssertIter(iter.get(), "cc", "cccc"); - iter->Prev(); - AssertIter(iter.get(), "c", "cc"); - iter->Prev(); - AssertIter(iter.get(), "a", "aa"); - iter->Prev(); - ASSERT_OK(iter->status()); - ASSERT_TRUE(!iter->Valid()); - - iter->Seek("c"); - AssertIter(iter.get(), "c", "cc"); - - iter->Seek("cb"); - AssertIter(iter.get(), "cc", "cccc"); - - iter->Seek("cc"); - AssertIter(iter.get(), "cc", "cccc"); - iter->Next(); - AssertIter(iter.get(), "d", "dd"); - - iter->Seek("e"); - AssertIter(iter.get(), "f", "ff"); - - iter->Prev(); - AssertIter(iter.get(), "d", "dd"); - - iter->Next(); - AssertIter(iter.get(), "f", "ff"); - } - - { - KVMap empty_map; - std::unique_ptr<Iterator> iter( - batch.NewIteratorWithBase(&cf1, new KVIter(&empty_map))); - - iter->SeekToFirst(); - AssertIter(iter.get(), "a", "aa"); - iter->Next(); - AssertIter(iter.get(), "c", "cc"); - iter->Next(); - AssertIter(iter.get(), "d", "dd"); - iter->Next(); - ASSERT_OK(iter->status()); - ASSERT_TRUE(!iter->Valid()); - - iter->SeekToLast(); - AssertIter(iter.get(), "d", "dd"); - iter->Prev(); - AssertIter(iter.get(), "c", "cc"); - iter->Prev(); - AssertIter(iter.get(), "a", "aa"); - - iter->Prev(); - ASSERT_OK(iter->status()); - ASSERT_TRUE(!iter->Valid()); - - iter->Seek("aa"); - AssertIter(iter.get(), "c", "cc"); - iter->Next(); - AssertIter(iter.get(), "d", "dd"); - - iter->Seek("ca"); - AssertIter(iter.get(), "d", "dd"); - - iter->Prev(); - AssertIter(iter.get(), "c", "cc"); - } -} - -TEST_F(WriteBatchWithIndexTest, TestIteraratorWithBaseReverseCmp) { - ColumnFamilyHandleImplDummy cf1(6, ReverseBytewiseComparator()); - ColumnFamilyHandleImplDummy cf2(2, ReverseBytewiseComparator()); - WriteBatchWithIndex batch(BytewiseComparator(), 20, true); - - // Test the case that there is one element in the write batch - batch.Put(&cf2, "zoo", "bar"); - batch.Put(&cf1, "a", "aa"); - { - KVMap empty_map; - std::unique_ptr<Iterator> iter( - batch.NewIteratorWithBase(&cf1, new KVIter(&empty_map))); - - iter->SeekToFirst(); - AssertIter(iter.get(), "a", "aa"); - iter->Next(); - ASSERT_OK(iter->status()); - ASSERT_TRUE(!iter->Valid()); - } - - batch.Put(&cf1, "c", "cc"); - { - KVMap map; - std::unique_ptr<Iterator> iter( - batch.NewIteratorWithBase(&cf1, new KVIter(&map))); - - iter->SeekToFirst(); - AssertIter(iter.get(), "c", "cc"); - iter->Next(); - AssertIter(iter.get(), "a", "aa"); - iter->Next(); - ASSERT_OK(iter->status()); - ASSERT_TRUE(!iter->Valid()); - - iter->SeekToLast(); - AssertIter(iter.get(), "a", "aa"); - iter->Prev(); - AssertIter(iter.get(), "c", "cc"); - iter->Prev(); - ASSERT_OK(iter->status()); - ASSERT_TRUE(!iter->Valid()); - - iter->Seek("b"); - AssertIter(iter.get(), "a", "aa"); - - iter->Prev(); - AssertIter(iter.get(), "c", "cc"); - - iter->Seek("a"); - AssertIter(iter.get(), "a", "aa"); - } - - // default column family - batch.Put("a", "b"); - { - KVMap map; - map["b"] = ""; - std::unique_ptr<Iterator> iter(batch.NewIteratorWithBase(new KVIter(&map))); - - iter->SeekToFirst(); - AssertIter(iter.get(), "a", "b"); - iter->Next(); - AssertIter(iter.get(), "b", ""); - iter->Next(); - ASSERT_OK(iter->status()); - ASSERT_TRUE(!iter->Valid()); - - iter->SeekToLast(); - AssertIter(iter.get(), "b", ""); - iter->Prev(); - AssertIter(iter.get(), "a", "b"); - iter->Prev(); - ASSERT_OK(iter->status()); - ASSERT_TRUE(!iter->Valid()); - - iter->Seek("b"); - AssertIter(iter.get(), "b", ""); - - iter->Prev(); - AssertIter(iter.get(), "a", "b"); - - iter->Seek("0"); - AssertIter(iter.get(), "a", "b"); - } -} - -TEST_F(WriteBatchWithIndexTest, TestGetFromBatch) { - Options options; - WriteBatchWithIndex batch; - Status s; - std::string value; - - s = batch.GetFromBatch(options, "b", &value); - ASSERT_TRUE(s.IsNotFound()); - - batch.Put("a", "a"); - batch.Put("b", "b"); - batch.Put("c", "c"); - batch.Put("a", "z"); - batch.Delete("c"); - batch.Delete("d"); - batch.Delete("e"); - batch.Put("e", "e"); - - s = batch.GetFromBatch(options, "b", &value); - ASSERT_OK(s); - ASSERT_EQ("b", value); - - s = batch.GetFromBatch(options, "a", &value); - ASSERT_OK(s); - ASSERT_EQ("z", value); - - s = batch.GetFromBatch(options, "c", &value); - ASSERT_TRUE(s.IsNotFound()); - - s = batch.GetFromBatch(options, "d", &value); - ASSERT_TRUE(s.IsNotFound()); - - s = batch.GetFromBatch(options, "x", &value); - ASSERT_TRUE(s.IsNotFound()); - - s = batch.GetFromBatch(options, "e", &value); - ASSERT_OK(s); - ASSERT_EQ("e", value); - - batch.Merge("z", "z"); - - s = batch.GetFromBatch(options, "z", &value); - ASSERT_NOK(s); // No merge operator specified. - - s = batch.GetFromBatch(options, "b", &value); - ASSERT_OK(s); - ASSERT_EQ("b", value); -} - -TEST_F(WriteBatchWithIndexTest, TestGetFromBatchMerge) { - DB* db; - Options options; - options.merge_operator = MergeOperators::CreateFromStringId("stringappend"); - options.create_if_missing = true; - - std::string dbname = test::TmpDir() + "/write_batch_with_index_test"; - - DestroyDB(dbname, options); - Status s = DB::Open(options, dbname, &db); - ASSERT_OK(s); - - ColumnFamilyHandle* column_family = db->DefaultColumnFamily(); - WriteBatchWithIndex batch; - std::string value; - - s = batch.GetFromBatch(options, "x", &value); - ASSERT_TRUE(s.IsNotFound()); - - batch.Put("x", "X"); - std::string expected = "X"; - - for (int i = 0; i < 5; i++) { - batch.Merge("x", ToString(i)); - expected = expected + "," + ToString(i); - - if (i % 2 == 0) { - batch.Put("y", ToString(i / 2)); - } - - batch.Merge("z", "z"); - - s = batch.GetFromBatch(column_family, options, "x", &value); - ASSERT_OK(s); - ASSERT_EQ(expected, value); - - s = batch.GetFromBatch(column_family, options, "y", &value); - ASSERT_OK(s); - ASSERT_EQ(ToString(i / 2), value); - - s = batch.GetFromBatch(column_family, options, "z", &value); - ASSERT_TRUE(s.IsMergeInProgress()); - } - - delete db; - DestroyDB(dbname, options); -} - -TEST_F(WriteBatchWithIndexTest, TestGetFromBatchMerge2) { - DB* db; - Options options; - options.merge_operator = MergeOperators::CreateFromStringId("stringappend"); - options.create_if_missing = true; - - std::string dbname = test::TmpDir() + "/write_batch_with_index_test"; - - DestroyDB(dbname, options); - Status s = DB::Open(options, dbname, &db); - ASSERT_OK(s); - - ColumnFamilyHandle* column_family = db->DefaultColumnFamily(); - - // Test batch with overwrite_key=true - WriteBatchWithIndex batch(BytewiseComparator(), 0, true); - std::string value; - - s = batch.GetFromBatch(column_family, options, "X", &value); - ASSERT_TRUE(s.IsNotFound()); - - batch.Put(column_family, "X", "x"); - s = batch.GetFromBatch(column_family, options, "X", &value); - ASSERT_OK(s); - ASSERT_EQ("x", value); - - batch.Put(column_family, "X", "x2"); - s = batch.GetFromBatch(column_family, options, "X", &value); - ASSERT_OK(s); - ASSERT_EQ("x2", value); - - batch.Merge(column_family, "X", "aaa"); - s = batch.GetFromBatch(column_family, options, "X", &value); - ASSERT_TRUE(s.IsMergeInProgress()); - - batch.Merge(column_family, "X", "bbb"); - s = batch.GetFromBatch(column_family, options, "X", &value); - ASSERT_TRUE(s.IsMergeInProgress()); - - batch.Put(column_family, "X", "x3"); - s = batch.GetFromBatch(column_family, options, "X", &value); - ASSERT_OK(s); - ASSERT_EQ("x3", value); - - batch.Merge(column_family, "X", "ccc"); - s = batch.GetFromBatch(column_family, options, "X", &value); - ASSERT_TRUE(s.IsMergeInProgress()); - - batch.Delete(column_family, "X"); - s = batch.GetFromBatch(column_family, options, "X", &value); - ASSERT_TRUE(s.IsNotFound()); - - batch.Merge(column_family, "X", "ddd"); - s = batch.GetFromBatch(column_family, options, "X", &value); - ASSERT_TRUE(s.IsMergeInProgress()); - - delete db; - DestroyDB(dbname, options); -} - -TEST_F(WriteBatchWithIndexTest, TestGetFromBatchAndDB) { - DB* db; - Options options; - options.create_if_missing = true; - std::string dbname = test::TmpDir() + "/write_batch_with_index_test"; - - DestroyDB(dbname, options); - Status s = DB::Open(options, dbname, &db); - ASSERT_OK(s); - - WriteBatchWithIndex batch; - ReadOptions read_options; - WriteOptions write_options; - std::string value; - - s = db->Put(write_options, "a", "a"); - ASSERT_OK(s); - - s = db->Put(write_options, "b", "b"); - ASSERT_OK(s); - - s = db->Put(write_options, "c", "c"); - ASSERT_OK(s); - - batch.Put("a", "batch.a"); - batch.Delete("b"); - - s = batch.GetFromBatchAndDB(db, read_options, "a", &value); - ASSERT_OK(s); - ASSERT_EQ("batch.a", value); - - s = batch.GetFromBatchAndDB(db, read_options, "b", &value); - ASSERT_TRUE(s.IsNotFound()); - - s = batch.GetFromBatchAndDB(db, read_options, "c", &value); - ASSERT_OK(s); - ASSERT_EQ("c", value); - - s = batch.GetFromBatchAndDB(db, read_options, "x", &value); - ASSERT_TRUE(s.IsNotFound()); - - db->Delete(write_options, "x"); - - s = batch.GetFromBatchAndDB(db, read_options, "x", &value); - ASSERT_TRUE(s.IsNotFound()); - - delete db; - DestroyDB(dbname, options); -} - -TEST_F(WriteBatchWithIndexTest, TestGetFromBatchAndDBMerge) { - DB* db; - Options options; - - options.create_if_missing = true; - std::string dbname = test::TmpDir() + "/write_batch_with_index_test"; - - options.merge_operator = MergeOperators::CreateFromStringId("stringappend"); - - DestroyDB(dbname, options); - Status s = DB::Open(options, dbname, &db); - assert(s.ok()); - - WriteBatchWithIndex batch; - ReadOptions read_options; - WriteOptions write_options; - std::string value; - - s = db->Put(write_options, "a", "a0"); - ASSERT_OK(s); - - s = db->Put(write_options, "b", "b0"); - ASSERT_OK(s); - - s = db->Merge(write_options, "b", "b1"); - ASSERT_OK(s); - - s = db->Merge(write_options, "c", "c0"); - ASSERT_OK(s); - - s = db->Merge(write_options, "d", "d0"); - ASSERT_OK(s); - - batch.Merge("a", "a1"); - batch.Merge("a", "a2"); - batch.Merge("b", "b2"); - batch.Merge("d", "d1"); - batch.Merge("e", "e0"); - - s = batch.GetFromBatchAndDB(db, read_options, "a", &value); - ASSERT_OK(s); - ASSERT_EQ("a0,a1,a2", value); - - s = batch.GetFromBatchAndDB(db, read_options, "b", &value); - ASSERT_OK(s); - ASSERT_EQ("b0,b1,b2", value); - - s = batch.GetFromBatchAndDB(db, read_options, "c", &value); - ASSERT_OK(s); - ASSERT_EQ("c0", value); - - s = batch.GetFromBatchAndDB(db, read_options, "d", &value); - ASSERT_OK(s); - ASSERT_EQ("d0,d1", value); - - s = batch.GetFromBatchAndDB(db, read_options, "e", &value); - ASSERT_OK(s); - ASSERT_EQ("e0", value); - - s = db->Delete(write_options, "x"); - ASSERT_OK(s); - - s = batch.GetFromBatchAndDB(db, read_options, "x", &value); - ASSERT_TRUE(s.IsNotFound()); - - const Snapshot* snapshot = db->GetSnapshot(); - ReadOptions snapshot_read_options; - snapshot_read_options.snapshot = snapshot; - - s = db->Delete(write_options, "a"); - ASSERT_OK(s); - - s = batch.GetFromBatchAndDB(db, read_options, "a", &value); - ASSERT_OK(s); - ASSERT_EQ("a1,a2", value); - - s = batch.GetFromBatchAndDB(db, snapshot_read_options, "a", &value); - ASSERT_OK(s); - ASSERT_EQ("a0,a1,a2", value); - - batch.Delete("a"); - - s = batch.GetFromBatchAndDB(db, read_options, "a", &value); - ASSERT_TRUE(s.IsNotFound()); - - s = batch.GetFromBatchAndDB(db, snapshot_read_options, "a", &value); - ASSERT_TRUE(s.IsNotFound()); - - s = db->Merge(write_options, "c", "c1"); - ASSERT_OK(s); - - s = batch.GetFromBatchAndDB(db, read_options, "c", &value); - ASSERT_OK(s); - ASSERT_EQ("c0,c1", value); - - s = batch.GetFromBatchAndDB(db, snapshot_read_options, "c", &value); - ASSERT_OK(s); - ASSERT_EQ("c0", value); - - s = db->Put(write_options, "e", "e1"); - ASSERT_OK(s); - - s = batch.GetFromBatchAndDB(db, read_options, "e", &value); - ASSERT_OK(s); - ASSERT_EQ("e1,e0", value); - - s = batch.GetFromBatchAndDB(db, snapshot_read_options, "e", &value); - ASSERT_OK(s); - ASSERT_EQ("e0", value); - - s = db->Delete(write_options, "e"); - ASSERT_OK(s); - - s = batch.GetFromBatchAndDB(db, read_options, "e", &value); - ASSERT_OK(s); - ASSERT_EQ("e0", value); - - s = batch.GetFromBatchAndDB(db, snapshot_read_options, "e", &value); - ASSERT_OK(s); - ASSERT_EQ("e0", value); - - db->ReleaseSnapshot(snapshot); - delete db; - DestroyDB(dbname, options); -} - -TEST_F(WriteBatchWithIndexTest, TestGetFromBatchAndDBMerge2) { - DB* db; - Options options; - - options.create_if_missing = true; - std::string dbname = test::TmpDir() + "/write_batch_with_index_test"; - - options.merge_operator = MergeOperators::CreateFromStringId("stringappend"); - - DestroyDB(dbname, options); - Status s = DB::Open(options, dbname, &db); - assert(s.ok()); - - // Test batch with overwrite_key=true - WriteBatchWithIndex batch(BytewiseComparator(), 0, true); - - ReadOptions read_options; - WriteOptions write_options; - std::string value; - - s = batch.GetFromBatchAndDB(db, read_options, "A", &value); - ASSERT_TRUE(s.IsNotFound()); - - batch.Merge("A", "xxx"); - - s = batch.GetFromBatchAndDB(db, read_options, "A", &value); - ASSERT_TRUE(s.IsMergeInProgress()); - - batch.Merge("A", "yyy"); - - s = batch.GetFromBatchAndDB(db, read_options, "A", &value); - ASSERT_TRUE(s.IsMergeInProgress()); - - s = db->Put(write_options, "A", "a0"); - ASSERT_OK(s); - - s = batch.GetFromBatchAndDB(db, read_options, "A", &value); - ASSERT_TRUE(s.IsMergeInProgress()); - - batch.Delete("A"); - - s = batch.GetFromBatchAndDB(db, read_options, "A", &value); - ASSERT_TRUE(s.IsNotFound()); - - delete db; - DestroyDB(dbname, options); -} - -void AssertKey(std::string key, WBWIIterator* iter) { - ASSERT_TRUE(iter->Valid()); - ASSERT_EQ(key, iter->Entry().key.ToString()); -} - -void AssertValue(std::string value, WBWIIterator* iter) { - ASSERT_TRUE(iter->Valid()); - ASSERT_EQ(value, iter->Entry().value.ToString()); -} - -// Tests that we can write to the WBWI while we iterate (from a single thread). -// iteration should see the newest writes -TEST_F(WriteBatchWithIndexTest, MutateWhileIteratingCorrectnessTest) { - WriteBatchWithIndex batch(BytewiseComparator(), 0, true); - for (char c = 'a'; c <= 'z'; ++c) { - batch.Put(std::string(1, c), std::string(1, c)); - } - - std::unique_ptr<WBWIIterator> iter(batch.NewIterator()); - iter->Seek("k"); - AssertKey("k", iter.get()); - iter->Next(); - AssertKey("l", iter.get()); - batch.Put("ab", "cc"); - iter->Next(); - AssertKey("m", iter.get()); - batch.Put("mm", "kk"); - iter->Next(); - AssertKey("mm", iter.get()); - AssertValue("kk", iter.get()); - batch.Delete("mm"); - - iter->Next(); - AssertKey("n", iter.get()); - iter->Prev(); - AssertKey("mm", iter.get()); - ASSERT_EQ(kDeleteRecord, iter->Entry().type); - - iter->Seek("ab"); - AssertKey("ab", iter.get()); - batch.Delete("x"); - iter->Seek("x"); - AssertKey("x", iter.get()); - ASSERT_EQ(kDeleteRecord, iter->Entry().type); - iter->Prev(); - AssertKey("w", iter.get()); -} - -void AssertIterKey(std::string key, Iterator* iter) { - ASSERT_TRUE(iter->Valid()); - ASSERT_EQ(key, iter->key().ToString()); -} - -void AssertIterValue(std::string value, Iterator* iter) { - ASSERT_TRUE(iter->Valid()); - ASSERT_EQ(value, iter->value().ToString()); -} - -// same thing as above, but testing IteratorWithBase -TEST_F(WriteBatchWithIndexTest, MutateWhileIteratingBaseCorrectnessTest) { - WriteBatchWithIndex batch(BytewiseComparator(), 0, true); - for (char c = 'a'; c <= 'z'; ++c) { - batch.Put(std::string(1, c), std::string(1, c)); - } - - KVMap map; - map["aa"] = "aa"; - map["cc"] = "cc"; - map["ee"] = "ee"; - map["em"] = "me"; - - std::unique_ptr<Iterator> iter( - batch.NewIteratorWithBase(new KVIter(&map))); - iter->Seek("k"); - AssertIterKey("k", iter.get()); - iter->Next(); - AssertIterKey("l", iter.get()); - batch.Put("ab", "cc"); - iter->Next(); - AssertIterKey("m", iter.get()); - batch.Put("mm", "kk"); - iter->Next(); - AssertIterKey("mm", iter.get()); - AssertIterValue("kk", iter.get()); - batch.Delete("mm"); - iter->Next(); - AssertIterKey("n", iter.get()); - iter->Prev(); - // "mm" is deleted, so we're back at "m" - AssertIterKey("m", iter.get()); - - iter->Seek("ab"); - AssertIterKey("ab", iter.get()); - iter->Prev(); - AssertIterKey("aa", iter.get()); - iter->Prev(); - AssertIterKey("a", iter.get()); - batch.Delete("aa"); - iter->Next(); - AssertIterKey("ab", iter.get()); - iter->Prev(); - AssertIterKey("a", iter.get()); - - batch.Delete("x"); - iter->Seek("x"); - AssertIterKey("y", iter.get()); - iter->Next(); - AssertIterKey("z", iter.get()); - iter->Prev(); - iter->Prev(); - AssertIterKey("w", iter.get()); - - batch.Delete("e"); - iter->Seek("e"); - AssertIterKey("ee", iter.get()); - AssertIterValue("ee", iter.get()); - batch.Put("ee", "xx"); - // still the same value - AssertIterValue("ee", iter.get()); - iter->Next(); - AssertIterKey("em", iter.get()); - iter->Prev(); - // new value - AssertIterValue("xx", iter.get()); -} - -// stress testing mutations with IteratorWithBase -TEST_F(WriteBatchWithIndexTest, MutateWhileIteratingBaseStressTest) { - WriteBatchWithIndex batch(BytewiseComparator(), 0, true); - for (char c = 'a'; c <= 'z'; ++c) { - batch.Put(std::string(1, c), std::string(1, c)); - } - - KVMap map; - for (char c = 'a'; c <= 'z'; ++c) { - map[std::string(2, c)] = std::string(2, c); - } - - std::unique_ptr<Iterator> iter( - batch.NewIteratorWithBase(new KVIter(&map))); - - Random rnd(301); - for (int i = 0; i < 1000000; ++i) { - int random = rnd.Uniform(8); - char c = static_cast<char>(rnd.Uniform(26) + 'a'); - switch (random) { - case 0: - batch.Put(std::string(1, c), "xxx"); - break; - case 1: - batch.Put(std::string(2, c), "xxx"); - break; - case 2: - batch.Delete(std::string(1, c)); - break; - case 3: - batch.Delete(std::string(2, c)); - break; - case 4: - iter->Seek(std::string(1, c)); - break; - case 5: - iter->Seek(std::string(2, c)); - break; - case 6: - if (iter->Valid()) { - iter->Next(); - } - break; - case 7: - if (iter->Valid()) { - iter->Prev(); - } - break; - default: - assert(false); - } - } -} - -static std::string PrintContents(WriteBatchWithIndex* batch, - ColumnFamilyHandle* column_family) { - std::string result; - - WBWIIterator* iter; - if (column_family == nullptr) { - iter = batch->NewIterator(); - } else { - iter = batch->NewIterator(column_family); - } - - iter->SeekToFirst(); - while (iter->Valid()) { - WriteEntry e = iter->Entry(); - - if (e.type == kPutRecord) { - result.append("PUT("); - result.append(e.key.ToString()); - result.append("):"); - result.append(e.value.ToString()); - } else if (e.type == kMergeRecord) { - result.append("MERGE("); - result.append(e.key.ToString()); - result.append("):"); - result.append(e.value.ToString()); - } else if (e.type == kSingleDeleteRecord) { - result.append("SINGLE-DEL("); - result.append(e.key.ToString()); - result.append(")"); - } else { - assert(e.type == kDeleteRecord); - result.append("DEL("); - result.append(e.key.ToString()); - result.append(")"); - } - - result.append(","); - iter->Next(); - } - - delete iter; - return result; -} - -static std::string PrintContents(WriteBatchWithIndex* batch, KVMap* base_map, - ColumnFamilyHandle* column_family) { - std::string result; - - Iterator* iter; - if (column_family == nullptr) { - iter = batch->NewIteratorWithBase(new KVIter(base_map)); - } else { - iter = batch->NewIteratorWithBase(column_family, new KVIter(base_map)); - } - - iter->SeekToFirst(); - while (iter->Valid()) { - assert(iter->status().ok()); - - Slice key = iter->key(); - Slice value = iter->value(); - - result.append(key.ToString()); - result.append(":"); - result.append(value.ToString()); - result.append(","); - - iter->Next(); - } - - delete iter; - return result; -} - -TEST_F(WriteBatchWithIndexTest, SavePointTest) { - WriteBatchWithIndex batch; - ColumnFamilyHandleImplDummy cf1(1, BytewiseComparator()); - Status s; - - batch.Put("A", "a"); - batch.Put("B", "b"); - batch.Put("A", "aa"); - batch.Put(&cf1, "A", "a1"); - batch.Delete(&cf1, "B"); - batch.Put(&cf1, "C", "c1"); - batch.Put(&cf1, "E", "e1"); - - batch.SetSavePoint(); // 1 - - batch.Put("C", "cc"); - batch.Put("B", "bb"); - batch.Delete("A"); - batch.Put(&cf1, "B", "b1"); - batch.Delete(&cf1, "A"); - batch.SingleDelete(&cf1, "E"); - batch.SetSavePoint(); // 2 - - batch.Put("A", "aaa"); - batch.Put("A", "xxx"); - batch.Delete("B"); - batch.Put(&cf1, "B", "b2"); - batch.Delete(&cf1, "C"); - batch.SetSavePoint(); // 3 - batch.SetSavePoint(); // 4 - batch.SingleDelete("D"); - batch.Delete(&cf1, "D"); - batch.Delete(&cf1, "E"); - - ASSERT_EQ( - "PUT(A):a,PUT(A):aa,DEL(A),PUT(A):aaa,PUT(A):xxx,PUT(B):b,PUT(B):bb,DEL(" - "B)" - ",PUT(C):cc,SINGLE-DEL(D),", - PrintContents(&batch, nullptr)); - - ASSERT_EQ( - "PUT(A):a1,DEL(A),DEL(B),PUT(B):b1,PUT(B):b2,PUT(C):c1,DEL(C)," - "DEL(D),PUT(E):e1,SINGLE-DEL(E),DEL(E),", - PrintContents(&batch, &cf1)); - - ASSERT_OK(batch.RollbackToSavePoint()); // rollback to 4 - ASSERT_EQ( - "PUT(A):a,PUT(A):aa,DEL(A),PUT(A):aaa,PUT(A):xxx,PUT(B):b,PUT(B):bb,DEL(" - "B)" - ",PUT(C):cc,", - PrintContents(&batch, nullptr)); - - ASSERT_EQ( - "PUT(A):a1,DEL(A),DEL(B),PUT(B):b1,PUT(B):b2,PUT(C):c1,DEL(C)," - "PUT(E):e1,SINGLE-DEL(E),", - PrintContents(&batch, &cf1)); - - ASSERT_OK(batch.RollbackToSavePoint()); // rollback to 3 - ASSERT_EQ( - "PUT(A):a,PUT(A):aa,DEL(A),PUT(A):aaa,PUT(A):xxx,PUT(B):b,PUT(B):bb,DEL(" - "B)" - ",PUT(C):cc,", - PrintContents(&batch, nullptr)); - - ASSERT_EQ( - "PUT(A):a1,DEL(A),DEL(B),PUT(B):b1,PUT(B):b2,PUT(C):c1,DEL(C)," - "PUT(E):e1,SINGLE-DEL(E),", - PrintContents(&batch, &cf1)); - - ASSERT_OK(batch.RollbackToSavePoint()); // rollback to 2 - ASSERT_EQ("PUT(A):a,PUT(A):aa,DEL(A),PUT(B):b,PUT(B):bb,PUT(C):cc,", - PrintContents(&batch, nullptr)); - - ASSERT_EQ( - "PUT(A):a1,DEL(A),DEL(B),PUT(B):b1,PUT(C):c1," - "PUT(E):e1,SINGLE-DEL(E),", - PrintContents(&batch, &cf1)); - - batch.SetSavePoint(); // 5 - batch.Put("X", "x"); - - ASSERT_EQ("PUT(A):a,PUT(A):aa,DEL(A),PUT(B):b,PUT(B):bb,PUT(C):cc,PUT(X):x,", - PrintContents(&batch, nullptr)); - - ASSERT_OK(batch.RollbackToSavePoint()); // rollback to 5 - ASSERT_EQ("PUT(A):a,PUT(A):aa,DEL(A),PUT(B):b,PUT(B):bb,PUT(C):cc,", - PrintContents(&batch, nullptr)); - - ASSERT_EQ( - "PUT(A):a1,DEL(A),DEL(B),PUT(B):b1,PUT(C):c1," - "PUT(E):e1,SINGLE-DEL(E),", - PrintContents(&batch, &cf1)); - - ASSERT_OK(batch.RollbackToSavePoint()); // rollback to 1 - ASSERT_EQ("PUT(A):a,PUT(A):aa,PUT(B):b,", PrintContents(&batch, nullptr)); - - ASSERT_EQ("PUT(A):a1,DEL(B),PUT(C):c1,PUT(E):e1,", - PrintContents(&batch, &cf1)); - - s = batch.RollbackToSavePoint(); // no savepoint found - ASSERT_TRUE(s.IsNotFound()); - ASSERT_EQ("PUT(A):a,PUT(A):aa,PUT(B):b,", PrintContents(&batch, nullptr)); - - ASSERT_EQ("PUT(A):a1,DEL(B),PUT(C):c1,PUT(E):e1,", - PrintContents(&batch, &cf1)); - - batch.SetSavePoint(); // 6 - - batch.Clear(); - ASSERT_EQ("", PrintContents(&batch, nullptr)); - ASSERT_EQ("", PrintContents(&batch, &cf1)); - - s = batch.RollbackToSavePoint(); // rollback to 6 - ASSERT_TRUE(s.IsNotFound()); -} - -TEST_F(WriteBatchWithIndexTest, SingleDeleteTest) { - WriteBatchWithIndex batch; - Status s; - std::string value; - DBOptions db_options; - - batch.SingleDelete("A"); - - s = batch.GetFromBatch(db_options, "A", &value); - ASSERT_TRUE(s.IsNotFound()); - s = batch.GetFromBatch(db_options, "B", &value); - ASSERT_TRUE(s.IsNotFound()); - value = PrintContents(&batch, nullptr); - ASSERT_EQ("SINGLE-DEL(A),", value); - - batch.Clear(); - batch.Put("A", "a"); - batch.Put("A", "a2"); - batch.Put("B", "b"); - batch.SingleDelete("A"); - - s = batch.GetFromBatch(db_options, "A", &value); - ASSERT_TRUE(s.IsNotFound()); - s = batch.GetFromBatch(db_options, "B", &value); - ASSERT_OK(s); - ASSERT_EQ("b", value); - - value = PrintContents(&batch, nullptr); - ASSERT_EQ("PUT(A):a,PUT(A):a2,SINGLE-DEL(A),PUT(B):b,", value); - - batch.Put("C", "c"); - batch.Put("A", "a3"); - batch.Delete("B"); - batch.SingleDelete("B"); - batch.SingleDelete("C"); - - s = batch.GetFromBatch(db_options, "A", &value); - ASSERT_OK(s); - ASSERT_EQ("a3", value); - s = batch.GetFromBatch(db_options, "B", &value); - ASSERT_TRUE(s.IsNotFound()); - s = batch.GetFromBatch(db_options, "C", &value); - ASSERT_TRUE(s.IsNotFound()); - s = batch.GetFromBatch(db_options, "D", &value); - ASSERT_TRUE(s.IsNotFound()); - - value = PrintContents(&batch, nullptr); - ASSERT_EQ( - "PUT(A):a,PUT(A):a2,SINGLE-DEL(A),PUT(A):a3,PUT(B):b,DEL(B),SINGLE-DEL(B)" - ",PUT(C):c,SINGLE-DEL(C),", - value); - - batch.Put("B", "b4"); - batch.Put("C", "c4"); - batch.Put("D", "d4"); - batch.SingleDelete("D"); - batch.SingleDelete("D"); - batch.Delete("A"); - - s = batch.GetFromBatch(db_options, "A", &value); - ASSERT_TRUE(s.IsNotFound()); - s = batch.GetFromBatch(db_options, "B", &value); - ASSERT_OK(s); - ASSERT_EQ("b4", value); - s = batch.GetFromBatch(db_options, "C", &value); - ASSERT_OK(s); - ASSERT_EQ("c4", value); - s = batch.GetFromBatch(db_options, "D", &value); - ASSERT_TRUE(s.IsNotFound()); - - value = PrintContents(&batch, nullptr); - ASSERT_EQ( - "PUT(A):a,PUT(A):a2,SINGLE-DEL(A),PUT(A):a3,DEL(A),PUT(B):b,DEL(B)," - "SINGLE-DEL(B),PUT(B):b4,PUT(C):c,SINGLE-DEL(C),PUT(C):c4,PUT(D):d4," - "SINGLE-DEL(D),SINGLE-DEL(D),", - value); -} - -TEST_F(WriteBatchWithIndexTest, SingleDeleteDeltaIterTest) { - Status s; - std::string value; - DBOptions db_options; - WriteBatchWithIndex batch(BytewiseComparator(), 20, true /* overwrite_key */); - batch.Put("A", "a"); - batch.Put("A", "a2"); - batch.Put("B", "b"); - batch.SingleDelete("A"); - batch.Delete("B"); - - KVMap map; - value = PrintContents(&batch, &map, nullptr); - ASSERT_EQ("", value); - - map["A"] = "aa"; - map["C"] = "cc"; - map["D"] = "dd"; - - batch.SingleDelete("B"); - batch.SingleDelete("C"); - batch.SingleDelete("Z"); - - value = PrintContents(&batch, &map, nullptr); - ASSERT_EQ("D:dd,", value); - - batch.Put("A", "a3"); - batch.Put("B", "b3"); - batch.SingleDelete("A"); - batch.SingleDelete("A"); - batch.SingleDelete("D"); - batch.SingleDelete("D"); - batch.Delete("D"); - - map["E"] = "ee"; - - value = PrintContents(&batch, &map, nullptr); - ASSERT_EQ("B:b3,E:ee,", value); -} - -} // namespace - -int main(int argc, char** argv) { - rocksdb::port::InstallStackTraceHandler(); - ::testing::InitGoogleTest(&argc, argv); - return RUN_ALL_TESTS(); -} - -#else -#include <stdio.h> - -int main() { - fprintf(stderr, "SKIPPED\n"); - return 0; -} - -#endif // !ROCKSDB_LITE