// Copyright (c) 2011-present, Facebook, Inc. All rights reserved. // This source code is licensed under the BSD-style license found in the // LICENSE file in the root directory of this source tree. An additional grant // of patent rights can be found in the PATENTS file in the same directory. // // Copyright (c) 2011 The LevelDB Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. See the AUTHORS file for names of contributors. #include "db/db_test_util.h" #include "port/stack_trace.h" #include "util/sync_point.h" namespace rocksdb { class DBOptionsTest : public DBTestBase { public: DBOptionsTest() : DBTestBase("/db_options_test") {} }; // RocksDB lite don't support dynamic options. #ifndef ROCKSDB_LITE // When write stalls, user can enable auto compaction to unblock writes. // However, we had an issue where the stalled write thread blocks the attempt // to persist auto compaction option, thus creating a deadlock. The test // verifies the issue is fixed. TEST_F(DBOptionsTest, EnableAutoCompactionToUnblockWrites) { Options options; options.disable_auto_compactions = true; options.write_buffer_size = 1000 * 1000; // 1M options.level0_file_num_compaction_trigger = 1; options.level0_slowdown_writes_trigger = 1; options.level0_stop_writes_trigger = 1; options.compression = kNoCompression; SyncPoint::GetInstance()->LoadDependency( {{"DBImpl::DelayWrite:Wait", "DBOptionsTest::EnableAutoCompactionToUnblockWrites:1"}, {"DBImpl::BackgroundCompaction:Finish", "DBOptionsTest::EnableAutoCompactionToUnblockWrites:1"}}); SyncPoint::GetInstance()->EnableProcessing(); // Stall writes. Reopen(options); env_->StartThread( [](void* arg) { std::string value(1000, 'v'); auto* t = static_cast(arg); for (int i = 0; i < 2000; i++) { ASSERT_OK(t->Put(t->Key(i), value)); } }, this); TEST_SYNC_POINT("DBOptionsTest::EnableAutoCompactionToUnblockWrites:1"); ASSERT_TRUE(dbfull()->TEST_write_controler().IsStopped()); ColumnFamilyHandle* handle = dbfull()->DefaultColumnFamily(); // We will get a deadlock here if we hit the issue. ASSERT_OK(dbfull()->EnableAutoCompaction({handle})); env_->WaitForJoin(); } // Similar to EnableAutoCompactionAfterStallDeadlock. See comments there. TEST_F(DBOptionsTest, ToggleStopTriggerToUnblockWrites) { Options options; options.disable_auto_compactions = true; options.write_buffer_size = 1000 * 1000; // 1M options.level0_file_num_compaction_trigger = 1; options.level0_slowdown_writes_trigger = 1; options.level0_stop_writes_trigger = 1; options.compression = kNoCompression; SyncPoint::GetInstance()->LoadDependency( {{"DBImpl::DelayWrite:Wait", "DBOptionsTest::ToggleStopTriggerToUnblockWrites:1"}, {"DBImpl::BackgroundCompaction:Finish", "DBOptionsTest::ToggleStopTriggerToUnblockWrites:1"}}); SyncPoint::GetInstance()->EnableProcessing(); // Stall writes. Reopen(options); env_->StartThread( [](void* arg) { std::string value(1000, 'v'); auto* t = static_cast(arg); for (int i = 0; i < 2000; i++) { ASSERT_OK(t->Put(t->Key(i), value)); } }, this); TEST_SYNC_POINT("DBOptionsTest::ToggleStopTriggerToUnblockWrites:1"); ASSERT_TRUE(dbfull()->TEST_write_controler().IsStopped()); // We will get a deadlock here if we hit the issue. ASSERT_OK( dbfull()->SetOptions({{"level0_stop_writes_trigger", "1000000"}, {"level0_slowdown_writes_trigger", "1000000"}})); env_->WaitForJoin(); } #endif // ROCKSDB_LITE } // namespace rocksdb int main(int argc, char** argv) { rocksdb::port::InstallStackTraceHandler(); ::testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); }