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