From b87dcae1a33cdac95cb00eef675ac3c9caa3dccc Mon Sep 17 00:00:00 2001 From: Deon Nicholas Date: Tue, 20 Aug 2013 13:35:28 -0700 Subject: [PATCH] Made merge_oprator a shared_ptr; and added TTL unit tests Test Plan: - make all check; - make release; - make stringappend_test; ./stringappend_test Reviewers: haobo, emayanke Reviewed By: haobo CC: leveldb, kailiu Differential Revision: https://reviews.facebook.net/D12381 --- db/builder.cc | 2 +- db/db_bench.cc | 8 +- db/db_impl.cc | 2 +- db/db_iter.cc | 2 +- db/db_test.cc | 5 +- db/memtable.cc | 2 +- db/merge_test.cc | 3 +- db/version_set.cc | 2 +- include/leveldb/options.h | 2 +- tools/db_stress.cc | 5 +- .../string_append/stringappend_test.cc | 447 +++++++++--------- utilities/ttl/db_ttl.cc | 4 +- utilities/ttl/db_ttl.h | 5 +- 13 files changed, 241 insertions(+), 248 deletions(-) diff --git a/db/builder.cc b/db/builder.cc index 27643ddd9..03e703000 100644 --- a/db/builder.cc +++ b/db/builder.cc @@ -54,7 +54,7 @@ Status BuildTable(const std::string& dbname, meta->smallest_seqno = GetInternalKeySeqno(key); meta->largest_seqno = meta->smallest_seqno; - MergeHelper merge(user_comparator, options.merge_operator, + MergeHelper merge(user_comparator, options.merge_operator.get(), options.info_log.get(), true /* internal key corruption is not ok */); diff --git a/db/db_bench.cc b/db/db_bench.cc index 805ac552f..56ddd2356 100644 --- a/db/db_bench.cc +++ b/db/db_bench.cc @@ -637,7 +637,6 @@ class Benchmark { int key_size_; int entries_per_batch_; WriteOptions write_options_; - std::shared_ptr merge_operator_; long reads_; long writes_; long readwrites_; @@ -779,7 +778,6 @@ class Benchmark { value_size_(FLAGS_value_size), key_size_(FLAGS_key_size), entries_per_batch_(1), - merge_operator_(nullptr), reads_(FLAGS_reads < 0 ? FLAGS_num : FLAGS_reads), writes_(FLAGS_writes < 0 ? FLAGS_num : FLAGS_writes), readwrites_((FLAGS_writes < 0 && FLAGS_reads < 0)? FLAGS_num : @@ -1212,13 +1210,13 @@ class Benchmark { options.bytes_per_sync = FLAGS_bytes_per_sync; // merge operator options - merge_operator_ = MergeOperators::CreateFromStringId(FLAGS_merge_operator); - if (merge_operator_ == nullptr && !FLAGS_merge_operator.empty()) { + options.merge_operator = MergeOperators::CreateFromStringId( + FLAGS_merge_operator); + if (options.merge_operator == nullptr && !FLAGS_merge_operator.empty()) { fprintf(stderr, "invalid merge operator: %s\n", FLAGS_merge_operator.c_str()); exit(1); } - options.merge_operator = merge_operator_.get(); Status s; if(FLAGS_read_only) { diff --git a/db/db_impl.cc b/db/db_impl.cc index 1326148bb..5ea8ef33e 100644 --- a/db/db_impl.cc +++ b/db/db_impl.cc @@ -1777,7 +1777,7 @@ Status DBImpl::DoCompactionWork(CompactionState* compact) { SequenceNumber visible_in_snapshot = kMaxSequenceNumber; std::string compaction_filter_value; std::vector delete_key; // for compaction filter - MergeHelper merge(user_comparator(), options_.merge_operator, + MergeHelper merge(user_comparator(), options_.merge_operator.get(), options_.info_log.get(), false /* internal key corruption is expected */); auto compaction_filter = options_.compaction_filter; diff --git a/db/db_iter.cc b/db/db_iter.cc index 5051b3553..b0c8e078e 100644 --- a/db/db_iter.cc +++ b/db/db_iter.cc @@ -57,7 +57,7 @@ class DBIter: public Iterator { env_(env), logger_(options.info_log), user_comparator_(cmp), - user_merge_operator_(options.merge_operator), + user_merge_operator_(options.merge_operator.get()), iter_(iter), sequence_(s), direction_(kForward), diff --git a/db/db_test.cc b/db/db_test.cc index a087edf2c..870f9fd98 100644 --- a/db/db_test.cc +++ b/db/db_test.cc @@ -224,8 +224,6 @@ class DBTest { }; int option_config_; - std::shared_ptr merge_operator_; - public: std::string dbname_; SpecialEnv* env_; @@ -242,7 +240,6 @@ class DBTest { }; DBTest() : option_config_(kDefault), - merge_operator_(MergeOperators::CreatePutOperator()), env_(new SpecialEnv(Env::Default())) { filter_policy_ = NewBloomFilterPolicy(10); dbname_ = test::TmpDir() + "/db_test"; @@ -297,7 +294,7 @@ class DBTest { Options options; switch (option_config_) { case kMergePut: - options.merge_operator = merge_operator_.get(); + options.merge_operator = MergeOperators::CreatePutOperator(); break; case kFilter: options.filter_policy = filter_policy_; diff --git a/db/memtable.cc b/db/memtable.cc index 37ab55852..e2fa482f0 100644 --- a/db/memtable.cc +++ b/db/memtable.cc @@ -139,7 +139,7 @@ bool MemTable::Get(const LookupKey& key, std::string* value, Status* s, assert(operands != nullptr); bool merge_in_progress = s->IsMergeInProgress(); - auto merge_operator = options.merge_operator; + auto merge_operator = options.merge_operator.get(); auto logger = options.info_log; std::string merge_result; diff --git a/db/merge_test.cc b/db/merge_test.cc index 837faec3a..61e090838 100644 --- a/db/merge_test.cc +++ b/db/merge_test.cc @@ -16,14 +16,13 @@ using namespace std; using namespace leveldb; -auto mergeOperator = MergeOperators::CreateUInt64AddOperator(); std::shared_ptr OpenDb(const string& dbname, const bool ttl = false) { DB* db; StackableDB* sdb; Options options; options.create_if_missing = true; - options.merge_operator = mergeOperator.get(); + options.merge_operator = MergeOperators::CreateUInt64AddOperator(); Status s; DestroyDB(dbname, Options()); if (ttl) { diff --git a/db/version_set.cc b/db/version_set.cc index 609965224..c22349bea 100644 --- a/db/version_set.cc +++ b/db/version_set.cc @@ -381,7 +381,7 @@ void Version::Get(const ReadOptions& options, Slice user_key = k.user_key(); const Comparator* ucmp = vset_->icmp_.user_comparator(); - auto merge_operator = db_options.merge_operator; + auto merge_operator = db_options.merge_operator.get(); auto logger = db_options.info_log; assert(status->ok() || status->IsMergeInProgress()); diff --git a/include/leveldb/options.h b/include/leveldb/options.h index 8e3c64e4a..b34042a00 100644 --- a/include/leveldb/options.h +++ b/include/leveldb/options.h @@ -85,7 +85,7 @@ struct Options { // for the first time. It's necessary to specify a merge operator when // openning the DB in this case. // Default: nullptr - const MergeOperator* merge_operator; + shared_ptr merge_operator; // The client must provide compaction_filter_factory if it requires a new // compaction filter to be used for different compaction processes diff --git a/tools/db_stress.cc b/tools/db_stress.cc index 45cf99f01..b8a251e2f 100644 --- a/tools/db_stress.cc +++ b/tools/db_stress.cc @@ -537,7 +537,6 @@ class StressTest { FLAGS_test_batches_snapshots ? sizeof(long) : sizeof(long)-1)), db_(nullptr), - merge_operator_(MergeOperators::CreatePutOperator()), num_times_reopened_(0) { if (FLAGS_destroy_db_initially) { std::vector files; @@ -553,7 +552,6 @@ class StressTest { ~StressTest() { delete db_; - merge_operator_ = nullptr; delete filter_policy_; delete prefix_extractor_; } @@ -1140,7 +1138,7 @@ class StressTest { } if (FLAGS_use_merge_put) { - options.merge_operator = merge_operator_.get(); + options.merge_operator = MergeOperators::CreatePutOperator(); } fprintf(stdout, "DB path: [%s]\n", FLAGS_db); @@ -1188,7 +1186,6 @@ class StressTest { const SliceTransform* prefix_extractor_; DB* db_; StackableDB* sdb_; - std::shared_ptr merge_operator_; int num_times_reopened_; }; diff --git a/utilities/merge_operators/string_append/stringappend_test.cc b/utilities/merge_operators/string_append/stringappend_test.cc index 5ec30a4c4..50e3f7779 100644 --- a/utilities/merge_operators/string_append/stringappend_test.cc +++ b/utilities/merge_operators/string_append/stringappend_test.cc @@ -13,6 +13,8 @@ #include "leveldb/merge_operator.h" #include "utilities/merge_operators.h" #include "utilities/merge_operators/string_append/stringappend.h" +#include "utilities/merge_operators/string_append/stringappend2.h" +#include "utilities/ttl/db_ttl.h" #include "util/testharness.h" #include "util/random.h" @@ -24,21 +26,29 @@ namespace leveldb { const std::string kDbName = "/tmp/mergetestdb"; // OpenDb opens a (possibly new) rocksdb database with a StringAppendOperator -std::shared_ptr OpenDb(StringAppendOperator* append_op) { - DB* db; - Options options; - options.create_if_missing = true; - options.merge_operator = append_op; - Status s = DB::Open(options, kDbName, &db); - if (!s.ok()) { - std::cerr << s.ToString() << std::endl; - assert(false); - } - return std::shared_ptr(db); +std::shared_ptr OpenNormalDb(char delim_char) { + DB* db; + Options options; + options.create_if_missing = true; + options.merge_operator.reset(new StringAppendOperator(delim_char)); + ASSERT_OK(DB::Open(options, kDbName, &db)); + return std::shared_ptr(db); +} + +// Open a TtlDB with a non-associative StringAppendTESTOperator +std::shared_ptr OpenTtlDb(char delim_char) { + StackableDB* db; + Options options; + options.create_if_missing = true; + options.merge_operator.reset(new StringAppendTESTOperator(delim_char)); + Status s; + db = new DBWithTTL(123456, options, kDbName, s, false); + ASSERT_OK(s); + return std::shared_ptr(db); } /// StringLists represents a set of string-lists, each with a key-index. -/// Supports Append(list,string) and Get(list) +/// Supports Append(list, string) and Get(list) class StringLists { public: @@ -52,8 +62,8 @@ class StringLists { // Append string val onto the list defined by key; return true on success bool Append(const std::string& key, const std::string& val){ - Slice valSlice(val.data(),val.size()); - auto s = db_->Merge(merge_option_,key,valSlice); + Slice valSlice(val.data(), val.size()); + auto s = db_->Merge(merge_option_, key, valSlice); if (s.ok()) { return true; @@ -66,7 +76,6 @@ class StringLists { // Returns the list of strings associated with key (or "" if does not exist) bool Get(const std::string& key, std::string* const result){ assert(result != NULL); // we should have a place to store the result - auto s = db_->Get(get_option_, key, result); if (s.ok()) { @@ -86,6 +95,7 @@ class StringLists { return false; } + private: std::shared_ptr db_; WriteOptions merge_option_; @@ -93,23 +103,40 @@ class StringLists { }; + +// The class for unit-testing +class StringAppendOperatorTest { + public: + StringAppendOperatorTest() { + DestroyDB(kDbName, Options()); // Start each test with a fresh DB + } + + typedef std::shared_ptr (* OpenFuncPtr)(char); + + // Allows user to open databases with different configurations. + // e.g.: Can open a DB or a TtlDB, etc. + static void SetOpenDbFunction(OpenFuncPtr func) { + OpenDb = func; + } + + protected: + static OpenFuncPtr OpenDb; +}; +StringAppendOperatorTest::OpenFuncPtr StringAppendOperatorTest::OpenDb = nullptr; + // THE TEST CASES BEGIN HERE -class StringAppendOperatorTest { }; TEST(StringAppendOperatorTest, IteratorTest) { - DestroyDB(kDbName, Options()); // Start this test with a fresh DB - - StringAppendOperator append_op(','); - auto db_ = OpenDb(&append_op); + auto db_ = OpenDb(','); StringLists slists(db_); - slists.Append("k1","v1"); - slists.Append("k1","v2"); - slists.Append("k1","v3"); + slists.Append("k1", "v1"); + slists.Append("k1", "v2"); + slists.Append("k1", "v3"); - slists.Append("k2","a1"); - slists.Append("k2","a2"); - slists.Append("k2","a3"); + slists.Append("k2", "a1"); + slists.Append("k2", "a2"); + slists.Append("k2", "a3"); std::string res; std::unique_ptr it(db_->NewIterator(ReadOptions())); @@ -165,7 +192,7 @@ TEST(StringAppendOperatorTest, IteratorTest) { } } - slists.Append("k3","g1"); + slists.Append("k3", "g1"); it.reset(db_->NewIterator(ReadOptions())); first = true; @@ -192,101 +219,86 @@ TEST(StringAppendOperatorTest, IteratorTest) { } -TEST(StringAppendOperatorTest,SimpleTest) { - DestroyDB(kDbName, Options()); // Start this test with a fresh DB - - StringAppendOperator append_op(','); - auto db = OpenDb(&append_op); +TEST(StringAppendOperatorTest, SimpleTest) { + auto db = OpenDb(','); StringLists slists(db); - slists.Append("k1","v1"); - slists.Append("k1","v2"); - slists.Append("k1","v3"); + slists.Append("k1", "v1"); + slists.Append("k1", "v2"); + slists.Append("k1", "v3"); std::string res; - bool status = slists.Get("k1",&res); + bool status = slists.Get("k1", &res); ASSERT_TRUE(status); - ASSERT_EQ(res,"v1,v2,v3"); + ASSERT_EQ(res, "v1,v2,v3"); } -TEST(StringAppendOperatorTest,SimpleDelimiterTest) { - DestroyDB(kDbName, Options()); // Start this test with a fresh DB - - StringAppendOperator append_op('|'); - auto db = OpenDb(&append_op); +TEST(StringAppendOperatorTest, SimpleDelimiterTest) { + auto db = OpenDb('|'); StringLists slists(db); - slists.Append("k1","v1"); - slists.Append("k1","v2"); - slists.Append("k1","v3"); + slists.Append("k1", "v1"); + slists.Append("k1", "v2"); + slists.Append("k1", "v3"); std::string res; - slists.Get("k1",&res); - ASSERT_EQ(res,"v1|v2|v3"); + slists.Get("k1", &res); + ASSERT_EQ(res, "v1|v2|v3"); } -TEST(StringAppendOperatorTest,OneValueNoDelimiterTest) { - DestroyDB(kDbName, Options()); // Start this test with a fresh DB - - StringAppendOperator append_op('!'); - auto db = OpenDb(&append_op); +TEST(StringAppendOperatorTest, OneValueNoDelimiterTest) { + auto db = OpenDb('!'); StringLists slists(db); - slists.Append("random_key","single_val"); + slists.Append("random_key", "single_val"); std::string res; - slists.Get("random_key",&res); - ASSERT_EQ(res,"single_val"); + slists.Get("random_key", &res); + ASSERT_EQ(res, "single_val"); } -TEST(StringAppendOperatorTest,VariousKeys) { - DestroyDB(kDbName, Options()); // Start this test with a fresh DB - - StringAppendOperator append_op('\n'); - auto db = OpenDb(&append_op); +TEST(StringAppendOperatorTest, VariousKeys) { + auto db = OpenDb('\n'); StringLists slists(db); - slists.Append("c","asdasd"); - slists.Append("a","x"); - slists.Append("b","y"); - slists.Append("a","t"); - slists.Append("a","r"); - slists.Append("b","2"); - slists.Append("c","asdasd"); + slists.Append("c", "asdasd"); + slists.Append("a", "x"); + slists.Append("b", "y"); + slists.Append("a", "t"); + slists.Append("a", "r"); + slists.Append("b", "2"); + slists.Append("c", "asdasd"); - std::string a,b,c; - bool sa,sb,sc; - sa = slists.Get("a",&a); - sb = slists.Get("b",&b); - sc = slists.Get("c",&c); + std::string a, b, c; + bool sa, sb, sc; + sa = slists.Get("a", &a); + sb = slists.Get("b", &b); + sc = slists.Get("c", &c); ASSERT_TRUE(sa && sb && sc); // All three keys should have been found - ASSERT_EQ(a,"x\nt\nr"); - ASSERT_EQ(b,"y\n2"); - ASSERT_EQ(c,"asdasd\nasdasd"); + ASSERT_EQ(a, "x\nt\nr"); + ASSERT_EQ(b, "y\n2"); + ASSERT_EQ(c, "asdasd\nasdasd"); } // Generate semi random keys/words from a small distribution. -TEST(StringAppendOperatorTest,RandomMixGetAppend) { - DestroyDB(kDbName, Options()); // Start this test with a fresh DB - - StringAppendOperator append_op(' '); - auto db = OpenDb(&append_op); +TEST(StringAppendOperatorTest, RandomMixGetAppend) { + auto db = OpenDb(' '); StringLists slists(db); // Generate a list of random keys and values const int kWordCount = 15; - std::string words[] = {"sdasd","triejf","fnjsdfn","dfjisdfsf","342839", - "dsuha","mabuais","sadajsid","jf9834hf","2d9j89", - "dj9823jd","a","dk02ed2dh","$(jd4h984$(*", "mabz"}; + std::string words[] = {"sdasd", "triejf", "fnjsdfn", "dfjisdfsf", "342839", + "dsuha", "mabuais", "sadajsid", "jf9834hf", "2d9j89", + "dj9823jd", "a", "dk02ed2dh", "$(jd4h984$(*", "mabz"}; const int kKeyCount = 6; - std::string keys[] = {"dhaiusdhu","denidw","daisda","keykey","muki", + std::string keys[] = {"dhaiusdhu", "denidw", "daisda", "keykey", "muki", "shzassdianmd"}; // Will store a local copy of all data in order to verify correctness - std::map parallel_copy; + std::map parallel_copy; // Generate a bunch of random queries (Append and Get)! enum query_t { APPEND_OP, GET_OP, NUM_OPS }; @@ -299,14 +311,11 @@ TEST(StringAppendOperatorTest,RandomMixGetAppend) { std::string key = keys[randomGen.Uniform((int)kKeyCount)]; std::string word = words[randomGen.Uniform((int)kWordCount)]; - // Debug message. - //std::cout << (int)query << " " << key << " " << word << std::endl; - // Apply the query and any checks. if (query == APPEND_OP) { // Apply the rocksdb test-harness Append defined above - slists.Append(key,word); //apply the rocksdb append + slists.Append(key, word); //apply the rocksdb append // Apply the similar "Append" to the parallel copy if (parallel_copy[key].size() > 0) { @@ -318,32 +327,29 @@ TEST(StringAppendOperatorTest,RandomMixGetAppend) { } else if (query == GET_OP) { // Assumes that a non-existent key just returns std::string res; - slists.Get(key,&res); - ASSERT_EQ(res,parallel_copy[key]); + slists.Get(key, &res); + ASSERT_EQ(res, parallel_copy[key]); } } } -TEST(StringAppendOperatorTest,BIGRandomMixGetAppend) { - DestroyDB(kDbName, Options()); // Start this test with a fresh DB - - StringAppendOperator append_op(' '); - auto db = OpenDb(&append_op); +TEST(StringAppendOperatorTest, BIGRandomMixGetAppend) { + auto db = OpenDb(' '); StringLists slists(db); // Generate a list of random keys and values const int kWordCount = 15; - std::string words[] = {"sdasd","triejf","fnjsdfn","dfjisdfsf","342839", - "dsuha","mabuais","sadajsid","jf9834hf","2d9j89", - "dj9823jd","a","dk02ed2dh","$(jd4h984$(*", "mabz"}; + std::string words[] = {"sdasd", "triejf", "fnjsdfn", "dfjisdfsf", "342839", + "dsuha", "mabuais", "sadajsid", "jf9834hf", "2d9j89", + "dj9823jd", "a", "dk02ed2dh", "$(jd4h984$(*", "mabz"}; const int kKeyCount = 6; - std::string keys[] = {"dhaiusdhu","denidw","daisda","keykey","muki", + std::string keys[] = {"dhaiusdhu", "denidw", "daisda", "keykey", "muki", "shzassdianmd"}; // Will store a local copy of all data in order to verify correctness - std::map parallel_copy; + std::map parallel_copy; // Generate a bunch of random queries (Append and Get)! enum query_t { APPEND_OP, GET_OP, NUM_OPS }; @@ -356,14 +362,11 @@ TEST(StringAppendOperatorTest,BIGRandomMixGetAppend) { std::string key = keys[randomGen.Uniform((int)kKeyCount)]; std::string word = words[randomGen.Uniform((int)kWordCount)]; - // Debug message. - //std::cout << (int)query << " " << key << " " << word << std::endl; - //Apply the query and any checks. if (query == APPEND_OP) { // Apply the rocksdb test-harness Append defined above - slists.Append(key,word); //apply the rocksdb append + slists.Append(key, word); //apply the rocksdb append // Apply the similar "Append" to the parallel copy if (parallel_copy[key].size() > 0) { @@ -375,8 +378,8 @@ TEST(StringAppendOperatorTest,BIGRandomMixGetAppend) { } else if (query == GET_OP) { // Assumes that a non-existent key just returns std::string res; - slists.Get(key,&res); - ASSERT_EQ(res,parallel_copy[key]); + slists.Get(key, &res); + ASSERT_EQ(res, parallel_copy[key]); } } @@ -384,191 +387,179 @@ TEST(StringAppendOperatorTest,BIGRandomMixGetAppend) { } -TEST(StringAppendOperatorTest,PersistentVariousKeys) { - DestroyDB(kDbName, Options()); // Start this test with a fresh DB - +TEST(StringAppendOperatorTest, PersistentVariousKeys) { // Perform the following operations in limited scope { - StringAppendOperator append_op('\n'); - auto db = OpenDb(&append_op); + auto db = OpenDb('\n'); StringLists slists(db); - slists.Append("c","asdasd"); - slists.Append("a","x"); - slists.Append("b","y"); - slists.Append("a","t"); - slists.Append("a","r"); - slists.Append("b","2"); - slists.Append("c","asdasd"); + slists.Append("c", "asdasd"); + slists.Append("a", "x"); + slists.Append("b", "y"); + slists.Append("a", "t"); + slists.Append("a", "r"); + slists.Append("b", "2"); + slists.Append("c", "asdasd"); - std::string a,b,c; - slists.Get("a",&a); - slists.Get("b",&b); - slists.Get("c",&c); + std::string a, b, c; + slists.Get("a", &a); + slists.Get("b", &b); + slists.Get("c", &c); - ASSERT_EQ(a,"x\nt\nr"); - ASSERT_EQ(b,"y\n2"); - ASSERT_EQ(c,"asdasd\nasdasd"); + ASSERT_EQ(a, "x\nt\nr"); + ASSERT_EQ(b, "y\n2"); + ASSERT_EQ(c, "asdasd\nasdasd"); } // Reopen the database (the previous changes should persist / be remembered) { - StringAppendOperator append_op('\n'); - auto db = OpenDb(&append_op); + auto db = OpenDb('\n'); StringLists slists(db); - slists.Append("c","bbnagnagsx"); - slists.Append("a","sa"); - slists.Append("b","df"); - slists.Append("a","gh"); - slists.Append("a","jk"); - slists.Append("b","l;"); - slists.Append("c","rogosh"); + slists.Append("c", "bbnagnagsx"); + slists.Append("a", "sa"); + slists.Append("b", "df"); + slists.Append("a", "gh"); + slists.Append("a", "jk"); + slists.Append("b", "l;"); + slists.Append("c", "rogosh"); // The previous changes should be on disk (L0) // The most recent changes should be in memory (MemTable) // Hence, this will test both Get() paths. - std::string a,b,c; - slists.Get("a",&a); - slists.Get("b",&b); - slists.Get("c",&c); + std::string a, b, c; + slists.Get("a", &a); + slists.Get("b", &b); + slists.Get("c", &c); - ASSERT_EQ(a,"x\nt\nr\nsa\ngh\njk"); - ASSERT_EQ(b,"y\n2\ndf\nl;"); - ASSERT_EQ(c,"asdasd\nasdasd\nbbnagnagsx\nrogosh"); + ASSERT_EQ(a, "x\nt\nr\nsa\ngh\njk"); + ASSERT_EQ(b, "y\n2\ndf\nl;"); + ASSERT_EQ(c, "asdasd\nasdasd\nbbnagnagsx\nrogosh"); } // Reopen the database (the previous changes should persist / be remembered) { - StringAppendOperator append_op('\n'); - auto db = OpenDb(&append_op); + auto db = OpenDb('\n'); StringLists slists(db); // All changes should be on disk. This will test VersionSet Get() - std::string a,b,c; - slists.Get("a",&a); - slists.Get("b",&b); - slists.Get("c",&c); + std::string a, b, c; + slists.Get("a", &a); + slists.Get("b", &b); + slists.Get("c", &c); - ASSERT_EQ(a,"x\nt\nr\nsa\ngh\njk"); - ASSERT_EQ(b,"y\n2\ndf\nl;"); - ASSERT_EQ(c,"asdasd\nasdasd\nbbnagnagsx\nrogosh"); + ASSERT_EQ(a, "x\nt\nr\nsa\ngh\njk"); + ASSERT_EQ(b, "y\n2\ndf\nl;"); + ASSERT_EQ(c, "asdasd\nasdasd\nbbnagnagsx\nrogosh"); } } -TEST(StringAppendOperatorTest,PersistentFlushAndCompaction) { - DestroyDB(kDbName, Options()); // Start this test with a fresh DB - - StringAppendOperator append_op('\n'); - +TEST(StringAppendOperatorTest, PersistentFlushAndCompaction) { // Perform the following operations in limited scope { - auto db = OpenDb(&append_op); + auto db = OpenDb('\n'); StringLists slists(db); - std::string a,b,c; + std::string a, b, c; bool success; // Append, Flush, Get - slists.Append("c","asdasd"); + slists.Append("c", "asdasd"); db->Flush(leveldb::FlushOptions()); - success = slists.Get("c",&c); + success = slists.Get("c", &c); ASSERT_TRUE(success); - ASSERT_EQ(c,"asdasd"); + ASSERT_EQ(c, "asdasd"); // Append, Flush, Append, Get - slists.Append("a","x"); - slists.Append("b","y"); + slists.Append("a", "x"); + slists.Append("b", "y"); db->Flush(leveldb::FlushOptions()); - slists.Append("a","t"); - slists.Append("a","r"); - slists.Append("b","2"); + slists.Append("a", "t"); + slists.Append("a", "r"); + slists.Append("b", "2"); - success = slists.Get("a",&a); + success = slists.Get("a", &a); assert(success == true); - ASSERT_EQ(a,"x\nt\nr"); + ASSERT_EQ(a, "x\nt\nr"); - success = slists.Get("b",&b); + success = slists.Get("b", &b); assert(success == true); - ASSERT_EQ(b,"y\n2"); + ASSERT_EQ(b, "y\n2"); // Append, Get - success = slists.Append("c","asdasd"); + success = slists.Append("c", "asdasd"); assert(success); - success = slists.Append("b","monkey"); + success = slists.Append("b", "monkey"); assert(success); // I omit the "assert(success)" checks here. - slists.Get("a",&a); - slists.Get("b",&b); - slists.Get("c",&c); + slists.Get("a", &a); + slists.Get("b", &b); + slists.Get("c", &c); - ASSERT_EQ(a,"x\nt\nr"); - ASSERT_EQ(b,"y\n2\nmonkey"); - ASSERT_EQ(c,"asdasd\nasdasd"); + ASSERT_EQ(a, "x\nt\nr"); + ASSERT_EQ(b, "y\n2\nmonkey"); + ASSERT_EQ(c, "asdasd\nasdasd"); } // Reopen the database (the previous changes should persist / be remembered) { - auto db = OpenDb(&append_op); + auto db = OpenDb('\n'); StringLists slists(db); - std::string a,b,c; + std::string a, b, c; // Get (Quick check for persistence of previous database) - slists.Get("a",&a); - ASSERT_EQ(a,"x\nt\nr"); + slists.Get("a", &a); + ASSERT_EQ(a, "x\nt\nr"); //Append, Compact, Get - slists.Append("c","bbnagnagsx"); - slists.Append("a","sa"); - slists.Append("b","df"); - db->CompactRange(nullptr,nullptr); - slists.Get("a",&a); - slists.Get("b",&b); - slists.Get("c",&c); - ASSERT_EQ(a,"x\nt\nr\nsa"); - ASSERT_EQ(b,"y\n2\nmonkey\ndf"); - ASSERT_EQ(c,"asdasd\nasdasd\nbbnagnagsx"); + slists.Append("c", "bbnagnagsx"); + slists.Append("a", "sa"); + slists.Append("b", "df"); + db->CompactRange(nullptr, nullptr); + slists.Get("a", &a); + slists.Get("b", &b); + slists.Get("c", &c); + ASSERT_EQ(a, "x\nt\nr\nsa"); + ASSERT_EQ(b, "y\n2\nmonkey\ndf"); + ASSERT_EQ(c, "asdasd\nasdasd\nbbnagnagsx"); // Append, Get - slists.Append("a","gh"); - slists.Append("a","jk"); - slists.Append("b","l;"); - slists.Append("c","rogosh"); - slists.Get("a",&a); - slists.Get("b",&b); - slists.Get("c",&c); - ASSERT_EQ(a,"x\nt\nr\nsa\ngh\njk"); - ASSERT_EQ(b,"y\n2\nmonkey\ndf\nl;"); - ASSERT_EQ(c,"asdasd\nasdasd\nbbnagnagsx\nrogosh"); + slists.Append("a", "gh"); + slists.Append("a", "jk"); + slists.Append("b", "l;"); + slists.Append("c", "rogosh"); + slists.Get("a", &a); + slists.Get("b", &b); + slists.Get("c", &c); + ASSERT_EQ(a, "x\nt\nr\nsa\ngh\njk"); + ASSERT_EQ(b, "y\n2\nmonkey\ndf\nl;"); + ASSERT_EQ(c, "asdasd\nasdasd\nbbnagnagsx\nrogosh"); // Compact, Get - db->CompactRange(nullptr,nullptr); - ASSERT_EQ(a,"x\nt\nr\nsa\ngh\njk"); - ASSERT_EQ(b,"y\n2\nmonkey\ndf\nl;"); - ASSERT_EQ(c,"asdasd\nasdasd\nbbnagnagsx\nrogosh"); + db->CompactRange(nullptr, nullptr); + ASSERT_EQ(a, "x\nt\nr\nsa\ngh\njk"); + ASSERT_EQ(b, "y\n2\nmonkey\ndf\nl;"); + ASSERT_EQ(c, "asdasd\nasdasd\nbbnagnagsx\nrogosh"); // Append, Flush, Compact, Get - slists.Append("b","afcg"); + slists.Append("b", "afcg"); db->Flush(leveldb::FlushOptions()); - db->CompactRange(nullptr,nullptr); - slists.Get("b",&b); - ASSERT_EQ(b,"y\n2\nmonkey\ndf\nl;\nafcg"); + db->CompactRange(nullptr, nullptr); + slists.Get("b", &b); + ASSERT_EQ(b, "y\n2\nmonkey\ndf\nl;\nafcg"); } } -TEST(StringAppendOperatorTest,SimpleTestNullDelimiter) { - DestroyDB(kDbName, Options()); // Start this test with a fresh DB - - StringAppendOperator append_op('\0'); - auto db = OpenDb(&append_op); +TEST(StringAppendOperatorTest, SimpleTestNullDelimiter) { + auto db = OpenDb('\0'); StringLists slists(db); - slists.Append("k1","v1"); - slists.Append("k1","v2"); - slists.Append("k1","v3"); + slists.Append("k1", "v1"); + slists.Append("k1", "v2"); + slists.Append("k1", "v3"); std::string res; - bool status = slists.Get("k1",&res); + bool status = slists.Get("k1", &res); ASSERT_TRUE(status); // Construct the desired string. Default constructor doesn't like '\0' chars. @@ -579,13 +570,25 @@ TEST(StringAppendOperatorTest,SimpleTestNullDelimiter) { // Check that the leveldb result string matches the desired string assert(res.size() == checker.size()); - ASSERT_EQ(res,checker); + ASSERT_EQ(res, checker); } - } // namespace leveldb int main(int arc, char** argv) { - leveldb::test::RunAllTests(); + // Run with regular database + { + fprintf(stderr, "Running tests with regular db and operator.\n"); + StringAppendOperatorTest::SetOpenDbFunction(&OpenNormalDb); + leveldb::test::RunAllTests(); + } + + // Run with TTL + { + fprintf(stderr, "Running tests with ttl db and generic operator.\n"); + StringAppendOperatorTest::SetOpenDbFunction(&OpenTtlDb); + leveldb::test::RunAllTests(); + } + return 0; } diff --git a/utilities/ttl/db_ttl.cc b/utilities/ttl/db_ttl.cc index 9babecd0f..a7e6b938a 100644 --- a/utilities/ttl/db_ttl.cc +++ b/utilities/ttl/db_ttl.cc @@ -32,8 +32,8 @@ DBWithTTL::DBWithTTL(const int32_t ttl, } if (options.merge_operator) { - ttl_merge_op_.reset(new TtlMergeOperator(options.merge_operator)); - options_to_open.merge_operator = ttl_merge_op_.get(); + options_to_open.merge_operator.reset( + new TtlMergeOperator(options.merge_operator)); } if (read_only) { diff --git a/utilities/ttl/db_ttl.h b/utilities/ttl/db_ttl.h index dbba5c63a..3a6103ac2 100644 --- a/utilities/ttl/db_ttl.h +++ b/utilities/ttl/db_ttl.h @@ -112,7 +112,6 @@ class DBWithTTL : public StackableDB { private: DB* db_; int32_t ttl_; - unique_ptr ttl_merge_op_; unique_ptr ttl_comp_filter_; }; @@ -258,7 +257,7 @@ class TtlCompactionFilterFactory : public CompactionFilterFactory { class TtlMergeOperator : public MergeOperator { public: - explicit TtlMergeOperator(const MergeOperator* merge_op) + explicit TtlMergeOperator(const std::shared_ptr merge_op) : user_merge_op_(merge_op) { assert(merge_op); } @@ -356,7 +355,7 @@ class TtlMergeOperator : public MergeOperator { } private: - const MergeOperator* user_merge_op_; + std::shared_ptr user_merge_op_; }; }