2018-11-27 21:59:27 +01:00
|
|
|
// 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
|
|
|
|
|
2019-06-06 22:52:39 +02:00
|
|
|
#include <cinttypes>
|
2018-11-27 21:59:27 +01:00
|
|
|
|
2019-03-26 18:15:43 +01:00
|
|
|
#include "rocksdb/db.h"
|
2018-11-27 21:59:27 +01:00
|
|
|
#include "rocksdb/sst_file_reader.h"
|
|
|
|
#include "rocksdb/sst_file_writer.h"
|
2019-03-26 18:15:43 +01:00
|
|
|
#include "table/sst_file_writer_collectors.h"
|
2019-05-30 20:21:38 +02:00
|
|
|
#include "test_util/testharness.h"
|
|
|
|
#include "test_util/testutil.h"
|
2018-11-27 21:59:27 +01:00
|
|
|
#include "utilities/merge_operators.h"
|
|
|
|
|
|
|
|
namespace rocksdb {
|
|
|
|
|
|
|
|
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");
|
|
|
|
}
|
|
|
|
|
2019-03-26 18:15:43 +01:00
|
|
|
~SstFileReaderTest() {
|
|
|
|
Status s = Env::Default()->DeleteFile(sst_name_);
|
|
|
|
assert(s.ok());
|
|
|
|
}
|
|
|
|
|
|
|
|
void CreateFile(const std::string& file_name,
|
|
|
|
const std::vector<std::string>& keys) {
|
2018-11-27 21:59:27 +01:00
|
|
|
SstFileWriter writer(soptions_, options_);
|
2019-03-26 18:15:43 +01:00
|
|
|
ASSERT_OK(writer.Open(file_name));
|
2018-11-27 21:59:27 +01:00
|
|
|
for (size_t i = 0; i + 2 < keys.size(); i += 3) {
|
|
|
|
ASSERT_OK(writer.Put(keys[i], keys[i]));
|
2018-12-13 23:12:02 +01:00
|
|
|
ASSERT_OK(writer.Merge(keys[i + 1], EncodeAsUint64(i + 1)));
|
|
|
|
ASSERT_OK(writer.Delete(keys[i + 2]));
|
2018-11-27 21:59:27 +01:00
|
|
|
}
|
|
|
|
ASSERT_OK(writer.Finish());
|
2019-03-26 18:15:43 +01:00
|
|
|
}
|
2018-11-27 21:59:27 +01:00
|
|
|
|
2019-03-26 18:15:43 +01:00
|
|
|
void CheckFile(const std::string& file_name,
|
|
|
|
const std::vector<std::string>& keys,
|
|
|
|
bool check_global_seqno = false) {
|
2018-11-27 21:59:27 +01:00
|
|
|
ReadOptions ropts;
|
|
|
|
SstFileReader reader(options_);
|
2019-03-26 18:15:43 +01:00
|
|
|
ASSERT_OK(reader.Open(file_name));
|
2018-11-27 21:59:27 +01:00
|
|
|
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());
|
2018-12-13 23:12:02 +01:00
|
|
|
ASSERT_EQ(iter->key().compare(keys[i + 1]), 0);
|
|
|
|
ASSERT_EQ(iter->value().compare(EncodeAsUint64(i + 1)), 0);
|
2018-11-27 21:59:27 +01:00
|
|
|
iter->Next();
|
|
|
|
}
|
|
|
|
ASSERT_FALSE(iter->Valid());
|
2019-03-26 18:15:43 +01:00
|
|
|
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);
|
2018-11-27 21:59:27 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2019-03-26 18:15:43 +01:00
|
|
|
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));
|
|
|
|
}
|
|
|
|
|
2018-11-27 21:59:27 +01:00
|
|
|
} // namespace rocksdb
|
|
|
|
|
|
|
|
int main(int argc, char** argv) {
|
|
|
|
::testing::InitGoogleTest(&argc, argv);
|
|
|
|
return RUN_ALL_TESTS();
|
|
|
|
}
|
|
|
|
|
2018-11-29 19:49:07 +01:00
|
|
|
#else
|
|
|
|
#include <stdio.h>
|
|
|
|
|
|
|
|
int main(int /*argc*/, char** /*argv*/) {
|
2018-12-13 23:12:02 +01:00
|
|
|
fprintf(stderr,
|
|
|
|
"SKIPPED as SstFileReader is not supported in ROCKSDB_LITE\n");
|
2018-11-29 19:49:07 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2018-11-27 21:59:27 +01:00
|
|
|
#endif // ROCKSDB_LITE
|