sst_file_reader_test.cc 5.0 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. #ifndef ROCKSDB_LITE
  6. #include <cinttypes>
  7. #include "rocksdb/db.h"
  8. #include "rocksdb/sst_file_reader.h"
  9. #include "rocksdb/sst_file_writer.h"
  10. #include "table/sst_file_writer_collectors.h"
  11. #include "test_util/testharness.h"
  12. #include "test_util/testutil.h"
  13. #include "utilities/merge_operators.h"
  14. namespace ROCKSDB_NAMESPACE {
  15. std::string EncodeAsString(uint64_t v) {
  16. char buf[16];
  17. snprintf(buf, sizeof(buf), "%08" PRIu64, v);
  18. return std::string(buf);
  19. }
  20. std::string EncodeAsUint64(uint64_t v) {
  21. std::string dst;
  22. PutFixed64(&dst, v);
  23. return dst;
  24. }
  25. class SstFileReaderTest : public testing::Test {
  26. public:
  27. SstFileReaderTest() {
  28. options_.merge_operator = MergeOperators::CreateUInt64AddOperator();
  29. sst_name_ = test::PerThreadDBPath("sst_file");
  30. }
  31. ~SstFileReaderTest() {
  32. Status s = Env::Default()->DeleteFile(sst_name_);
  33. assert(s.ok());
  34. }
  35. void CreateFile(const std::string& file_name,
  36. const std::vector<std::string>& keys) {
  37. SstFileWriter writer(soptions_, options_);
  38. ASSERT_OK(writer.Open(file_name));
  39. for (size_t i = 0; i + 2 < keys.size(); i += 3) {
  40. ASSERT_OK(writer.Put(keys[i], keys[i]));
  41. ASSERT_OK(writer.Merge(keys[i + 1], EncodeAsUint64(i + 1)));
  42. ASSERT_OK(writer.Delete(keys[i + 2]));
  43. }
  44. ASSERT_OK(writer.Finish());
  45. }
  46. void CheckFile(const std::string& file_name,
  47. const std::vector<std::string>& keys,
  48. bool check_global_seqno = false) {
  49. ReadOptions ropts;
  50. SstFileReader reader(options_);
  51. ASSERT_OK(reader.Open(file_name));
  52. ASSERT_OK(reader.VerifyChecksum());
  53. std::unique_ptr<Iterator> iter(reader.NewIterator(ropts));
  54. iter->SeekToFirst();
  55. for (size_t i = 0; i + 2 < keys.size(); i += 3) {
  56. ASSERT_TRUE(iter->Valid());
  57. ASSERT_EQ(iter->key().compare(keys[i]), 0);
  58. ASSERT_EQ(iter->value().compare(keys[i]), 0);
  59. iter->Next();
  60. ASSERT_TRUE(iter->Valid());
  61. ASSERT_EQ(iter->key().compare(keys[i + 1]), 0);
  62. ASSERT_EQ(iter->value().compare(EncodeAsUint64(i + 1)), 0);
  63. iter->Next();
  64. }
  65. ASSERT_FALSE(iter->Valid());
  66. if (check_global_seqno) {
  67. auto properties = reader.GetTableProperties();
  68. ASSERT_TRUE(properties);
  69. auto& user_properties = properties->user_collected_properties;
  70. ASSERT_TRUE(
  71. user_properties.count(ExternalSstFilePropertyNames::kGlobalSeqno));
  72. }
  73. }
  74. void CreateFileAndCheck(const std::vector<std::string>& keys) {
  75. CreateFile(sst_name_, keys);
  76. CheckFile(sst_name_, keys);
  77. }
  78. protected:
  79. Options options_;
  80. EnvOptions soptions_;
  81. std::string sst_name_;
  82. };
  83. const uint64_t kNumKeys = 100;
  84. TEST_F(SstFileReaderTest, Basic) {
  85. std::vector<std::string> keys;
  86. for (uint64_t i = 0; i < kNumKeys; i++) {
  87. keys.emplace_back(EncodeAsString(i));
  88. }
  89. CreateFileAndCheck(keys);
  90. }
  91. TEST_F(SstFileReaderTest, Uint64Comparator) {
  92. options_.comparator = test::Uint64Comparator();
  93. std::vector<std::string> keys;
  94. for (uint64_t i = 0; i < kNumKeys; i++) {
  95. keys.emplace_back(EncodeAsUint64(i));
  96. }
  97. CreateFileAndCheck(keys);
  98. }
  99. TEST_F(SstFileReaderTest, ReadFileWithGlobalSeqno) {
  100. std::vector<std::string> keys;
  101. for (uint64_t i = 0; i < kNumKeys; i++) {
  102. keys.emplace_back(EncodeAsString(i));
  103. }
  104. // Generate a SST file.
  105. CreateFile(sst_name_, keys);
  106. // Ingest the file into a db, to assign it a global sequence number.
  107. Options options;
  108. options.create_if_missing = true;
  109. std::string db_name = test::PerThreadDBPath("test_db");
  110. DB* db;
  111. ASSERT_OK(DB::Open(options, db_name, &db));
  112. // Bump sequence number.
  113. ASSERT_OK(db->Put(WriteOptions(), keys[0], "foo"));
  114. ASSERT_OK(db->Flush(FlushOptions()));
  115. // Ingest the file.
  116. IngestExternalFileOptions ingest_options;
  117. ingest_options.write_global_seqno = true;
  118. ASSERT_OK(db->IngestExternalFile({sst_name_}, ingest_options));
  119. std::vector<std::string> live_files;
  120. uint64_t manifest_file_size = 0;
  121. ASSERT_OK(db->GetLiveFiles(live_files, &manifest_file_size));
  122. // Get the ingested file.
  123. std::string ingested_file;
  124. for (auto& live_file : live_files) {
  125. if (live_file.substr(live_file.size() - 4, std::string::npos) == ".sst") {
  126. if (ingested_file.empty() || ingested_file < live_file) {
  127. ingested_file = live_file;
  128. }
  129. }
  130. }
  131. ASSERT_FALSE(ingested_file.empty());
  132. delete db;
  133. // Verify the file can be open and read by SstFileReader.
  134. CheckFile(db_name + ingested_file, keys, true /* check_global_seqno */);
  135. // Cleanup.
  136. ASSERT_OK(DestroyDB(db_name, options));
  137. }
  138. } // namespace ROCKSDB_NAMESPACE
  139. int main(int argc, char** argv) {
  140. ::testing::InitGoogleTest(&argc, argv);
  141. return RUN_ALL_TESTS();
  142. }
  143. #else
  144. #include <stdio.h>
  145. int main(int /*argc*/, char** /*argv*/) {
  146. fprintf(stderr,
  147. "SKIPPED as SstFileReader is not supported in ROCKSDB_LITE\n");
  148. return 0;
  149. }
  150. #endif // ROCKSDB_LITE