]> git.proxmox.com Git - ceph.git/blame - ceph/src/rocksdb/db/version_edit_test.cc
import quincy beta 17.1.0
[ceph.git] / ceph / src / rocksdb / db / version_edit_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// Copyright (c) 2011 The LevelDB Authors. All rights reserved.
7// Use of this source code is governed by a BSD-style license that can be
8// found in the LICENSE file. See the AUTHORS file for names of contributors.
9
10#include "db/version_edit.h"
f67539c2
TL
11#include "test_util/sync_point.h"
12#include "test_util/testharness.h"
494da23a 13#include "util/coding.h"
20effc67 14#include "util/string_util.h"
7c673cae 15
f67539c2 16namespace ROCKSDB_NAMESPACE {
7c673cae
FG
17
18static void TestEncodeDecode(const VersionEdit& edit) {
19 std::string encoded, encoded2;
20 edit.EncodeTo(&encoded);
21 VersionEdit parsed;
22 Status s = parsed.DecodeFrom(encoded);
23 ASSERT_TRUE(s.ok()) << s.ToString();
24 parsed.EncodeTo(&encoded2);
25 ASSERT_EQ(encoded, encoded2);
26}
27
28class VersionEditTest : public testing::Test {};
29
30TEST_F(VersionEditTest, EncodeDecode) {
31 static const uint64_t kBig = 1ull << 50;
32 static const uint32_t kBig32Bit = 1ull << 30;
33
34 VersionEdit edit;
35 for (int i = 0; i < 4; i++) {
36 TestEncodeDecode(edit);
37 edit.AddFile(3, kBig + 300 + i, kBig32Bit + 400 + i, 0,
38 InternalKey("foo", kBig + 500 + i, kTypeValue),
39 InternalKey("zoo", kBig + 600 + i, kTypeDeletion),
f67539c2
TL
40 kBig + 500 + i, kBig + 600 + i, false, kInvalidBlobFileNumber,
41 888, 678, "234", "crc32c");
7c673cae
FG
42 edit.DeleteFile(4, kBig + 700 + i);
43 }
44
45 edit.SetComparatorName("foo");
46 edit.SetLogNumber(kBig + 100);
47 edit.SetNextFile(kBig + 200);
48 edit.SetLastSequence(kBig + 1000);
49 TestEncodeDecode(edit);
50}
51
52TEST_F(VersionEditTest, EncodeDecodeNewFile4) {
53 static const uint64_t kBig = 1ull << 50;
54
55 VersionEdit edit;
56 edit.AddFile(3, 300, 3, 100, InternalKey("foo", kBig + 500, kTypeValue),
57 InternalKey("zoo", kBig + 600, kTypeDeletion), kBig + 500,
f67539c2
TL
58 kBig + 600, true, kInvalidBlobFileNumber,
59 kUnknownOldestAncesterTime, kUnknownFileCreationTime,
60 kUnknownFileChecksum, kUnknownFileChecksumFuncName);
7c673cae
FG
61 edit.AddFile(4, 301, 3, 100, InternalKey("foo", kBig + 501, kTypeValue),
62 InternalKey("zoo", kBig + 601, kTypeDeletion), kBig + 501,
f67539c2
TL
63 kBig + 601, false, kInvalidBlobFileNumber,
64 kUnknownOldestAncesterTime, kUnknownFileCreationTime,
65 kUnknownFileChecksum, kUnknownFileChecksumFuncName);
7c673cae
FG
66 edit.AddFile(5, 302, 0, 100, InternalKey("foo", kBig + 502, kTypeValue),
67 InternalKey("zoo", kBig + 602, kTypeDeletion), kBig + 502,
f67539c2
TL
68 kBig + 602, true, kInvalidBlobFileNumber, 666, 888,
69 kUnknownFileChecksum, kUnknownFileChecksumFuncName);
70 edit.AddFile(5, 303, 0, 100, InternalKey("foo", kBig + 503, kTypeBlobIndex),
71 InternalKey("zoo", kBig + 603, kTypeBlobIndex), kBig + 503,
72 kBig + 603, true, 1001, kUnknownOldestAncesterTime,
73 kUnknownFileCreationTime, kUnknownFileChecksum,
74 kUnknownFileChecksumFuncName);
75 ;
7c673cae
FG
76
77 edit.DeleteFile(4, 700);
78
79 edit.SetComparatorName("foo");
80 edit.SetLogNumber(kBig + 100);
81 edit.SetNextFile(kBig + 200);
82 edit.SetLastSequence(kBig + 1000);
83 TestEncodeDecode(edit);
84
85 std::string encoded, encoded2;
86 edit.EncodeTo(&encoded);
87 VersionEdit parsed;
88 Status s = parsed.DecodeFrom(encoded);
89 ASSERT_TRUE(s.ok()) << s.ToString();
90 auto& new_files = parsed.GetNewFiles();
91 ASSERT_TRUE(new_files[0].second.marked_for_compaction);
92 ASSERT_TRUE(!new_files[1].second.marked_for_compaction);
93 ASSERT_TRUE(new_files[2].second.marked_for_compaction);
f67539c2
TL
94 ASSERT_TRUE(new_files[3].second.marked_for_compaction);
95 ASSERT_EQ(3u, new_files[0].second.fd.GetPathId());
96 ASSERT_EQ(3u, new_files[1].second.fd.GetPathId());
97 ASSERT_EQ(0u, new_files[2].second.fd.GetPathId());
98 ASSERT_EQ(0u, new_files[3].second.fd.GetPathId());
99 ASSERT_EQ(kInvalidBlobFileNumber,
100 new_files[0].second.oldest_blob_file_number);
101 ASSERT_EQ(kInvalidBlobFileNumber,
102 new_files[1].second.oldest_blob_file_number);
103 ASSERT_EQ(kInvalidBlobFileNumber,
104 new_files[2].second.oldest_blob_file_number);
105 ASSERT_EQ(1001, new_files[3].second.oldest_blob_file_number);
7c673cae
FG
106}
107
108TEST_F(VersionEditTest, ForwardCompatibleNewFile4) {
109 static const uint64_t kBig = 1ull << 50;
110 VersionEdit edit;
111 edit.AddFile(3, 300, 3, 100, InternalKey("foo", kBig + 500, kTypeValue),
112 InternalKey("zoo", kBig + 600, kTypeDeletion), kBig + 500,
f67539c2
TL
113 kBig + 600, true, kInvalidBlobFileNumber,
114 kUnknownOldestAncesterTime, kUnknownFileCreationTime,
115 kUnknownFileChecksum, kUnknownFileChecksumFuncName);
7c673cae
FG
116 edit.AddFile(4, 301, 3, 100, InternalKey("foo", kBig + 501, kTypeValue),
117 InternalKey("zoo", kBig + 601, kTypeDeletion), kBig + 501,
f67539c2
TL
118 kBig + 601, false, kInvalidBlobFileNumber, 686, 868, "234",
119 "crc32c");
7c673cae
FG
120 edit.DeleteFile(4, 700);
121
122 edit.SetComparatorName("foo");
123 edit.SetLogNumber(kBig + 100);
124 edit.SetNextFile(kBig + 200);
125 edit.SetLastSequence(kBig + 1000);
126
127 std::string encoded;
128
129 // Call back function to add extra customized builds.
130 bool first = true;
f67539c2 131 ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->SetCallBack(
7c673cae
FG
132 "VersionEdit::EncodeTo:NewFile4:CustomizeFields", [&](void* arg) {
133 std::string* str = reinterpret_cast<std::string*>(arg);
134 PutVarint32(str, 33);
135 const std::string str1 = "random_string";
136 PutLengthPrefixedSlice(str, str1);
137 if (first) {
138 first = false;
139 PutVarint32(str, 22);
140 const std::string str2 = "s";
141 PutLengthPrefixedSlice(str, str2);
142 }
143 });
f67539c2 144 ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->EnableProcessing();
7c673cae 145 edit.EncodeTo(&encoded);
f67539c2 146 ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->DisableProcessing();
7c673cae
FG
147
148 VersionEdit parsed;
149 Status s = parsed.DecodeFrom(encoded);
150 ASSERT_TRUE(s.ok()) << s.ToString();
151 ASSERT_TRUE(!first);
152 auto& new_files = parsed.GetNewFiles();
153 ASSERT_TRUE(new_files[0].second.marked_for_compaction);
154 ASSERT_TRUE(!new_files[1].second.marked_for_compaction);
f67539c2
TL
155 ASSERT_EQ(3u, new_files[0].second.fd.GetPathId());
156 ASSERT_EQ(3u, new_files[1].second.fd.GetPathId());
7c673cae
FG
157 ASSERT_EQ(1u, parsed.GetDeletedFiles().size());
158}
159
160TEST_F(VersionEditTest, NewFile4NotSupportedField) {
161 static const uint64_t kBig = 1ull << 50;
162 VersionEdit edit;
163 edit.AddFile(3, 300, 3, 100, InternalKey("foo", kBig + 500, kTypeValue),
164 InternalKey("zoo", kBig + 600, kTypeDeletion), kBig + 500,
f67539c2
TL
165 kBig + 600, true, kInvalidBlobFileNumber,
166 kUnknownOldestAncesterTime, kUnknownFileCreationTime,
167 kUnknownFileChecksum, kUnknownFileChecksumFuncName);
7c673cae
FG
168
169 edit.SetComparatorName("foo");
170 edit.SetLogNumber(kBig + 100);
171 edit.SetNextFile(kBig + 200);
172 edit.SetLastSequence(kBig + 1000);
173
174 std::string encoded;
175
176 // Call back function to add extra customized builds.
f67539c2 177 ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->SetCallBack(
7c673cae
FG
178 "VersionEdit::EncodeTo:NewFile4:CustomizeFields", [&](void* arg) {
179 std::string* str = reinterpret_cast<std::string*>(arg);
180 const std::string str1 = "s";
181 PutLengthPrefixedSlice(str, str1);
182 });
f67539c2 183 ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->EnableProcessing();
7c673cae 184 edit.EncodeTo(&encoded);
f67539c2 185 ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->DisableProcessing();
7c673cae
FG
186
187 VersionEdit parsed;
188 Status s = parsed.DecodeFrom(encoded);
189 ASSERT_NOK(s);
190}
191
192TEST_F(VersionEditTest, EncodeEmptyFile) {
193 VersionEdit edit;
f67539c2
TL
194 edit.AddFile(0, 0, 0, 0, InternalKey(), InternalKey(), 0, 0, false,
195 kInvalidBlobFileNumber, kUnknownOldestAncesterTime,
196 kUnknownFileCreationTime, kUnknownFileChecksum,
197 kUnknownFileChecksumFuncName);
7c673cae
FG
198 std::string buffer;
199 ASSERT_TRUE(!edit.EncodeTo(&buffer));
200}
201
202TEST_F(VersionEditTest, ColumnFamilyTest) {
203 VersionEdit edit;
204 edit.SetColumnFamily(2);
205 edit.AddColumnFamily("column_family");
206 edit.SetMaxColumnFamily(5);
207 TestEncodeDecode(edit);
208
209 edit.Clear();
210 edit.SetColumnFamily(3);
211 edit.DropColumnFamily();
212 TestEncodeDecode(edit);
213}
214
11fdf7f2
TL
215TEST_F(VersionEditTest, MinLogNumberToKeep) {
216 VersionEdit edit;
217 edit.SetMinLogNumberToKeep(13);
218 TestEncodeDecode(edit);
219
220 edit.Clear();
221 edit.SetMinLogNumberToKeep(23);
222 TestEncodeDecode(edit);
223}
224
225TEST_F(VersionEditTest, AtomicGroupTest) {
226 VersionEdit edit;
227 edit.MarkAtomicGroup(1);
228 TestEncodeDecode(edit);
229}
230
494da23a
TL
231TEST_F(VersionEditTest, IgnorableField) {
232 VersionEdit ve;
233 std::string encoded;
234
235 // Size of ignorable field is too large
236 PutVarint32Varint64(&encoded, 2 /* kLogNumber */, 66);
237 // This is a customized ignorable tag
238 PutVarint32Varint64(&encoded,
239 0x2710 /* A field with kTagSafeIgnoreMask set */,
240 5 /* fieldlength 5 */);
241 encoded += "abc"; // Only fills 3 bytes,
242 ASSERT_NOK(ve.DecodeFrom(encoded));
243
244 encoded.clear();
245 // Error when seeing unidentified tag that is not ignorable
246 PutVarint32Varint64(&encoded, 2 /* kLogNumber */, 66);
247 // This is a customized ignorable tag
248 PutVarint32Varint64(&encoded, 666 /* A field with kTagSafeIgnoreMask unset */,
249 3 /* fieldlength 3 */);
250 encoded += "abc"; // Fill 3 bytes
251 PutVarint32Varint64(&encoded, 3 /* next file number */, 88);
252 ASSERT_NOK(ve.DecodeFrom(encoded));
253
254 // Safely ignore an identified but safely ignorable entry
255 encoded.clear();
256 PutVarint32Varint64(&encoded, 2 /* kLogNumber */, 66);
257 // This is a customized ignorable tag
258 PutVarint32Varint64(&encoded,
259 0x2710 /* A field with kTagSafeIgnoreMask set */,
260 3 /* fieldlength 3 */);
261 encoded += "abc"; // Fill 3 bytes
262 PutVarint32Varint64(&encoded, 3 /* kNextFileNumber */, 88);
263
264 ASSERT_OK(ve.DecodeFrom(encoded));
265
f67539c2
TL
266 ASSERT_TRUE(ve.HasLogNumber());
267 ASSERT_TRUE(ve.HasNextFile());
268 ASSERT_EQ(66, ve.GetLogNumber());
269 ASSERT_EQ(88, ve.GetNextFile());
494da23a
TL
270}
271
f67539c2
TL
272TEST_F(VersionEditTest, DbId) {
273 VersionEdit edit;
274 edit.SetDBId("ab34-cd12-435f-er00");
275 TestEncodeDecode(edit);
276
277 edit.Clear();
278 edit.SetDBId("34ba-cd12-435f-er01");
279 TestEncodeDecode(edit);
280}
281
20effc67
TL
282TEST_F(VersionEditTest, BlobFileAdditionAndGarbage) {
283 VersionEdit edit;
284
285 const std::string checksum_method_prefix = "Hash";
286 const std::string checksum_value_prefix = "Value";
287
288 for (uint64_t blob_file_number = 1; blob_file_number <= 10;
289 ++blob_file_number) {
290 const uint64_t total_blob_count = blob_file_number << 10;
291 const uint64_t total_blob_bytes = blob_file_number << 20;
292
293 std::string checksum_method(checksum_method_prefix);
294 AppendNumberTo(&checksum_method, blob_file_number);
295
296 std::string checksum_value(checksum_value_prefix);
297 AppendNumberTo(&checksum_value, blob_file_number);
298
299 edit.AddBlobFile(blob_file_number, total_blob_count, total_blob_bytes,
300 checksum_method, checksum_value);
301
302 const uint64_t garbage_blob_count = total_blob_count >> 2;
303 const uint64_t garbage_blob_bytes = total_blob_bytes >> 1;
304
305 edit.AddBlobFileGarbage(blob_file_number, garbage_blob_count,
306 garbage_blob_bytes);
307 }
308
309 TestEncodeDecode(edit);
310}
311
312TEST_F(VersionEditTest, AddWalEncodeDecode) {
313 VersionEdit edit;
314 for (uint64_t log_number = 1; log_number <= 20; log_number++) {
315 WalMetadata meta;
316 bool has_size = rand() % 2 == 0;
317 if (has_size) {
318 meta.SetSyncedSizeInBytes(rand() % 1000);
319 }
320 edit.AddWal(log_number, meta);
321 }
322 TestEncodeDecode(edit);
323}
324
325TEST_F(VersionEditTest, AddWalDecodeBadLogNumber) {
326 std::string encoded;
327 PutVarint32(&encoded, Tag::kWalAddition);
328
329 {
330 // No log number.
331 VersionEdit edit;
332 Status s = edit.DecodeFrom(encoded);
333 ASSERT_TRUE(s.IsCorruption());
334 ASSERT_TRUE(s.ToString().find("Error decoding WAL log number") !=
335 std::string::npos)
336 << s.ToString();
337 }
338
339 {
340 // log number should be varint64,
341 // but we only encode 128 which is not a valid representation of varint64.
342 char c = 0;
343 unsigned char* ptr = reinterpret_cast<unsigned char*>(&c);
344 *ptr = 128;
345 encoded.append(1, c);
346 VersionEdit edit;
347 Status s = edit.DecodeFrom(encoded);
348 ASSERT_TRUE(s.IsCorruption());
349 ASSERT_TRUE(s.ToString().find("Error decoding WAL log number") !=
350 std::string::npos)
351 << s.ToString();
352 }
353}
354
355TEST_F(VersionEditTest, AddWalDecodeBadTag) {
356 constexpr WalNumber kLogNumber = 100;
357 constexpr uint64_t kSizeInBytes = 100;
358
359 std::string encoded_without_tag;
360 PutVarint32(&encoded_without_tag, Tag::kWalAddition);
361 PutVarint64(&encoded_without_tag, kLogNumber);
362
363 {
364 // No tag.
365 VersionEdit edit;
366 Status s = edit.DecodeFrom(encoded_without_tag);
367 ASSERT_TRUE(s.IsCorruption());
368 ASSERT_TRUE(s.ToString().find("Error decoding tag") != std::string::npos)
369 << s.ToString();
370 }
371
372 {
373 // Only has size tag, no terminate tag.
374 std::string encoded_with_size = encoded_without_tag;
375 PutVarint32(&encoded_with_size,
376 static_cast<uint32_t>(WalAdditionTag::kSyncedSize));
377 PutVarint64(&encoded_with_size, kSizeInBytes);
378 VersionEdit edit;
379 Status s = edit.DecodeFrom(encoded_with_size);
380 ASSERT_TRUE(s.IsCorruption());
381 ASSERT_TRUE(s.ToString().find("Error decoding tag") != std::string::npos)
382 << s.ToString();
383 }
384
385 {
386 // Only has terminate tag.
387 std::string encoded_with_terminate = encoded_without_tag;
388 PutVarint32(&encoded_with_terminate,
389 static_cast<uint32_t>(WalAdditionTag::kTerminate));
390 VersionEdit edit;
391 ASSERT_OK(edit.DecodeFrom(encoded_with_terminate));
392 auto& wal_addition = edit.GetWalAdditions()[0];
393 ASSERT_EQ(wal_addition.GetLogNumber(), kLogNumber);
394 ASSERT_FALSE(wal_addition.GetMetadata().HasSyncedSize());
395 }
396}
397
398TEST_F(VersionEditTest, AddWalDecodeNoSize) {
399 constexpr WalNumber kLogNumber = 100;
400
401 std::string encoded;
402 PutVarint32(&encoded, Tag::kWalAddition);
403 PutVarint64(&encoded, kLogNumber);
404 PutVarint32(&encoded, static_cast<uint32_t>(WalAdditionTag::kSyncedSize));
405 // No real size after the size tag.
406
407 {
408 // Without terminate tag.
409 VersionEdit edit;
410 Status s = edit.DecodeFrom(encoded);
411 ASSERT_TRUE(s.IsCorruption());
412 ASSERT_TRUE(s.ToString().find("Error decoding WAL file size") !=
413 std::string::npos)
414 << s.ToString();
415 }
416
417 {
418 // With terminate tag.
419 PutVarint32(&encoded, static_cast<uint32_t>(WalAdditionTag::kTerminate));
420 VersionEdit edit;
421 Status s = edit.DecodeFrom(encoded);
422 ASSERT_TRUE(s.IsCorruption());
423 // The terminate tag is misunderstood as the size.
424 ASSERT_TRUE(s.ToString().find("Error decoding tag") != std::string::npos)
425 << s.ToString();
426 }
427}
428
429TEST_F(VersionEditTest, AddWalDebug) {
430 constexpr int n = 2;
431 constexpr std::array<uint64_t, n> kLogNumbers{{10, 20}};
432 constexpr std::array<uint64_t, n> kSizeInBytes{{100, 200}};
433
434 VersionEdit edit;
435 for (int i = 0; i < n; i++) {
436 edit.AddWal(kLogNumbers[i], WalMetadata(kSizeInBytes[i]));
437 }
438
439 const WalAdditions& wals = edit.GetWalAdditions();
440
441 ASSERT_TRUE(edit.IsWalAddition());
442 ASSERT_EQ(wals.size(), n);
443 for (int i = 0; i < n; i++) {
444 const WalAddition& wal = wals[i];
445 ASSERT_EQ(wal.GetLogNumber(), kLogNumbers[i]);
446 ASSERT_EQ(wal.GetMetadata().GetSyncedSizeInBytes(), kSizeInBytes[i]);
447 }
448
449 std::string expected_str = "VersionEdit {\n";
450 for (int i = 0; i < n; i++) {
451 std::stringstream ss;
452 ss << " WalAddition: log_number: " << kLogNumbers[i]
453 << " synced_size_in_bytes: " << kSizeInBytes[i] << "\n";
454 expected_str += ss.str();
455 }
456 expected_str += " ColumnFamily: 0\n}\n";
457 ASSERT_EQ(edit.DebugString(true), expected_str);
458
459 std::string expected_json = "{\"EditNumber\": 4, \"WalAdditions\": [";
460 for (int i = 0; i < n; i++) {
461 std::stringstream ss;
462 ss << "{\"LogNumber\": " << kLogNumbers[i] << ", "
463 << "\"SyncedSizeInBytes\": " << kSizeInBytes[i] << "}";
464 if (i < n - 1) ss << ", ";
465 expected_json += ss.str();
466 }
467 expected_json += "], \"ColumnFamily\": 0}";
468 ASSERT_EQ(edit.DebugJSON(4, true), expected_json);
469}
470
471TEST_F(VersionEditTest, DeleteWalEncodeDecode) {
472 VersionEdit edit;
473 edit.DeleteWalsBefore(rand() % 100);
474 TestEncodeDecode(edit);
475}
476
477TEST_F(VersionEditTest, DeleteWalDebug) {
478 constexpr int n = 2;
479 constexpr std::array<uint64_t, n> kLogNumbers{{10, 20}};
480
481 VersionEdit edit;
482 edit.DeleteWalsBefore(kLogNumbers[n - 1]);
483
484 const WalDeletion& wal = edit.GetWalDeletion();
485
486 ASSERT_TRUE(edit.IsWalDeletion());
487 ASSERT_EQ(wal.GetLogNumber(), kLogNumbers[n - 1]);
488
489 std::string expected_str = "VersionEdit {\n";
490 {
491 std::stringstream ss;
492 ss << " WalDeletion: log_number: " << kLogNumbers[n - 1] << "\n";
493 expected_str += ss.str();
494 }
495 expected_str += " ColumnFamily: 0\n}\n";
496 ASSERT_EQ(edit.DebugString(true), expected_str);
497
498 std::string expected_json = "{\"EditNumber\": 4, \"WalDeletion\": ";
499 {
500 std::stringstream ss;
501 ss << "{\"LogNumber\": " << kLogNumbers[n - 1] << "}";
502 expected_json += ss.str();
503 }
504 expected_json += ", \"ColumnFamily\": 0}";
505 ASSERT_EQ(edit.DebugJSON(4, true), expected_json);
506}
507
f67539c2 508} // namespace ROCKSDB_NAMESPACE
7c673cae
FG
509
510int main(int argc, char** argv) {
511 ::testing::InitGoogleTest(&argc, argv);
512 return RUN_ALL_TESTS();
513}