Prevent manual compaction hanging in read-only mode (#4611)
Summary: A background compaction with pre-picked files (i.e., either a manual compaction or a bottom-pri compaction) fails when the DB is in read-only mode. In the failure handling, we forgot to unregister the compaction and the files it covered. Then subsequent manual compactions could conflict with this zombie compaction (possibly Halloween related) and wait forever for it to finish. Pull Request resolved: https://github.com/facebook/rocksdb/pull/4611 Differential Revision: D12871217 Pulled By: ajkr fbshipit-source-id: 9d24e921d5bbd2ee8c2c9536a30abfa42a220c6e
This commit is contained in:
parent
50895e5f0d
commit
b8f68bac38
@ -12,7 +12,9 @@
|
||||
#include "port/port.h"
|
||||
#include "rocksdb/experimental.h"
|
||||
#include "rocksdb/utilities/convenience.h"
|
||||
#include "util/fault_injection_test_env.h"
|
||||
#include "util/sync_point.h"
|
||||
|
||||
namespace rocksdb {
|
||||
|
||||
// SYNC_POINT is not supported in released Windows mode.
|
||||
@ -4029,6 +4031,46 @@ TEST_F(DBCompactionTest, PartialManualCompaction) {
|
||||
dbfull()->CompactRange(cro, nullptr, nullptr);
|
||||
}
|
||||
|
||||
TEST_F(DBCompactionTest, ManualCompactionFailsInReadOnlyMode) {
|
||||
// Regression test for bug where manual compaction hangs forever when the DB
|
||||
// is in read-only mode. Verify it now at least returns, despite failing.
|
||||
const int kNumL0Files = 4;
|
||||
std::unique_ptr<FaultInjectionTestEnv> mock_env(
|
||||
new FaultInjectionTestEnv(Env::Default()));
|
||||
Options opts = CurrentOptions();
|
||||
opts.disable_auto_compactions = true;
|
||||
opts.env = mock_env.get();
|
||||
DestroyAndReopen(opts);
|
||||
|
||||
Random rnd(301);
|
||||
for (int i = 0; i < kNumL0Files; ++i) {
|
||||
// Make sure files are overlapping in key-range to prevent trivial move.
|
||||
Put("key1", RandomString(&rnd, 1024));
|
||||
Put("key2", RandomString(&rnd, 1024));
|
||||
Flush();
|
||||
}
|
||||
ASSERT_EQ(kNumL0Files, NumTableFilesAtLevel(0));
|
||||
|
||||
// Enter read-only mode by failing a write.
|
||||
mock_env->SetFilesystemActive(false);
|
||||
// Make sure this is outside `CompactRange`'s range so that it doesn't fail
|
||||
// early trying to flush memtable.
|
||||
ASSERT_NOK(Put("key3", RandomString(&rnd, 1024)));
|
||||
|
||||
// In the bug scenario, the first manual compaction would fail and forget to
|
||||
// unregister itself, causing the second one to hang forever due to conflict
|
||||
// with a non-running compaction.
|
||||
CompactRangeOptions cro;
|
||||
cro.exclusive_manual_compaction = false;
|
||||
Slice begin_key("key1");
|
||||
Slice end_key("key2");
|
||||
ASSERT_NOK(dbfull()->CompactRange(cro, &begin_key, &end_key));
|
||||
ASSERT_NOK(dbfull()->CompactRange(cro, &begin_key, &end_key));
|
||||
|
||||
// Close before mock_env destruct.
|
||||
Close();
|
||||
}
|
||||
|
||||
#endif // !defined(ROCKSDB_LITE)
|
||||
} // namespace rocksdb
|
||||
|
||||
|
@ -2170,6 +2170,10 @@ Status DBImpl::BackgroundCompaction(bool* made_progress,
|
||||
manual_compaction->in_progress = false;
|
||||
manual_compaction = nullptr;
|
||||
}
|
||||
if (c) {
|
||||
c->ReleaseCompactionFiles(status);
|
||||
c.reset();
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user