blob_garbage_meter_test.cc 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197
  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_garbage_meter.h"
  6. #include <string>
  7. #include <vector>
  8. #include "db/blob/blob_index.h"
  9. #include "db/blob/blob_log_format.h"
  10. #include "db/dbformat.h"
  11. #include "test_util/testharness.h"
  12. namespace ROCKSDB_NAMESPACE {
  13. TEST(BlobGarbageMeterTest, MeasureGarbage) {
  14. BlobGarbageMeter blob_garbage_meter;
  15. struct BlobDescriptor {
  16. std::string user_key;
  17. uint64_t blob_file_number;
  18. uint64_t offset;
  19. uint64_t size;
  20. CompressionType compression_type;
  21. bool has_in_flow;
  22. bool has_out_flow;
  23. uint64_t GetExpectedBytes() const {
  24. return size +
  25. BlobLogRecord::CalculateAdjustmentForRecordHeader(user_key.size());
  26. }
  27. };
  28. // Note: blob file 4 has the same inflow and outflow and hence no additional
  29. // garbage. Blob file 5 has less outflow than inflow and thus it does have
  30. // additional garbage. Blob file 6 is a newly written file (i.e. no inflow,
  31. // only outflow) and is thus not tracked by the meter.
  32. std::vector<BlobDescriptor> blobs{
  33. {"key", 4, 1234, 555, kLZ4Compression, true, true},
  34. {"other_key", 4, 6789, 101010, kLZ4Compression, true, true},
  35. {"yet_another_key", 5, 22222, 3456, kLZ4Compression, true, true},
  36. {"foo_key", 5, 77777, 8888, kLZ4Compression, true, true},
  37. {"bar_key", 5, 999999, 1212, kLZ4Compression, true, false},
  38. {"baz_key", 5, 1234567, 890, kLZ4Compression, true, false},
  39. {"new_key", 6, 7777, 9999, kNoCompression, false, true}};
  40. for (const auto& blob : blobs) {
  41. constexpr SequenceNumber seq = 123;
  42. const InternalKey key(blob.user_key, seq, kTypeBlobIndex);
  43. const Slice key_slice = key.Encode();
  44. std::string value;
  45. BlobIndex::EncodeBlob(&value, blob.blob_file_number, blob.offset, blob.size,
  46. blob.compression_type);
  47. const Slice value_slice(value);
  48. if (blob.has_in_flow) {
  49. ASSERT_OK(blob_garbage_meter.ProcessInFlow(key_slice, value_slice));
  50. }
  51. if (blob.has_out_flow) {
  52. ASSERT_OK(blob_garbage_meter.ProcessOutFlow(key_slice, value_slice));
  53. }
  54. }
  55. const auto& flows = blob_garbage_meter.flows();
  56. ASSERT_EQ(flows.size(), 2);
  57. {
  58. const auto it = flows.find(4);
  59. ASSERT_NE(it, flows.end());
  60. const auto& flow = it->second;
  61. constexpr uint64_t expected_count = 2;
  62. const uint64_t expected_bytes =
  63. blobs[0].GetExpectedBytes() + blobs[1].GetExpectedBytes();
  64. const auto& in = flow.GetInFlow();
  65. ASSERT_EQ(in.GetCount(), expected_count);
  66. ASSERT_EQ(in.GetBytes(), expected_bytes);
  67. const auto& out = flow.GetOutFlow();
  68. ASSERT_EQ(out.GetCount(), expected_count);
  69. ASSERT_EQ(out.GetBytes(), expected_bytes);
  70. ASSERT_TRUE(flow.IsValid());
  71. ASSERT_FALSE(flow.HasGarbage());
  72. }
  73. {
  74. const auto it = flows.find(5);
  75. ASSERT_NE(it, flows.end());
  76. const auto& flow = it->second;
  77. const auto& in = flow.GetInFlow();
  78. constexpr uint64_t expected_in_count = 4;
  79. const uint64_t expected_in_bytes =
  80. blobs[2].GetExpectedBytes() + blobs[3].GetExpectedBytes() +
  81. blobs[4].GetExpectedBytes() + blobs[5].GetExpectedBytes();
  82. ASSERT_EQ(in.GetCount(), expected_in_count);
  83. ASSERT_EQ(in.GetBytes(), expected_in_bytes);
  84. const auto& out = flow.GetOutFlow();
  85. constexpr uint64_t expected_out_count = 2;
  86. const uint64_t expected_out_bytes =
  87. blobs[2].GetExpectedBytes() + blobs[3].GetExpectedBytes();
  88. ASSERT_EQ(out.GetCount(), expected_out_count);
  89. ASSERT_EQ(out.GetBytes(), expected_out_bytes);
  90. ASSERT_TRUE(flow.IsValid());
  91. ASSERT_TRUE(flow.HasGarbage());
  92. ASSERT_EQ(flow.GetGarbageCount(), expected_in_count - expected_out_count);
  93. ASSERT_EQ(flow.GetGarbageBytes(), expected_in_bytes - expected_out_bytes);
  94. }
  95. }
  96. TEST(BlobGarbageMeterTest, PlainValue) {
  97. constexpr char user_key[] = "user_key";
  98. constexpr SequenceNumber seq = 123;
  99. const InternalKey key(user_key, seq, kTypeValue);
  100. const Slice key_slice = key.Encode();
  101. constexpr char value[] = "value";
  102. const Slice value_slice(value);
  103. BlobGarbageMeter blob_garbage_meter;
  104. ASSERT_OK(blob_garbage_meter.ProcessInFlow(key_slice, value_slice));
  105. ASSERT_OK(blob_garbage_meter.ProcessOutFlow(key_slice, value_slice));
  106. ASSERT_TRUE(blob_garbage_meter.flows().empty());
  107. }
  108. TEST(BlobGarbageMeterTest, CorruptInternalKey) {
  109. constexpr char corrupt_key[] = "i_am_corrupt";
  110. const Slice key_slice(corrupt_key);
  111. constexpr char value[] = "value";
  112. const Slice value_slice(value);
  113. BlobGarbageMeter blob_garbage_meter;
  114. ASSERT_NOK(blob_garbage_meter.ProcessInFlow(key_slice, value_slice));
  115. ASSERT_NOK(blob_garbage_meter.ProcessOutFlow(key_slice, value_slice));
  116. }
  117. TEST(BlobGarbageMeterTest, CorruptBlobIndex) {
  118. constexpr char user_key[] = "user_key";
  119. constexpr SequenceNumber seq = 123;
  120. const InternalKey key(user_key, seq, kTypeBlobIndex);
  121. const Slice key_slice = key.Encode();
  122. constexpr char value[] = "i_am_not_a_blob_index";
  123. const Slice value_slice(value);
  124. BlobGarbageMeter blob_garbage_meter;
  125. ASSERT_NOK(blob_garbage_meter.ProcessInFlow(key_slice, value_slice));
  126. ASSERT_NOK(blob_garbage_meter.ProcessOutFlow(key_slice, value_slice));
  127. }
  128. TEST(BlobGarbageMeterTest, InlinedTTLBlobIndex) {
  129. constexpr char user_key[] = "user_key";
  130. constexpr SequenceNumber seq = 123;
  131. const InternalKey key(user_key, seq, kTypeBlobIndex);
  132. const Slice key_slice = key.Encode();
  133. constexpr uint64_t expiration = 1234567890;
  134. constexpr char inlined_value[] = "inlined";
  135. std::string value;
  136. BlobIndex::EncodeInlinedTTL(&value, expiration, inlined_value);
  137. const Slice value_slice(value);
  138. BlobGarbageMeter blob_garbage_meter;
  139. ASSERT_NOK(blob_garbage_meter.ProcessInFlow(key_slice, value_slice));
  140. ASSERT_NOK(blob_garbage_meter.ProcessOutFlow(key_slice, value_slice));
  141. }
  142. } // namespace ROCKSDB_NAMESPACE
  143. int main(int argc, char** argv) {
  144. ROCKSDB_NAMESPACE::port::InstallStackTraceHandler();
  145. ::testing::InitGoogleTest(&argc, argv);
  146. return RUN_ALL_TESTS();
  147. }