]> git.proxmox.com Git - ceph.git/blame - ceph/src/rocksdb/db/table_properties_collector_test.cc
import 14.2.4 nautilus point release
[ceph.git] / ceph / src / rocksdb / db / table_properties_collector_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#include <map>
7#include <memory>
8#include <string>
9#include <utility>
10#include <vector>
11
12#include "db/db_impl.h"
13#include "db/dbformat.h"
14#include "db/table_properties_collector.h"
15#include "options/cf_options.h"
16#include "rocksdb/table.h"
17#include "table/block_based_table_factory.h"
18#include "table/meta_blocks.h"
19#include "table/plain_table_factory.h"
20#include "table/table_builder.h"
21#include "util/coding.h"
22#include "util/file_reader_writer.h"
23#include "util/testharness.h"
24#include "util/testutil.h"
25
26namespace rocksdb {
27
28class TablePropertiesTest : public testing::Test,
29 public testing::WithParamInterface<bool> {
30 public:
494da23a 31 void SetUp() override { backward_mode_ = GetParam(); }
7c673cae
FG
32
33 bool backward_mode_;
34};
35
36// Utilities test functions
37namespace {
38static const uint32_t kTestColumnFamilyId = 66;
39static const std::string kTestColumnFamilyName = "test_column_fam";
40
41void MakeBuilder(const Options& options, const ImmutableCFOptions& ioptions,
11fdf7f2 42 const MutableCFOptions& moptions,
7c673cae
FG
43 const InternalKeyComparator& internal_comparator,
44 const std::vector<std::unique_ptr<IntTblPropCollectorFactory>>*
45 int_tbl_prop_collector_factories,
46 std::unique_ptr<WritableFileWriter>* writable,
47 std::unique_ptr<TableBuilder>* builder) {
494da23a 48 std::unique_ptr<WritableFile> wf(new test::StringSink);
11fdf7f2
TL
49 writable->reset(
50 new WritableFileWriter(std::move(wf), "" /* don't care */, EnvOptions()));
7c673cae
FG
51 int unknown_level = -1;
52 builder->reset(NewTableBuilder(
11fdf7f2
TL
53 ioptions, moptions, internal_comparator, int_tbl_prop_collector_factories,
54 kTestColumnFamilyId, kTestColumnFamilyName, writable->get(),
494da23a
TL
55 options.compression, options.sample_for_compression,
56 options.compression_opts, unknown_level));
7c673cae
FG
57}
58} // namespace
59
60// Collects keys that starts with "A" in a table.
61class RegularKeysStartWithA: public TablePropertiesCollector {
62 public:
63 const char* Name() const override { return "RegularKeysStartWithA"; }
64
65 Status Finish(UserCollectedProperties* properties) override {
66 std::string encoded;
67 std::string encoded_num_puts;
68 std::string encoded_num_deletes;
69 std::string encoded_num_single_deletes;
70 std::string encoded_num_size_changes;
71 PutVarint32(&encoded, count_);
72 PutVarint32(&encoded_num_puts, num_puts_);
73 PutVarint32(&encoded_num_deletes, num_deletes_);
74 PutVarint32(&encoded_num_single_deletes, num_single_deletes_);
75 PutVarint32(&encoded_num_size_changes, num_size_changes_);
76 *properties = UserCollectedProperties{
77 {"TablePropertiesTest", message_},
78 {"Count", encoded},
79 {"NumPuts", encoded_num_puts},
80 {"NumDeletes", encoded_num_deletes},
81 {"NumSingleDeletes", encoded_num_single_deletes},
82 {"NumSizeChanges", encoded_num_size_changes},
83 };
84 return Status::OK();
85 }
86
11fdf7f2
TL
87 Status AddUserKey(const Slice& user_key, const Slice& /*value*/,
88 EntryType type, SequenceNumber /*seq*/,
89 uint64_t file_size) override {
7c673cae
FG
90 // simply asssume all user keys are not empty.
91 if (user_key.data()[0] == 'A') {
92 ++count_;
93 }
94 if (type == kEntryPut) {
95 num_puts_++;
96 } else if (type == kEntryDelete) {
97 num_deletes_++;
98 } else if (type == kEntrySingleDelete) {
99 num_single_deletes_++;
100 }
101 if (file_size < file_size_) {
102 message_ = "File size should not decrease.";
103 } else if (file_size != file_size_) {
104 num_size_changes_++;
105 }
106
107 return Status::OK();
108 }
109
494da23a 110 UserCollectedProperties GetReadableProperties() const override {
7c673cae
FG
111 return UserCollectedProperties{};
112 }
113
114 private:
115 std::string message_ = "Rocksdb";
116 uint32_t count_ = 0;
117 uint32_t num_puts_ = 0;
118 uint32_t num_deletes_ = 0;
119 uint32_t num_single_deletes_ = 0;
120 uint32_t num_size_changes_ = 0;
121 uint64_t file_size_ = 0;
122};
123
124// Collects keys that starts with "A" in a table. Backward compatible mode
125// It is also used to test internal key table property collector
126class RegularKeysStartWithABackwardCompatible
127 : public TablePropertiesCollector {
128 public:
129 const char* Name() const override { return "RegularKeysStartWithA"; }
130
131 Status Finish(UserCollectedProperties* properties) override {
132 std::string encoded;
133 PutVarint32(&encoded, count_);
134 *properties = UserCollectedProperties{{"TablePropertiesTest", "Rocksdb"},
135 {"Count", encoded}};
136 return Status::OK();
137 }
138
11fdf7f2 139 Status Add(const Slice& user_key, const Slice& /*value*/) override {
7c673cae
FG
140 // simply asssume all user keys are not empty.
141 if (user_key.data()[0] == 'A') {
142 ++count_;
143 }
144 return Status::OK();
145 }
146
494da23a 147 UserCollectedProperties GetReadableProperties() const override {
7c673cae
FG
148 return UserCollectedProperties{};
149 }
150
151 private:
152 uint32_t count_ = 0;
153};
154
155class RegularKeysStartWithAInternal : public IntTblPropCollector {
156 public:
157 const char* Name() const override { return "RegularKeysStartWithA"; }
158
159 Status Finish(UserCollectedProperties* properties) override {
160 std::string encoded;
161 PutVarint32(&encoded, count_);
162 *properties = UserCollectedProperties{{"TablePropertiesTest", "Rocksdb"},
163 {"Count", encoded}};
164 return Status::OK();
165 }
166
11fdf7f2
TL
167 Status InternalAdd(const Slice& user_key, const Slice& /*value*/,
168 uint64_t /*file_size*/) override {
7c673cae
FG
169 // simply asssume all user keys are not empty.
170 if (user_key.data()[0] == 'A') {
171 ++count_;
172 }
173 return Status::OK();
174 }
175
494da23a
TL
176 void BlockAdd(uint64_t /* blockRawBytes */,
177 uint64_t /* blockCompressedBytesFast */,
178 uint64_t /* blockCompressedBytesSlow */) override {
179 // Nothing to do.
180 return;
181 }
182
183 UserCollectedProperties GetReadableProperties() const override {
7c673cae
FG
184 return UserCollectedProperties{};
185 }
186
187 private:
188 uint32_t count_ = 0;
189};
190
191class RegularKeysStartWithAFactory : public IntTblPropCollectorFactory,
192 public TablePropertiesCollectorFactory {
193 public:
194 explicit RegularKeysStartWithAFactory(bool backward_mode)
195 : backward_mode_(backward_mode) {}
494da23a 196 TablePropertiesCollector* CreateTablePropertiesCollector(
7c673cae
FG
197 TablePropertiesCollectorFactory::Context context) override {
198 EXPECT_EQ(kTestColumnFamilyId, context.column_family_id);
199 if (!backward_mode_) {
200 return new RegularKeysStartWithA();
201 } else {
202 return new RegularKeysStartWithABackwardCompatible();
203 }
204 }
494da23a 205 IntTblPropCollector* CreateIntTblPropCollector(
11fdf7f2 206 uint32_t /*column_family_id*/) override {
7c673cae
FG
207 return new RegularKeysStartWithAInternal();
208 }
209 const char* Name() const override { return "RegularKeysStartWithA"; }
210
211 bool backward_mode_;
212};
213
214class FlushBlockEveryThreePolicy : public FlushBlockPolicy {
215 public:
494da23a 216 bool Update(const Slice& /*key*/, const Slice& /*value*/) override {
7c673cae
FG
217 return (++count_ % 3U == 0);
218 }
219
220 private:
221 uint64_t count_ = 0;
222};
223
224class FlushBlockEveryThreePolicyFactory : public FlushBlockPolicyFactory {
225 public:
226 explicit FlushBlockEveryThreePolicyFactory() {}
227
228 const char* Name() const override {
229 return "FlushBlockEveryThreePolicyFactory";
230 }
231
232 FlushBlockPolicy* NewFlushBlockPolicy(
11fdf7f2
TL
233 const BlockBasedTableOptions& /*table_options*/,
234 const BlockBuilder& /*data_block_builder*/) const override {
7c673cae
FG
235 return new FlushBlockEveryThreePolicy;
236 }
237};
238
239extern const uint64_t kBlockBasedTableMagicNumber;
240extern const uint64_t kPlainTableMagicNumber;
241namespace {
242void TestCustomizedTablePropertiesCollector(
243 bool backward_mode, uint64_t magic_number, bool test_int_tbl_prop_collector,
244 const Options& options, const InternalKeyComparator& internal_comparator) {
245 // make sure the entries will be inserted with order.
246 std::map<std::pair<std::string, ValueType>, std::string> kvs = {
247 {{"About ", kTypeValue}, "val5"}, // starts with 'A'
248 {{"Abstract", kTypeValue}, "val2"}, // starts with 'A'
249 {{"Around ", kTypeValue}, "val7"}, // starts with 'A'
250 {{"Beyond ", kTypeValue}, "val3"},
251 {{"Builder ", kTypeValue}, "val1"},
252 {{"Love ", kTypeDeletion}, ""},
253 {{"Cancel ", kTypeValue}, "val4"},
254 {{"Find ", kTypeValue}, "val6"},
255 {{"Rocks ", kTypeDeletion}, ""},
256 {{"Foo ", kTypeSingleDeletion}, ""},
257 };
258
259 // -- Step 1: build table
260 std::unique_ptr<TableBuilder> builder;
261 std::unique_ptr<WritableFileWriter> writer;
262 const ImmutableCFOptions ioptions(options);
11fdf7f2 263 const MutableCFOptions moptions(options);
7c673cae
FG
264 std::vector<std::unique_ptr<IntTblPropCollectorFactory>>
265 int_tbl_prop_collector_factories;
266 if (test_int_tbl_prop_collector) {
267 int_tbl_prop_collector_factories.emplace_back(
268 new RegularKeysStartWithAFactory(backward_mode));
269 } else {
270 GetIntTblPropCollectorFactory(ioptions, &int_tbl_prop_collector_factories);
271 }
11fdf7f2 272 MakeBuilder(options, ioptions, moptions, internal_comparator,
7c673cae
FG
273 &int_tbl_prop_collector_factories, &writer, &builder);
274
275 SequenceNumber seqNum = 0U;
276 for (const auto& kv : kvs) {
277 InternalKey ikey(kv.first.first, seqNum++, kv.first.second);
278 builder->Add(ikey.Encode(), kv.second);
279 }
280 ASSERT_OK(builder->Finish());
281 writer->Flush();
282
283 // -- Step 2: Read properties
284 test::StringSink* fwf =
285 static_cast<test::StringSink*>(writer->writable_file());
286 std::unique_ptr<RandomAccessFileReader> fake_file_reader(
287 test::GetRandomAccessFileReader(
288 new test::StringSource(fwf->contents())));
289 TableProperties* props;
290 Status s = ReadTableProperties(fake_file_reader.get(), fwf->contents().size(),
11fdf7f2
TL
291 magic_number, ioptions, &props,
292 true /* compression_type_missing */);
7c673cae
FG
293 std::unique_ptr<TableProperties> props_guard(props);
294 ASSERT_OK(s);
295
296 auto user_collected = props->user_collected_properties;
297
298 ASSERT_NE(user_collected.find("TablePropertiesTest"), user_collected.end());
299 ASSERT_EQ("Rocksdb", user_collected.at("TablePropertiesTest"));
300
301 uint32_t starts_with_A = 0;
302 ASSERT_NE(user_collected.find("Count"), user_collected.end());
303 Slice key(user_collected.at("Count"));
304 ASSERT_TRUE(GetVarint32(&key, &starts_with_A));
305 ASSERT_EQ(3u, starts_with_A);
306
307 if (!backward_mode && !test_int_tbl_prop_collector) {
308 uint32_t num_puts;
309 ASSERT_NE(user_collected.find("NumPuts"), user_collected.end());
310 Slice key_puts(user_collected.at("NumPuts"));
311 ASSERT_TRUE(GetVarint32(&key_puts, &num_puts));
312 ASSERT_EQ(7u, num_puts);
313
314 uint32_t num_deletes;
315 ASSERT_NE(user_collected.find("NumDeletes"), user_collected.end());
316 Slice key_deletes(user_collected.at("NumDeletes"));
317 ASSERT_TRUE(GetVarint32(&key_deletes, &num_deletes));
318 ASSERT_EQ(2u, num_deletes);
319
320 uint32_t num_single_deletes;
321 ASSERT_NE(user_collected.find("NumSingleDeletes"), user_collected.end());
322 Slice key_single_deletes(user_collected.at("NumSingleDeletes"));
323 ASSERT_TRUE(GetVarint32(&key_single_deletes, &num_single_deletes));
324 ASSERT_EQ(1u, num_single_deletes);
325
326 uint32_t num_size_changes;
327 ASSERT_NE(user_collected.find("NumSizeChanges"), user_collected.end());
328 Slice key_size_changes(user_collected.at("NumSizeChanges"));
329 ASSERT_TRUE(GetVarint32(&key_size_changes, &num_size_changes));
330 ASSERT_GE(num_size_changes, 2u);
331 }
332}
333} // namespace
334
335TEST_P(TablePropertiesTest, CustomizedTablePropertiesCollector) {
336 // Test properties collectors with internal keys or regular keys
337 // for block based table
338 for (bool encode_as_internal : { true, false }) {
339 Options options;
340 BlockBasedTableOptions table_options;
341 table_options.flush_block_policy_factory =
342 std::make_shared<FlushBlockEveryThreePolicyFactory>();
343 options.table_factory.reset(NewBlockBasedTableFactory(table_options));
344
345 test::PlainInternalKeyComparator ikc(options.comparator);
346 std::shared_ptr<TablePropertiesCollectorFactory> collector_factory(
347 new RegularKeysStartWithAFactory(backward_mode_));
348 options.table_properties_collector_factories.resize(1);
349 options.table_properties_collector_factories[0] = collector_factory;
350
351 TestCustomizedTablePropertiesCollector(backward_mode_,
352 kBlockBasedTableMagicNumber,
353 encode_as_internal, options, ikc);
354
355#ifndef ROCKSDB_LITE // PlainTable is not supported in Lite
356 // test plain table
357 PlainTableOptions plain_table_options;
358 plain_table_options.user_key_len = 8;
359 plain_table_options.bloom_bits_per_key = 8;
360 plain_table_options.hash_table_ratio = 0;
361
362 options.table_factory =
363 std::make_shared<PlainTableFactory>(plain_table_options);
364 TestCustomizedTablePropertiesCollector(backward_mode_,
365 kPlainTableMagicNumber,
366 encode_as_internal, options, ikc);
367#endif // !ROCKSDB_LITE
368 }
369}
370
371namespace {
372void TestInternalKeyPropertiesCollector(
373 bool backward_mode, uint64_t magic_number, bool sanitized,
374 std::shared_ptr<TableFactory> table_factory) {
375 InternalKey keys[] = {
376 InternalKey("A ", 0, ValueType::kTypeValue),
377 InternalKey("B ", 1, ValueType::kTypeValue),
378 InternalKey("C ", 2, ValueType::kTypeValue),
379 InternalKey("W ", 3, ValueType::kTypeDeletion),
380 InternalKey("X ", 4, ValueType::kTypeDeletion),
381 InternalKey("Y ", 5, ValueType::kTypeDeletion),
382 InternalKey("Z ", 6, ValueType::kTypeDeletion),
383 InternalKey("a ", 7, ValueType::kTypeSingleDeletion),
384 InternalKey("b ", 8, ValueType::kTypeMerge),
385 InternalKey("c ", 9, ValueType::kTypeMerge),
386 };
387
388 std::unique_ptr<TableBuilder> builder;
389 std::unique_ptr<WritableFileWriter> writable;
390 Options options;
391 test::PlainInternalKeyComparator pikc(options.comparator);
392
393 std::vector<std::unique_ptr<IntTblPropCollectorFactory>>
394 int_tbl_prop_collector_factories;
395 options.table_factory = table_factory;
396 if (sanitized) {
397 options.table_properties_collector_factories.emplace_back(
398 new RegularKeysStartWithAFactory(backward_mode));
399 // with sanitization, even regular properties collector will be able to
400 // handle internal keys.
401 auto comparator = options.comparator;
402 // HACK: Set options.info_log to avoid writing log in
403 // SanitizeOptions().
404 options.info_log = std::make_shared<test::NullLogger>();
405 options = SanitizeOptions("db", // just a place holder
406 options);
407 ImmutableCFOptions ioptions(options);
408 GetIntTblPropCollectorFactory(ioptions, &int_tbl_prop_collector_factories);
409 options.comparator = comparator;
7c673cae
FG
410 }
411 const ImmutableCFOptions ioptions(options);
11fdf7f2 412 MutableCFOptions moptions(options);
7c673cae
FG
413
414 for (int iter = 0; iter < 2; ++iter) {
11fdf7f2
TL
415 MakeBuilder(options, ioptions, moptions, pikc,
416 &int_tbl_prop_collector_factories, &writable, &builder);
7c673cae
FG
417 for (const auto& k : keys) {
418 builder->Add(k.Encode(), "val");
419 }
420
421 ASSERT_OK(builder->Finish());
422 writable->Flush();
423
424 test::StringSink* fwf =
425 static_cast<test::StringSink*>(writable->writable_file());
494da23a
TL
426 std::unique_ptr<RandomAccessFileReader> reader(
427 test::GetRandomAccessFileReader(
428 new test::StringSource(fwf->contents())));
7c673cae
FG
429 TableProperties* props;
430 Status s =
431 ReadTableProperties(reader.get(), fwf->contents().size(), magic_number,
11fdf7f2 432 ioptions, &props, true /* compression_type_missing */);
7c673cae
FG
433 ASSERT_OK(s);
434
435 std::unique_ptr<TableProperties> props_guard(props);
436 auto user_collected = props->user_collected_properties;
437 uint64_t deleted = GetDeletedKeys(user_collected);
438 ASSERT_EQ(5u, deleted); // deletes + single-deletes
439
440 bool property_present;
441 uint64_t merges = GetMergeOperands(user_collected, &property_present);
442 ASSERT_TRUE(property_present);
443 ASSERT_EQ(2u, merges);
444
445 if (sanitized) {
446 uint32_t starts_with_A = 0;
447 ASSERT_NE(user_collected.find("Count"), user_collected.end());
448 Slice key(user_collected.at("Count"));
449 ASSERT_TRUE(GetVarint32(&key, &starts_with_A));
450 ASSERT_EQ(1u, starts_with_A);
451
452 if (!backward_mode) {
453 uint32_t num_puts;
454 ASSERT_NE(user_collected.find("NumPuts"), user_collected.end());
455 Slice key_puts(user_collected.at("NumPuts"));
456 ASSERT_TRUE(GetVarint32(&key_puts, &num_puts));
457 ASSERT_EQ(3u, num_puts);
458
459 uint32_t num_deletes;
460 ASSERT_NE(user_collected.find("NumDeletes"), user_collected.end());
461 Slice key_deletes(user_collected.at("NumDeletes"));
462 ASSERT_TRUE(GetVarint32(&key_deletes, &num_deletes));
463 ASSERT_EQ(4u, num_deletes);
464
465 uint32_t num_single_deletes;
466 ASSERT_NE(user_collected.find("NumSingleDeletes"),
467 user_collected.end());
468 Slice key_single_deletes(user_collected.at("NumSingleDeletes"));
469 ASSERT_TRUE(GetVarint32(&key_single_deletes, &num_single_deletes));
470 ASSERT_EQ(1u, num_single_deletes);
471 }
472 }
473 }
474}
475} // namespace
476
477TEST_P(TablePropertiesTest, InternalKeyPropertiesCollector) {
478 TestInternalKeyPropertiesCollector(
479 backward_mode_, kBlockBasedTableMagicNumber, true /* sanitize */,
480 std::make_shared<BlockBasedTableFactory>());
481 if (backward_mode_) {
482 TestInternalKeyPropertiesCollector(
483 backward_mode_, kBlockBasedTableMagicNumber, false /* not sanitize */,
484 std::make_shared<BlockBasedTableFactory>());
485 }
486
487#ifndef ROCKSDB_LITE // PlainTable is not supported in Lite
488 PlainTableOptions plain_table_options;
489 plain_table_options.user_key_len = 8;
490 plain_table_options.bloom_bits_per_key = 8;
491 plain_table_options.hash_table_ratio = 0;
492
493 TestInternalKeyPropertiesCollector(
494 backward_mode_, kPlainTableMagicNumber, false /* not sanitize */,
495 std::make_shared<PlainTableFactory>(plain_table_options));
496#endif // !ROCKSDB_LITE
497}
498
499INSTANTIATE_TEST_CASE_P(InternalKeyPropertiesCollector, TablePropertiesTest,
500 ::testing::Bool());
501
502INSTANTIATE_TEST_CASE_P(CustomizedTablePropertiesCollector, TablePropertiesTest,
503 ::testing::Bool());
504
505} // namespace rocksdb
506
507int main(int argc, char** argv) {
508 ::testing::InitGoogleTest(&argc, argv);
509 return RUN_ALL_TESTS();
510}