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