mirror of https://github.com/facebook/rocksdb.git
Add a `fail_if_not_bottommost_level` to IngestExternalFileOptions (#9849)
Summary: This new options allows application to specify that files must be ingested to bottommost level, otherwise the ingestion will fail instead of silently ingesting to a non-bottommost level. Pull Request resolved: https://github.com/facebook/rocksdb/pull/9849 Test Plan: make check Reviewed By: ajkr Differential Revision: D35680307 Pulled By: riversand963 fbshipit-source-id: 01cf54ef6c76198f7654dc06b5544631dea1be1e
This commit is contained in:
parent
0c7f455f85
commit
be81609b43
|
@ -28,6 +28,7 @@
|
||||||
|
|
||||||
### Public API changes
|
### Public API changes
|
||||||
* Exposed APIs to examine results of block cache stats collections in a structured way. In particular, users of `GetMapProperty()` with property `kBlockCacheEntryStats` can now use the functions in `BlockCacheEntryStatsMapKeys` to find stats in the map.
|
* Exposed APIs to examine results of block cache stats collections in a structured way. In particular, users of `GetMapProperty()` with property `kBlockCacheEntryStats` can now use the functions in `BlockCacheEntryStatsMapKeys` to find stats in the map.
|
||||||
|
* Add `fail_if_not_bottommost_level` to IngestExternalFileOptions so that ingestion will fail if the file(s) cannot be ingested to the bottommost level.
|
||||||
|
|
||||||
## 7.1.0 (03/23/2022)
|
## 7.1.0 (03/23/2022)
|
||||||
### New Features
|
### New Features
|
||||||
|
|
|
@ -1796,6 +1796,54 @@ TEST_F(ExternalSSTFileBasicTest, IngestWithTemperature) {
|
||||||
ASSERT_EQ(std::atoi(prop.c_str()), 0);
|
ASSERT_EQ(std::atoi(prop.c_str()), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(ExternalSSTFileBasicTest, FailIfNotBottommostLevel) {
|
||||||
|
Options options = GetDefaultOptions();
|
||||||
|
|
||||||
|
std::string file_path = sst_files_dir_ + ToString(1);
|
||||||
|
SstFileWriter sfw(EnvOptions(), options);
|
||||||
|
|
||||||
|
ASSERT_OK(sfw.Open(file_path));
|
||||||
|
ASSERT_OK(sfw.Put("b", "dontcare"));
|
||||||
|
ASSERT_OK(sfw.Finish());
|
||||||
|
|
||||||
|
// Test universal compaction + ingest with snapshot consistency
|
||||||
|
options.create_if_missing = true;
|
||||||
|
options.compaction_style = CompactionStyle::kCompactionStyleUniversal;
|
||||||
|
DestroyAndReopen(options);
|
||||||
|
{
|
||||||
|
const Snapshot* snapshot = db_->GetSnapshot();
|
||||||
|
ManagedSnapshot snapshot_guard(db_, snapshot);
|
||||||
|
IngestExternalFileOptions ifo;
|
||||||
|
ifo.fail_if_not_bottommost_level = true;
|
||||||
|
ifo.snapshot_consistency = true;
|
||||||
|
const Status s = db_->IngestExternalFile({file_path}, ifo);
|
||||||
|
ASSERT_TRUE(s.IsTryAgain());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test level compaction
|
||||||
|
options.compaction_style = CompactionStyle::kCompactionStyleLevel;
|
||||||
|
options.num_levels = 2;
|
||||||
|
DestroyAndReopen(options);
|
||||||
|
ASSERT_OK(db_->Put(WriteOptions(), "a", "dontcare"));
|
||||||
|
ASSERT_OK(db_->Put(WriteOptions(), "c", "dontcare"));
|
||||||
|
ASSERT_OK(db_->Flush(FlushOptions()));
|
||||||
|
|
||||||
|
ASSERT_OK(db_->Put(WriteOptions(), "b", "dontcare"));
|
||||||
|
ASSERT_OK(db_->Put(WriteOptions(), "d", "dontcare"));
|
||||||
|
ASSERT_OK(db_->Flush(FlushOptions()));
|
||||||
|
|
||||||
|
{
|
||||||
|
CompactRangeOptions cro;
|
||||||
|
cro.bottommost_level_compaction = BottommostLevelCompaction::kForce;
|
||||||
|
ASSERT_OK(db_->CompactRange(cro, nullptr, nullptr));
|
||||||
|
|
||||||
|
IngestExternalFileOptions ifo;
|
||||||
|
ifo.fail_if_not_bottommost_level = true;
|
||||||
|
const Status s = db_->IngestExternalFile({file_path}, ifo);
|
||||||
|
ASSERT_TRUE(s.IsTryAgain());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
INSTANTIATE_TEST_CASE_P(ExternalSSTFileBasicTest, ExternalSSTFileBasicTest,
|
INSTANTIATE_TEST_CASE_P(ExternalSSTFileBasicTest, ExternalSSTFileBasicTest,
|
||||||
testing::Values(std::make_tuple(true, true),
|
testing::Values(std::make_tuple(true, true),
|
||||||
std::make_tuple(true, false),
|
std::make_tuple(true, false),
|
||||||
|
|
|
@ -739,6 +739,12 @@ Status ExternalSstFileIngestionJob::AssignLevelAndSeqnoForIngestedFile(
|
||||||
if (force_global_seqno) {
|
if (force_global_seqno) {
|
||||||
*assigned_seqno = last_seqno + 1;
|
*assigned_seqno = last_seqno + 1;
|
||||||
if (compaction_style == kCompactionStyleUniversal || files_overlap_) {
|
if (compaction_style == kCompactionStyleUniversal || files_overlap_) {
|
||||||
|
if (ingestion_options_.fail_if_not_bottommost_level) {
|
||||||
|
status = Status::TryAgain(
|
||||||
|
"Files cannot be ingested to Lmax. Please make sure key range of "
|
||||||
|
"Lmax does not overlap with files to ingest.");
|
||||||
|
return status;
|
||||||
|
}
|
||||||
file_to_ingest->picked_level = 0;
|
file_to_ingest->picked_level = 0;
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
@ -808,6 +814,15 @@ Status ExternalSstFileIngestionJob::AssignLevelAndSeqnoForIngestedFile(
|
||||||
target_level = 0;
|
target_level = 0;
|
||||||
*assigned_seqno = last_seqno + 1;
|
*assigned_seqno = last_seqno + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ingestion_options_.fail_if_not_bottommost_level &&
|
||||||
|
target_level < cfd_->NumberLevels() - 1) {
|
||||||
|
status = Status::TryAgain(
|
||||||
|
"Files cannot be ingested to Lmax. Please make sure key range of Lmax "
|
||||||
|
"does not overlap with files to ingest.");
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
TEST_SYNC_POINT_CALLBACK(
|
TEST_SYNC_POINT_CALLBACK(
|
||||||
"ExternalSstFileIngestionJob::AssignLevelAndSeqnoForIngestedFile",
|
"ExternalSstFileIngestionJob::AssignLevelAndSeqnoForIngestedFile",
|
||||||
&overlap_with_db);
|
&overlap_with_db);
|
||||||
|
|
|
@ -1566,6 +1566,11 @@ class DB {
|
||||||
// (3) If IngestExternalFileOptions->ingest_behind is set to true,
|
// (3) If IngestExternalFileOptions->ingest_behind is set to true,
|
||||||
// we always ingest at the bottommost level, which should be reserved
|
// we always ingest at the bottommost level, which should be reserved
|
||||||
// for this purpose (see DBOPtions::allow_ingest_behind flag).
|
// for this purpose (see DBOPtions::allow_ingest_behind flag).
|
||||||
|
// (4) If IngestExternalFileOptions->fail_if_not_bottommost_level is set to
|
||||||
|
// true, then this method can return Status:TryAgain() indicating that
|
||||||
|
// the files cannot be ingested to the bottommost level, and it is the
|
||||||
|
// user's responsibility to clear the bottommost level in the overlapping
|
||||||
|
// range before re-attempting the ingestion.
|
||||||
virtual Status IngestExternalFile(
|
virtual Status IngestExternalFile(
|
||||||
ColumnFamilyHandle* column_family,
|
ColumnFamilyHandle* column_family,
|
||||||
const std::vector<std::string>& external_files,
|
const std::vector<std::string>& external_files,
|
||||||
|
|
|
@ -1855,6 +1855,14 @@ struct IngestExternalFileOptions {
|
||||||
// ingestion. However, if no checksum information is provided with the
|
// ingestion. However, if no checksum information is provided with the
|
||||||
// ingested files, DB will generate the checksum and store in the Manifest.
|
// ingested files, DB will generate the checksum and store in the Manifest.
|
||||||
bool verify_file_checksum = true;
|
bool verify_file_checksum = true;
|
||||||
|
// Set to TRUE if user wants file to be ingested to the bottommost level. An
|
||||||
|
// error of Status::TryAgain() will be returned if a file cannot fit in the
|
||||||
|
// bottommost level when calling
|
||||||
|
// DB::IngestExternalFile()/DB::IngestExternalFiles(). The user should clear
|
||||||
|
// the bottommost level in the overlapping range before re-attempt.
|
||||||
|
//
|
||||||
|
// ingest_behind takes precedence over fail_if_not_bottommost_level.
|
||||||
|
bool fail_if_not_bottommost_level = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
enum TraceFilterType : uint64_t {
|
enum TraceFilterType : uint64_t {
|
||||||
|
|
Loading…
Reference in New Issue