blob_file_garbage_test.cc 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174
  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. #include "db/blob/blob_file_garbage.h"
  6. #include <cstdint>
  7. #include <cstring>
  8. #include <string>
  9. #include "test_util/sync_point.h"
  10. #include "test_util/testharness.h"
  11. #include "util/coding.h"
  12. namespace ROCKSDB_NAMESPACE {
  13. class BlobFileGarbageTest : public testing::Test {
  14. public:
  15. static void TestEncodeDecode(const BlobFileGarbage& blob_file_garbage) {
  16. std::string encoded;
  17. blob_file_garbage.EncodeTo(&encoded);
  18. BlobFileGarbage decoded;
  19. Slice input(encoded);
  20. ASSERT_OK(decoded.DecodeFrom(&input));
  21. ASSERT_EQ(blob_file_garbage, decoded);
  22. }
  23. };
  24. TEST_F(BlobFileGarbageTest, Empty) {
  25. BlobFileGarbage blob_file_garbage;
  26. ASSERT_EQ(blob_file_garbage.GetBlobFileNumber(), kInvalidBlobFileNumber);
  27. ASSERT_EQ(blob_file_garbage.GetGarbageBlobCount(), 0);
  28. ASSERT_EQ(blob_file_garbage.GetGarbageBlobBytes(), 0);
  29. TestEncodeDecode(blob_file_garbage);
  30. }
  31. TEST_F(BlobFileGarbageTest, NonEmpty) {
  32. constexpr uint64_t blob_file_number = 123;
  33. constexpr uint64_t garbage_blob_count = 1;
  34. constexpr uint64_t garbage_blob_bytes = 9876;
  35. BlobFileGarbage blob_file_garbage(blob_file_number, garbage_blob_count,
  36. garbage_blob_bytes);
  37. ASSERT_EQ(blob_file_garbage.GetBlobFileNumber(), blob_file_number);
  38. ASSERT_EQ(blob_file_garbage.GetGarbageBlobCount(), garbage_blob_count);
  39. ASSERT_EQ(blob_file_garbage.GetGarbageBlobBytes(), garbage_blob_bytes);
  40. TestEncodeDecode(blob_file_garbage);
  41. }
  42. TEST_F(BlobFileGarbageTest, DecodeErrors) {
  43. std::string str;
  44. Slice slice(str);
  45. BlobFileGarbage blob_file_garbage;
  46. {
  47. const Status s = blob_file_garbage.DecodeFrom(&slice);
  48. ASSERT_TRUE(s.IsCorruption());
  49. ASSERT_TRUE(std::strstr(s.getState(), "blob file number"));
  50. }
  51. constexpr uint64_t blob_file_number = 123;
  52. PutVarint64(&str, blob_file_number);
  53. slice = str;
  54. {
  55. const Status s = blob_file_garbage.DecodeFrom(&slice);
  56. ASSERT_TRUE(s.IsCorruption());
  57. ASSERT_TRUE(std::strstr(s.getState(), "garbage blob count"));
  58. }
  59. constexpr uint64_t garbage_blob_count = 4567;
  60. PutVarint64(&str, garbage_blob_count);
  61. slice = str;
  62. {
  63. const Status s = blob_file_garbage.DecodeFrom(&slice);
  64. ASSERT_TRUE(s.IsCorruption());
  65. ASSERT_TRUE(std::strstr(s.getState(), "garbage blob bytes"));
  66. }
  67. constexpr uint64_t garbage_blob_bytes = 12345678;
  68. PutVarint64(&str, garbage_blob_bytes);
  69. slice = str;
  70. {
  71. const Status s = blob_file_garbage.DecodeFrom(&slice);
  72. ASSERT_TRUE(s.IsCorruption());
  73. ASSERT_TRUE(std::strstr(s.getState(), "custom field tag"));
  74. }
  75. constexpr uint32_t custom_tag = 2;
  76. PutVarint32(&str, custom_tag);
  77. slice = str;
  78. {
  79. const Status s = blob_file_garbage.DecodeFrom(&slice);
  80. ASSERT_TRUE(s.IsCorruption());
  81. ASSERT_TRUE(std::strstr(s.getState(), "custom field value"));
  82. }
  83. }
  84. TEST_F(BlobFileGarbageTest, ForwardCompatibleCustomField) {
  85. SyncPoint::GetInstance()->SetCallBack(
  86. "BlobFileGarbage::EncodeTo::CustomFields", [&](void* arg) {
  87. std::string* output = static_cast<std::string*>(arg);
  88. constexpr uint32_t forward_compatible_tag = 2;
  89. PutVarint32(output, forward_compatible_tag);
  90. PutLengthPrefixedSlice(output, "deadbeef");
  91. });
  92. SyncPoint::GetInstance()->EnableProcessing();
  93. constexpr uint64_t blob_file_number = 678;
  94. constexpr uint64_t garbage_blob_count = 9999;
  95. constexpr uint64_t garbage_blob_bytes = 100000000;
  96. BlobFileGarbage blob_file_garbage(blob_file_number, garbage_blob_count,
  97. garbage_blob_bytes);
  98. TestEncodeDecode(blob_file_garbage);
  99. SyncPoint::GetInstance()->DisableProcessing();
  100. SyncPoint::GetInstance()->ClearAllCallBacks();
  101. }
  102. TEST_F(BlobFileGarbageTest, ForwardIncompatibleCustomField) {
  103. SyncPoint::GetInstance()->SetCallBack(
  104. "BlobFileGarbage::EncodeTo::CustomFields", [&](void* arg) {
  105. std::string* output = static_cast<std::string*>(arg);
  106. constexpr uint32_t forward_incompatible_tag = (1 << 6) + 1;
  107. PutVarint32(output, forward_incompatible_tag);
  108. PutLengthPrefixedSlice(output, "foobar");
  109. });
  110. SyncPoint::GetInstance()->EnableProcessing();
  111. constexpr uint64_t blob_file_number = 456;
  112. constexpr uint64_t garbage_blob_count = 100;
  113. constexpr uint64_t garbage_blob_bytes = 2000000;
  114. BlobFileGarbage blob_file_garbage(blob_file_number, garbage_blob_count,
  115. garbage_blob_bytes);
  116. std::string encoded;
  117. blob_file_garbage.EncodeTo(&encoded);
  118. BlobFileGarbage decoded_blob_file_addition;
  119. Slice input(encoded);
  120. const Status s = decoded_blob_file_addition.DecodeFrom(&input);
  121. ASSERT_TRUE(s.IsCorruption());
  122. ASSERT_TRUE(std::strstr(s.getState(), "Forward incompatible"));
  123. SyncPoint::GetInstance()->DisableProcessing();
  124. SyncPoint::GetInstance()->ClearAllCallBacks();
  125. }
  126. } // namespace ROCKSDB_NAMESPACE
  127. int main(int argc, char** argv) {
  128. ROCKSDB_NAMESPACE::port::InstallStackTraceHandler();
  129. ::testing::InitGoogleTest(&argc, argv);
  130. return RUN_ALL_TESTS();
  131. }