| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174 | // Copyright (c) 2011-present, Facebook, Inc. All rights reserved.//  This source code is licensed under both the GPLv2 (found in the//  COPYING file in the root directory) and Apache 2.0 License//  (found in the LICENSE.Apache file in the root directory).#ifndef ROCKSDB_LITE#include <cinttypes>#include "rocksdb/db.h"#include "rocksdb/sst_file_reader.h"#include "rocksdb/sst_file_writer.h"#include "table/sst_file_writer_collectors.h"#include "test_util/testharness.h"#include "test_util/testutil.h"#include "utilities/merge_operators.h"namespace ROCKSDB_NAMESPACE {std::string EncodeAsString(uint64_t v) {  char buf[16];  snprintf(buf, sizeof(buf), "%08" PRIu64, v);  return std::string(buf);}std::string EncodeAsUint64(uint64_t v) {  std::string dst;  PutFixed64(&dst, v);  return dst;}class SstFileReaderTest : public testing::Test { public:  SstFileReaderTest() {    options_.merge_operator = MergeOperators::CreateUInt64AddOperator();    sst_name_ = test::PerThreadDBPath("sst_file");  }  ~SstFileReaderTest() {    Status s = Env::Default()->DeleteFile(sst_name_);    assert(s.ok());  }  void CreateFile(const std::string& file_name,                  const std::vector<std::string>& keys) {    SstFileWriter writer(soptions_, options_);    ASSERT_OK(writer.Open(file_name));    for (size_t i = 0; i + 2 < keys.size(); i += 3) {      ASSERT_OK(writer.Put(keys[i], keys[i]));      ASSERT_OK(writer.Merge(keys[i + 1], EncodeAsUint64(i + 1)));      ASSERT_OK(writer.Delete(keys[i + 2]));    }    ASSERT_OK(writer.Finish());  }  void CheckFile(const std::string& file_name,                 const std::vector<std::string>& keys,                 bool check_global_seqno = false) {    ReadOptions ropts;    SstFileReader reader(options_);    ASSERT_OK(reader.Open(file_name));    ASSERT_OK(reader.VerifyChecksum());    std::unique_ptr<Iterator> iter(reader.NewIterator(ropts));    iter->SeekToFirst();    for (size_t i = 0; i + 2 < keys.size(); i += 3) {      ASSERT_TRUE(iter->Valid());      ASSERT_EQ(iter->key().compare(keys[i]), 0);      ASSERT_EQ(iter->value().compare(keys[i]), 0);      iter->Next();      ASSERT_TRUE(iter->Valid());      ASSERT_EQ(iter->key().compare(keys[i + 1]), 0);      ASSERT_EQ(iter->value().compare(EncodeAsUint64(i + 1)), 0);      iter->Next();    }    ASSERT_FALSE(iter->Valid());    if (check_global_seqno) {      auto properties = reader.GetTableProperties();      ASSERT_TRUE(properties);      auto& user_properties = properties->user_collected_properties;      ASSERT_TRUE(          user_properties.count(ExternalSstFilePropertyNames::kGlobalSeqno));    }  }  void CreateFileAndCheck(const std::vector<std::string>& keys) {    CreateFile(sst_name_, keys);    CheckFile(sst_name_, keys);  } protected:  Options options_;  EnvOptions soptions_;  std::string sst_name_;};const uint64_t kNumKeys = 100;TEST_F(SstFileReaderTest, Basic) {  std::vector<std::string> keys;  for (uint64_t i = 0; i < kNumKeys; i++) {    keys.emplace_back(EncodeAsString(i));  }  CreateFileAndCheck(keys);}TEST_F(SstFileReaderTest, Uint64Comparator) {  options_.comparator = test::Uint64Comparator();  std::vector<std::string> keys;  for (uint64_t i = 0; i < kNumKeys; i++) {    keys.emplace_back(EncodeAsUint64(i));  }  CreateFileAndCheck(keys);}TEST_F(SstFileReaderTest, ReadFileWithGlobalSeqno) {  std::vector<std::string> keys;  for (uint64_t i = 0; i < kNumKeys; i++) {    keys.emplace_back(EncodeAsString(i));  }  // Generate a SST file.  CreateFile(sst_name_, keys);  // Ingest the file into a db, to assign it a global sequence number.  Options options;  options.create_if_missing = true;  std::string db_name = test::PerThreadDBPath("test_db");  DB* db;  ASSERT_OK(DB::Open(options, db_name, &db));  // Bump sequence number.  ASSERT_OK(db->Put(WriteOptions(), keys[0], "foo"));  ASSERT_OK(db->Flush(FlushOptions()));  // Ingest the file.  IngestExternalFileOptions ingest_options;  ingest_options.write_global_seqno = true;  ASSERT_OK(db->IngestExternalFile({sst_name_}, ingest_options));  std::vector<std::string> live_files;  uint64_t manifest_file_size = 0;  ASSERT_OK(db->GetLiveFiles(live_files, &manifest_file_size));  // Get the ingested file.  std::string ingested_file;  for (auto& live_file : live_files) {    if (live_file.substr(live_file.size() - 4, std::string::npos) == ".sst") {      if (ingested_file.empty() || ingested_file < live_file) {        ingested_file = live_file;      }    }  }  ASSERT_FALSE(ingested_file.empty());  delete db;  // Verify the file can be open and read by SstFileReader.  CheckFile(db_name + ingested_file, keys, true /* check_global_seqno */);  // Cleanup.  ASSERT_OK(DestroyDB(db_name, options));}}  // namespace ROCKSDB_NAMESPACEint main(int argc, char** argv) {  ::testing::InitGoogleTest(&argc, argv);  return RUN_ALL_TESTS();}#else#include <stdio.h>int main(int /*argc*/, char** /*argv*/) {  fprintf(stderr,          "SKIPPED as SstFileReader is not supported in ROCKSDB_LITE\n");  return 0;}#endif  // ROCKSDB_LITE
 |