db_merge_operand_test.cc 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240
  1. // Copyright (c) 2018-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/db_test_util.h"
  6. #include "port/stack_trace.h"
  7. #include "rocksdb/perf_context.h"
  8. #include "rocksdb/utilities/debug.h"
  9. #include "table/block_based/block_builder.h"
  10. #include "test_util/fault_injection_test_env.h"
  11. #if !defined(ROCKSDB_LITE)
  12. #include "test_util/sync_point.h"
  13. #endif
  14. #include "rocksdb/merge_operator.h"
  15. #include "utilities/merge_operators.h"
  16. #include "utilities/merge_operators/sortlist.h"
  17. #include "utilities/merge_operators/string_append/stringappend2.h"
  18. namespace ROCKSDB_NAMESPACE {
  19. class DBMergeOperandTest : public DBTestBase {
  20. public:
  21. DBMergeOperandTest() : DBTestBase("/db_merge_operand_test") {}
  22. };
  23. TEST_F(DBMergeOperandTest, GetMergeOperandsBasic) {
  24. class LimitedStringAppendMergeOp : public StringAppendTESTOperator {
  25. public:
  26. LimitedStringAppendMergeOp(int limit, char delim)
  27. : StringAppendTESTOperator(delim), limit_(limit) {}
  28. const char* Name() const override {
  29. return "DBMergeOperatorTest::LimitedStringAppendMergeOp";
  30. }
  31. bool ShouldMerge(const std::vector<Slice>& operands) const override {
  32. if (operands.size() > 0 && limit_ > 0 && operands.size() >= limit_) {
  33. return true;
  34. }
  35. return false;
  36. }
  37. private:
  38. size_t limit_ = 0;
  39. };
  40. Options options;
  41. options.create_if_missing = true;
  42. // Use only the latest two merge operands.
  43. options.merge_operator = std::make_shared<LimitedStringAppendMergeOp>(2, ',');
  44. options.env = env_;
  45. Reopen(options);
  46. int num_records = 4;
  47. int number_of_operands = 0;
  48. std::vector<PinnableSlice> values(num_records);
  49. GetMergeOperandsOptions merge_operands_info;
  50. merge_operands_info.expected_max_number_of_operands = num_records;
  51. // k0 value in memtable
  52. Put("k0", "PutARock");
  53. db_->GetMergeOperands(ReadOptions(), db_->DefaultColumnFamily(), "k0",
  54. values.data(), &merge_operands_info,
  55. &number_of_operands);
  56. ASSERT_EQ(values[0], "PutARock");
  57. // k0.1 value in SST
  58. Put("k0.1", "RockInSST");
  59. ASSERT_OK(Flush());
  60. db_->GetMergeOperands(ReadOptions(), db_->DefaultColumnFamily(), "k0.1",
  61. values.data(), &merge_operands_info,
  62. &number_of_operands);
  63. ASSERT_EQ(values[0], "RockInSST");
  64. // All k1 values are in memtable.
  65. ASSERT_OK(Merge("k1", "a"));
  66. Put("k1", "x");
  67. ASSERT_OK(Merge("k1", "b"));
  68. ASSERT_OK(Merge("k1", "c"));
  69. ASSERT_OK(Merge("k1", "d"));
  70. db_->GetMergeOperands(ReadOptions(), db_->DefaultColumnFamily(), "k1",
  71. values.data(), &merge_operands_info,
  72. &number_of_operands);
  73. ASSERT_EQ(values[0], "x");
  74. ASSERT_EQ(values[1], "b");
  75. ASSERT_EQ(values[2], "c");
  76. ASSERT_EQ(values[3], "d");
  77. // expected_max_number_of_operands is less than number of merge operands so
  78. // status should be Incomplete.
  79. merge_operands_info.expected_max_number_of_operands = num_records - 1;
  80. Status status = db_->GetMergeOperands(
  81. ReadOptions(), db_->DefaultColumnFamily(), "k1", values.data(),
  82. &merge_operands_info, &number_of_operands);
  83. ASSERT_EQ(status.IsIncomplete(), true);
  84. merge_operands_info.expected_max_number_of_operands = num_records;
  85. // All k1.1 values are in memtable.
  86. ASSERT_OK(Merge("k1.1", "r"));
  87. Delete("k1.1");
  88. ASSERT_OK(Merge("k1.1", "c"));
  89. ASSERT_OK(Merge("k1.1", "k"));
  90. ASSERT_OK(Merge("k1.1", "s"));
  91. db_->GetMergeOperands(ReadOptions(), db_->DefaultColumnFamily(), "k1.1",
  92. values.data(), &merge_operands_info,
  93. &number_of_operands);
  94. ASSERT_EQ(values[0], "c");
  95. ASSERT_EQ(values[1], "k");
  96. ASSERT_EQ(values[2], "s");
  97. // All k2 values are flushed to L0 into a single file.
  98. ASSERT_OK(Merge("k2", "q"));
  99. ASSERT_OK(Merge("k2", "w"));
  100. ASSERT_OK(Merge("k2", "e"));
  101. ASSERT_OK(Merge("k2", "r"));
  102. ASSERT_OK(Flush());
  103. db_->GetMergeOperands(ReadOptions(), db_->DefaultColumnFamily(), "k2",
  104. values.data(), &merge_operands_info,
  105. &number_of_operands);
  106. ASSERT_EQ(values[0], "q");
  107. ASSERT_EQ(values[1], "w");
  108. ASSERT_EQ(values[2], "e");
  109. ASSERT_EQ(values[3], "r");
  110. // All k2.1 values are flushed to L0 into a single file.
  111. ASSERT_OK(Merge("k2.1", "m"));
  112. Put("k2.1", "l");
  113. ASSERT_OK(Merge("k2.1", "n"));
  114. ASSERT_OK(Merge("k2.1", "o"));
  115. ASSERT_OK(Flush());
  116. db_->GetMergeOperands(ReadOptions(), db_->DefaultColumnFamily(), "k2.1",
  117. values.data(), &merge_operands_info,
  118. &number_of_operands);
  119. ASSERT_EQ(values[0], "l,n,o");
  120. // All k2.2 values are flushed to L0 into a single file.
  121. ASSERT_OK(Merge("k2.2", "g"));
  122. Delete("k2.2");
  123. ASSERT_OK(Merge("k2.2", "o"));
  124. ASSERT_OK(Merge("k2.2", "t"));
  125. ASSERT_OK(Flush());
  126. db_->GetMergeOperands(ReadOptions(), db_->DefaultColumnFamily(), "k2.2",
  127. values.data(), &merge_operands_info,
  128. &number_of_operands);
  129. ASSERT_EQ(values[0], "o,t");
  130. // Do some compaction that will make the following tests more predictable
  131. // Slice start("PutARock");
  132. // Slice end("t");
  133. db_->CompactRange(CompactRangeOptions(), nullptr, nullptr);
  134. // All k3 values are flushed and are in different files.
  135. ASSERT_OK(Merge("k3", "ab"));
  136. ASSERT_OK(Flush());
  137. ASSERT_OK(Merge("k3", "bc"));
  138. ASSERT_OK(Flush());
  139. ASSERT_OK(Merge("k3", "cd"));
  140. ASSERT_OK(Flush());
  141. ASSERT_OK(Merge("k3", "de"));
  142. db_->GetMergeOperands(ReadOptions(), db_->DefaultColumnFamily(), "k3",
  143. values.data(), &merge_operands_info,
  144. &number_of_operands);
  145. ASSERT_EQ(values[0], "ab");
  146. ASSERT_EQ(values[1], "bc");
  147. ASSERT_EQ(values[2], "cd");
  148. ASSERT_EQ(values[3], "de");
  149. // All k3.1 values are flushed and are in different files.
  150. ASSERT_OK(Merge("k3.1", "ab"));
  151. ASSERT_OK(Flush());
  152. Put("k3.1", "bc");
  153. ASSERT_OK(Flush());
  154. ASSERT_OK(Merge("k3.1", "cd"));
  155. ASSERT_OK(Flush());
  156. ASSERT_OK(Merge("k3.1", "de"));
  157. db_->GetMergeOperands(ReadOptions(), db_->DefaultColumnFamily(), "k3.1",
  158. values.data(), &merge_operands_info,
  159. &number_of_operands);
  160. ASSERT_EQ(values[0], "bc");
  161. ASSERT_EQ(values[1], "cd");
  162. ASSERT_EQ(values[2], "de");
  163. // All k3.2 values are flushed and are in different files.
  164. ASSERT_OK(Merge("k3.2", "ab"));
  165. ASSERT_OK(Flush());
  166. Delete("k3.2");
  167. ASSERT_OK(Flush());
  168. ASSERT_OK(Merge("k3.2", "cd"));
  169. ASSERT_OK(Flush());
  170. ASSERT_OK(Merge("k3.2", "de"));
  171. db_->GetMergeOperands(ReadOptions(), db_->DefaultColumnFamily(), "k3.2",
  172. values.data(), &merge_operands_info,
  173. &number_of_operands);
  174. ASSERT_EQ(values[0], "cd");
  175. ASSERT_EQ(values[1], "de");
  176. // All K4 values are in different levels
  177. ASSERT_OK(Merge("k4", "ba"));
  178. ASSERT_OK(Flush());
  179. MoveFilesToLevel(4);
  180. ASSERT_OK(Merge("k4", "cb"));
  181. ASSERT_OK(Flush());
  182. MoveFilesToLevel(3);
  183. ASSERT_OK(Merge("k4", "dc"));
  184. ASSERT_OK(Flush());
  185. MoveFilesToLevel(1);
  186. ASSERT_OK(Merge("k4", "ed"));
  187. db_->GetMergeOperands(ReadOptions(), db_->DefaultColumnFamily(), "k4",
  188. values.data(), &merge_operands_info,
  189. &number_of_operands);
  190. ASSERT_EQ(values[0], "ba");
  191. ASSERT_EQ(values[1], "cb");
  192. ASSERT_EQ(values[2], "dc");
  193. ASSERT_EQ(values[3], "ed");
  194. // First 3 k5 values are in SST and next 4 k5 values are in Immutable Memtable
  195. ASSERT_OK(Merge("k5", "who"));
  196. ASSERT_OK(Merge("k5", "am"));
  197. ASSERT_OK(Merge("k5", "i"));
  198. ASSERT_OK(Flush());
  199. Put("k5", "remember");
  200. ASSERT_OK(Merge("k5", "i"));
  201. ASSERT_OK(Merge("k5", "am"));
  202. ASSERT_OK(Merge("k5", "rocks"));
  203. dbfull()->TEST_SwitchMemtable();
  204. db_->GetMergeOperands(ReadOptions(), db_->DefaultColumnFamily(), "k5",
  205. values.data(), &merge_operands_info,
  206. &number_of_operands);
  207. ASSERT_EQ(values[0], "remember");
  208. ASSERT_EQ(values[1], "i");
  209. ASSERT_EQ(values[2], "am");
  210. }
  211. } // namespace ROCKSDB_NAMESPACE
  212. int main(int argc, char** argv) {
  213. ROCKSDB_NAMESPACE::port::InstallStackTraceHandler();
  214. ::testing::InitGoogleTest(&argc, argv);
  215. return RUN_ALL_TESTS();
  216. }