]> git.proxmox.com Git - ceph.git/blame - ceph/src/rocksdb/db/cuckoo_table_db_test.cc
bump version to 18.2.2-pve1
[ceph.git] / ceph / src / rocksdb / db / cuckoo_table_db_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
7
f67539c2 8#include "db/db_impl/db_impl.h"
1e59de90 9#include "db/db_test_util.h"
7c673cae
FG
10#include "rocksdb/db.h"
11#include "rocksdb/env.h"
f67539c2
TL
12#include "table/cuckoo/cuckoo_table_factory.h"
13#include "table/cuckoo/cuckoo_table_reader.h"
7c673cae 14#include "table/meta_blocks.h"
f67539c2
TL
15#include "test_util/testharness.h"
16#include "test_util/testutil.h"
20effc67 17#include "util/cast_util.h"
7c673cae 18#include "util/string_util.h"
7c673cae 19
f67539c2 20namespace ROCKSDB_NAMESPACE {
7c673cae
FG
21
22class CuckooTableDBTest : public testing::Test {
23 private:
24 std::string dbname_;
25 Env* env_;
26 DB* db_;
27
28 public:
29 CuckooTableDBTest() : env_(Env::Default()) {
11fdf7f2 30 dbname_ = test::PerThreadDBPath("cuckoo_table_db_test");
7c673cae
FG
31 EXPECT_OK(DestroyDB(dbname_, Options()));
32 db_ = nullptr;
33 Reopen();
34 }
35
494da23a 36 ~CuckooTableDBTest() override {
7c673cae
FG
37 delete db_;
38 EXPECT_OK(DestroyDB(dbname_, Options()));
39 }
40
41 Options CurrentOptions() {
42 Options options;
43 options.table_factory.reset(NewCuckooTableFactory());
44 options.memtable_factory.reset(NewHashLinkListRepFactory(4, 0, 3, true));
45 options.allow_mmap_reads = true;
46 options.create_if_missing = true;
47 options.allow_concurrent_memtable_write = false;
48 return options;
49 }
50
20effc67 51 DBImpl* dbfull() { return static_cast_with_check<DBImpl>(db_); }
7c673cae
FG
52
53 // The following util methods are copied from plain_table_db_test.
54 void Reopen(Options* options = nullptr) {
55 delete db_;
56 db_ = nullptr;
57 Options opts;
58 if (options != nullptr) {
59 opts = *options;
60 } else {
61 opts = CurrentOptions();
62 opts.create_if_missing = true;
63 }
64 ASSERT_OK(DB::Open(opts, dbname_, &db_));
65 }
66
20effc67
TL
67 void DestroyAndReopen(Options* options) {
68 assert(options);
69 ASSERT_OK(db_->Close());
70 delete db_;
71 db_ = nullptr;
72 ASSERT_OK(DestroyDB(dbname_, *options));
73 Reopen(options);
74 }
75
7c673cae
FG
76 Status Put(const Slice& k, const Slice& v) {
77 return db_->Put(WriteOptions(), k, v);
78 }
79
1e59de90 80 Status Delete(const std::string& k) { return db_->Delete(WriteOptions(), k); }
7c673cae
FG
81
82 std::string Get(const std::string& k) {
83 ReadOptions options;
84 std::string result;
85 Status s = db_->Get(options, k, &result);
86 if (s.IsNotFound()) {
87 result = "NOT_FOUND";
88 } else if (!s.ok()) {
89 result = s.ToString();
90 }
91 return result;
92 }
93
94 int NumTableFilesAtLevel(int level) {
95 std::string property;
96 EXPECT_TRUE(db_->GetProperty(
1e59de90 97 "rocksdb.num-files-at-level" + std::to_string(level), &property));
7c673cae
FG
98 return atoi(property.c_str());
99 }
100
101 // Return spread of files per level
102 std::string FilesPerLevel() {
103 std::string result;
104 size_t last_non_zero_offset = 0;
105 for (int level = 0; level < db_->NumberLevels(); level++) {
106 int f = NumTableFilesAtLevel(level);
107 char buf[100];
108 snprintf(buf, sizeof(buf), "%s%d", (level ? "," : ""), f);
109 result += buf;
110 if (f > 0) {
111 last_non_zero_offset = result.size();
112 }
113 }
114 result.resize(last_non_zero_offset);
115 return result;
116 }
117};
118
119TEST_F(CuckooTableDBTest, Flush) {
120 // Try with empty DB first.
121 ASSERT_TRUE(dbfull() != nullptr);
122 ASSERT_EQ("NOT_FOUND", Get("key2"));
123
124 // Add some values to db.
125 Options options = CurrentOptions();
126 Reopen(&options);
127
128 ASSERT_OK(Put("key1", "v1"));
129 ASSERT_OK(Put("key2", "v2"));
130 ASSERT_OK(Put("key3", "v3"));
1e59de90 131 ASSERT_OK(dbfull()->TEST_FlushMemTable());
7c673cae
FG
132
133 TablePropertiesCollection ptc;
1e59de90
TL
134 ASSERT_OK(reinterpret_cast<DB*>(dbfull())->GetPropertiesOfAllTables(&ptc));
135 VerifySstUniqueIds(ptc);
7c673cae
FG
136 ASSERT_EQ(1U, ptc.size());
137 ASSERT_EQ(3U, ptc.begin()->second->num_entries);
138 ASSERT_EQ("1", FilesPerLevel());
139
140 ASSERT_EQ("v1", Get("key1"));
141 ASSERT_EQ("v2", Get("key2"));
142 ASSERT_EQ("v3", Get("key3"));
143 ASSERT_EQ("NOT_FOUND", Get("key4"));
144
145 // Now add more keys and flush.
146 ASSERT_OK(Put("key4", "v4"));
147 ASSERT_OK(Put("key5", "v5"));
148 ASSERT_OK(Put("key6", "v6"));
1e59de90 149 ASSERT_OK(dbfull()->TEST_FlushMemTable());
7c673cae 150
1e59de90
TL
151 ASSERT_OK(reinterpret_cast<DB*>(dbfull())->GetPropertiesOfAllTables(&ptc));
152 VerifySstUniqueIds(ptc);
7c673cae
FG
153 ASSERT_EQ(2U, ptc.size());
154 auto row = ptc.begin();
155 ASSERT_EQ(3U, row->second->num_entries);
156 ASSERT_EQ(3U, (++row)->second->num_entries);
157 ASSERT_EQ("2", FilesPerLevel());
158 ASSERT_EQ("v1", Get("key1"));
159 ASSERT_EQ("v2", Get("key2"));
160 ASSERT_EQ("v3", Get("key3"));
161 ASSERT_EQ("v4", Get("key4"));
162 ASSERT_EQ("v5", Get("key5"));
163 ASSERT_EQ("v6", Get("key6"));
164
165 ASSERT_OK(Delete("key6"));
166 ASSERT_OK(Delete("key5"));
167 ASSERT_OK(Delete("key4"));
1e59de90
TL
168 ASSERT_OK(dbfull()->TEST_FlushMemTable());
169 ASSERT_OK(reinterpret_cast<DB*>(dbfull())->GetPropertiesOfAllTables(&ptc));
170 VerifySstUniqueIds(ptc);
7c673cae
FG
171 ASSERT_EQ(3U, ptc.size());
172 row = ptc.begin();
173 ASSERT_EQ(3U, row->second->num_entries);
174 ASSERT_EQ(3U, (++row)->second->num_entries);
175 ASSERT_EQ(3U, (++row)->second->num_entries);
176 ASSERT_EQ("3", FilesPerLevel());
177 ASSERT_EQ("v1", Get("key1"));
178 ASSERT_EQ("v2", Get("key2"));
179 ASSERT_EQ("v3", Get("key3"));
180 ASSERT_EQ("NOT_FOUND", Get("key4"));
181 ASSERT_EQ("NOT_FOUND", Get("key5"));
182 ASSERT_EQ("NOT_FOUND", Get("key6"));
183}
184
185TEST_F(CuckooTableDBTest, FlushWithDuplicateKeys) {
186 Options options = CurrentOptions();
187 Reopen(&options);
188 ASSERT_OK(Put("key1", "v1"));
189 ASSERT_OK(Put("key2", "v2"));
190 ASSERT_OK(Put("key1", "v3")); // Duplicate
1e59de90 191 ASSERT_OK(dbfull()->TEST_FlushMemTable());
7c673cae
FG
192
193 TablePropertiesCollection ptc;
1e59de90
TL
194 ASSERT_OK(reinterpret_cast<DB*>(dbfull())->GetPropertiesOfAllTables(&ptc));
195 VerifySstUniqueIds(ptc);
7c673cae
FG
196 ASSERT_EQ(1U, ptc.size());
197 ASSERT_EQ(2U, ptc.begin()->second->num_entries);
198 ASSERT_EQ("1", FilesPerLevel());
199 ASSERT_EQ("v3", Get("key1"));
200 ASSERT_EQ("v2", Get("key2"));
201}
202
203namespace {
204static std::string Key(int i) {
205 char buf[100];
206 snprintf(buf, sizeof(buf), "key_______%06d", i);
207 return std::string(buf);
208}
209static std::string Uint64Key(uint64_t i) {
210 std::string str;
211 str.resize(8);
212 memcpy(&str[0], static_cast<void*>(&i), 8);
213 return str;
214}
215} // namespace.
216
217TEST_F(CuckooTableDBTest, Uint64Comparator) {
218 Options options = CurrentOptions();
219 options.comparator = test::Uint64Comparator();
20effc67 220 DestroyAndReopen(&options);
7c673cae
FG
221
222 ASSERT_OK(Put(Uint64Key(1), "v1"));
223 ASSERT_OK(Put(Uint64Key(2), "v2"));
224 ASSERT_OK(Put(Uint64Key(3), "v3"));
1e59de90 225 ASSERT_OK(dbfull()->TEST_FlushMemTable());
7c673cae
FG
226
227 ASSERT_EQ("v1", Get(Uint64Key(1)));
228 ASSERT_EQ("v2", Get(Uint64Key(2)));
229 ASSERT_EQ("v3", Get(Uint64Key(3)));
230 ASSERT_EQ("NOT_FOUND", Get(Uint64Key(4)));
231
232 // Add more keys.
233 ASSERT_OK(Delete(Uint64Key(2))); // Delete.
1e59de90 234 ASSERT_OK(dbfull()->TEST_FlushMemTable());
7c673cae
FG
235 ASSERT_OK(Put(Uint64Key(3), "v0")); // Update.
236 ASSERT_OK(Put(Uint64Key(4), "v4"));
1e59de90 237 ASSERT_OK(dbfull()->TEST_FlushMemTable());
7c673cae
FG
238 ASSERT_EQ("v1", Get(Uint64Key(1)));
239 ASSERT_EQ("NOT_FOUND", Get(Uint64Key(2)));
240 ASSERT_EQ("v0", Get(Uint64Key(3)));
241 ASSERT_EQ("v4", Get(Uint64Key(4)));
242}
243
244TEST_F(CuckooTableDBTest, CompactionIntoMultipleFiles) {
245 // Create a big L0 file and check it compacts into multiple files in L1.
246 Options options = CurrentOptions();
247 options.write_buffer_size = 270 << 10;
248 // Two SST files should be created, each containing 14 keys.
249 // Number of buckets will be 16. Total size ~156 KB.
250 options.target_file_size_base = 160 << 10;
251 Reopen(&options);
252
253 // Write 28 values, each 10016 B ~ 10KB
254 for (int idx = 0; idx < 28; ++idx) {
11fdf7f2 255 ASSERT_OK(Put(Key(idx), std::string(10000, 'a' + char(idx))));
7c673cae 256 }
1e59de90 257 ASSERT_OK(dbfull()->TEST_WaitForFlushMemTable());
7c673cae
FG
258 ASSERT_EQ("1", FilesPerLevel());
259
1e59de90
TL
260 ASSERT_OK(dbfull()->TEST_CompactRange(0, nullptr, nullptr, nullptr,
261 true /* disallow trivial move */));
7c673cae
FG
262 ASSERT_EQ("0,2", FilesPerLevel());
263 for (int idx = 0; idx < 28; ++idx) {
11fdf7f2 264 ASSERT_EQ(std::string(10000, 'a' + char(idx)), Get(Key(idx)));
7c673cae
FG
265 }
266}
267
268TEST_F(CuckooTableDBTest, SameKeyInsertedInTwoDifferentFilesAndCompacted) {
269 // Insert same key twice so that they go to different SST files. Then wait for
270 // compaction and check if the latest value is stored and old value removed.
271 Options options = CurrentOptions();
272 options.write_buffer_size = 100 << 10; // 100KB
273 options.level0_file_num_compaction_trigger = 2;
274 Reopen(&options);
275
276 // Write 11 values, each 10016 B
277 for (int idx = 0; idx < 11; ++idx) {
278 ASSERT_OK(Put(Key(idx), std::string(10000, 'a')));
279 }
1e59de90 280 ASSERT_OK(dbfull()->TEST_WaitForFlushMemTable());
7c673cae
FG
281 ASSERT_EQ("1", FilesPerLevel());
282
283 // Generate one more file in level-0, and should trigger level-0 compaction
284 for (int idx = 0; idx < 11; ++idx) {
11fdf7f2 285 ASSERT_OK(Put(Key(idx), std::string(10000, 'a' + char(idx))));
7c673cae 286 }
1e59de90
TL
287 ASSERT_OK(dbfull()->TEST_WaitForFlushMemTable());
288 ASSERT_OK(dbfull()->TEST_CompactRange(0, nullptr, nullptr));
7c673cae
FG
289
290 ASSERT_EQ("0,1", FilesPerLevel());
291 for (int idx = 0; idx < 11; ++idx) {
11fdf7f2 292 ASSERT_EQ(std::string(10000, 'a' + char(idx)), Get(Key(idx)));
7c673cae
FG
293 }
294}
295
296TEST_F(CuckooTableDBTest, AdaptiveTable) {
297 Options options = CurrentOptions();
298
f67539c2
TL
299 // Ensure options compatible with PlainTable
300 options.prefix_extractor.reset(NewCappedPrefixTransform(8));
301
7c673cae
FG
302 // Write some keys using cuckoo table.
303 options.table_factory.reset(NewCuckooTableFactory());
304 Reopen(&options);
305
306 ASSERT_OK(Put("key1", "v1"));
307 ASSERT_OK(Put("key2", "v2"));
308 ASSERT_OK(Put("key3", "v3"));
1e59de90 309 ASSERT_OK(dbfull()->TEST_FlushMemTable());
7c673cae
FG
310
311 // Write some keys using plain table.
f67539c2
TL
312 std::shared_ptr<TableFactory> block_based_factory(
313 NewBlockBasedTableFactory());
1e59de90
TL
314 std::shared_ptr<TableFactory> plain_table_factory(NewPlainTableFactory());
315 std::shared_ptr<TableFactory> cuckoo_table_factory(NewCuckooTableFactory());
7c673cae 316 options.create_if_missing = false;
1e59de90
TL
317 options.table_factory.reset(
318 NewAdaptiveTableFactory(plain_table_factory, block_based_factory,
319 plain_table_factory, cuckoo_table_factory));
7c673cae
FG
320 Reopen(&options);
321 ASSERT_OK(Put("key4", "v4"));
322 ASSERT_OK(Put("key1", "v5"));
1e59de90 323 ASSERT_OK(dbfull()->TEST_FlushMemTable());
7c673cae
FG
324
325 // Write some keys using block based table.
1e59de90
TL
326 options.table_factory.reset(
327 NewAdaptiveTableFactory(block_based_factory, block_based_factory,
328 plain_table_factory, cuckoo_table_factory));
7c673cae
FG
329 Reopen(&options);
330 ASSERT_OK(Put("key5", "v6"));
331 ASSERT_OK(Put("key2", "v7"));
1e59de90 332 ASSERT_OK(dbfull()->TEST_FlushMemTable());
7c673cae
FG
333
334 ASSERT_EQ("v5", Get("key1"));
335 ASSERT_EQ("v7", Get("key2"));
336 ASSERT_EQ("v3", Get("key3"));
337 ASSERT_EQ("v4", Get("key4"));
338 ASSERT_EQ("v6", Get("key5"));
339}
f67539c2 340} // namespace ROCKSDB_NAMESPACE
7c673cae
FG
341
342int main(int argc, char** argv) {
f67539c2 343 if (ROCKSDB_NAMESPACE::port::kLittleEndian) {
1e59de90 344 ROCKSDB_NAMESPACE::port::InstallStackTraceHandler();
7c673cae
FG
345 ::testing::InitGoogleTest(&argc, argv);
346 return RUN_ALL_TESTS();
f67539c2 347 } else {
7c673cae
FG
348 fprintf(stderr, "SKIPPED as Cuckoo table doesn't support Big Endian\n");
349 return 0;
350 }
351}
352
353#else
354#include <stdio.h>
355
11fdf7f2 356int main(int /*argc*/, char** /*argv*/) {
7c673cae
FG
357 fprintf(stderr, "SKIPPED as Cuckoo table is not supported in ROCKSDB_LITE\n");
358 return 0;
359}
360
361#endif // ROCKSDB_LITE