1 // Copyright (c) Meta Platforms, Inc. and affiliates.
3 // This source code is licensed under both the GPLv2 (found in the
4 // COPYING file in the root directory) and Apache 2.0 License
5 // (found in the LICENSE.Apache file in the root directory).
7 #include "db/periodic_task_scheduler.h"
9 #include "db/db_test_util.h"
10 #include "env/composite_env_wrapper.h"
11 #include "test_util/mock_time_env.h"
13 namespace ROCKSDB_NAMESPACE
{
16 class PeriodicTaskSchedulerTest
: public DBTestBase
{
18 PeriodicTaskSchedulerTest()
19 : DBTestBase("periodic_task_scheduler_test", /*env_do_fsync=*/true) {
20 mock_clock_
= std::make_shared
<MockSystemClock
>(env_
->GetSystemClock());
21 mock_env_
.reset(new CompositeEnvWrapper(env_
, mock_clock_
));
25 std::unique_ptr
<Env
> mock_env_
;
26 std::shared_ptr
<MockSystemClock
> mock_clock_
;
28 void SetUp() override
{
29 mock_clock_
->InstallTimedWaitFixCallback();
30 SyncPoint::GetInstance()->SetCallBack(
31 "DBImpl::StartPeriodicTaskScheduler:Init", [&](void* arg
) {
32 auto periodic_task_scheduler_ptr
=
33 reinterpret_cast<PeriodicTaskScheduler
*>(arg
);
34 periodic_task_scheduler_ptr
->TEST_OverrideTimer(mock_clock_
.get());
39 TEST_F(PeriodicTaskSchedulerTest
, Basic
) {
40 constexpr unsigned int kPeriodSec
= 10;
43 options
.stats_dump_period_sec
= kPeriodSec
;
44 options
.stats_persist_period_sec
= kPeriodSec
;
45 options
.create_if_missing
= true;
46 options
.env
= mock_env_
.get();
48 int dump_st_counter
= 0;
49 SyncPoint::GetInstance()->SetCallBack("DBImpl::DumpStats:StartRunning",
50 [&](void*) { dump_st_counter
++; });
52 int pst_st_counter
= 0;
53 SyncPoint::GetInstance()->SetCallBack("DBImpl::PersistStats:StartRunning",
54 [&](void*) { pst_st_counter
++; });
56 int flush_info_log_counter
= 0;
57 SyncPoint::GetInstance()->SetCallBack(
58 "DBImpl::FlushInfoLog:StartRunning",
59 [&](void*) { flush_info_log_counter
++; });
60 SyncPoint::GetInstance()->EnableProcessing();
64 ASSERT_EQ(kPeriodSec
, dbfull()->GetDBOptions().stats_dump_period_sec
);
65 ASSERT_EQ(kPeriodSec
, dbfull()->GetDBOptions().stats_persist_period_sec
);
67 ASSERT_GT(kPeriodSec
, 1u);
68 dbfull()->TEST_WaitForPeridicTaskRun([&] {
69 mock_clock_
->MockSleepForSeconds(static_cast<int>(kPeriodSec
) - 1);
72 const PeriodicTaskScheduler
& scheduler
=
73 dbfull()->TEST_GetPeriodicTaskScheduler();
74 ASSERT_EQ(3, scheduler
.TEST_GetValidTaskNum());
76 ASSERT_EQ(1, dump_st_counter
);
77 ASSERT_EQ(1, pst_st_counter
);
78 ASSERT_EQ(1, flush_info_log_counter
);
80 dbfull()->TEST_WaitForPeridicTaskRun(
81 [&] { mock_clock_
->MockSleepForSeconds(static_cast<int>(kPeriodSec
)); });
83 ASSERT_EQ(2, dump_st_counter
);
84 ASSERT_EQ(2, pst_st_counter
);
85 ASSERT_EQ(2, flush_info_log_counter
);
87 dbfull()->TEST_WaitForPeridicTaskRun(
88 [&] { mock_clock_
->MockSleepForSeconds(static_cast<int>(kPeriodSec
)); });
90 ASSERT_EQ(3, dump_st_counter
);
91 ASSERT_EQ(3, pst_st_counter
);
92 ASSERT_EQ(3, flush_info_log_counter
);
94 // Disable scheduler with SetOption
95 ASSERT_OK(dbfull()->SetDBOptions(
96 {{"stats_dump_period_sec", "0"}, {"stats_persist_period_sec", "0"}}));
97 ASSERT_EQ(0u, dbfull()->GetDBOptions().stats_dump_period_sec
);
98 ASSERT_EQ(0u, dbfull()->GetDBOptions().stats_persist_period_sec
);
100 // Info log flush should still run.
101 dbfull()->TEST_WaitForPeridicTaskRun(
102 [&] { mock_clock_
->MockSleepForSeconds(static_cast<int>(kPeriodSec
)); });
103 ASSERT_EQ(3, dump_st_counter
);
104 ASSERT_EQ(3, pst_st_counter
);
105 ASSERT_EQ(4, flush_info_log_counter
);
107 ASSERT_EQ(1u, scheduler
.TEST_GetValidTaskNum());
109 // Re-enable one task
110 ASSERT_OK(dbfull()->SetDBOptions({{"stats_dump_period_sec", "5"}}));
111 ASSERT_EQ(5u, dbfull()->GetDBOptions().stats_dump_period_sec
);
112 ASSERT_EQ(0u, dbfull()->GetDBOptions().stats_persist_period_sec
);
114 ASSERT_EQ(2, scheduler
.TEST_GetValidTaskNum());
116 dbfull()->TEST_WaitForPeridicTaskRun(
117 [&] { mock_clock_
->MockSleepForSeconds(static_cast<int>(kPeriodSec
)); });
118 ASSERT_EQ(4, dump_st_counter
);
119 ASSERT_EQ(3, pst_st_counter
);
120 ASSERT_EQ(5, flush_info_log_counter
);
125 TEST_F(PeriodicTaskSchedulerTest
, MultiInstances
) {
126 constexpr int kPeriodSec
= 5;
127 const int kInstanceNum
= 10;
131 options
.stats_dump_period_sec
= kPeriodSec
;
132 options
.stats_persist_period_sec
= kPeriodSec
;
133 options
.create_if_missing
= true;
134 options
.env
= mock_env_
.get();
136 int dump_st_counter
= 0;
137 SyncPoint::GetInstance()->SetCallBack("DBImpl::DumpStats:2",
138 [&](void*) { dump_st_counter
++; });
140 int pst_st_counter
= 0;
141 SyncPoint::GetInstance()->SetCallBack("DBImpl::PersistStats:StartRunning",
142 [&](void*) { pst_st_counter
++; });
143 SyncPoint::GetInstance()->EnableProcessing();
145 auto dbs
= std::vector
<DB
*>(kInstanceNum
);
146 for (int i
= 0; i
< kInstanceNum
; i
++) {
148 DB::Open(options
, test::PerThreadDBPath(std::to_string(i
)), &(dbs
[i
])));
151 auto dbi
= static_cast_with_check
<DBImpl
>(dbs
[kInstanceNum
- 1]);
153 const PeriodicTaskScheduler
& scheduler
= dbi
->TEST_GetPeriodicTaskScheduler();
154 ASSERT_EQ(kInstanceNum
* 3, scheduler
.TEST_GetValidTaskNum());
156 int expected_run
= kInstanceNum
;
157 dbi
->TEST_WaitForPeridicTaskRun(
158 [&] { mock_clock_
->MockSleepForSeconds(kPeriodSec
- 1); });
159 ASSERT_EQ(expected_run
, dump_st_counter
);
160 ASSERT_EQ(expected_run
, pst_st_counter
);
162 expected_run
+= kInstanceNum
;
163 dbi
->TEST_WaitForPeridicTaskRun(
164 [&] { mock_clock_
->MockSleepForSeconds(kPeriodSec
); });
165 ASSERT_EQ(expected_run
, dump_st_counter
);
166 ASSERT_EQ(expected_run
, pst_st_counter
);
168 expected_run
+= kInstanceNum
;
169 dbi
->TEST_WaitForPeridicTaskRun(
170 [&] { mock_clock_
->MockSleepForSeconds(kPeriodSec
); });
171 ASSERT_EQ(expected_run
, dump_st_counter
);
172 ASSERT_EQ(expected_run
, pst_st_counter
);
174 int half
= kInstanceNum
/ 2;
175 for (int i
= 0; i
< half
; i
++) {
179 expected_run
+= (kInstanceNum
- half
) * 2;
181 dbi
->TEST_WaitForPeridicTaskRun(
182 [&] { mock_clock_
->MockSleepForSeconds(kPeriodSec
); });
183 dbi
->TEST_WaitForPeridicTaskRun(
184 [&] { mock_clock_
->MockSleepForSeconds(kPeriodSec
); });
185 ASSERT_EQ(expected_run
, dump_st_counter
);
186 ASSERT_EQ(expected_run
, pst_st_counter
);
188 for (int i
= half
; i
< kInstanceNum
; i
++) {
189 ASSERT_OK(dbs
[i
]->Close());
194 TEST_F(PeriodicTaskSchedulerTest
, MultiEnv
) {
195 constexpr int kDumpPeriodSec
= 5;
196 constexpr int kPersistPeriodSec
= 10;
199 options1
.stats_dump_period_sec
= kDumpPeriodSec
;
200 options1
.stats_persist_period_sec
= kPersistPeriodSec
;
201 options1
.create_if_missing
= true;
202 options1
.env
= mock_env_
.get();
206 std::unique_ptr
<Env
> mock_env2(
207 new CompositeEnvWrapper(Env::Default(), mock_clock_
));
209 options2
.stats_dump_period_sec
= kDumpPeriodSec
;
210 options2
.stats_persist_period_sec
= kPersistPeriodSec
;
211 options2
.create_if_missing
= true;
212 options1
.env
= mock_env2
.get();
214 std::string dbname
= test::PerThreadDBPath("multi_env_test");
216 ASSERT_OK(DB::Open(options2
, dbname
, &db
));
218 ASSERT_OK(db
->Close());
223 #endif // !ROCKSDB_LITE
224 } // namespace ROCKSDB_NAMESPACE
226 int main(int argc
, char** argv
) {
227 ROCKSDB_NAMESPACE::port::InstallStackTraceHandler();
228 ::testing::InitGoogleTest(&argc
, argv
);
230 return RUN_ALL_TESTS();