Update test to cover a new case in file ingestion (#4614)

Summary:
The new case is directIO = true, write_global_seqno = false in which we no longer write global_seqno to the external SST file.
Pull Request resolved: https://github.com/facebook/rocksdb/pull/4614

Differential Revision: D12885001

Pulled By: riversand963

fbshipit-source-id: 7541bdc608b3a0c93d3c3c435da1b162b36673d4
This commit is contained in:
Yanqin Jin 2018-11-01 16:21:30 -07:00 committed by Facebook Github Bot
parent 3f8f81cfeb
commit de18a2d82e
4 changed files with 234 additions and 137 deletions

View File

@ -259,6 +259,47 @@ bool DBTestBase::ChangeFilterOptions() {
return true; return true;
} }
// Switch between different DB options for file ingestion tests.
bool DBTestBase::ChangeOptionsForFileIngestionTest() {
if (option_config_ == kDefault) {
option_config_ = kUniversalCompaction;
Destroy(last_options_);
auto options = CurrentOptions();
options.create_if_missing = true;
TryReopen(options);
return true;
} else if (option_config_ == kUniversalCompaction) {
option_config_ = kUniversalCompactionMultiLevel;
Destroy(last_options_);
auto options = CurrentOptions();
options.create_if_missing = true;
TryReopen(options);
return true;
} else if (option_config_ == kUniversalCompactionMultiLevel) {
option_config_ = kLevelSubcompactions;
Destroy(last_options_);
auto options = CurrentOptions();
assert(options.max_subcompactions > 1);
TryReopen(options);
return true;
} else if (option_config_ == kLevelSubcompactions) {
option_config_ = kUniversalSubcompactions;
Destroy(last_options_);
auto options = CurrentOptions();
assert(options.max_subcompactions > 1);
TryReopen(options);
return true;
} else if (option_config_ == kUniversalSubcompactions) {
option_config_ = kDirectIO;
Destroy(last_options_);
auto options = CurrentOptions();
TryReopen(options);
return true;
} else {
return false;
}
}
// Return the current option configuration. // Return the current option configuration.
Options DBTestBase::CurrentOptions( Options DBTestBase::CurrentOptions(
const anon::OptionsOverride& options_override) const { const anon::OptionsOverride& options_override) const {

View File

@ -747,6 +747,9 @@ class DBTestBase : public testing::Test {
// Jump from kDefault to kFilter to kFullFilter // Jump from kDefault to kFilter to kFullFilter
bool ChangeFilterOptions(); bool ChangeFilterOptions();
// Switch between different DB options for file ingestion tests.
bool ChangeOptionsForFileIngestionTest();
// Return the current option configuration. // Return the current option configuration.
Options CurrentOptions(const anon::OptionsOverride& options_override = Options CurrentOptions(const anon::OptionsOverride& options_override =
anon::OptionsOverride()) const; anon::OptionsOverride()) const;

View File

@ -14,7 +14,8 @@
namespace rocksdb { namespace rocksdb {
#ifndef ROCKSDB_LITE #ifndef ROCKSDB_LITE
class ExternalSSTFileBasicTest : public DBTestBase { class ExternalSSTFileBasicTest : public DBTestBase,
public ::testing::WithParamInterface<bool> {
public: public:
ExternalSSTFileBasicTest() : DBTestBase("/external_sst_file_test") { ExternalSSTFileBasicTest() : DBTestBase("/external_sst_file_test") {
sst_files_dir_ = dbname_ + "/sst_files/"; sst_files_dir_ = dbname_ + "/sst_files/";
@ -41,7 +42,7 @@ class ExternalSSTFileBasicTest : public DBTestBase {
const Options options, std::vector<int> keys, const Options options, std::vector<int> keys,
const std::vector<ValueType>& value_types, const std::vector<ValueType>& value_types,
std::vector<std::pair<int, int>> range_deletions, int file_id, std::vector<std::pair<int, int>> range_deletions, int file_id,
std::map<std::string, std::string>* true_data) { bool write_global_seqno, std::map<std::string, std::string>* true_data) {
assert(value_types.size() == 1 || keys.size() == value_types.size()); assert(value_types.size() == 1 || keys.size() == value_types.size());
std::string file_path = sst_files_dir_ + ToString(file_id); std::string file_path = sst_files_dir_ + ToString(file_id);
SstFileWriter sst_file_writer(EnvOptions(), options); SstFileWriter sst_file_writer(EnvOptions(), options);
@ -105,6 +106,7 @@ class ExternalSSTFileBasicTest : public DBTestBase {
if (s.ok()) { if (s.ok()) {
IngestExternalFileOptions ifo; IngestExternalFileOptions ifo;
ifo.allow_global_seqno = true; ifo.allow_global_seqno = true;
ifo.write_global_seqno = write_global_seqno;
s = db_->IngestExternalFile({file_path}, ifo); s = db_->IngestExternalFile({file_path}, ifo);
} }
return s; return s;
@ -113,17 +115,18 @@ class ExternalSSTFileBasicTest : public DBTestBase {
Status GenerateAndAddExternalFile( Status GenerateAndAddExternalFile(
const Options options, std::vector<int> keys, const Options options, std::vector<int> keys,
const std::vector<ValueType>& value_types, int file_id, const std::vector<ValueType>& value_types, int file_id,
std::map<std::string, std::string>* true_data) { bool write_global_seqno, std::map<std::string, std::string>* true_data) {
return GenerateAndAddExternalFile(options, keys, value_types, {}, file_id, return GenerateAndAddExternalFile(options, keys, value_types, {}, file_id,
true_data); write_global_seqno, true_data);
} }
Status GenerateAndAddExternalFile( Status GenerateAndAddExternalFile(
const Options options, std::vector<int> keys, const ValueType value_type, const Options options, std::vector<int> keys, const ValueType value_type,
int file_id, std::map<std::string, std::string>* true_data) { int file_id, bool write_global_seqno,
std::map<std::string, std::string>* true_data) {
return GenerateAndAddExternalFile(options, keys, return GenerateAndAddExternalFile(options, keys,
std::vector<ValueType>(1, value_type), std::vector<ValueType>(1, value_type),
file_id, true_data); file_id, write_global_seqno, true_data);
} }
~ExternalSSTFileBasicTest() { test::DestroyDir(env_, sst_files_dir_); } ~ExternalSSTFileBasicTest() { test::DestroyDir(env_, sst_files_dir_); }
@ -245,7 +248,8 @@ TEST_F(ExternalSSTFileBasicTest, NoCopy) {
} }
} }
TEST_F(ExternalSSTFileBasicTest, IngestFileWithGlobalSeqnoPickedSeqno) { TEST_P(ExternalSSTFileBasicTest, IngestFileWithGlobalSeqnoPickedSeqno) {
bool write_global_seqno = GetParam();
do { do {
Options options = CurrentOptions(); Options options = CurrentOptions();
DestroyAndReopen(options); DestroyAndReopen(options);
@ -255,33 +259,37 @@ TEST_F(ExternalSSTFileBasicTest, IngestFileWithGlobalSeqnoPickedSeqno) {
ASSERT_OK(GenerateAndAddExternalFile(options, {1, 2, 3, 4, 5, 6}, ASSERT_OK(GenerateAndAddExternalFile(options, {1, 2, 3, 4, 5, 6},
ValueType::kTypeValue, file_id++, ValueType::kTypeValue, file_id++,
&true_data)); write_global_seqno, &true_data));
// File doesn't overwrite any keys, no seqno needed // File doesn't overwrite any keys, no seqno needed
ASSERT_EQ(dbfull()->GetLatestSequenceNumber(), 0); ASSERT_EQ(dbfull()->GetLatestSequenceNumber(), 0);
ASSERT_OK(GenerateAndAddExternalFile(options, {10, 11, 12, 13}, ASSERT_OK(GenerateAndAddExternalFile(options, {10, 11, 12, 13},
ValueType::kTypeValue, file_id++, ValueType::kTypeValue, file_id++,
&true_data)); write_global_seqno, &true_data));
// File doesn't overwrite any keys, no seqno needed // File doesn't overwrite any keys, no seqno needed
ASSERT_EQ(dbfull()->GetLatestSequenceNumber(), 0); ASSERT_EQ(dbfull()->GetLatestSequenceNumber(), 0);
ASSERT_OK(GenerateAndAddExternalFile( ASSERT_OK(GenerateAndAddExternalFile(options, {1, 4, 6},
options, {1, 4, 6}, ValueType::kTypeValue, file_id++, &true_data)); ValueType::kTypeValue, file_id++,
write_global_seqno, &true_data));
// File overwrites some keys, a seqno will be assigned // File overwrites some keys, a seqno will be assigned
ASSERT_EQ(dbfull()->GetLatestSequenceNumber(), 1); ASSERT_EQ(dbfull()->GetLatestSequenceNumber(), 1);
ASSERT_OK(GenerateAndAddExternalFile( ASSERT_OK(GenerateAndAddExternalFile(options, {11, 15, 19},
options, {11, 15, 19}, ValueType::kTypeValue, file_id++, &true_data)); ValueType::kTypeValue, file_id++,
write_global_seqno, &true_data));
// File overwrites some keys, a seqno will be assigned // File overwrites some keys, a seqno will be assigned
ASSERT_EQ(dbfull()->GetLatestSequenceNumber(), 2); ASSERT_EQ(dbfull()->GetLatestSequenceNumber(), 2);
ASSERT_OK(GenerateAndAddExternalFile( ASSERT_OK(GenerateAndAddExternalFile(options, {120, 130},
options, {120, 130}, ValueType::kTypeValue, file_id++, &true_data)); ValueType::kTypeValue, file_id++,
write_global_seqno, &true_data));
// File doesn't overwrite any keys, no seqno needed // File doesn't overwrite any keys, no seqno needed
ASSERT_EQ(dbfull()->GetLatestSequenceNumber(), 2); ASSERT_EQ(dbfull()->GetLatestSequenceNumber(), 2);
ASSERT_OK(GenerateAndAddExternalFile( ASSERT_OK(GenerateAndAddExternalFile(options, {1, 130},
options, {1, 130}, ValueType::kTypeValue, file_id++, &true_data)); ValueType::kTypeValue, file_id++,
write_global_seqno, &true_data));
// File overwrites some keys, a seqno will be assigned // File overwrites some keys, a seqno will be assigned
ASSERT_EQ(dbfull()->GetLatestSequenceNumber(), 3); ASSERT_EQ(dbfull()->GetLatestSequenceNumber(), 3);
@ -292,18 +300,21 @@ TEST_F(ExternalSSTFileBasicTest, IngestFileWithGlobalSeqnoPickedSeqno) {
} }
SequenceNumber last_seqno = dbfull()->GetLatestSequenceNumber(); SequenceNumber last_seqno = dbfull()->GetLatestSequenceNumber();
ASSERT_OK(GenerateAndAddExternalFile( ASSERT_OK(GenerateAndAddExternalFile(options, {60, 61, 62},
options, {60, 61, 62}, ValueType::kTypeValue, file_id++, &true_data)); ValueType::kTypeValue, file_id++,
write_global_seqno, &true_data));
// File doesn't overwrite any keys, no seqno needed // File doesn't overwrite any keys, no seqno needed
ASSERT_EQ(dbfull()->GetLatestSequenceNumber(), last_seqno); ASSERT_EQ(dbfull()->GetLatestSequenceNumber(), last_seqno);
ASSERT_OK(GenerateAndAddExternalFile( ASSERT_OK(GenerateAndAddExternalFile(options, {40, 41, 42},
options, {40, 41, 42}, ValueType::kTypeValue, file_id++, &true_data)); ValueType::kTypeValue, file_id++,
write_global_seqno, &true_data));
// File overwrites some keys, a seqno will be assigned // File overwrites some keys, a seqno will be assigned
ASSERT_EQ(dbfull()->GetLatestSequenceNumber(), last_seqno + 1); ASSERT_EQ(dbfull()->GetLatestSequenceNumber(), last_seqno + 1);
ASSERT_OK(GenerateAndAddExternalFile( ASSERT_OK(GenerateAndAddExternalFile(options, {20, 30, 40},
options, {20, 30, 40}, ValueType::kTypeValue, file_id++, &true_data)); ValueType::kTypeValue, file_id++,
write_global_seqno, &true_data));
// File overwrites some keys, a seqno will be assigned // File overwrites some keys, a seqno will be assigned
ASSERT_EQ(dbfull()->GetLatestSequenceNumber(), last_seqno + 2); ASSERT_EQ(dbfull()->GetLatestSequenceNumber(), last_seqno + 2);
@ -311,35 +322,39 @@ TEST_F(ExternalSSTFileBasicTest, IngestFileWithGlobalSeqnoPickedSeqno) {
// We will need a seqno for the file regardless if the file overwrite // We will need a seqno for the file regardless if the file overwrite
// keys in the DB or not because we have a snapshot // keys in the DB or not because we have a snapshot
ASSERT_OK(GenerateAndAddExternalFile( ASSERT_OK(GenerateAndAddExternalFile(options, {1000, 1002},
options, {1000, 1002}, ValueType::kTypeValue, file_id++, &true_data)); ValueType::kTypeValue, file_id++,
write_global_seqno, &true_data));
// A global seqno will be assigned anyway because of the snapshot // A global seqno will be assigned anyway because of the snapshot
ASSERT_EQ(dbfull()->GetLatestSequenceNumber(), last_seqno + 3); ASSERT_EQ(dbfull()->GetLatestSequenceNumber(), last_seqno + 3);
ASSERT_OK(GenerateAndAddExternalFile( ASSERT_OK(GenerateAndAddExternalFile(options, {2000, 3002},
options, {2000, 3002}, ValueType::kTypeValue, file_id++, &true_data)); ValueType::kTypeValue, file_id++,
write_global_seqno, &true_data));
// A global seqno will be assigned anyway because of the snapshot // A global seqno will be assigned anyway because of the snapshot
ASSERT_EQ(dbfull()->GetLatestSequenceNumber(), last_seqno + 4); ASSERT_EQ(dbfull()->GetLatestSequenceNumber(), last_seqno + 4);
ASSERT_OK(GenerateAndAddExternalFile(options, {1, 20, 40, 100, 150}, ASSERT_OK(GenerateAndAddExternalFile(options, {1, 20, 40, 100, 150},
ValueType::kTypeValue, file_id++, ValueType::kTypeValue, file_id++,
&true_data)); write_global_seqno, &true_data));
// A global seqno will be assigned anyway because of the snapshot // A global seqno will be assigned anyway because of the snapshot
ASSERT_EQ(dbfull()->GetLatestSequenceNumber(), last_seqno + 5); ASSERT_EQ(dbfull()->GetLatestSequenceNumber(), last_seqno + 5);
db_->ReleaseSnapshot(snapshot); db_->ReleaseSnapshot(snapshot);
ASSERT_OK(GenerateAndAddExternalFile( ASSERT_OK(GenerateAndAddExternalFile(options, {5000, 5001},
options, {5000, 5001}, ValueType::kTypeValue, file_id++, &true_data)); ValueType::kTypeValue, file_id++,
write_global_seqno, &true_data));
// No snapshot anymore, no need to assign a seqno // No snapshot anymore, no need to assign a seqno
ASSERT_EQ(dbfull()->GetLatestSequenceNumber(), last_seqno + 5); ASSERT_EQ(dbfull()->GetLatestSequenceNumber(), last_seqno + 5);
size_t kcnt = 0; size_t kcnt = 0;
VerifyDBFromMap(true_data, &kcnt, false); VerifyDBFromMap(true_data, &kcnt, false);
} while (ChangeCompactOptions()); } while (ChangeOptionsForFileIngestionTest());
} }
TEST_F(ExternalSSTFileBasicTest, IngestFileWithMultipleValueType) { TEST_P(ExternalSSTFileBasicTest, IngestFileWithMultipleValueType) {
bool write_global_seqno = GetParam();
do { do {
Options options = CurrentOptions(); Options options = CurrentOptions();
options.merge_operator.reset(new TestPutOperator()); options.merge_operator.reset(new TestPutOperator());
@ -350,52 +365,57 @@ TEST_F(ExternalSSTFileBasicTest, IngestFileWithMultipleValueType) {
ASSERT_OK(GenerateAndAddExternalFile(options, {1, 2, 3, 4, 5, 6}, ASSERT_OK(GenerateAndAddExternalFile(options, {1, 2, 3, 4, 5, 6},
ValueType::kTypeValue, file_id++, ValueType::kTypeValue, file_id++,
&true_data)); write_global_seqno, &true_data));
// File doesn't overwrite any keys, no seqno needed // File doesn't overwrite any keys, no seqno needed
ASSERT_EQ(dbfull()->GetLatestSequenceNumber(), 0); ASSERT_EQ(dbfull()->GetLatestSequenceNumber(), 0);
ASSERT_OK(GenerateAndAddExternalFile(options, {10, 11, 12, 13}, ASSERT_OK(GenerateAndAddExternalFile(options, {10, 11, 12, 13},
ValueType::kTypeValue, file_id++, ValueType::kTypeValue, file_id++,
&true_data)); write_global_seqno, &true_data));
// File doesn't overwrite any keys, no seqno needed // File doesn't overwrite any keys, no seqno needed
ASSERT_EQ(dbfull()->GetLatestSequenceNumber(), 0); ASSERT_EQ(dbfull()->GetLatestSequenceNumber(), 0);
ASSERT_OK(GenerateAndAddExternalFile( ASSERT_OK(GenerateAndAddExternalFile(options, {1, 4, 6},
options, {1, 4, 6}, ValueType::kTypeMerge, file_id++, &true_data)); ValueType::kTypeMerge, file_id++,
write_global_seqno, &true_data));
// File overwrites some keys, a seqno will be assigned // File overwrites some keys, a seqno will be assigned
ASSERT_EQ(dbfull()->GetLatestSequenceNumber(), 1); ASSERT_EQ(dbfull()->GetLatestSequenceNumber(), 1);
ASSERT_OK(GenerateAndAddExternalFile(options, {11, 15, 19}, ASSERT_OK(GenerateAndAddExternalFile(options, {11, 15, 19},
ValueType::kTypeDeletion, file_id++, ValueType::kTypeDeletion, file_id++,
&true_data)); write_global_seqno, &true_data));
// File overwrites some keys, a seqno will be assigned // File overwrites some keys, a seqno will be assigned
ASSERT_EQ(dbfull()->GetLatestSequenceNumber(), 2); ASSERT_EQ(dbfull()->GetLatestSequenceNumber(), 2);
ASSERT_OK(GenerateAndAddExternalFile( ASSERT_OK(GenerateAndAddExternalFile(options, {120, 130},
options, {120, 130}, ValueType::kTypeMerge, file_id++, &true_data)); ValueType::kTypeMerge, file_id++,
write_global_seqno, &true_data));
// File doesn't overwrite any keys, no seqno needed // File doesn't overwrite any keys, no seqno needed
ASSERT_EQ(dbfull()->GetLatestSequenceNumber(), 2); ASSERT_EQ(dbfull()->GetLatestSequenceNumber(), 2);
ASSERT_OK(GenerateAndAddExternalFile( ASSERT_OK(GenerateAndAddExternalFile(options, {1, 130},
options, {1, 130}, ValueType::kTypeDeletion, file_id++, &true_data)); ValueType::kTypeDeletion, file_id++,
write_global_seqno, &true_data));
// File overwrites some keys, a seqno will be assigned // File overwrites some keys, a seqno will be assigned
ASSERT_EQ(dbfull()->GetLatestSequenceNumber(), 3); ASSERT_EQ(dbfull()->GetLatestSequenceNumber(), 3);
ASSERT_OK(GenerateAndAddExternalFile(options, {120}, ASSERT_OK(GenerateAndAddExternalFile(
{ValueType::kTypeValue}, {{120, 135}}, options, {120}, {ValueType::kTypeValue}, {{120, 135}}, file_id++,
file_id++, &true_data)); write_global_seqno, &true_data));
// File overwrites some keys, a seqno will be assigned // File overwrites some keys, a seqno will be assigned
ASSERT_EQ(dbfull()->GetLatestSequenceNumber(), 4); ASSERT_EQ(dbfull()->GetLatestSequenceNumber(), 4);
ASSERT_OK(GenerateAndAddExternalFile(options, {}, {}, {{110, 120}}, ASSERT_OK(GenerateAndAddExternalFile(options, {}, {}, {{110, 120}},
file_id++, &true_data)); file_id++, write_global_seqno,
&true_data));
// The range deletion ends on a key, but it doesn't actually delete // The range deletion ends on a key, but it doesn't actually delete
// this key because the largest key in the range is exclusive. Still, // this key because the largest key in the range is exclusive. Still,
// it counts as an overlap so a new seqno will be assigned. // it counts as an overlap so a new seqno will be assigned.
ASSERT_EQ(dbfull()->GetLatestSequenceNumber(), 5); ASSERT_EQ(dbfull()->GetLatestSequenceNumber(), 5);
ASSERT_OK(GenerateAndAddExternalFile(options, {}, {}, {{100, 109}}, ASSERT_OK(GenerateAndAddExternalFile(options, {}, {}, {{100, 109}},
file_id++, &true_data)); file_id++, write_global_seqno,
&true_data));
// File doesn't overwrite any keys, no seqno needed // File doesn't overwrite any keys, no seqno needed
ASSERT_EQ(dbfull()->GetLatestSequenceNumber(), 5); ASSERT_EQ(dbfull()->GetLatestSequenceNumber(), 5);
@ -406,19 +426,21 @@ TEST_F(ExternalSSTFileBasicTest, IngestFileWithMultipleValueType) {
} }
SequenceNumber last_seqno = dbfull()->GetLatestSequenceNumber(); SequenceNumber last_seqno = dbfull()->GetLatestSequenceNumber();
ASSERT_OK(GenerateAndAddExternalFile( ASSERT_OK(GenerateAndAddExternalFile(options, {60, 61, 62},
options, {60, 61, 62}, ValueType::kTypeValue, file_id++, &true_data)); ValueType::kTypeValue, file_id++,
write_global_seqno, &true_data));
// File doesn't overwrite any keys, no seqno needed // File doesn't overwrite any keys, no seqno needed
ASSERT_EQ(dbfull()->GetLatestSequenceNumber(), last_seqno); ASSERT_EQ(dbfull()->GetLatestSequenceNumber(), last_seqno);
ASSERT_OK(GenerateAndAddExternalFile( ASSERT_OK(GenerateAndAddExternalFile(options, {40, 41, 42},
options, {40, 41, 42}, ValueType::kTypeMerge, file_id++, &true_data)); ValueType::kTypeMerge, file_id++,
write_global_seqno, &true_data));
// File overwrites some keys, a seqno will be assigned // File overwrites some keys, a seqno will be assigned
ASSERT_EQ(dbfull()->GetLatestSequenceNumber(), last_seqno + 1); ASSERT_EQ(dbfull()->GetLatestSequenceNumber(), last_seqno + 1);
ASSERT_OK(GenerateAndAddExternalFile(options, {20, 30, 40}, ASSERT_OK(GenerateAndAddExternalFile(options, {20, 30, 40},
ValueType::kTypeDeletion, file_id++, ValueType::kTypeDeletion, file_id++,
&true_data)); write_global_seqno, &true_data));
// File overwrites some keys, a seqno will be assigned // File overwrites some keys, a seqno will be assigned
ASSERT_EQ(dbfull()->GetLatestSequenceNumber(), last_seqno + 2); ASSERT_EQ(dbfull()->GetLatestSequenceNumber(), last_seqno + 2);
@ -426,35 +448,39 @@ TEST_F(ExternalSSTFileBasicTest, IngestFileWithMultipleValueType) {
// We will need a seqno for the file regardless if the file overwrite // We will need a seqno for the file regardless if the file overwrite
// keys in the DB or not because we have a snapshot // keys in the DB or not because we have a snapshot
ASSERT_OK(GenerateAndAddExternalFile( ASSERT_OK(GenerateAndAddExternalFile(options, {1000, 1002},
options, {1000, 1002}, ValueType::kTypeMerge, file_id++, &true_data)); ValueType::kTypeMerge, file_id++,
write_global_seqno, &true_data));
// A global seqno will be assigned anyway because of the snapshot // A global seqno will be assigned anyway because of the snapshot
ASSERT_EQ(dbfull()->GetLatestSequenceNumber(), last_seqno + 3); ASSERT_EQ(dbfull()->GetLatestSequenceNumber(), last_seqno + 3);
ASSERT_OK(GenerateAndAddExternalFile( ASSERT_OK(GenerateAndAddExternalFile(options, {2000, 3002},
options, {2000, 3002}, ValueType::kTypeMerge, file_id++, &true_data)); ValueType::kTypeMerge, file_id++,
write_global_seqno, &true_data));
// A global seqno will be assigned anyway because of the snapshot // A global seqno will be assigned anyway because of the snapshot
ASSERT_EQ(dbfull()->GetLatestSequenceNumber(), last_seqno + 4); ASSERT_EQ(dbfull()->GetLatestSequenceNumber(), last_seqno + 4);
ASSERT_OK(GenerateAndAddExternalFile(options, {1, 20, 40, 100, 150}, ASSERT_OK(GenerateAndAddExternalFile(options, {1, 20, 40, 100, 150},
ValueType::kTypeMerge, file_id++, ValueType::kTypeMerge, file_id++,
&true_data)); write_global_seqno, &true_data));
// A global seqno will be assigned anyway because of the snapshot // A global seqno will be assigned anyway because of the snapshot
ASSERT_EQ(dbfull()->GetLatestSequenceNumber(), last_seqno + 5); ASSERT_EQ(dbfull()->GetLatestSequenceNumber(), last_seqno + 5);
db_->ReleaseSnapshot(snapshot); db_->ReleaseSnapshot(snapshot);
ASSERT_OK(GenerateAndAddExternalFile( ASSERT_OK(GenerateAndAddExternalFile(options, {5000, 5001},
options, {5000, 5001}, ValueType::kTypeValue, file_id++, &true_data)); ValueType::kTypeValue, file_id++,
write_global_seqno, &true_data));
// No snapshot anymore, no need to assign a seqno // No snapshot anymore, no need to assign a seqno
ASSERT_EQ(dbfull()->GetLatestSequenceNumber(), last_seqno + 5); ASSERT_EQ(dbfull()->GetLatestSequenceNumber(), last_seqno + 5);
size_t kcnt = 0; size_t kcnt = 0;
VerifyDBFromMap(true_data, &kcnt, false); VerifyDBFromMap(true_data, &kcnt, false);
} while (ChangeCompactOptions()); } while (ChangeOptionsForFileIngestionTest());
} }
TEST_F(ExternalSSTFileBasicTest, IngestFileWithMixedValueType) { TEST_P(ExternalSSTFileBasicTest, IngestFileWithMixedValueType) {
bool write_global_seqno = GetParam();
do { do {
Options options = CurrentOptions(); Options options = CurrentOptions();
options.merge_operator.reset(new TestPutOperator()); options.merge_operator.reset(new TestPutOperator());
@ -467,7 +493,7 @@ TEST_F(ExternalSSTFileBasicTest, IngestFileWithMixedValueType) {
options, {1, 2, 3, 4, 5, 6}, options, {1, 2, 3, 4, 5, 6},
{ValueType::kTypeValue, ValueType::kTypeMerge, ValueType::kTypeValue, {ValueType::kTypeValue, ValueType::kTypeMerge, ValueType::kTypeValue,
ValueType::kTypeMerge, ValueType::kTypeValue, ValueType::kTypeMerge}, ValueType::kTypeMerge, ValueType::kTypeValue, ValueType::kTypeMerge},
file_id++, &true_data)); file_id++, write_global_seqno, &true_data));
// File doesn't overwrite any keys, no seqno needed // File doesn't overwrite any keys, no seqno needed
ASSERT_EQ(dbfull()->GetLatestSequenceNumber(), 0); ASSERT_EQ(dbfull()->GetLatestSequenceNumber(), 0);
@ -475,33 +501,35 @@ TEST_F(ExternalSSTFileBasicTest, IngestFileWithMixedValueType) {
options, {10, 11, 12, 13}, options, {10, 11, 12, 13},
{ValueType::kTypeValue, ValueType::kTypeMerge, ValueType::kTypeValue, {ValueType::kTypeValue, ValueType::kTypeMerge, ValueType::kTypeValue,
ValueType::kTypeMerge}, ValueType::kTypeMerge},
file_id++, &true_data)); file_id++, write_global_seqno, &true_data));
// File doesn't overwrite any keys, no seqno needed // File doesn't overwrite any keys, no seqno needed
ASSERT_EQ(dbfull()->GetLatestSequenceNumber(), 0); ASSERT_EQ(dbfull()->GetLatestSequenceNumber(), 0);
ASSERT_OK(GenerateAndAddExternalFile( ASSERT_OK(GenerateAndAddExternalFile(
options, {1, 4, 6}, {ValueType::kTypeDeletion, ValueType::kTypeValue, options, {1, 4, 6},
ValueType::kTypeMerge}, {ValueType::kTypeDeletion, ValueType::kTypeValue,
file_id++, &true_data)); ValueType::kTypeMerge},
file_id++, write_global_seqno, &true_data));
// File overwrites some keys, a seqno will be assigned // File overwrites some keys, a seqno will be assigned
ASSERT_EQ(dbfull()->GetLatestSequenceNumber(), 1); ASSERT_EQ(dbfull()->GetLatestSequenceNumber(), 1);
ASSERT_OK(GenerateAndAddExternalFile( ASSERT_OK(GenerateAndAddExternalFile(
options, {11, 15, 19}, {ValueType::kTypeDeletion, ValueType::kTypeMerge, options, {11, 15, 19},
ValueType::kTypeValue}, {ValueType::kTypeDeletion, ValueType::kTypeMerge,
file_id++, &true_data)); ValueType::kTypeValue},
file_id++, write_global_seqno, &true_data));
// File overwrites some keys, a seqno will be assigned // File overwrites some keys, a seqno will be assigned
ASSERT_EQ(dbfull()->GetLatestSequenceNumber(), 2); ASSERT_EQ(dbfull()->GetLatestSequenceNumber(), 2);
ASSERT_OK(GenerateAndAddExternalFile( ASSERT_OK(GenerateAndAddExternalFile(
options, {120, 130}, {ValueType::kTypeValue, ValueType::kTypeMerge}, options, {120, 130}, {ValueType::kTypeValue, ValueType::kTypeMerge},
file_id++, &true_data)); file_id++, write_global_seqno, &true_data));
// File doesn't overwrite any keys, no seqno needed // File doesn't overwrite any keys, no seqno needed
ASSERT_EQ(dbfull()->GetLatestSequenceNumber(), 2); ASSERT_EQ(dbfull()->GetLatestSequenceNumber(), 2);
ASSERT_OK(GenerateAndAddExternalFile( ASSERT_OK(GenerateAndAddExternalFile(
options, {1, 130}, {ValueType::kTypeMerge, ValueType::kTypeDeletion}, options, {1, 130}, {ValueType::kTypeMerge, ValueType::kTypeDeletion},
file_id++, &true_data)); file_id++, write_global_seqno, &true_data));
// File overwrites some keys, a seqno will be assigned // File overwrites some keys, a seqno will be assigned
ASSERT_EQ(dbfull()->GetLatestSequenceNumber(), 3); ASSERT_EQ(dbfull()->GetLatestSequenceNumber(), 3);
@ -509,14 +537,14 @@ TEST_F(ExternalSSTFileBasicTest, IngestFileWithMixedValueType) {
options, {150, 151, 152}, options, {150, 151, 152},
{ValueType::kTypeValue, ValueType::kTypeMerge, {ValueType::kTypeValue, ValueType::kTypeMerge,
ValueType::kTypeDeletion}, ValueType::kTypeDeletion},
{{150, 160}, {180, 190}}, file_id++, &true_data)); {{150, 160}, {180, 190}}, file_id++, write_global_seqno, &true_data));
// File doesn't overwrite any keys, no seqno needed // File doesn't overwrite any keys, no seqno needed
ASSERT_EQ(dbfull()->GetLatestSequenceNumber(), 3); ASSERT_EQ(dbfull()->GetLatestSequenceNumber(), 3);
ASSERT_OK(GenerateAndAddExternalFile( ASSERT_OK(GenerateAndAddExternalFile(
options, {150, 151, 152}, options, {150, 151, 152},
{ValueType::kTypeValue, ValueType::kTypeMerge, ValueType::kTypeValue}, {ValueType::kTypeValue, ValueType::kTypeMerge, ValueType::kTypeValue},
{{200, 250}}, file_id++, &true_data)); {{200, 250}}, file_id++, write_global_seqno, &true_data));
// File overwrites some keys, a seqno will be assigned // File overwrites some keys, a seqno will be assigned
ASSERT_EQ(dbfull()->GetLatestSequenceNumber(), 4); ASSERT_EQ(dbfull()->GetLatestSequenceNumber(), 4);
@ -524,7 +552,7 @@ TEST_F(ExternalSSTFileBasicTest, IngestFileWithMixedValueType) {
options, {300, 301, 302}, options, {300, 301, 302},
{ValueType::kTypeValue, ValueType::kTypeMerge, {ValueType::kTypeValue, ValueType::kTypeMerge,
ValueType::kTypeDeletion}, ValueType::kTypeDeletion},
{{1, 2}, {152, 154}}, file_id++, &true_data)); {{1, 2}, {152, 154}}, file_id++, write_global_seqno, &true_data));
// File overwrites some keys, a seqno will be assigned // File overwrites some keys, a seqno will be assigned
ASSERT_EQ(dbfull()->GetLatestSequenceNumber(), 5); ASSERT_EQ(dbfull()->GetLatestSequenceNumber(), 5);
@ -538,7 +566,7 @@ TEST_F(ExternalSSTFileBasicTest, IngestFileWithMixedValueType) {
ASSERT_OK(GenerateAndAddExternalFile( ASSERT_OK(GenerateAndAddExternalFile(
options, {60, 61, 62}, options, {60, 61, 62},
{ValueType::kTypeValue, ValueType::kTypeMerge, ValueType::kTypeValue}, {ValueType::kTypeValue, ValueType::kTypeMerge, ValueType::kTypeValue},
file_id++, &true_data)); file_id++, write_global_seqno, &true_data));
// File doesn't overwrite any keys, no seqno needed // File doesn't overwrite any keys, no seqno needed
ASSERT_EQ(dbfull()->GetLatestSequenceNumber(), last_seqno); ASSERT_EQ(dbfull()->GetLatestSequenceNumber(), last_seqno);
@ -546,7 +574,7 @@ TEST_F(ExternalSSTFileBasicTest, IngestFileWithMixedValueType) {
options, {40, 41, 42}, options, {40, 41, 42},
{ValueType::kTypeValue, ValueType::kTypeDeletion, {ValueType::kTypeValue, ValueType::kTypeDeletion,
ValueType::kTypeDeletion}, ValueType::kTypeDeletion},
file_id++, &true_data)); file_id++, write_global_seqno, &true_data));
// File overwrites some keys, a seqno will be assigned // File overwrites some keys, a seqno will be assigned
ASSERT_EQ(dbfull()->GetLatestSequenceNumber(), last_seqno + 1); ASSERT_EQ(dbfull()->GetLatestSequenceNumber(), last_seqno + 1);
@ -554,7 +582,7 @@ TEST_F(ExternalSSTFileBasicTest, IngestFileWithMixedValueType) {
options, {20, 30, 40}, options, {20, 30, 40},
{ValueType::kTypeDeletion, ValueType::kTypeDeletion, {ValueType::kTypeDeletion, ValueType::kTypeDeletion,
ValueType::kTypeDeletion}, ValueType::kTypeDeletion},
file_id++, &true_data)); file_id++, write_global_seqno, &true_data));
// File overwrites some keys, a seqno will be assigned // File overwrites some keys, a seqno will be assigned
ASSERT_EQ(dbfull()->GetLatestSequenceNumber(), last_seqno + 2); ASSERT_EQ(dbfull()->GetLatestSequenceNumber(), last_seqno + 2);
@ -564,13 +592,13 @@ TEST_F(ExternalSSTFileBasicTest, IngestFileWithMixedValueType) {
// keys in the DB or not because we have a snapshot // keys in the DB or not because we have a snapshot
ASSERT_OK(GenerateAndAddExternalFile( ASSERT_OK(GenerateAndAddExternalFile(
options, {1000, 1002}, {ValueType::kTypeValue, ValueType::kTypeMerge}, options, {1000, 1002}, {ValueType::kTypeValue, ValueType::kTypeMerge},
file_id++, &true_data)); file_id++, write_global_seqno, &true_data));
// A global seqno will be assigned anyway because of the snapshot // A global seqno will be assigned anyway because of the snapshot
ASSERT_EQ(dbfull()->GetLatestSequenceNumber(), last_seqno + 3); ASSERT_EQ(dbfull()->GetLatestSequenceNumber(), last_seqno + 3);
ASSERT_OK(GenerateAndAddExternalFile( ASSERT_OK(GenerateAndAddExternalFile(
options, {2000, 3002}, {ValueType::kTypeValue, ValueType::kTypeMerge}, options, {2000, 3002}, {ValueType::kTypeValue, ValueType::kTypeMerge},
file_id++, &true_data)); file_id++, write_global_seqno, &true_data));
// A global seqno will be assigned anyway because of the snapshot // A global seqno will be assigned anyway because of the snapshot
ASSERT_EQ(dbfull()->GetLatestSequenceNumber(), last_seqno + 4); ASSERT_EQ(dbfull()->GetLatestSequenceNumber(), last_seqno + 4);
@ -578,7 +606,7 @@ TEST_F(ExternalSSTFileBasicTest, IngestFileWithMixedValueType) {
options, {1, 20, 40, 100, 150}, options, {1, 20, 40, 100, 150},
{ValueType::kTypeDeletion, ValueType::kTypeDeletion, {ValueType::kTypeDeletion, ValueType::kTypeDeletion,
ValueType::kTypeValue, ValueType::kTypeMerge, ValueType::kTypeMerge}, ValueType::kTypeValue, ValueType::kTypeMerge, ValueType::kTypeMerge},
file_id++, &true_data)); file_id++, write_global_seqno, &true_data));
// A global seqno will be assigned anyway because of the snapshot // A global seqno will be assigned anyway because of the snapshot
ASSERT_EQ(dbfull()->GetLatestSequenceNumber(), last_seqno + 5); ASSERT_EQ(dbfull()->GetLatestSequenceNumber(), last_seqno + 5);
@ -586,13 +614,13 @@ TEST_F(ExternalSSTFileBasicTest, IngestFileWithMixedValueType) {
ASSERT_OK(GenerateAndAddExternalFile( ASSERT_OK(GenerateAndAddExternalFile(
options, {5000, 5001}, {ValueType::kTypeValue, ValueType::kTypeMerge}, options, {5000, 5001}, {ValueType::kTypeValue, ValueType::kTypeMerge},
file_id++, &true_data)); file_id++, write_global_seqno, &true_data));
// No snapshot anymore, no need to assign a seqno // No snapshot anymore, no need to assign a seqno
ASSERT_EQ(dbfull()->GetLatestSequenceNumber(), last_seqno + 5); ASSERT_EQ(dbfull()->GetLatestSequenceNumber(), last_seqno + 5);
size_t kcnt = 0; size_t kcnt = 0;
VerifyDBFromMap(true_data, &kcnt, false); VerifyDBFromMap(true_data, &kcnt, false);
} while (ChangeCompactOptions()); } while (ChangeOptionsForFileIngestionTest());
} }
TEST_F(ExternalSSTFileBasicTest, FadviseTrigger) { TEST_F(ExternalSSTFileBasicTest, FadviseTrigger) {
@ -635,7 +663,7 @@ TEST_F(ExternalSSTFileBasicTest, FadviseTrigger) {
rocksdb::SyncPoint::GetInstance()->DisableProcessing(); rocksdb::SyncPoint::GetInstance()->DisableProcessing();
} }
TEST_F(ExternalSSTFileBasicTest, IngestionWithRangeDeletions) { TEST_P(ExternalSSTFileBasicTest, IngestionWithRangeDeletions) {
int kNumLevels = 7; int kNumLevels = 7;
Options options = CurrentOptions(); Options options = CurrentOptions();
options.disable_auto_compactions = true; options.disable_auto_compactions = true;
@ -662,12 +690,13 @@ TEST_F(ExternalSSTFileBasicTest, IngestionWithRangeDeletions) {
ASSERT_EQ(0, NumTableFilesAtLevel(kNumLevels - 2)); ASSERT_EQ(0, NumTableFilesAtLevel(kNumLevels - 2));
ASSERT_EQ(1, NumTableFilesAtLevel(kNumLevels - 1)); ASSERT_EQ(1, NumTableFilesAtLevel(kNumLevels - 1));
bool write_global_seqno = GetParam();
// overlaps with L0 file but not memtable, so flush is skipped and file is // overlaps with L0 file but not memtable, so flush is skipped and file is
// ingested into L0 // ingested into L0
SequenceNumber last_seqno = dbfull()->GetLatestSequenceNumber(); SequenceNumber last_seqno = dbfull()->GetLatestSequenceNumber();
ASSERT_OK(GenerateAndAddExternalFile( ASSERT_OK(GenerateAndAddExternalFile(
options, {60, 90}, {ValueType::kTypeValue, ValueType::kTypeValue}, options, {60, 90}, {ValueType::kTypeValue, ValueType::kTypeValue},
{{65, 70}, {70, 85}}, file_id++, &true_data)); {{65, 70}, {70, 85}}, file_id++, write_global_seqno, &true_data));
ASSERT_EQ(dbfull()->GetLatestSequenceNumber(), ++last_seqno); ASSERT_EQ(dbfull()->GetLatestSequenceNumber(), ++last_seqno);
ASSERT_EQ(2, NumTableFilesAtLevel(0)); ASSERT_EQ(2, NumTableFilesAtLevel(0));
ASSERT_EQ(0, NumTableFilesAtLevel(kNumLevels - 2)); ASSERT_EQ(0, NumTableFilesAtLevel(kNumLevels - 2));
@ -677,7 +706,7 @@ TEST_F(ExternalSSTFileBasicTest, IngestionWithRangeDeletions) {
// file is ingested into L5 // file is ingested into L5
ASSERT_OK(GenerateAndAddExternalFile( ASSERT_OK(GenerateAndAddExternalFile(
options, {10, 40}, {ValueType::kTypeValue, ValueType::kTypeValue}, options, {10, 40}, {ValueType::kTypeValue, ValueType::kTypeValue},
file_id++, &true_data)); file_id++, write_global_seqno, &true_data));
ASSERT_EQ(dbfull()->GetLatestSequenceNumber(), ++last_seqno); ASSERT_EQ(dbfull()->GetLatestSequenceNumber(), ++last_seqno);
ASSERT_EQ(2, NumTableFilesAtLevel(0)); ASSERT_EQ(2, NumTableFilesAtLevel(0));
ASSERT_EQ(1, NumTableFilesAtLevel(kNumLevels - 2)); ASSERT_EQ(1, NumTableFilesAtLevel(kNumLevels - 2));
@ -686,7 +715,7 @@ TEST_F(ExternalSSTFileBasicTest, IngestionWithRangeDeletions) {
// overlaps with L5 file but not memtable or L0 file, so flush is skipped and // overlaps with L5 file but not memtable or L0 file, so flush is skipped and
// file is ingested into L4 // file is ingested into L4
ASSERT_OK(GenerateAndAddExternalFile(options, {}, {}, {{5, 15}}, file_id++, ASSERT_OK(GenerateAndAddExternalFile(options, {}, {}, {{5, 15}}, file_id++,
&true_data)); write_global_seqno, &true_data));
ASSERT_EQ(dbfull()->GetLatestSequenceNumber(), ++last_seqno); ASSERT_EQ(dbfull()->GetLatestSequenceNumber(), ++last_seqno);
ASSERT_EQ(2, NumTableFilesAtLevel(0)); ASSERT_EQ(2, NumTableFilesAtLevel(0));
ASSERT_EQ(1, NumTableFilesAtLevel(kNumLevels - 2)); ASSERT_EQ(1, NumTableFilesAtLevel(kNumLevels - 2));
@ -698,7 +727,7 @@ TEST_F(ExternalSSTFileBasicTest, IngestionWithRangeDeletions) {
// count increases by two. // count increases by two.
ASSERT_OK(GenerateAndAddExternalFile( ASSERT_OK(GenerateAndAddExternalFile(
options, {100, 140}, {ValueType::kTypeValue, ValueType::kTypeValue}, options, {100, 140}, {ValueType::kTypeValue, ValueType::kTypeValue},
file_id++, &true_data)); file_id++, write_global_seqno, &true_data));
ASSERT_EQ(dbfull()->GetLatestSequenceNumber(), ++last_seqno); ASSERT_EQ(dbfull()->GetLatestSequenceNumber(), ++last_seqno);
ASSERT_EQ(4, NumTableFilesAtLevel(0)); ASSERT_EQ(4, NumTableFilesAtLevel(0));
ASSERT_EQ(1, NumTableFilesAtLevel(kNumLevels - 2)); ASSERT_EQ(1, NumTableFilesAtLevel(kNumLevels - 2));
@ -711,13 +740,16 @@ TEST_F(ExternalSSTFileBasicTest, IngestionWithRangeDeletions) {
// seqnum. // seqnum.
ASSERT_OK(GenerateAndAddExternalFile( ASSERT_OK(GenerateAndAddExternalFile(
options, {151, 175}, {ValueType::kTypeValue, ValueType::kTypeValue}, options, {151, 175}, {ValueType::kTypeValue, ValueType::kTypeValue},
{{160, 200}}, file_id++, &true_data)); {{160, 200}}, file_id++, write_global_seqno, &true_data));
ASSERT_EQ(dbfull()->GetLatestSequenceNumber(), last_seqno); ASSERT_EQ(dbfull()->GetLatestSequenceNumber(), last_seqno);
ASSERT_EQ(4, NumTableFilesAtLevel(0)); ASSERT_EQ(4, NumTableFilesAtLevel(0));
ASSERT_EQ(1, NumTableFilesAtLevel(kNumLevels - 2)); ASSERT_EQ(1, NumTableFilesAtLevel(kNumLevels - 2));
ASSERT_EQ(2, NumTableFilesAtLevel(options.num_levels - 1)); ASSERT_EQ(2, NumTableFilesAtLevel(options.num_levels - 1));
} }
INSTANTIATE_TEST_CASE_P(ExternalSSTFileBasicTest, ExternalSSTFileBasicTest,
testing::Bool());
#endif // ROCKSDB_LITE #endif // ROCKSDB_LITE
} // namespace rocksdb } // namespace rocksdb

View File

@ -15,7 +15,8 @@
namespace rocksdb { namespace rocksdb {
class ExternalSSTFileTest : public DBTestBase { class ExternalSSTFileTest : public DBTestBase,
public ::testing::WithParamInterface<bool> {
public: public:
ExternalSSTFileTest() : DBTestBase("/external_sst_file_test") { ExternalSSTFileTest() : DBTestBase("/external_sst_file_test") {
sst_files_dir_ = dbname_ + "/sst_files/"; sst_files_dir_ = dbname_ + "/sst_files/";
@ -30,7 +31,8 @@ class ExternalSSTFileTest : public DBTestBase {
Status GenerateAndAddExternalFile( Status GenerateAndAddExternalFile(
const Options options, const Options options,
std::vector<std::pair<std::string, std::string>> data, int file_id = -1, std::vector<std::pair<std::string, std::string>> data, int file_id = -1,
bool allow_global_seqno = false, bool sort_data = false, bool allow_global_seqno = false, bool write_global_seqno = false,
bool sort_data = false,
std::map<std::string, std::string>* true_data = nullptr, std::map<std::string, std::string>* true_data = nullptr,
ColumnFamilyHandle* cfh = nullptr) { ColumnFamilyHandle* cfh = nullptr) {
// Generate a file id if not provided // Generate a file id if not provided
@ -73,6 +75,7 @@ class ExternalSSTFileTest : public DBTestBase {
if (s.ok()) { if (s.ok()) {
IngestExternalFileOptions ifo; IngestExternalFileOptions ifo;
ifo.allow_global_seqno = allow_global_seqno; ifo.allow_global_seqno = allow_global_seqno;
ifo.write_global_seqno = allow_global_seqno ? write_global_seqno : false;
if (cfh) { if (cfh) {
s = db_->IngestExternalFile(cfh, {file_path}, ifo); s = db_->IngestExternalFile(cfh, {file_path}, ifo);
} else { } else {
@ -149,11 +152,10 @@ class ExternalSSTFileTest : public DBTestBase {
return s; return s;
} }
Status GenerateAndAddExternalFile( Status GenerateAndAddExternalFile(
const Options options, std::vector<std::pair<int, std::string>> data, const Options options, std::vector<std::pair<int, std::string>> data,
int file_id = -1, bool allow_global_seqno = false, bool sort_data = false, int file_id = -1, bool allow_global_seqno = false,
bool write_global_seqno = false, bool sort_data = false,
std::map<std::string, std::string>* true_data = nullptr, std::map<std::string, std::string>* true_data = nullptr,
ColumnFamilyHandle* cfh = nullptr) { ColumnFamilyHandle* cfh = nullptr) {
std::vector<std::pair<std::string, std::string>> file_data; std::vector<std::pair<std::string, std::string>> file_data;
@ -161,13 +163,14 @@ class ExternalSSTFileTest : public DBTestBase {
file_data.emplace_back(Key(entry.first), entry.second); file_data.emplace_back(Key(entry.first), entry.second);
} }
return GenerateAndAddExternalFile(options, file_data, file_id, return GenerateAndAddExternalFile(options, file_data, file_id,
allow_global_seqno, sort_data, true_data, allow_global_seqno, write_global_seqno,
cfh); sort_data, true_data, cfh);
} }
Status GenerateAndAddExternalFile( Status GenerateAndAddExternalFile(
const Options options, std::vector<int> keys, int file_id = -1, const Options options, std::vector<int> keys, int file_id = -1,
bool allow_global_seqno = false, bool sort_data = false, bool allow_global_seqno = false, bool write_global_seqno = false,
bool sort_data = false,
std::map<std::string, std::string>* true_data = nullptr, std::map<std::string, std::string>* true_data = nullptr,
ColumnFamilyHandle* cfh = nullptr) { ColumnFamilyHandle* cfh = nullptr) {
std::vector<std::pair<std::string, std::string>> file_data; std::vector<std::pair<std::string, std::string>> file_data;
@ -175,18 +178,20 @@ class ExternalSSTFileTest : public DBTestBase {
file_data.emplace_back(Key(k), Key(k) + ToString(file_id)); file_data.emplace_back(Key(k), Key(k) + ToString(file_id));
} }
return GenerateAndAddExternalFile(options, file_data, file_id, return GenerateAndAddExternalFile(options, file_data, file_id,
allow_global_seqno, sort_data, true_data, allow_global_seqno, write_global_seqno,
cfh); sort_data, true_data, cfh);
} }
Status DeprecatedAddFile(const std::vector<std::string>& files, Status DeprecatedAddFile(const std::vector<std::string>& files,
bool move_files = false, bool move_files = false,
bool skip_snapshot_check = false) { bool skip_snapshot_check = false,
bool skip_write_global_seqno = false) {
IngestExternalFileOptions opts; IngestExternalFileOptions opts;
opts.move_files = move_files; opts.move_files = move_files;
opts.snapshot_consistency = !skip_snapshot_check; opts.snapshot_consistency = !skip_snapshot_check;
opts.allow_global_seqno = false; opts.allow_global_seqno = false;
opts.allow_blocking_flush = false; opts.allow_blocking_flush = false;
opts.write_global_seqno = !skip_write_global_seqno;
return db_->IngestExternalFile(files, opts); return db_->IngestExternalFile(files, opts);
} }
@ -453,6 +458,7 @@ TEST_F(ExternalSSTFileTest, Basic) {
} while (ChangeOptions(kSkipPlainTable | kSkipFIFOCompaction | } while (ChangeOptions(kSkipPlainTable | kSkipFIFOCompaction |
kRangeDelSkipConfigs)); kRangeDelSkipConfigs));
} }
class SstFileWriterCollector : public TablePropertiesCollector { class SstFileWriterCollector : public TablePropertiesCollector {
public: public:
explicit SstFileWriterCollector(const std::string prefix) : prefix_(prefix) { explicit SstFileWriterCollector(const std::string prefix) : prefix_(prefix) {
@ -1141,7 +1147,7 @@ TEST_F(ExternalSSTFileTest, OverlappingRanges) {
} while (ChangeOptions(kSkipPlainTable | kSkipFIFOCompaction)); } while (ChangeOptions(kSkipPlainTable | kSkipFIFOCompaction));
} }
TEST_F(ExternalSSTFileTest, PickedLevel) { TEST_P(ExternalSSTFileTest, PickedLevel) {
Options options = CurrentOptions(); Options options = CurrentOptions();
options.disable_auto_compactions = false; options.disable_auto_compactions = false;
options.level0_file_num_compaction_trigger = 4; options.level0_file_num_compaction_trigger = 4;
@ -1152,11 +1158,11 @@ TEST_F(ExternalSSTFileTest, PickedLevel) {
// File 0 will go to last level (L3) // File 0 will go to last level (L3)
ASSERT_OK(GenerateAndAddExternalFile(options, {1, 10}, -1, false, false, ASSERT_OK(GenerateAndAddExternalFile(options, {1, 10}, -1, false, false,
&true_data)); false, &true_data));
EXPECT_EQ(FilesPerLevel(), "0,0,0,1"); EXPECT_EQ(FilesPerLevel(), "0,0,0,1");
// File 1 will go to level L2 (since it overlap with file 0 in L3) // File 1 will go to level L2 (since it overlap with file 0 in L3)
ASSERT_OK(GenerateAndAddExternalFile(options, {2, 9}, -1, false, false, ASSERT_OK(GenerateAndAddExternalFile(options, {2, 9}, -1, false, false, false,
&true_data)); &true_data));
EXPECT_EQ(FilesPerLevel(), "0,0,1,1"); EXPECT_EQ(FilesPerLevel(), "0,0,1,1");
@ -1186,13 +1192,13 @@ TEST_F(ExternalSSTFileTest, PickedLevel) {
// This file overlaps with file 0 (L3), file 1 (L2) and the // This file overlaps with file 0 (L3), file 1 (L2) and the
// output of compaction going to L1 // output of compaction going to L1
ASSERT_OK(GenerateAndAddExternalFile(options, {4, 7}, -1, false, false, ASSERT_OK(GenerateAndAddExternalFile(options, {4, 7}, -1, false, false, false,
&true_data)); &true_data));
EXPECT_EQ(FilesPerLevel(), "5,0,1,1"); EXPECT_EQ(FilesPerLevel(), "5,0,1,1");
// This file does not overlap with any file or with the running compaction // This file does not overlap with any file or with the running compaction
ASSERT_OK(GenerateAndAddExternalFile(options, {9000, 9001}, -1, false, false, ASSERT_OK(GenerateAndAddExternalFile(options, {9000, 9001}, -1, false, false,
&true_data)); false, &true_data));
EXPECT_EQ(FilesPerLevel(), "5,0,1,2"); EXPECT_EQ(FilesPerLevel(), "5,0,1,2");
// Hold compaction from finishing // Hold compaction from finishing
@ -1422,12 +1428,12 @@ TEST_F(ExternalSSTFileTest, PickedLevelDynamic) {
// This file overlaps with the output of the compaction (going to L3) // This file overlaps with the output of the compaction (going to L3)
// so the file will be added to L0 since L3 is the base level // so the file will be added to L0 since L3 is the base level
ASSERT_OK(GenerateAndAddExternalFile(options, {31, 32, 33, 34}, -1, false, ASSERT_OK(GenerateAndAddExternalFile(options, {31, 32, 33, 34}, -1, false,
false, &true_data)); false, false, &true_data));
EXPECT_EQ(FilesPerLevel(), "5"); EXPECT_EQ(FilesPerLevel(), "5");
// This file does not overlap with the current running compactiong // This file does not overlap with the current running compactiong
ASSERT_OK(GenerateAndAddExternalFile(options, {9000, 9001}, -1, false, false, ASSERT_OK(GenerateAndAddExternalFile(options, {9000, 9001}, -1, false, false,
&true_data)); false, &true_data));
EXPECT_EQ(FilesPerLevel(), "5,0,0,1"); EXPECT_EQ(FilesPerLevel(), "5,0,0,1");
// Hold compaction from finishing // Hold compaction from finishing
@ -1442,24 +1448,24 @@ TEST_F(ExternalSSTFileTest, PickedLevelDynamic) {
Reopen(options); Reopen(options);
ASSERT_OK(GenerateAndAddExternalFile(options, {1, 15, 19}, -1, false, false, ASSERT_OK(GenerateAndAddExternalFile(options, {1, 15, 19}, -1, false, false,
&true_data)); false, &true_data));
ASSERT_EQ(FilesPerLevel(), "1,0,0,3"); ASSERT_EQ(FilesPerLevel(), "1,0,0,3");
ASSERT_OK(GenerateAndAddExternalFile(options, {1000, 1001, 1002}, -1, false, ASSERT_OK(GenerateAndAddExternalFile(options, {1000, 1001, 1002}, -1, false,
false, &true_data)); false, false, &true_data));
ASSERT_EQ(FilesPerLevel(), "1,0,0,4"); ASSERT_EQ(FilesPerLevel(), "1,0,0,4");
ASSERT_OK(GenerateAndAddExternalFile(options, {500, 600, 700}, -1, false, ASSERT_OK(GenerateAndAddExternalFile(options, {500, 600, 700}, -1, false,
false, &true_data)); false, false, &true_data));
ASSERT_EQ(FilesPerLevel(), "1,0,0,5"); ASSERT_EQ(FilesPerLevel(), "1,0,0,5");
// File 5 overlaps with file 2 (L3 / base level) // File 5 overlaps with file 2 (L3 / base level)
ASSERT_OK(GenerateAndAddExternalFile(options, {2, 10}, -1, false, false, ASSERT_OK(GenerateAndAddExternalFile(options, {2, 10}, -1, false, false,
&true_data)); false, &true_data));
ASSERT_EQ(FilesPerLevel(), "2,0,0,5"); ASSERT_EQ(FilesPerLevel(), "2,0,0,5");
// File 6 overlaps with file 2 (L3 / base level) and file 5 (L0) // File 6 overlaps with file 2 (L3 / base level) and file 5 (L0)
ASSERT_OK(GenerateAndAddExternalFile(options, {3, 9}, -1, false, false, ASSERT_OK(GenerateAndAddExternalFile(options, {3, 9}, -1, false, false, false,
&true_data)); &true_data));
ASSERT_EQ(FilesPerLevel(), "3,0,0,5"); ASSERT_EQ(FilesPerLevel(), "3,0,0,5");
@ -1479,7 +1485,7 @@ TEST_F(ExternalSSTFileTest, PickedLevelDynamic) {
// File 7 overlaps with file 4 (L3) // File 7 overlaps with file 4 (L3)
ASSERT_OK(GenerateAndAddExternalFile(options, {650, 651, 652}, -1, false, ASSERT_OK(GenerateAndAddExternalFile(options, {650, 651, 652}, -1, false,
false, &true_data)); false, false, &true_data));
ASSERT_EQ(FilesPerLevel(), "5,0,0,5"); ASSERT_EQ(FilesPerLevel(), "5,0,0,5");
VerifyDBFromMap(true_data, &kcnt, false); VerifyDBFromMap(true_data, &kcnt, false);
@ -1613,12 +1619,13 @@ TEST_F(ExternalSSTFileTest, SstFileWriterNonSharedKeys) {
ASSERT_OK(DeprecatedAddFile({file_path})); ASSERT_OK(DeprecatedAddFile({file_path}));
} }
TEST_F(ExternalSSTFileTest, IngestFileWithGlobalSeqnoRandomized) { TEST_P(ExternalSSTFileTest, IngestFileWithGlobalSeqnoRandomized) {
Options options = CurrentOptions(); Options options = CurrentOptions();
options.IncreaseParallelism(20); options.IncreaseParallelism(20);
options.level0_slowdown_writes_trigger = 256; options.level0_slowdown_writes_trigger = 256;
options.level0_stop_writes_trigger = 256; options.level0_stop_writes_trigger = 256;
bool write_global_seqno = GetParam();
for (int iter = 0; iter < 2; iter++) { for (int iter = 0; iter < 2; iter++) {
bool write_to_memtable = (iter == 0); bool write_to_memtable = (iter == 0);
DestroyAndReopen(options); DestroyAndReopen(options);
@ -1643,7 +1650,8 @@ TEST_F(ExternalSSTFileTest, IngestFileWithGlobalSeqnoRandomized) {
} }
} else { } else {
ASSERT_OK(GenerateAndAddExternalFile(options, random_data, -1, true, ASSERT_OK(GenerateAndAddExternalFile(options, random_data, -1, true,
true, &true_data)); write_global_seqno, true,
&true_data));
} }
} }
size_t kcnt = 0; size_t kcnt = 0;
@ -1653,7 +1661,7 @@ TEST_F(ExternalSSTFileTest, IngestFileWithGlobalSeqnoRandomized) {
} }
} }
TEST_F(ExternalSSTFileTest, IngestFileWithGlobalSeqnoAssignedLevel) { TEST_P(ExternalSSTFileTest, IngestFileWithGlobalSeqnoAssignedLevel) {
Options options = CurrentOptions(); Options options = CurrentOptions();
options.num_levels = 5; options.num_levels = 5;
options.disable_auto_compactions = true; options.disable_auto_compactions = true;
@ -1672,8 +1680,9 @@ TEST_F(ExternalSSTFileTest, IngestFileWithGlobalSeqnoAssignedLevel) {
for (int i = 0; i <= 20; i++) { for (int i = 0; i <= 20; i++) {
file_data.emplace_back(Key(i), "L4"); file_data.emplace_back(Key(i), "L4");
} }
ASSERT_OK(GenerateAndAddExternalFile(options, file_data, -1, true, false, bool write_global_seqno = GetParam();
&true_data)); ASSERT_OK(GenerateAndAddExternalFile(options, file_data, -1, true,
write_global_seqno, false, &true_data));
// This file dont overlap with anything in the DB, will go to L4 // This file dont overlap with anything in the DB, will go to L4
ASSERT_EQ("0,0,0,0,1", FilesPerLevel()); ASSERT_EQ("0,0,0,0,1", FilesPerLevel());
@ -1683,8 +1692,8 @@ TEST_F(ExternalSSTFileTest, IngestFileWithGlobalSeqnoAssignedLevel) {
for (int i = 80; i <= 130; i++) { for (int i = 80; i <= 130; i++) {
file_data.emplace_back(Key(i), "L0"); file_data.emplace_back(Key(i), "L0");
} }
ASSERT_OK(GenerateAndAddExternalFile(options, file_data, -1, true, false, ASSERT_OK(GenerateAndAddExternalFile(options, file_data, -1, true,
&true_data)); write_global_seqno, false, &true_data));
// This file overlap with the memtable, so it will flush it and add // This file overlap with the memtable, so it will flush it and add
// it self to L0 // it self to L0
@ -1695,8 +1704,8 @@ TEST_F(ExternalSSTFileTest, IngestFileWithGlobalSeqnoAssignedLevel) {
for (int i = 30; i <= 50; i++) { for (int i = 30; i <= 50; i++) {
file_data.emplace_back(Key(i), "L4"); file_data.emplace_back(Key(i), "L4");
} }
ASSERT_OK(GenerateAndAddExternalFile(options, file_data, -1, true, false, ASSERT_OK(GenerateAndAddExternalFile(options, file_data, -1, true,
&true_data)); write_global_seqno, false, &true_data));
// This file dont overlap with anything in the DB and fit in L4 as well // This file dont overlap with anything in the DB and fit in L4 as well
ASSERT_EQ("2,0,0,0,2", FilesPerLevel()); ASSERT_EQ("2,0,0,0,2", FilesPerLevel());
@ -1706,8 +1715,8 @@ TEST_F(ExternalSSTFileTest, IngestFileWithGlobalSeqnoAssignedLevel) {
for (int i = 10; i <= 40; i++) { for (int i = 10; i <= 40; i++) {
file_data.emplace_back(Key(i), "L3"); file_data.emplace_back(Key(i), "L3");
} }
ASSERT_OK(GenerateAndAddExternalFile(options, file_data, -1, true, false, ASSERT_OK(GenerateAndAddExternalFile(options, file_data, -1, true,
&true_data)); write_global_seqno, false, &true_data));
// This file overlap with files in L4, we will ingest it in L3 // This file overlap with files in L4, we will ingest it in L3
ASSERT_EQ("2,0,0,1,2", FilesPerLevel()); ASSERT_EQ("2,0,0,1,2", FilesPerLevel());
@ -1716,7 +1725,7 @@ TEST_F(ExternalSSTFileTest, IngestFileWithGlobalSeqnoAssignedLevel) {
VerifyDBFromMap(true_data, &kcnt, false); VerifyDBFromMap(true_data, &kcnt, false);
} }
TEST_F(ExternalSSTFileTest, IngestFileWithGlobalSeqnoMemtableFlush) { TEST_P(ExternalSSTFileTest, IngestFileWithGlobalSeqnoMemtableFlush) {
Options options = CurrentOptions(); Options options = CurrentOptions();
DestroyAndReopen(options); DestroyAndReopen(options);
uint64_t entries_in_memtable; uint64_t entries_in_memtable;
@ -1730,16 +1739,17 @@ TEST_F(ExternalSSTFileTest, IngestFileWithGlobalSeqnoMemtableFlush) {
&entries_in_memtable); &entries_in_memtable);
ASSERT_GE(entries_in_memtable, 1); ASSERT_GE(entries_in_memtable, 1);
bool write_global_seqno = GetParam();
// No need for flush // No need for flush
ASSERT_OK(GenerateAndAddExternalFile(options, {90, 100, 110}, -1, true, false, ASSERT_OK(GenerateAndAddExternalFile(options, {90, 100, 110}, -1, true,
&true_data)); write_global_seqno, false, &true_data));
db_->GetIntProperty(DB::Properties::kNumEntriesActiveMemTable, db_->GetIntProperty(DB::Properties::kNumEntriesActiveMemTable,
&entries_in_memtable); &entries_in_memtable);
ASSERT_GE(entries_in_memtable, 1); ASSERT_GE(entries_in_memtable, 1);
// This file will flush the memtable // This file will flush the memtable
ASSERT_OK(GenerateAndAddExternalFile(options, {19, 20, 21}, -1, true, false, ASSERT_OK(GenerateAndAddExternalFile(options, {19, 20, 21}, -1, true,
&true_data)); write_global_seqno, false, &true_data));
db_->GetIntProperty(DB::Properties::kNumEntriesActiveMemTable, db_->GetIntProperty(DB::Properties::kNumEntriesActiveMemTable,
&entries_in_memtable); &entries_in_memtable);
ASSERT_EQ(entries_in_memtable, 0); ASSERT_EQ(entries_in_memtable, 0);
@ -1754,14 +1764,14 @@ TEST_F(ExternalSSTFileTest, IngestFileWithGlobalSeqnoMemtableFlush) {
// No need for flush, this file keys fit between the memtable keys // No need for flush, this file keys fit between the memtable keys
ASSERT_OK(GenerateAndAddExternalFile(options, {202, 203, 204}, -1, true, ASSERT_OK(GenerateAndAddExternalFile(options, {202, 203, 204}, -1, true,
false, &true_data)); write_global_seqno, false, &true_data));
db_->GetIntProperty(DB::Properties::kNumEntriesActiveMemTable, db_->GetIntProperty(DB::Properties::kNumEntriesActiveMemTable,
&entries_in_memtable); &entries_in_memtable);
ASSERT_GE(entries_in_memtable, 1); ASSERT_GE(entries_in_memtable, 1);
// This file will flush the memtable // This file will flush the memtable
ASSERT_OK(GenerateAndAddExternalFile(options, {206, 207}, -1, true, false, ASSERT_OK(GenerateAndAddExternalFile(options, {206, 207}, -1, true, false,
&true_data)); write_global_seqno, &true_data));
db_->GetIntProperty(DB::Properties::kNumEntriesActiveMemTable, db_->GetIntProperty(DB::Properties::kNumEntriesActiveMemTable,
&entries_in_memtable); &entries_in_memtable);
ASSERT_EQ(entries_in_memtable, 0); ASSERT_EQ(entries_in_memtable, 0);
@ -1770,7 +1780,7 @@ TEST_F(ExternalSSTFileTest, IngestFileWithGlobalSeqnoMemtableFlush) {
VerifyDBFromMap(true_data, &kcnt, false); VerifyDBFromMap(true_data, &kcnt, false);
} }
TEST_F(ExternalSSTFileTest, L0SortingIssue) { TEST_P(ExternalSSTFileTest, L0SortingIssue) {
Options options = CurrentOptions(); Options options = CurrentOptions();
options.num_levels = 2; options.num_levels = 2;
DestroyAndReopen(options); DestroyAndReopen(options);
@ -1779,10 +1789,13 @@ TEST_F(ExternalSSTFileTest, L0SortingIssue) {
ASSERT_OK(Put(Key(1), "memtable")); ASSERT_OK(Put(Key(1), "memtable"));
ASSERT_OK(Put(Key(10), "memtable")); ASSERT_OK(Put(Key(10), "memtable"));
bool write_global_seqno = GetParam();
// No Flush needed, No global seqno needed, Ingest in L1 // No Flush needed, No global seqno needed, Ingest in L1
ASSERT_OK(GenerateAndAddExternalFile(options, {7, 8}, -1, true, false)); ASSERT_OK(GenerateAndAddExternalFile(options, {7, 8}, -1, true,
write_global_seqno, false));
// No Flush needed, but need a global seqno, Ingest in L0 // No Flush needed, but need a global seqno, Ingest in L0
ASSERT_OK(GenerateAndAddExternalFile(options, {7, 8}, -1, true, false)); ASSERT_OK(GenerateAndAddExternalFile(options, {7, 8}, -1, true,
write_global_seqno, false));
printf("%s\n", FilesPerLevel().c_str()); printf("%s\n", FilesPerLevel().c_str());
// Overwrite what we added using external files // Overwrite what we added using external files
@ -2011,15 +2024,17 @@ class TestIngestExternalFileListener : public EventListener {
std::vector<ExternalFileIngestionInfo> ingested_files; std::vector<ExternalFileIngestionInfo> ingested_files;
}; };
TEST_F(ExternalSSTFileTest, IngestionListener) { TEST_P(ExternalSSTFileTest, IngestionListener) {
Options options = CurrentOptions(); Options options = CurrentOptions();
TestIngestExternalFileListener* listener = TestIngestExternalFileListener* listener =
new TestIngestExternalFileListener(); new TestIngestExternalFileListener();
options.listeners.emplace_back(listener); options.listeners.emplace_back(listener);
CreateAndReopenWithCF({"koko", "toto"}, options); CreateAndReopenWithCF({"koko", "toto"}, options);
bool write_global_seqno = GetParam();
// Ingest into default cf // Ingest into default cf
ASSERT_OK(GenerateAndAddExternalFile(options, {1, 2}, -1, true, true, nullptr, ASSERT_OK(GenerateAndAddExternalFile(options, {1, 2}, -1, true,
write_global_seqno, true, nullptr,
handles_[0])); handles_[0]));
ASSERT_EQ(listener->ingested_files.size(), 1); ASSERT_EQ(listener->ingested_files.size(), 1);
ASSERT_EQ(listener->ingested_files.back().cf_name, "default"); ASSERT_EQ(listener->ingested_files.back().cf_name, "default");
@ -2030,7 +2045,8 @@ TEST_F(ExternalSSTFileTest, IngestionListener) {
"default"); "default");
// Ingest into cf1 // Ingest into cf1
ASSERT_OK(GenerateAndAddExternalFile(options, {1, 2}, -1, true, true, nullptr, ASSERT_OK(GenerateAndAddExternalFile(options, {1, 2}, -1, true,
write_global_seqno, true, nullptr,
handles_[1])); handles_[1]));
ASSERT_EQ(listener->ingested_files.size(), 2); ASSERT_EQ(listener->ingested_files.size(), 2);
ASSERT_EQ(listener->ingested_files.back().cf_name, "koko"); ASSERT_EQ(listener->ingested_files.back().cf_name, "koko");
@ -2041,7 +2057,8 @@ TEST_F(ExternalSSTFileTest, IngestionListener) {
"koko"); "koko");
// Ingest into cf2 // Ingest into cf2
ASSERT_OK(GenerateAndAddExternalFile(options, {1, 2}, -1, true, true, nullptr, ASSERT_OK(GenerateAndAddExternalFile(options, {1, 2}, -1, true,
write_global_seqno, true, nullptr,
handles_[2])); handles_[2]));
ASSERT_EQ(listener->ingested_files.size(), 3); ASSERT_EQ(listener->ingested_files.size(), 3);
ASSERT_EQ(listener->ingested_files.back().cf_name, "toto"); ASSERT_EQ(listener->ingested_files.back().cf_name, "toto");
@ -2084,7 +2101,7 @@ TEST_F(ExternalSSTFileTest, SnapshotInconsistencyBug) {
db_->ReleaseSnapshot(snap); db_->ReleaseSnapshot(snap);
} }
TEST_F(ExternalSSTFileTest, IngestBehind) { TEST_P(ExternalSSTFileTest, IngestBehind) {
Options options = CurrentOptions(); Options options = CurrentOptions();
options.compaction_style = kCompactionStyleUniversal; options.compaction_style = kCompactionStyleUniversal;
options.num_levels = 3; options.num_levels = 3;
@ -2108,6 +2125,7 @@ TEST_F(ExternalSSTFileTest, IngestBehind) {
IngestExternalFileOptions ifo; IngestExternalFileOptions ifo;
ifo.allow_global_seqno = true; ifo.allow_global_seqno = true;
ifo.ingest_behind = true; ifo.ingest_behind = true;
ifo.write_global_seqno = GetParam();
// Can't ingest behind since allow_ingest_behind isn't set to true // Can't ingest behind since allow_ingest_behind isn't set to true
ASSERT_NOK(GenerateAndAddExternalFileIngestBehind(options, ifo, ASSERT_NOK(GenerateAndAddExternalFileIngestBehind(options, ifo,
@ -2195,6 +2213,9 @@ TEST_F(ExternalSSTFileTest, SkipBloomFilter) {
} }
} }
INSTANTIATE_TEST_CASE_P(ExternalSSTFileTest, ExternalSSTFileTest,
testing::Bool());
} // namespace rocksdb } // namespace rocksdb
int main(int argc, char** argv) { int main(int argc, char** argv) {