]> git.proxmox.com Git - ceph.git/blame - ceph/src/rocksdb/utilities/options/options_util_test.cc
update source to Ceph Pacific 16.2.2
[ceph.git] / ceph / src / rocksdb / utilities / options / options_util_test.cc
CommitLineData
7c673cae 1// Copyright (c) 2011-present, Facebook, Inc. All rights reserved.
11fdf7f2
TL
2// This source code is licensed under both the GPLv2 (found in the
3// COPYING file in the root directory) and Apache 2.0 License
4// (found in the LICENSE.Apache file in the root directory).
7c673cae
FG
5
6#ifndef ROCKSDB_LITE
7c673cae 7
f67539c2 8#include <cinttypes>
7c673cae
FG
9
10#include <cctype>
11#include <unordered_map>
12
13#include "options/options_parser.h"
14#include "rocksdb/db.h"
15#include "rocksdb/table.h"
16#include "rocksdb/utilities/options_util.h"
f67539c2
TL
17#include "test_util/testharness.h"
18#include "test_util/testutil.h"
7c673cae 19#include "util/random.h"
7c673cae
FG
20
21#ifndef GFLAGS
22bool FLAGS_enable_print = false;
23#else
11fdf7f2
TL
24#include "util/gflags_compat.h"
25using GFLAGS_NAMESPACE::ParseCommandLineFlags;
7c673cae
FG
26DEFINE_bool(enable_print, false, "Print options generated to console.");
27#endif // GFLAGS
28
f67539c2 29namespace ROCKSDB_NAMESPACE {
7c673cae
FG
30class OptionsUtilTest : public testing::Test {
31 public:
32 OptionsUtilTest() : rnd_(0xFB) {
33 env_.reset(new test::StringEnv(Env::Default()));
f67539c2 34 fs_.reset(new LegacyFileSystemWrapper(env_.get()));
11fdf7f2 35 dbname_ = test::PerThreadDBPath("options_util_test");
7c673cae
FG
36 }
37
38 protected:
39 std::unique_ptr<test::StringEnv> env_;
f67539c2 40 std::unique_ptr<LegacyFileSystemWrapper> fs_;
7c673cae
FG
41 std::string dbname_;
42 Random rnd_;
43};
44
45bool IsBlockBasedTableFactory(TableFactory* tf) {
46 return tf->Name() == BlockBasedTableFactory().Name();
47}
48
49TEST_F(OptionsUtilTest, SaveAndLoad) {
50 const size_t kCFCount = 5;
51
52 DBOptions db_opt;
53 std::vector<std::string> cf_names;
54 std::vector<ColumnFamilyOptions> cf_opts;
55 test::RandomInitDBOptions(&db_opt, &rnd_);
56 for (size_t i = 0; i < kCFCount; ++i) {
57 cf_names.push_back(i == 0 ? kDefaultColumnFamilyName
58 : test::RandomName(&rnd_, 10));
59 cf_opts.emplace_back();
f67539c2 60 test::RandomInitCFOptions(&cf_opts.back(), db_opt, &rnd_);
7c673cae
FG
61 }
62
63 const std::string kFileName = "OPTIONS-123456";
f67539c2 64 PersistRocksDBOptions(db_opt, cf_names, cf_opts, kFileName, fs_.get());
7c673cae
FG
65
66 DBOptions loaded_db_opt;
67 std::vector<ColumnFamilyDescriptor> loaded_cf_descs;
68 ASSERT_OK(LoadOptionsFromFile(kFileName, env_.get(), &loaded_db_opt,
69 &loaded_cf_descs));
70
71 ASSERT_OK(RocksDBOptionsParser::VerifyDBOptions(db_opt, loaded_db_opt));
72 test::RandomInitDBOptions(&db_opt, &rnd_);
73 ASSERT_NOK(RocksDBOptionsParser::VerifyDBOptions(db_opt, loaded_db_opt));
74
75 for (size_t i = 0; i < kCFCount; ++i) {
76 ASSERT_EQ(cf_names[i], loaded_cf_descs[i].name);
77 ASSERT_OK(RocksDBOptionsParser::VerifyCFOptions(
78 cf_opts[i], loaded_cf_descs[i].options));
79 if (IsBlockBasedTableFactory(cf_opts[i].table_factory.get())) {
80 ASSERT_OK(RocksDBOptionsParser::VerifyTableFactory(
81 cf_opts[i].table_factory.get(),
82 loaded_cf_descs[i].options.table_factory.get()));
83 }
f67539c2 84 test::RandomInitCFOptions(&cf_opts[i], db_opt, &rnd_);
7c673cae
FG
85 ASSERT_NOK(RocksDBOptionsParser::VerifyCFOptions(
86 cf_opts[i], loaded_cf_descs[i].options));
87 }
88
89 for (size_t i = 0; i < kCFCount; ++i) {
90 if (cf_opts[i].compaction_filter) {
91 delete cf_opts[i].compaction_filter;
92 }
93 }
94}
95
494da23a
TL
96TEST_F(OptionsUtilTest, SaveAndLoadWithCacheCheck) {
97 // creating db
98 DBOptions db_opt;
99 db_opt.create_if_missing = true;
100 // initialize BlockBasedTableOptions
101 std::shared_ptr<Cache> cache = NewLRUCache(1 * 1024);
102 BlockBasedTableOptions bbt_opts;
103 bbt_opts.block_size = 32 * 1024;
104 // saving cf options
105 std::vector<ColumnFamilyOptions> cf_opts;
106 ColumnFamilyOptions default_column_family_opt = ColumnFamilyOptions();
107 default_column_family_opt.table_factory.reset(
108 NewBlockBasedTableFactory(bbt_opts));
109 cf_opts.push_back(default_column_family_opt);
110
111 ColumnFamilyOptions cf_opt_sample = ColumnFamilyOptions();
112 cf_opt_sample.table_factory.reset(NewBlockBasedTableFactory(bbt_opts));
113 cf_opts.push_back(cf_opt_sample);
114
115 ColumnFamilyOptions cf_opt_plain_table_opt = ColumnFamilyOptions();
116 cf_opt_plain_table_opt.table_factory.reset(NewPlainTableFactory());
117 cf_opts.push_back(cf_opt_plain_table_opt);
118
119 std::vector<std::string> cf_names;
120 cf_names.push_back(kDefaultColumnFamilyName);
121 cf_names.push_back("cf_sample");
122 cf_names.push_back("cf_plain_table_sample");
123 // Saving DB in file
124 const std::string kFileName = "OPTIONS-LOAD_CACHE_123456";
f67539c2 125 PersistRocksDBOptions(db_opt, cf_names, cf_opts, kFileName, fs_.get());
494da23a
TL
126 DBOptions loaded_db_opt;
127 std::vector<ColumnFamilyDescriptor> loaded_cf_descs;
128 ASSERT_OK(LoadOptionsFromFile(kFileName, env_.get(), &loaded_db_opt,
129 &loaded_cf_descs, false, &cache));
130 for (size_t i = 0; i < loaded_cf_descs.size(); i++) {
131 if (IsBlockBasedTableFactory(cf_opts[i].table_factory.get())) {
132 auto* loaded_bbt_opt = reinterpret_cast<BlockBasedTableOptions*>(
133 loaded_cf_descs[i].options.table_factory->GetOptions());
134 // Expect the same cache will be loaded
135 if (loaded_bbt_opt != nullptr) {
136 ASSERT_EQ(loaded_bbt_opt->block_cache.get(), cache.get());
137 }
138 }
139 }
140}
141
7c673cae
FG
142namespace {
143class DummyTableFactory : public TableFactory {
144 public:
145 DummyTableFactory() {}
494da23a 146 ~DummyTableFactory() override {}
7c673cae 147
494da23a 148 const char* Name() const override { return "DummyTableFactory"; }
7c673cae 149
494da23a 150 Status NewTableReader(
11fdf7f2 151 const TableReaderOptions& /*table_reader_options*/,
494da23a
TL
152 std::unique_ptr<RandomAccessFileReader>&& /*file*/,
153 uint64_t /*file_size*/, std::unique_ptr<TableReader>* /*table_reader*/,
11fdf7f2 154 bool /*prefetch_index_and_filter_in_cache*/) const override {
7c673cae
FG
155 return Status::NotSupported();
156 }
157
494da23a 158 TableBuilder* NewTableBuilder(
11fdf7f2
TL
159 const TableBuilderOptions& /*table_builder_options*/,
160 uint32_t /*column_family_id*/,
161 WritableFileWriter* /*file*/) const override {
7c673cae
FG
162 return nullptr;
163 }
164
494da23a 165 Status SanitizeOptions(
11fdf7f2
TL
166 const DBOptions& /*db_opts*/,
167 const ColumnFamilyOptions& /*cf_opts*/) const override {
7c673cae
FG
168 return Status::NotSupported();
169 }
170
494da23a 171 std::string GetPrintableTableOptions() const override { return ""; }
11fdf7f2
TL
172
173 Status GetOptionString(std::string* /*opt_string*/,
174 const std::string& /*delimiter*/) const override {
175 return Status::OK();
176 }
7c673cae
FG
177};
178
179class DummyMergeOperator : public MergeOperator {
180 public:
181 DummyMergeOperator() {}
494da23a 182 ~DummyMergeOperator() override {}
7c673cae 183
494da23a
TL
184 bool FullMergeV2(const MergeOperationInput& /*merge_in*/,
185 MergeOperationOutput* /*merge_out*/) const override {
7c673cae
FG
186 return false;
187 }
188
494da23a
TL
189 bool PartialMergeMulti(const Slice& /*key*/,
190 const std::deque<Slice>& /*operand_list*/,
191 std::string* /*new_value*/,
192 Logger* /*logger*/) const override {
7c673cae
FG
193 return false;
194 }
195
494da23a 196 const char* Name() const override { return "DummyMergeOperator"; }
7c673cae
FG
197};
198
199class DummySliceTransform : public SliceTransform {
200 public:
201 DummySliceTransform() {}
494da23a 202 ~DummySliceTransform() override {}
7c673cae
FG
203
204 // Return the name of this transformation.
494da23a 205 const char* Name() const override { return "DummySliceTransform"; }
7c673cae
FG
206
207 // transform a src in domain to a dst in the range
494da23a 208 Slice Transform(const Slice& src) const override { return src; }
7c673cae
FG
209
210 // determine whether this is a valid src upon the function applies
494da23a 211 bool InDomain(const Slice& /*src*/) const override { return false; }
7c673cae
FG
212
213 // determine whether dst=Transform(src) for some src
494da23a 214 bool InRange(const Slice& /*dst*/) const override { return false; }
7c673cae
FG
215};
216
217} // namespace
218
219TEST_F(OptionsUtilTest, SanityCheck) {
220 DBOptions db_opt;
221 std::vector<ColumnFamilyDescriptor> cf_descs;
222 const size_t kCFCount = 5;
223 for (size_t i = 0; i < kCFCount; ++i) {
224 cf_descs.emplace_back();
225 cf_descs.back().name =
226 (i == 0) ? kDefaultColumnFamilyName : test::RandomName(&rnd_, 10);
227
228 cf_descs.back().options.table_factory.reset(NewBlockBasedTableFactory());
229 // Assign non-null values to prefix_extractors except the first cf.
230 cf_descs.back().options.prefix_extractor.reset(
231 i != 0 ? test::RandomSliceTransform(&rnd_) : nullptr);
232 cf_descs.back().options.merge_operator.reset(
233 test::RandomMergeOperator(&rnd_));
234 }
235
236 db_opt.create_missing_column_families = true;
237 db_opt.create_if_missing = true;
238
239 DestroyDB(dbname_, Options(db_opt, cf_descs[0].options));
240 DB* db;
241 std::vector<ColumnFamilyHandle*> handles;
242 // open and persist the options
243 ASSERT_OK(DB::Open(db_opt, dbname_, cf_descs, &handles, &db));
244
245 // close the db
246 for (auto* handle : handles) {
247 delete handle;
248 }
249 delete db;
250
251 // perform sanity check
252 ASSERT_OK(
253 CheckOptionsCompatibility(dbname_, Env::Default(), db_opt, cf_descs));
254
255 ASSERT_GE(kCFCount, 5);
256 // merge operator
257 {
258 std::shared_ptr<MergeOperator> merge_op =
259 cf_descs[0].options.merge_operator;
260
261 ASSERT_NE(merge_op.get(), nullptr);
262 cf_descs[0].options.merge_operator.reset();
263 ASSERT_NOK(
264 CheckOptionsCompatibility(dbname_, Env::Default(), db_opt, cf_descs));
265
266 cf_descs[0].options.merge_operator.reset(new DummyMergeOperator());
267 ASSERT_NOK(
268 CheckOptionsCompatibility(dbname_, Env::Default(), db_opt, cf_descs));
269
270 cf_descs[0].options.merge_operator = merge_op;
271 ASSERT_OK(
272 CheckOptionsCompatibility(dbname_, Env::Default(), db_opt, cf_descs));
273 }
274
275 // prefix extractor
276 {
277 std::shared_ptr<const SliceTransform> prefix_extractor =
278 cf_descs[1].options.prefix_extractor;
279
280 // It's okay to set prefix_extractor to nullptr.
281 ASSERT_NE(prefix_extractor, nullptr);
282 cf_descs[1].options.prefix_extractor.reset();
283 ASSERT_OK(
284 CheckOptionsCompatibility(dbname_, Env::Default(), db_opt, cf_descs));
285
286 cf_descs[1].options.prefix_extractor.reset(new DummySliceTransform());
11fdf7f2 287 ASSERT_OK(
7c673cae
FG
288 CheckOptionsCompatibility(dbname_, Env::Default(), db_opt, cf_descs));
289
290 cf_descs[1].options.prefix_extractor = prefix_extractor;
291 ASSERT_OK(
292 CheckOptionsCompatibility(dbname_, Env::Default(), db_opt, cf_descs));
293 }
294
295 // prefix extractor nullptr case
296 {
297 std::shared_ptr<const SliceTransform> prefix_extractor =
298 cf_descs[0].options.prefix_extractor;
299
300 // It's okay to set prefix_extractor to nullptr.
301 ASSERT_EQ(prefix_extractor, nullptr);
302 cf_descs[0].options.prefix_extractor.reset();
303 ASSERT_OK(
304 CheckOptionsCompatibility(dbname_, Env::Default(), db_opt, cf_descs));
305
306 // It's okay to change prefix_extractor from nullptr to non-nullptr
307 cf_descs[0].options.prefix_extractor.reset(new DummySliceTransform());
308 ASSERT_OK(
309 CheckOptionsCompatibility(dbname_, Env::Default(), db_opt, cf_descs));
310
311 cf_descs[0].options.prefix_extractor = prefix_extractor;
312 ASSERT_OK(
313 CheckOptionsCompatibility(dbname_, Env::Default(), db_opt, cf_descs));
314 }
315
316 // comparator
317 {
318 test::SimpleSuffixReverseComparator comparator;
319
320 auto* prev_comparator = cf_descs[2].options.comparator;
321 cf_descs[2].options.comparator = &comparator;
322 ASSERT_NOK(
323 CheckOptionsCompatibility(dbname_, Env::Default(), db_opt, cf_descs));
324
325 cf_descs[2].options.comparator = prev_comparator;
326 ASSERT_OK(
327 CheckOptionsCompatibility(dbname_, Env::Default(), db_opt, cf_descs));
328 }
329
330 // table factory
331 {
332 std::shared_ptr<TableFactory> table_factory =
333 cf_descs[3].options.table_factory;
334
335 ASSERT_NE(table_factory, nullptr);
336 cf_descs[3].options.table_factory.reset(new DummyTableFactory());
337 ASSERT_NOK(
338 CheckOptionsCompatibility(dbname_, Env::Default(), db_opt, cf_descs));
339
340 cf_descs[3].options.table_factory = table_factory;
341 ASSERT_OK(
342 CheckOptionsCompatibility(dbname_, Env::Default(), db_opt, cf_descs));
343 }
344}
345
f67539c2 346} // namespace ROCKSDB_NAMESPACE
7c673cae
FG
347
348int main(int argc, char** argv) {
349 ::testing::InitGoogleTest(&argc, argv);
350#ifdef GFLAGS
351 ParseCommandLineFlags(&argc, &argv, true);
352#endif // GFLAGS
353 return RUN_ALL_TESTS();
354}
355
356#else
357#include <cstdio>
358
11fdf7f2 359int main(int /*argc*/, char** /*argv*/) {
7c673cae
FG
360 printf("Skipped in RocksDBLite as utilities are not supported.\n");
361 return 0;
362}
363#endif // !ROCKSDB_LITE