compaction_job_test.cc 41 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082
  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. #ifndef ROCKSDB_LITE
  6. #include <algorithm>
  7. #include <array>
  8. #include <cinttypes>
  9. #include <map>
  10. #include <string>
  11. #include <tuple>
  12. #include "db/blob_index.h"
  13. #include "db/column_family.h"
  14. #include "db/compaction/compaction_job.h"
  15. #include "db/db_impl/db_impl.h"
  16. #include "db/error_handler.h"
  17. #include "db/version_set.h"
  18. #include "file/writable_file_writer.h"
  19. #include "rocksdb/cache.h"
  20. #include "rocksdb/db.h"
  21. #include "rocksdb/options.h"
  22. #include "rocksdb/write_buffer_manager.h"
  23. #include "table/mock_table.h"
  24. #include "test_util/testharness.h"
  25. #include "test_util/testutil.h"
  26. #include "util/string_util.h"
  27. #include "utilities/merge_operators.h"
  28. namespace ROCKSDB_NAMESPACE {
  29. namespace {
  30. void VerifyInitializationOfCompactionJobStats(
  31. const CompactionJobStats& compaction_job_stats) {
  32. #if !defined(IOS_CROSS_COMPILE)
  33. ASSERT_EQ(compaction_job_stats.elapsed_micros, 0U);
  34. ASSERT_EQ(compaction_job_stats.num_input_records, 0U);
  35. ASSERT_EQ(compaction_job_stats.num_input_files, 0U);
  36. ASSERT_EQ(compaction_job_stats.num_input_files_at_output_level, 0U);
  37. ASSERT_EQ(compaction_job_stats.num_output_records, 0U);
  38. ASSERT_EQ(compaction_job_stats.num_output_files, 0U);
  39. ASSERT_EQ(compaction_job_stats.is_manual_compaction, true);
  40. ASSERT_EQ(compaction_job_stats.total_input_bytes, 0U);
  41. ASSERT_EQ(compaction_job_stats.total_output_bytes, 0U);
  42. ASSERT_EQ(compaction_job_stats.total_input_raw_key_bytes, 0U);
  43. ASSERT_EQ(compaction_job_stats.total_input_raw_value_bytes, 0U);
  44. ASSERT_EQ(compaction_job_stats.smallest_output_key_prefix[0], 0);
  45. ASSERT_EQ(compaction_job_stats.largest_output_key_prefix[0], 0);
  46. ASSERT_EQ(compaction_job_stats.num_records_replaced, 0U);
  47. ASSERT_EQ(compaction_job_stats.num_input_deletion_records, 0U);
  48. ASSERT_EQ(compaction_job_stats.num_expired_deletion_records, 0U);
  49. ASSERT_EQ(compaction_job_stats.num_corrupt_keys, 0U);
  50. #endif // !defined(IOS_CROSS_COMPILE)
  51. }
  52. } // namespace
  53. // TODO(icanadi) Make it simpler once we mock out VersionSet
  54. class CompactionJobTest : public testing::Test {
  55. public:
  56. CompactionJobTest()
  57. : env_(Env::Default()),
  58. fs_(std::make_shared<LegacyFileSystemWrapper>(env_)),
  59. dbname_(test::PerThreadDBPath("compaction_job_test")),
  60. db_options_(),
  61. mutable_cf_options_(cf_options_),
  62. table_cache_(NewLRUCache(50000, 16)),
  63. write_buffer_manager_(db_options_.db_write_buffer_size),
  64. versions_(new VersionSet(dbname_, &db_options_, env_options_,
  65. table_cache_.get(), &write_buffer_manager_,
  66. &write_controller_,
  67. /*block_cache_tracer=*/nullptr)),
  68. shutting_down_(false),
  69. preserve_deletes_seqnum_(0),
  70. mock_table_factory_(new mock::MockTableFactory()),
  71. error_handler_(nullptr, db_options_, &mutex_) {
  72. EXPECT_OK(env_->CreateDirIfMissing(dbname_));
  73. db_options_.env = env_;
  74. db_options_.fs = fs_;
  75. db_options_.db_paths.emplace_back(dbname_,
  76. std::numeric_limits<uint64_t>::max());
  77. }
  78. std::string GenerateFileName(uint64_t file_number) {
  79. FileMetaData meta;
  80. std::vector<DbPath> db_paths;
  81. db_paths.emplace_back(dbname_, std::numeric_limits<uint64_t>::max());
  82. meta.fd = FileDescriptor(file_number, 0, 0);
  83. return TableFileName(db_paths, meta.fd.GetNumber(), meta.fd.GetPathId());
  84. }
  85. static std::string KeyStr(const std::string& user_key,
  86. const SequenceNumber seq_num, const ValueType t) {
  87. return InternalKey(user_key, seq_num, t).Encode().ToString();
  88. }
  89. static std::string BlobStr(uint64_t blob_file_number, uint64_t offset,
  90. uint64_t size) {
  91. std::string blob_index;
  92. BlobIndex::EncodeBlob(&blob_index, blob_file_number, offset, size,
  93. kNoCompression);
  94. return blob_index;
  95. }
  96. static std::string BlobStrTTL(uint64_t blob_file_number, uint64_t offset,
  97. uint64_t size, uint64_t expiration) {
  98. std::string blob_index;
  99. BlobIndex::EncodeBlobTTL(&blob_index, expiration, blob_file_number, offset,
  100. size, kNoCompression);
  101. return blob_index;
  102. }
  103. static std::string BlobStrInlinedTTL(const Slice& value,
  104. uint64_t expiration) {
  105. std::string blob_index;
  106. BlobIndex::EncodeInlinedTTL(&blob_index, expiration, value);
  107. return blob_index;
  108. }
  109. void AddMockFile(const stl_wrappers::KVMap& contents, int level = 0) {
  110. assert(contents.size() > 0);
  111. bool first_key = true;
  112. std::string smallest, largest;
  113. InternalKey smallest_key, largest_key;
  114. SequenceNumber smallest_seqno = kMaxSequenceNumber;
  115. SequenceNumber largest_seqno = 0;
  116. uint64_t oldest_blob_file_number = kInvalidBlobFileNumber;
  117. for (auto kv : contents) {
  118. ParsedInternalKey key;
  119. std::string skey;
  120. std::string value;
  121. std::tie(skey, value) = kv;
  122. bool parsed = ParseInternalKey(skey, &key);
  123. smallest_seqno = std::min(smallest_seqno, key.sequence);
  124. largest_seqno = std::max(largest_seqno, key.sequence);
  125. if (first_key ||
  126. cfd_->user_comparator()->Compare(key.user_key, smallest) < 0) {
  127. smallest.assign(key.user_key.data(), key.user_key.size());
  128. smallest_key.DecodeFrom(skey);
  129. }
  130. if (first_key ||
  131. cfd_->user_comparator()->Compare(key.user_key, largest) > 0) {
  132. largest.assign(key.user_key.data(), key.user_key.size());
  133. largest_key.DecodeFrom(skey);
  134. }
  135. first_key = false;
  136. if (parsed && key.type == kTypeBlobIndex) {
  137. BlobIndex blob_index;
  138. const Status s = blob_index.DecodeFrom(value);
  139. if (!s.ok()) {
  140. continue;
  141. }
  142. if (blob_index.IsInlined() || blob_index.HasTTL() ||
  143. blob_index.file_number() == kInvalidBlobFileNumber) {
  144. continue;
  145. }
  146. if (oldest_blob_file_number == kInvalidBlobFileNumber ||
  147. oldest_blob_file_number > blob_index.file_number()) {
  148. oldest_blob_file_number = blob_index.file_number();
  149. }
  150. }
  151. }
  152. uint64_t file_number = versions_->NewFileNumber();
  153. EXPECT_OK(mock_table_factory_->CreateMockTable(
  154. env_, GenerateFileName(file_number), std::move(contents)));
  155. VersionEdit edit;
  156. edit.AddFile(level, file_number, 0, 10, smallest_key, largest_key,
  157. smallest_seqno, largest_seqno, false, oldest_blob_file_number,
  158. kUnknownOldestAncesterTime, kUnknownFileCreationTime,
  159. kUnknownFileChecksum, kUnknownFileChecksumFuncName);
  160. mutex_.Lock();
  161. versions_->LogAndApply(versions_->GetColumnFamilySet()->GetDefault(),
  162. mutable_cf_options_, &edit, &mutex_);
  163. mutex_.Unlock();
  164. }
  165. void SetLastSequence(const SequenceNumber sequence_number) {
  166. versions_->SetLastAllocatedSequence(sequence_number + 1);
  167. versions_->SetLastPublishedSequence(sequence_number + 1);
  168. versions_->SetLastSequence(sequence_number + 1);
  169. }
  170. // returns expected result after compaction
  171. stl_wrappers::KVMap CreateTwoFiles(bool gen_corrupted_keys) {
  172. auto expected_results = mock::MakeMockFile();
  173. const int kKeysPerFile = 10000;
  174. const int kCorruptKeysPerFile = 200;
  175. const int kMatchingKeys = kKeysPerFile / 2;
  176. SequenceNumber sequence_number = 0;
  177. auto corrupt_id = [&](int id) {
  178. return gen_corrupted_keys && id > 0 && id <= kCorruptKeysPerFile;
  179. };
  180. for (int i = 0; i < 2; ++i) {
  181. auto contents = mock::MakeMockFile();
  182. for (int k = 0; k < kKeysPerFile; ++k) {
  183. auto key = ToString(i * kMatchingKeys + k);
  184. auto value = ToString(i * kKeysPerFile + k);
  185. InternalKey internal_key(key, ++sequence_number, kTypeValue);
  186. // This is how the key will look like once it's written in bottommost
  187. // file
  188. InternalKey bottommost_internal_key(
  189. key, 0, kTypeValue);
  190. if (corrupt_id(k)) {
  191. test::CorruptKeyType(&internal_key);
  192. test::CorruptKeyType(&bottommost_internal_key);
  193. }
  194. contents.insert({ internal_key.Encode().ToString(), value });
  195. if (i == 1 || k < kMatchingKeys || corrupt_id(k - kMatchingKeys)) {
  196. expected_results.insert(
  197. { bottommost_internal_key.Encode().ToString(), value });
  198. }
  199. }
  200. AddMockFile(contents);
  201. }
  202. SetLastSequence(sequence_number);
  203. return expected_results;
  204. }
  205. void NewDB() {
  206. DestroyDB(dbname_, Options());
  207. EXPECT_OK(env_->CreateDirIfMissing(dbname_));
  208. versions_.reset(new VersionSet(dbname_, &db_options_, env_options_,
  209. table_cache_.get(), &write_buffer_manager_,
  210. &write_controller_,
  211. /*block_cache_tracer=*/nullptr));
  212. compaction_job_stats_.Reset();
  213. SetIdentityFile(env_, dbname_);
  214. VersionEdit new_db;
  215. if (db_options_.write_dbid_to_manifest) {
  216. DBImpl* impl = new DBImpl(DBOptions(), dbname_);
  217. std::string db_id;
  218. impl->GetDbIdentityFromIdentityFile(&db_id);
  219. new_db.SetDBId(db_id);
  220. }
  221. new_db.SetLogNumber(0);
  222. new_db.SetNextFile(2);
  223. new_db.SetLastSequence(0);
  224. const std::string manifest = DescriptorFileName(dbname_, 1);
  225. std::unique_ptr<WritableFile> file;
  226. Status s = env_->NewWritableFile(
  227. manifest, &file, env_->OptimizeForManifestWrite(env_options_));
  228. ASSERT_OK(s);
  229. std::unique_ptr<WritableFileWriter> file_writer(new WritableFileWriter(
  230. NewLegacyWritableFileWrapper(std::move(file)), manifest, env_options_));
  231. {
  232. log::Writer log(std::move(file_writer), 0, false);
  233. std::string record;
  234. new_db.EncodeTo(&record);
  235. s = log.AddRecord(record);
  236. }
  237. ASSERT_OK(s);
  238. // Make "CURRENT" file that points to the new manifest file.
  239. s = SetCurrentFile(env_, dbname_, 1, nullptr);
  240. std::vector<ColumnFamilyDescriptor> column_families;
  241. cf_options_.table_factory = mock_table_factory_;
  242. cf_options_.merge_operator = merge_op_;
  243. cf_options_.compaction_filter = compaction_filter_.get();
  244. column_families.emplace_back(kDefaultColumnFamilyName, cf_options_);
  245. EXPECT_OK(versions_->Recover(column_families, false));
  246. cfd_ = versions_->GetColumnFamilySet()->GetDefault();
  247. }
  248. void RunCompaction(
  249. const std::vector<std::vector<FileMetaData*>>& input_files,
  250. const stl_wrappers::KVMap& expected_results,
  251. const std::vector<SequenceNumber>& snapshots = {},
  252. SequenceNumber earliest_write_conflict_snapshot = kMaxSequenceNumber,
  253. int output_level = 1, bool verify = true,
  254. uint64_t expected_oldest_blob_file_number = kInvalidBlobFileNumber) {
  255. auto cfd = versions_->GetColumnFamilySet()->GetDefault();
  256. size_t num_input_files = 0;
  257. std::vector<CompactionInputFiles> compaction_input_files;
  258. for (size_t level = 0; level < input_files.size(); level++) {
  259. auto level_files = input_files[level];
  260. CompactionInputFiles compaction_level;
  261. compaction_level.level = static_cast<int>(level);
  262. compaction_level.files.insert(compaction_level.files.end(),
  263. level_files.begin(), level_files.end());
  264. compaction_input_files.push_back(compaction_level);
  265. num_input_files += level_files.size();
  266. }
  267. Compaction compaction(cfd->current()->storage_info(), *cfd->ioptions(),
  268. *cfd->GetLatestMutableCFOptions(),
  269. compaction_input_files, output_level, 1024 * 1024,
  270. 10 * 1024 * 1024, 0, kNoCompression,
  271. cfd->ioptions()->compression_opts, 0, {}, true);
  272. compaction.SetInputVersion(cfd->current());
  273. LogBuffer log_buffer(InfoLogLevel::INFO_LEVEL, db_options_.info_log.get());
  274. mutex_.Lock();
  275. EventLogger event_logger(db_options_.info_log.get());
  276. // TODO(yiwu) add a mock snapshot checker and add test for it.
  277. SnapshotChecker* snapshot_checker = nullptr;
  278. CompactionJob compaction_job(
  279. 0, &compaction, db_options_, env_options_, versions_.get(),
  280. &shutting_down_, preserve_deletes_seqnum_, &log_buffer, nullptr,
  281. nullptr, nullptr, &mutex_, &error_handler_, snapshots,
  282. earliest_write_conflict_snapshot, snapshot_checker, table_cache_,
  283. &event_logger, false, false, dbname_, &compaction_job_stats_,
  284. Env::Priority::USER);
  285. VerifyInitializationOfCompactionJobStats(compaction_job_stats_);
  286. compaction_job.Prepare();
  287. mutex_.Unlock();
  288. Status s;
  289. s = compaction_job.Run();
  290. ASSERT_OK(s);
  291. mutex_.Lock();
  292. ASSERT_OK(compaction_job.Install(*cfd->GetLatestMutableCFOptions()));
  293. mutex_.Unlock();
  294. if (verify) {
  295. ASSERT_GE(compaction_job_stats_.elapsed_micros, 0U);
  296. ASSERT_EQ(compaction_job_stats_.num_input_files, num_input_files);
  297. if (expected_results.empty()) {
  298. ASSERT_EQ(compaction_job_stats_.num_output_files, 0U);
  299. } else {
  300. ASSERT_EQ(compaction_job_stats_.num_output_files, 1U);
  301. mock_table_factory_->AssertLatestFile(expected_results);
  302. auto output_files =
  303. cfd->current()->storage_info()->LevelFiles(output_level);
  304. ASSERT_EQ(output_files.size(), 1);
  305. ASSERT_EQ(output_files[0]->oldest_blob_file_number,
  306. expected_oldest_blob_file_number);
  307. }
  308. }
  309. }
  310. Env* env_;
  311. std::shared_ptr<FileSystem> fs_;
  312. std::string dbname_;
  313. EnvOptions env_options_;
  314. ImmutableDBOptions db_options_;
  315. ColumnFamilyOptions cf_options_;
  316. MutableCFOptions mutable_cf_options_;
  317. std::shared_ptr<Cache> table_cache_;
  318. WriteController write_controller_;
  319. WriteBufferManager write_buffer_manager_;
  320. std::unique_ptr<VersionSet> versions_;
  321. InstrumentedMutex mutex_;
  322. std::atomic<bool> shutting_down_;
  323. SequenceNumber preserve_deletes_seqnum_;
  324. std::shared_ptr<mock::MockTableFactory> mock_table_factory_;
  325. CompactionJobStats compaction_job_stats_;
  326. ColumnFamilyData* cfd_;
  327. std::unique_ptr<CompactionFilter> compaction_filter_;
  328. std::shared_ptr<MergeOperator> merge_op_;
  329. ErrorHandler error_handler_;
  330. };
  331. TEST_F(CompactionJobTest, Simple) {
  332. NewDB();
  333. auto expected_results = CreateTwoFiles(false);
  334. auto cfd = versions_->GetColumnFamilySet()->GetDefault();
  335. auto files = cfd->current()->storage_info()->LevelFiles(0);
  336. ASSERT_EQ(2U, files.size());
  337. RunCompaction({ files }, expected_results);
  338. }
  339. TEST_F(CompactionJobTest, SimpleCorrupted) {
  340. NewDB();
  341. auto expected_results = CreateTwoFiles(true);
  342. auto cfd = versions_->GetColumnFamilySet()->GetDefault();
  343. auto files = cfd->current()->storage_info()->LevelFiles(0);
  344. RunCompaction({files}, expected_results);
  345. ASSERT_EQ(compaction_job_stats_.num_corrupt_keys, 400U);
  346. }
  347. TEST_F(CompactionJobTest, SimpleDeletion) {
  348. NewDB();
  349. auto file1 = mock::MakeMockFile({{KeyStr("c", 4U, kTypeDeletion), ""},
  350. {KeyStr("c", 3U, kTypeValue), "val"}});
  351. AddMockFile(file1);
  352. auto file2 = mock::MakeMockFile({{KeyStr("b", 2U, kTypeValue), "val"},
  353. {KeyStr("b", 1U, kTypeValue), "val"}});
  354. AddMockFile(file2);
  355. auto expected_results =
  356. mock::MakeMockFile({{KeyStr("b", 0U, kTypeValue), "val"}});
  357. SetLastSequence(4U);
  358. auto files = cfd_->current()->storage_info()->LevelFiles(0);
  359. RunCompaction({files}, expected_results);
  360. }
  361. TEST_F(CompactionJobTest, OutputNothing) {
  362. NewDB();
  363. auto file1 = mock::MakeMockFile({{KeyStr("a", 1U, kTypeValue), "val"}});
  364. AddMockFile(file1);
  365. auto file2 = mock::MakeMockFile({{KeyStr("a", 2U, kTypeDeletion), ""}});
  366. AddMockFile(file2);
  367. auto expected_results = mock::MakeMockFile();
  368. SetLastSequence(4U);
  369. auto files = cfd_->current()->storage_info()->LevelFiles(0);
  370. RunCompaction({files}, expected_results);
  371. }
  372. TEST_F(CompactionJobTest, SimpleOverwrite) {
  373. NewDB();
  374. auto file1 = mock::MakeMockFile({
  375. {KeyStr("a", 3U, kTypeValue), "val2"},
  376. {KeyStr("b", 4U, kTypeValue), "val3"},
  377. });
  378. AddMockFile(file1);
  379. auto file2 = mock::MakeMockFile({{KeyStr("a", 1U, kTypeValue), "val"},
  380. {KeyStr("b", 2U, kTypeValue), "val"}});
  381. AddMockFile(file2);
  382. auto expected_results =
  383. mock::MakeMockFile({{KeyStr("a", 0U, kTypeValue), "val2"},
  384. {KeyStr("b", 0U, kTypeValue), "val3"}});
  385. SetLastSequence(4U);
  386. auto files = cfd_->current()->storage_info()->LevelFiles(0);
  387. RunCompaction({files}, expected_results);
  388. }
  389. TEST_F(CompactionJobTest, SimpleNonLastLevel) {
  390. NewDB();
  391. auto file1 = mock::MakeMockFile({
  392. {KeyStr("a", 5U, kTypeValue), "val2"},
  393. {KeyStr("b", 6U, kTypeValue), "val3"},
  394. });
  395. AddMockFile(file1);
  396. auto file2 = mock::MakeMockFile({{KeyStr("a", 3U, kTypeValue), "val"},
  397. {KeyStr("b", 4U, kTypeValue), "val"}});
  398. AddMockFile(file2, 1);
  399. auto file3 = mock::MakeMockFile({{KeyStr("a", 1U, kTypeValue), "val"},
  400. {KeyStr("b", 2U, kTypeValue), "val"}});
  401. AddMockFile(file3, 2);
  402. // Because level 1 is not the last level, the sequence numbers of a and b
  403. // cannot be set to 0
  404. auto expected_results =
  405. mock::MakeMockFile({{KeyStr("a", 5U, kTypeValue), "val2"},
  406. {KeyStr("b", 6U, kTypeValue), "val3"}});
  407. SetLastSequence(6U);
  408. auto lvl0_files = cfd_->current()->storage_info()->LevelFiles(0);
  409. auto lvl1_files = cfd_->current()->storage_info()->LevelFiles(1);
  410. RunCompaction({lvl0_files, lvl1_files}, expected_results);
  411. }
  412. TEST_F(CompactionJobTest, SimpleMerge) {
  413. merge_op_ = MergeOperators::CreateStringAppendOperator();
  414. NewDB();
  415. auto file1 = mock::MakeMockFile({
  416. {KeyStr("a", 5U, kTypeMerge), "5"},
  417. {KeyStr("a", 4U, kTypeMerge), "4"},
  418. {KeyStr("a", 3U, kTypeValue), "3"},
  419. });
  420. AddMockFile(file1);
  421. auto file2 = mock::MakeMockFile(
  422. {{KeyStr("b", 2U, kTypeMerge), "2"}, {KeyStr("b", 1U, kTypeValue), "1"}});
  423. AddMockFile(file2);
  424. auto expected_results =
  425. mock::MakeMockFile({{KeyStr("a", 0U, kTypeValue), "3,4,5"},
  426. {KeyStr("b", 0U, kTypeValue), "1,2"}});
  427. SetLastSequence(5U);
  428. auto files = cfd_->current()->storage_info()->LevelFiles(0);
  429. RunCompaction({files}, expected_results);
  430. }
  431. TEST_F(CompactionJobTest, NonAssocMerge) {
  432. merge_op_ = MergeOperators::CreateStringAppendTESTOperator();
  433. NewDB();
  434. auto file1 = mock::MakeMockFile({
  435. {KeyStr("a", 5U, kTypeMerge), "5"},
  436. {KeyStr("a", 4U, kTypeMerge), "4"},
  437. {KeyStr("a", 3U, kTypeMerge), "3"},
  438. });
  439. AddMockFile(file1);
  440. auto file2 = mock::MakeMockFile(
  441. {{KeyStr("b", 2U, kTypeMerge), "2"}, {KeyStr("b", 1U, kTypeMerge), "1"}});
  442. AddMockFile(file2);
  443. auto expected_results =
  444. mock::MakeMockFile({{KeyStr("a", 0U, kTypeValue), "3,4,5"},
  445. {KeyStr("b", 0U, kTypeValue), "1,2"}});
  446. SetLastSequence(5U);
  447. auto files = cfd_->current()->storage_info()->LevelFiles(0);
  448. RunCompaction({files}, expected_results);
  449. }
  450. // Filters merge operands with value 10.
  451. TEST_F(CompactionJobTest, MergeOperandFilter) {
  452. merge_op_ = MergeOperators::CreateUInt64AddOperator();
  453. compaction_filter_.reset(new test::FilterNumber(10U));
  454. NewDB();
  455. auto file1 = mock::MakeMockFile(
  456. {{KeyStr("a", 5U, kTypeMerge), test::EncodeInt(5U)},
  457. {KeyStr("a", 4U, kTypeMerge), test::EncodeInt(10U)}, // Filtered
  458. {KeyStr("a", 3U, kTypeMerge), test::EncodeInt(3U)}});
  459. AddMockFile(file1);
  460. auto file2 = mock::MakeMockFile({
  461. {KeyStr("b", 2U, kTypeMerge), test::EncodeInt(2U)},
  462. {KeyStr("b", 1U, kTypeMerge), test::EncodeInt(10U)} // Filtered
  463. });
  464. AddMockFile(file2);
  465. auto expected_results =
  466. mock::MakeMockFile({{KeyStr("a", 0U, kTypeValue), test::EncodeInt(8U)},
  467. {KeyStr("b", 0U, kTypeValue), test::EncodeInt(2U)}});
  468. SetLastSequence(5U);
  469. auto files = cfd_->current()->storage_info()->LevelFiles(0);
  470. RunCompaction({files}, expected_results);
  471. }
  472. TEST_F(CompactionJobTest, FilterSomeMergeOperands) {
  473. merge_op_ = MergeOperators::CreateUInt64AddOperator();
  474. compaction_filter_.reset(new test::FilterNumber(10U));
  475. NewDB();
  476. auto file1 = mock::MakeMockFile(
  477. {{KeyStr("a", 5U, kTypeMerge), test::EncodeInt(5U)},
  478. {KeyStr("a", 4U, kTypeMerge), test::EncodeInt(10U)}, // Filtered
  479. {KeyStr("a", 3U, kTypeValue), test::EncodeInt(5U)},
  480. {KeyStr("d", 8U, kTypeMerge), test::EncodeInt(10U)}});
  481. AddMockFile(file1);
  482. auto file2 =
  483. mock::MakeMockFile({{KeyStr("b", 2U, kTypeMerge), test::EncodeInt(10U)},
  484. {KeyStr("b", 1U, kTypeMerge), test::EncodeInt(10U)},
  485. {KeyStr("c", 2U, kTypeMerge), test::EncodeInt(3U)},
  486. {KeyStr("c", 1U, kTypeValue), test::EncodeInt(7U)},
  487. {KeyStr("d", 1U, kTypeValue), test::EncodeInt(6U)}});
  488. AddMockFile(file2);
  489. auto file3 =
  490. mock::MakeMockFile({{KeyStr("a", 1U, kTypeMerge), test::EncodeInt(3U)}});
  491. AddMockFile(file3, 2);
  492. auto expected_results = mock::MakeMockFile({
  493. {KeyStr("a", 5U, kTypeValue), test::EncodeInt(10U)},
  494. {KeyStr("c", 2U, kTypeValue), test::EncodeInt(10U)},
  495. {KeyStr("d", 1U, kTypeValue), test::EncodeInt(6U)}
  496. // b does not appear because the operands are filtered
  497. });
  498. SetLastSequence(5U);
  499. auto files = cfd_->current()->storage_info()->LevelFiles(0);
  500. RunCompaction({files}, expected_results);
  501. }
  502. // Test where all operands/merge results are filtered out.
  503. TEST_F(CompactionJobTest, FilterAllMergeOperands) {
  504. merge_op_ = MergeOperators::CreateUInt64AddOperator();
  505. compaction_filter_.reset(new test::FilterNumber(10U));
  506. NewDB();
  507. auto file1 =
  508. mock::MakeMockFile({{KeyStr("a", 11U, kTypeMerge), test::EncodeInt(10U)},
  509. {KeyStr("a", 10U, kTypeMerge), test::EncodeInt(10U)},
  510. {KeyStr("a", 9U, kTypeMerge), test::EncodeInt(10U)}});
  511. AddMockFile(file1);
  512. auto file2 =
  513. mock::MakeMockFile({{KeyStr("b", 8U, kTypeMerge), test::EncodeInt(10U)},
  514. {KeyStr("b", 7U, kTypeMerge), test::EncodeInt(10U)},
  515. {KeyStr("b", 6U, kTypeMerge), test::EncodeInt(10U)},
  516. {KeyStr("b", 5U, kTypeMerge), test::EncodeInt(10U)},
  517. {KeyStr("b", 4U, kTypeMerge), test::EncodeInt(10U)},
  518. {KeyStr("b", 3U, kTypeMerge), test::EncodeInt(10U)},
  519. {KeyStr("b", 2U, kTypeMerge), test::EncodeInt(10U)},
  520. {KeyStr("c", 2U, kTypeMerge), test::EncodeInt(10U)},
  521. {KeyStr("c", 1U, kTypeMerge), test::EncodeInt(10U)}});
  522. AddMockFile(file2);
  523. auto file3 =
  524. mock::MakeMockFile({{KeyStr("a", 2U, kTypeMerge), test::EncodeInt(10U)},
  525. {KeyStr("b", 1U, kTypeMerge), test::EncodeInt(10U)}});
  526. AddMockFile(file3, 2);
  527. SetLastSequence(11U);
  528. auto files = cfd_->current()->storage_info()->LevelFiles(0);
  529. stl_wrappers::KVMap empty_map;
  530. RunCompaction({files}, empty_map);
  531. }
  532. TEST_F(CompactionJobTest, SimpleSingleDelete) {
  533. NewDB();
  534. auto file1 = mock::MakeMockFile({
  535. {KeyStr("a", 5U, kTypeDeletion), ""},
  536. {KeyStr("b", 6U, kTypeSingleDeletion), ""},
  537. });
  538. AddMockFile(file1);
  539. auto file2 = mock::MakeMockFile({{KeyStr("a", 3U, kTypeValue), "val"},
  540. {KeyStr("b", 4U, kTypeValue), "val"}});
  541. AddMockFile(file2);
  542. auto file3 = mock::MakeMockFile({
  543. {KeyStr("a", 1U, kTypeValue), "val"},
  544. });
  545. AddMockFile(file3, 2);
  546. auto expected_results =
  547. mock::MakeMockFile({{KeyStr("a", 5U, kTypeDeletion), ""}});
  548. SetLastSequence(6U);
  549. auto files = cfd_->current()->storage_info()->LevelFiles(0);
  550. RunCompaction({files}, expected_results);
  551. }
  552. TEST_F(CompactionJobTest, SingleDeleteSnapshots) {
  553. NewDB();
  554. auto file1 = mock::MakeMockFile({
  555. {KeyStr("A", 12U, kTypeSingleDeletion), ""},
  556. {KeyStr("a", 12U, kTypeSingleDeletion), ""},
  557. {KeyStr("b", 21U, kTypeSingleDeletion), ""},
  558. {KeyStr("c", 22U, kTypeSingleDeletion), ""},
  559. {KeyStr("d", 9U, kTypeSingleDeletion), ""},
  560. {KeyStr("f", 21U, kTypeSingleDeletion), ""},
  561. {KeyStr("j", 11U, kTypeSingleDeletion), ""},
  562. {KeyStr("j", 9U, kTypeSingleDeletion), ""},
  563. {KeyStr("k", 12U, kTypeSingleDeletion), ""},
  564. {KeyStr("k", 11U, kTypeSingleDeletion), ""},
  565. {KeyStr("l", 3U, kTypeSingleDeletion), ""},
  566. {KeyStr("l", 2U, kTypeSingleDeletion), ""},
  567. });
  568. AddMockFile(file1);
  569. auto file2 = mock::MakeMockFile({
  570. {KeyStr("0", 2U, kTypeSingleDeletion), ""},
  571. {KeyStr("a", 11U, kTypeValue), "val1"},
  572. {KeyStr("b", 11U, kTypeValue), "val2"},
  573. {KeyStr("c", 21U, kTypeValue), "val3"},
  574. {KeyStr("d", 8U, kTypeValue), "val4"},
  575. {KeyStr("e", 2U, kTypeSingleDeletion), ""},
  576. {KeyStr("f", 1U, kTypeValue), "val1"},
  577. {KeyStr("g", 11U, kTypeSingleDeletion), ""},
  578. {KeyStr("h", 2U, kTypeSingleDeletion), ""},
  579. {KeyStr("m", 12U, kTypeValue), "val1"},
  580. {KeyStr("m", 11U, kTypeSingleDeletion), ""},
  581. {KeyStr("m", 8U, kTypeValue), "val2"},
  582. });
  583. AddMockFile(file2);
  584. auto file3 = mock::MakeMockFile({
  585. {KeyStr("A", 1U, kTypeValue), "val"},
  586. {KeyStr("e", 1U, kTypeValue), "val"},
  587. });
  588. AddMockFile(file3, 2);
  589. auto expected_results = mock::MakeMockFile({
  590. {KeyStr("A", 12U, kTypeSingleDeletion), ""},
  591. {KeyStr("a", 12U, kTypeSingleDeletion), ""},
  592. {KeyStr("a", 11U, kTypeValue), ""},
  593. {KeyStr("b", 21U, kTypeSingleDeletion), ""},
  594. {KeyStr("b", 11U, kTypeValue), "val2"},
  595. {KeyStr("c", 22U, kTypeSingleDeletion), ""},
  596. {KeyStr("c", 21U, kTypeValue), ""},
  597. {KeyStr("e", 2U, kTypeSingleDeletion), ""},
  598. {KeyStr("f", 21U, kTypeSingleDeletion), ""},
  599. {KeyStr("f", 1U, kTypeValue), "val1"},
  600. {KeyStr("g", 11U, kTypeSingleDeletion), ""},
  601. {KeyStr("j", 11U, kTypeSingleDeletion), ""},
  602. {KeyStr("k", 11U, kTypeSingleDeletion), ""},
  603. {KeyStr("m", 12U, kTypeValue), "val1"},
  604. {KeyStr("m", 11U, kTypeSingleDeletion), ""},
  605. {KeyStr("m", 8U, kTypeValue), "val2"},
  606. });
  607. SetLastSequence(22U);
  608. auto files = cfd_->current()->storage_info()->LevelFiles(0);
  609. RunCompaction({files}, expected_results, {10U, 20U}, 10U);
  610. }
  611. TEST_F(CompactionJobTest, EarliestWriteConflictSnapshot) {
  612. NewDB();
  613. // Test multiple snapshots where the earliest snapshot is not a
  614. // write-conflic-snapshot.
  615. auto file1 = mock::MakeMockFile({
  616. {KeyStr("A", 24U, kTypeSingleDeletion), ""},
  617. {KeyStr("A", 23U, kTypeValue), "val"},
  618. {KeyStr("B", 24U, kTypeSingleDeletion), ""},
  619. {KeyStr("B", 23U, kTypeValue), "val"},
  620. {KeyStr("D", 24U, kTypeSingleDeletion), ""},
  621. {KeyStr("G", 32U, kTypeSingleDeletion), ""},
  622. {KeyStr("G", 31U, kTypeValue), "val"},
  623. {KeyStr("G", 24U, kTypeSingleDeletion), ""},
  624. {KeyStr("G", 23U, kTypeValue), "val2"},
  625. {KeyStr("H", 31U, kTypeValue), "val"},
  626. {KeyStr("H", 24U, kTypeSingleDeletion), ""},
  627. {KeyStr("H", 23U, kTypeValue), "val"},
  628. {KeyStr("I", 35U, kTypeSingleDeletion), ""},
  629. {KeyStr("I", 34U, kTypeValue), "val2"},
  630. {KeyStr("I", 33U, kTypeSingleDeletion), ""},
  631. {KeyStr("I", 32U, kTypeValue), "val3"},
  632. {KeyStr("I", 31U, kTypeSingleDeletion), ""},
  633. {KeyStr("J", 34U, kTypeValue), "val"},
  634. {KeyStr("J", 33U, kTypeSingleDeletion), ""},
  635. {KeyStr("J", 25U, kTypeValue), "val2"},
  636. {KeyStr("J", 24U, kTypeSingleDeletion), ""},
  637. });
  638. AddMockFile(file1);
  639. auto file2 = mock::MakeMockFile({
  640. {KeyStr("A", 14U, kTypeSingleDeletion), ""},
  641. {KeyStr("A", 13U, kTypeValue), "val2"},
  642. {KeyStr("C", 14U, kTypeSingleDeletion), ""},
  643. {KeyStr("C", 13U, kTypeValue), "val"},
  644. {KeyStr("E", 12U, kTypeSingleDeletion), ""},
  645. {KeyStr("F", 4U, kTypeSingleDeletion), ""},
  646. {KeyStr("F", 3U, kTypeValue), "val"},
  647. {KeyStr("G", 14U, kTypeSingleDeletion), ""},
  648. {KeyStr("G", 13U, kTypeValue), "val3"},
  649. {KeyStr("H", 14U, kTypeSingleDeletion), ""},
  650. {KeyStr("H", 13U, kTypeValue), "val2"},
  651. {KeyStr("I", 13U, kTypeValue), "val4"},
  652. {KeyStr("I", 12U, kTypeSingleDeletion), ""},
  653. {KeyStr("I", 11U, kTypeValue), "val5"},
  654. {KeyStr("J", 15U, kTypeValue), "val3"},
  655. {KeyStr("J", 14U, kTypeSingleDeletion), ""},
  656. });
  657. AddMockFile(file2);
  658. auto expected_results = mock::MakeMockFile({
  659. {KeyStr("A", 24U, kTypeSingleDeletion), ""},
  660. {KeyStr("A", 23U, kTypeValue), ""},
  661. {KeyStr("B", 24U, kTypeSingleDeletion), ""},
  662. {KeyStr("B", 23U, kTypeValue), ""},
  663. {KeyStr("D", 24U, kTypeSingleDeletion), ""},
  664. {KeyStr("E", 12U, kTypeSingleDeletion), ""},
  665. {KeyStr("G", 32U, kTypeSingleDeletion), ""},
  666. {KeyStr("G", 31U, kTypeValue), ""},
  667. {KeyStr("H", 31U, kTypeValue), "val"},
  668. {KeyStr("I", 35U, kTypeSingleDeletion), ""},
  669. {KeyStr("I", 34U, kTypeValue), ""},
  670. {KeyStr("I", 31U, kTypeSingleDeletion), ""},
  671. {KeyStr("I", 13U, kTypeValue), "val4"},
  672. {KeyStr("J", 34U, kTypeValue), "val"},
  673. {KeyStr("J", 33U, kTypeSingleDeletion), ""},
  674. {KeyStr("J", 25U, kTypeValue), "val2"},
  675. {KeyStr("J", 24U, kTypeSingleDeletion), ""},
  676. {KeyStr("J", 15U, kTypeValue), "val3"},
  677. {KeyStr("J", 14U, kTypeSingleDeletion), ""},
  678. });
  679. SetLastSequence(24U);
  680. auto files = cfd_->current()->storage_info()->LevelFiles(0);
  681. RunCompaction({files}, expected_results, {10U, 20U, 30U}, 20U);
  682. }
  683. TEST_F(CompactionJobTest, SingleDeleteZeroSeq) {
  684. NewDB();
  685. auto file1 = mock::MakeMockFile({
  686. {KeyStr("A", 10U, kTypeSingleDeletion), ""},
  687. {KeyStr("dummy", 5U, kTypeValue), "val2"},
  688. });
  689. AddMockFile(file1);
  690. auto file2 = mock::MakeMockFile({
  691. {KeyStr("A", 0U, kTypeValue), "val"},
  692. });
  693. AddMockFile(file2);
  694. auto expected_results = mock::MakeMockFile({
  695. {KeyStr("dummy", 0U, kTypeValue), "val2"},
  696. });
  697. SetLastSequence(22U);
  698. auto files = cfd_->current()->storage_info()->LevelFiles(0);
  699. RunCompaction({files}, expected_results, {});
  700. }
  701. TEST_F(CompactionJobTest, MultiSingleDelete) {
  702. // Tests three scenarios involving multiple single delete/put pairs:
  703. //
  704. // A: Put Snapshot SDel Put SDel -> Put Snapshot SDel
  705. // B: Snapshot Put SDel Put SDel Snapshot -> Snapshot SDel Snapshot
  706. // C: SDel Put SDel Snapshot Put -> Snapshot Put
  707. // D: (Put) SDel Snapshot Put SDel -> (Put) SDel Snapshot SDel
  708. // E: Put SDel Snapshot Put SDel -> Snapshot SDel
  709. // F: Put SDel Put Sdel Snapshot -> removed
  710. // G: Snapshot SDel Put SDel Put -> Snapshot Put SDel
  711. // H: (Put) Put SDel Put Sdel Snapshot -> Removed
  712. // I: (Put) Snapshot Put SDel Put SDel -> SDel
  713. // J: Put Put SDel Put SDel SDel Snapshot Put Put SDel SDel Put
  714. // -> Snapshot Put
  715. // K: SDel SDel Put SDel Put Put Snapshot SDel Put SDel SDel Put SDel
  716. // -> Snapshot Put Snapshot SDel
  717. // L: SDel Put Del Put SDel Snapshot Del Put Del SDel Put SDel
  718. // -> Snapshot SDel
  719. // M: (Put) SDel Put Del Put SDel Snapshot Put Del SDel Put SDel Del
  720. // -> SDel Snapshot Del
  721. NewDB();
  722. auto file1 = mock::MakeMockFile({
  723. {KeyStr("A", 14U, kTypeSingleDeletion), ""},
  724. {KeyStr("A", 13U, kTypeValue), "val5"},
  725. {KeyStr("A", 12U, kTypeSingleDeletion), ""},
  726. {KeyStr("B", 14U, kTypeSingleDeletion), ""},
  727. {KeyStr("B", 13U, kTypeValue), "val2"},
  728. {KeyStr("C", 14U, kTypeValue), "val3"},
  729. {KeyStr("D", 12U, kTypeSingleDeletion), ""},
  730. {KeyStr("D", 11U, kTypeValue), "val4"},
  731. {KeyStr("G", 15U, kTypeValue), "val"},
  732. {KeyStr("G", 14U, kTypeSingleDeletion), ""},
  733. {KeyStr("G", 13U, kTypeValue), "val"},
  734. {KeyStr("I", 14U, kTypeSingleDeletion), ""},
  735. {KeyStr("I", 13U, kTypeValue), "val"},
  736. {KeyStr("J", 15U, kTypeValue), "val"},
  737. {KeyStr("J", 14U, kTypeSingleDeletion), ""},
  738. {KeyStr("J", 13U, kTypeSingleDeletion), ""},
  739. {KeyStr("J", 12U, kTypeValue), "val"},
  740. {KeyStr("J", 11U, kTypeValue), "val"},
  741. {KeyStr("K", 16U, kTypeSingleDeletion), ""},
  742. {KeyStr("K", 15U, kTypeValue), "val1"},
  743. {KeyStr("K", 14U, kTypeSingleDeletion), ""},
  744. {KeyStr("K", 13U, kTypeSingleDeletion), ""},
  745. {KeyStr("K", 12U, kTypeValue), "val2"},
  746. {KeyStr("K", 11U, kTypeSingleDeletion), ""},
  747. {KeyStr("L", 16U, kTypeSingleDeletion), ""},
  748. {KeyStr("L", 15U, kTypeValue), "val"},
  749. {KeyStr("L", 14U, kTypeSingleDeletion), ""},
  750. {KeyStr("L", 13U, kTypeDeletion), ""},
  751. {KeyStr("L", 12U, kTypeValue), "val"},
  752. {KeyStr("L", 11U, kTypeDeletion), ""},
  753. {KeyStr("M", 16U, kTypeDeletion), ""},
  754. {KeyStr("M", 15U, kTypeSingleDeletion), ""},
  755. {KeyStr("M", 14U, kTypeValue), "val"},
  756. {KeyStr("M", 13U, kTypeSingleDeletion), ""},
  757. {KeyStr("M", 12U, kTypeDeletion), ""},
  758. {KeyStr("M", 11U, kTypeValue), "val"},
  759. });
  760. AddMockFile(file1);
  761. auto file2 = mock::MakeMockFile({
  762. {KeyStr("A", 10U, kTypeValue), "val"},
  763. {KeyStr("B", 12U, kTypeSingleDeletion), ""},
  764. {KeyStr("B", 11U, kTypeValue), "val2"},
  765. {KeyStr("C", 10U, kTypeSingleDeletion), ""},
  766. {KeyStr("C", 9U, kTypeValue), "val6"},
  767. {KeyStr("C", 8U, kTypeSingleDeletion), ""},
  768. {KeyStr("D", 10U, kTypeSingleDeletion), ""},
  769. {KeyStr("E", 12U, kTypeSingleDeletion), ""},
  770. {KeyStr("E", 11U, kTypeValue), "val"},
  771. {KeyStr("E", 5U, kTypeSingleDeletion), ""},
  772. {KeyStr("E", 4U, kTypeValue), "val"},
  773. {KeyStr("F", 6U, kTypeSingleDeletion), ""},
  774. {KeyStr("F", 5U, kTypeValue), "val"},
  775. {KeyStr("F", 4U, kTypeSingleDeletion), ""},
  776. {KeyStr("F", 3U, kTypeValue), "val"},
  777. {KeyStr("G", 12U, kTypeSingleDeletion), ""},
  778. {KeyStr("H", 6U, kTypeSingleDeletion), ""},
  779. {KeyStr("H", 5U, kTypeValue), "val"},
  780. {KeyStr("H", 4U, kTypeSingleDeletion), ""},
  781. {KeyStr("H", 3U, kTypeValue), "val"},
  782. {KeyStr("I", 12U, kTypeSingleDeletion), ""},
  783. {KeyStr("I", 11U, kTypeValue), "val"},
  784. {KeyStr("J", 6U, kTypeSingleDeletion), ""},
  785. {KeyStr("J", 5U, kTypeSingleDeletion), ""},
  786. {KeyStr("J", 4U, kTypeValue), "val"},
  787. {KeyStr("J", 3U, kTypeSingleDeletion), ""},
  788. {KeyStr("J", 2U, kTypeValue), "val"},
  789. {KeyStr("K", 8U, kTypeValue), "val3"},
  790. {KeyStr("K", 7U, kTypeValue), "val4"},
  791. {KeyStr("K", 6U, kTypeSingleDeletion), ""},
  792. {KeyStr("K", 5U, kTypeValue), "val5"},
  793. {KeyStr("K", 2U, kTypeSingleDeletion), ""},
  794. {KeyStr("K", 1U, kTypeSingleDeletion), ""},
  795. {KeyStr("L", 5U, kTypeSingleDeletion), ""},
  796. {KeyStr("L", 4U, kTypeValue), "val"},
  797. {KeyStr("L", 3U, kTypeDeletion), ""},
  798. {KeyStr("L", 2U, kTypeValue), "val"},
  799. {KeyStr("L", 1U, kTypeSingleDeletion), ""},
  800. {KeyStr("M", 10U, kTypeSingleDeletion), ""},
  801. {KeyStr("M", 7U, kTypeValue), "val"},
  802. {KeyStr("M", 5U, kTypeDeletion), ""},
  803. {KeyStr("M", 4U, kTypeValue), "val"},
  804. {KeyStr("M", 3U, kTypeSingleDeletion), ""},
  805. });
  806. AddMockFile(file2);
  807. auto file3 = mock::MakeMockFile({
  808. {KeyStr("D", 1U, kTypeValue), "val"},
  809. {KeyStr("H", 1U, kTypeValue), "val"},
  810. {KeyStr("I", 2U, kTypeValue), "val"},
  811. });
  812. AddMockFile(file3, 2);
  813. auto file4 = mock::MakeMockFile({
  814. {KeyStr("M", 1U, kTypeValue), "val"},
  815. });
  816. AddMockFile(file4, 2);
  817. auto expected_results =
  818. mock::MakeMockFile({{KeyStr("A", 14U, kTypeSingleDeletion), ""},
  819. {KeyStr("A", 13U, kTypeValue), ""},
  820. {KeyStr("A", 12U, kTypeSingleDeletion), ""},
  821. {KeyStr("A", 10U, kTypeValue), "val"},
  822. {KeyStr("B", 14U, kTypeSingleDeletion), ""},
  823. {KeyStr("B", 13U, kTypeValue), ""},
  824. {KeyStr("C", 14U, kTypeValue), "val3"},
  825. {KeyStr("D", 12U, kTypeSingleDeletion), ""},
  826. {KeyStr("D", 11U, kTypeValue), ""},
  827. {KeyStr("D", 10U, kTypeSingleDeletion), ""},
  828. {KeyStr("E", 12U, kTypeSingleDeletion), ""},
  829. {KeyStr("E", 11U, kTypeValue), ""},
  830. {KeyStr("G", 15U, kTypeValue), "val"},
  831. {KeyStr("G", 12U, kTypeSingleDeletion), ""},
  832. {KeyStr("I", 14U, kTypeSingleDeletion), ""},
  833. {KeyStr("I", 13U, kTypeValue), ""},
  834. {KeyStr("J", 15U, kTypeValue), "val"},
  835. {KeyStr("K", 16U, kTypeSingleDeletion), ""},
  836. {KeyStr("K", 15U, kTypeValue), ""},
  837. {KeyStr("K", 11U, kTypeSingleDeletion), ""},
  838. {KeyStr("K", 8U, kTypeValue), "val3"},
  839. {KeyStr("L", 16U, kTypeSingleDeletion), ""},
  840. {KeyStr("L", 15U, kTypeValue), ""},
  841. {KeyStr("M", 16U, kTypeDeletion), ""},
  842. {KeyStr("M", 3U, kTypeSingleDeletion), ""}});
  843. SetLastSequence(22U);
  844. auto files = cfd_->current()->storage_info()->LevelFiles(0);
  845. RunCompaction({files}, expected_results, {10U}, 10U);
  846. }
  847. // This test documents the behavior where a corrupt key follows a deletion or a
  848. // single deletion and the (single) deletion gets removed while the corrupt key
  849. // gets written out. TODO(noetzli): We probably want a better way to treat
  850. // corrupt keys.
  851. TEST_F(CompactionJobTest, CorruptionAfterDeletion) {
  852. NewDB();
  853. auto file1 =
  854. mock::MakeMockFile({{test::KeyStr("A", 6U, kTypeValue), "val3"},
  855. {test::KeyStr("a", 5U, kTypeDeletion), ""},
  856. {test::KeyStr("a", 4U, kTypeValue, true), "val"}});
  857. AddMockFile(file1);
  858. auto file2 =
  859. mock::MakeMockFile({{test::KeyStr("b", 3U, kTypeSingleDeletion), ""},
  860. {test::KeyStr("b", 2U, kTypeValue, true), "val"},
  861. {test::KeyStr("c", 1U, kTypeValue), "val2"}});
  862. AddMockFile(file2);
  863. auto expected_results =
  864. mock::MakeMockFile({{test::KeyStr("A", 0U, kTypeValue), "val3"},
  865. {test::KeyStr("a", 0U, kTypeValue, true), "val"},
  866. {test::KeyStr("b", 0U, kTypeValue, true), "val"},
  867. {test::KeyStr("c", 0U, kTypeValue), "val2"}});
  868. SetLastSequence(6U);
  869. auto files = cfd_->current()->storage_info()->LevelFiles(0);
  870. RunCompaction({files}, expected_results);
  871. }
  872. TEST_F(CompactionJobTest, OldestBlobFileNumber) {
  873. NewDB();
  874. // Note: blob1 is inlined TTL, so it will not be considered for the purposes
  875. // of identifying the oldest referenced blob file. Similarly, blob6 will be
  876. // ignored because it has TTL and hence refers to a TTL blob file.
  877. const stl_wrappers::KVMap::value_type blob1(
  878. KeyStr("a", 1U, kTypeBlobIndex), BlobStrInlinedTTL("foo", 1234567890ULL));
  879. const stl_wrappers::KVMap::value_type blob2(KeyStr("b", 2U, kTypeBlobIndex),
  880. BlobStr(59, 123456, 999));
  881. const stl_wrappers::KVMap::value_type blob3(KeyStr("c", 3U, kTypeBlobIndex),
  882. BlobStr(138, 1000, 1 << 8));
  883. auto file1 = mock::MakeMockFile({blob1, blob2, blob3});
  884. AddMockFile(file1);
  885. const stl_wrappers::KVMap::value_type blob4(KeyStr("d", 4U, kTypeBlobIndex),
  886. BlobStr(199, 3 << 10, 1 << 20));
  887. const stl_wrappers::KVMap::value_type blob5(KeyStr("e", 5U, kTypeBlobIndex),
  888. BlobStr(19, 6789, 333));
  889. const stl_wrappers::KVMap::value_type blob6(
  890. KeyStr("f", 6U, kTypeBlobIndex),
  891. BlobStrTTL(5, 2048, 1 << 7, 1234567890ULL));
  892. auto file2 = mock::MakeMockFile({blob4, blob5, blob6});
  893. AddMockFile(file2);
  894. const stl_wrappers::KVMap::value_type expected_blob1(
  895. KeyStr("a", 0U, kTypeBlobIndex), blob1.second);
  896. const stl_wrappers::KVMap::value_type expected_blob2(
  897. KeyStr("b", 0U, kTypeBlobIndex), blob2.second);
  898. const stl_wrappers::KVMap::value_type expected_blob3(
  899. KeyStr("c", 0U, kTypeBlobIndex), blob3.second);
  900. const stl_wrappers::KVMap::value_type expected_blob4(
  901. KeyStr("d", 0U, kTypeBlobIndex), blob4.second);
  902. const stl_wrappers::KVMap::value_type expected_blob5(
  903. KeyStr("e", 0U, kTypeBlobIndex), blob5.second);
  904. const stl_wrappers::KVMap::value_type expected_blob6(
  905. KeyStr("f", 0U, kTypeBlobIndex), blob6.second);
  906. auto expected_results =
  907. mock::MakeMockFile({expected_blob1, expected_blob2, expected_blob3,
  908. expected_blob4, expected_blob5, expected_blob6});
  909. SetLastSequence(6U);
  910. auto files = cfd_->current()->storage_info()->LevelFiles(0);
  911. RunCompaction({files}, expected_results, std::vector<SequenceNumber>(),
  912. kMaxSequenceNumber, /* output_level */ 1, /* verify */ true,
  913. /* expected_oldest_blob_file_number */ 19);
  914. }
  915. } // namespace ROCKSDB_NAMESPACE
  916. int main(int argc, char** argv) {
  917. ::testing::InitGoogleTest(&argc, argv);
  918. return RUN_ALL_TESTS();
  919. }
  920. #else
  921. #include <stdio.h>
  922. int main(int /*argc*/, char** /*argv*/) {
  923. fprintf(stderr,
  924. "SKIPPED as CompactionJobStats is not supported in ROCKSDB_LITE\n");
  925. return 0;
  926. }
  927. #endif // ROCKSDB_LITE