]>
Commit | Line | Data |
---|---|---|
1e59de90 TL |
1 | // Copyright (c) Meta Platforms, Inc. and affiliates. |
2 | // | |
20effc67 TL |
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). | |
6 | ||
1e59de90 | 7 | #include "db/periodic_task_scheduler.h" |
20effc67 TL |
8 | |
9 | #include "db/db_test_util.h" | |
1e59de90 TL |
10 | #include "env/composite_env_wrapper.h" |
11 | #include "test_util/mock_time_env.h" | |
20effc67 TL |
12 | |
13 | namespace ROCKSDB_NAMESPACE { | |
14 | ||
15 | #ifndef ROCKSDB_LITE | |
1e59de90 | 16 | class PeriodicTaskSchedulerTest : public DBTestBase { |
20effc67 | 17 | public: |
1e59de90 TL |
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_)); | |
20effc67 TL |
22 | } |
23 | ||
24 | protected: | |
1e59de90 TL |
25 | std::unique_ptr<Env> mock_env_; |
26 | std::shared_ptr<MockSystemClock> mock_clock_; | |
20effc67 TL |
27 | |
28 | void SetUp() override { | |
1e59de90 | 29 | mock_clock_->InstallTimedWaitFixCallback(); |
20effc67 | 30 | SyncPoint::GetInstance()->SetCallBack( |
1e59de90 TL |
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()); | |
20effc67 TL |
35 | }); |
36 | } | |
37 | }; | |
38 | ||
1e59de90 TL |
39 | TEST_F(PeriodicTaskSchedulerTest, Basic) { |
40 | constexpr unsigned int kPeriodSec = 10; | |
20effc67 TL |
41 | Close(); |
42 | Options options; | |
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(); | |
47 | ||
48 | int dump_st_counter = 0; | |
49 | SyncPoint::GetInstance()->SetCallBack("DBImpl::DumpStats:StartRunning", | |
50 | [&](void*) { dump_st_counter++; }); | |
51 | ||
52 | int pst_st_counter = 0; | |
53 | SyncPoint::GetInstance()->SetCallBack("DBImpl::PersistStats:StartRunning", | |
54 | [&](void*) { pst_st_counter++; }); | |
55 | ||
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(); | |
61 | ||
62 | Reopen(options); | |
63 | ||
64 | ASSERT_EQ(kPeriodSec, dbfull()->GetDBOptions().stats_dump_period_sec); | |
65 | ASSERT_EQ(kPeriodSec, dbfull()->GetDBOptions().stats_persist_period_sec); | |
66 | ||
67 | ASSERT_GT(kPeriodSec, 1u); | |
1e59de90 TL |
68 | dbfull()->TEST_WaitForPeridicTaskRun([&] { |
69 | mock_clock_->MockSleepForSeconds(static_cast<int>(kPeriodSec) - 1); | |
20effc67 TL |
70 | }); |
71 | ||
1e59de90 TL |
72 | const PeriodicTaskScheduler& scheduler = |
73 | dbfull()->TEST_GetPeriodicTaskScheduler(); | |
74 | ASSERT_EQ(3, scheduler.TEST_GetValidTaskNum()); | |
20effc67 TL |
75 | |
76 | ASSERT_EQ(1, dump_st_counter); | |
77 | ASSERT_EQ(1, pst_st_counter); | |
78 | ASSERT_EQ(1, flush_info_log_counter); | |
79 | ||
1e59de90 TL |
80 | dbfull()->TEST_WaitForPeridicTaskRun( |
81 | [&] { mock_clock_->MockSleepForSeconds(static_cast<int>(kPeriodSec)); }); | |
20effc67 TL |
82 | |
83 | ASSERT_EQ(2, dump_st_counter); | |
84 | ASSERT_EQ(2, pst_st_counter); | |
85 | ASSERT_EQ(2, flush_info_log_counter); | |
86 | ||
1e59de90 TL |
87 | dbfull()->TEST_WaitForPeridicTaskRun( |
88 | [&] { mock_clock_->MockSleepForSeconds(static_cast<int>(kPeriodSec)); }); | |
20effc67 TL |
89 | |
90 | ASSERT_EQ(3, dump_st_counter); | |
91 | ASSERT_EQ(3, pst_st_counter); | |
92 | ASSERT_EQ(3, flush_info_log_counter); | |
93 | ||
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); | |
99 | ||
100 | // Info log flush should still run. | |
1e59de90 TL |
101 | dbfull()->TEST_WaitForPeridicTaskRun( |
102 | [&] { mock_clock_->MockSleepForSeconds(static_cast<int>(kPeriodSec)); }); | |
20effc67 TL |
103 | ASSERT_EQ(3, dump_st_counter); |
104 | ASSERT_EQ(3, pst_st_counter); | |
105 | ASSERT_EQ(4, flush_info_log_counter); | |
106 | ||
1e59de90 | 107 | ASSERT_EQ(1u, scheduler.TEST_GetValidTaskNum()); |
20effc67 TL |
108 | |
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); | |
113 | ||
1e59de90 | 114 | ASSERT_EQ(2, scheduler.TEST_GetValidTaskNum()); |
20effc67 | 115 | |
1e59de90 TL |
116 | dbfull()->TEST_WaitForPeridicTaskRun( |
117 | [&] { mock_clock_->MockSleepForSeconds(static_cast<int>(kPeriodSec)); }); | |
20effc67 TL |
118 | ASSERT_EQ(4, dump_st_counter); |
119 | ASSERT_EQ(3, pst_st_counter); | |
120 | ASSERT_EQ(5, flush_info_log_counter); | |
121 | ||
122 | Close(); | |
123 | } | |
124 | ||
1e59de90 | 125 | TEST_F(PeriodicTaskSchedulerTest, MultiInstances) { |
20effc67 TL |
126 | constexpr int kPeriodSec = 5; |
127 | const int kInstanceNum = 10; | |
128 | ||
129 | Close(); | |
130 | Options options; | |
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(); | |
135 | ||
136 | int dump_st_counter = 0; | |
137 | SyncPoint::GetInstance()->SetCallBack("DBImpl::DumpStats:2", | |
138 | [&](void*) { dump_st_counter++; }); | |
139 | ||
140 | int pst_st_counter = 0; | |
141 | SyncPoint::GetInstance()->SetCallBack("DBImpl::PersistStats:StartRunning", | |
142 | [&](void*) { pst_st_counter++; }); | |
143 | SyncPoint::GetInstance()->EnableProcessing(); | |
144 | ||
145 | auto dbs = std::vector<DB*>(kInstanceNum); | |
146 | for (int i = 0; i < kInstanceNum; i++) { | |
147 | ASSERT_OK( | |
148 | DB::Open(options, test::PerThreadDBPath(std::to_string(i)), &(dbs[i]))); | |
149 | } | |
150 | ||
151 | auto dbi = static_cast_with_check<DBImpl>(dbs[kInstanceNum - 1]); | |
1e59de90 TL |
152 | |
153 | const PeriodicTaskScheduler& scheduler = dbi->TEST_GetPeriodicTaskScheduler(); | |
154 | ASSERT_EQ(kInstanceNum * 3, scheduler.TEST_GetValidTaskNum()); | |
20effc67 TL |
155 | |
156 | int expected_run = kInstanceNum; | |
1e59de90 TL |
157 | dbi->TEST_WaitForPeridicTaskRun( |
158 | [&] { mock_clock_->MockSleepForSeconds(kPeriodSec - 1); }); | |
20effc67 TL |
159 | ASSERT_EQ(expected_run, dump_st_counter); |
160 | ASSERT_EQ(expected_run, pst_st_counter); | |
161 | ||
162 | expected_run += kInstanceNum; | |
1e59de90 TL |
163 | dbi->TEST_WaitForPeridicTaskRun( |
164 | [&] { mock_clock_->MockSleepForSeconds(kPeriodSec); }); | |
20effc67 TL |
165 | ASSERT_EQ(expected_run, dump_st_counter); |
166 | ASSERT_EQ(expected_run, pst_st_counter); | |
167 | ||
168 | expected_run += kInstanceNum; | |
1e59de90 TL |
169 | dbi->TEST_WaitForPeridicTaskRun( |
170 | [&] { mock_clock_->MockSleepForSeconds(kPeriodSec); }); | |
20effc67 TL |
171 | ASSERT_EQ(expected_run, dump_st_counter); |
172 | ASSERT_EQ(expected_run, pst_st_counter); | |
173 | ||
174 | int half = kInstanceNum / 2; | |
175 | for (int i = 0; i < half; i++) { | |
176 | delete dbs[i]; | |
177 | } | |
178 | ||
179 | expected_run += (kInstanceNum - half) * 2; | |
180 | ||
1e59de90 TL |
181 | dbi->TEST_WaitForPeridicTaskRun( |
182 | [&] { mock_clock_->MockSleepForSeconds(kPeriodSec); }); | |
183 | dbi->TEST_WaitForPeridicTaskRun( | |
184 | [&] { mock_clock_->MockSleepForSeconds(kPeriodSec); }); | |
20effc67 TL |
185 | ASSERT_EQ(expected_run, dump_st_counter); |
186 | ASSERT_EQ(expected_run, pst_st_counter); | |
187 | ||
188 | for (int i = half; i < kInstanceNum; i++) { | |
1e59de90 | 189 | ASSERT_OK(dbs[i]->Close()); |
20effc67 TL |
190 | delete dbs[i]; |
191 | } | |
192 | } | |
193 | ||
1e59de90 | 194 | TEST_F(PeriodicTaskSchedulerTest, MultiEnv) { |
20effc67 TL |
195 | constexpr int kDumpPeriodSec = 5; |
196 | constexpr int kPersistPeriodSec = 10; | |
197 | Close(); | |
198 | Options options1; | |
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(); | |
203 | ||
204 | Reopen(options1); | |
205 | ||
1e59de90 TL |
206 | std::unique_ptr<Env> mock_env2( |
207 | new CompositeEnvWrapper(Env::Default(), mock_clock_)); | |
20effc67 TL |
208 | Options options2; |
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(); | |
213 | ||
214 | std::string dbname = test::PerThreadDBPath("multi_env_test"); | |
215 | DB* db; | |
216 | ASSERT_OK(DB::Open(options2, dbname, &db)); | |
20effc67 | 217 | |
1e59de90 | 218 | ASSERT_OK(db->Close()); |
20effc67 TL |
219 | delete db; |
220 | Close(); | |
221 | } | |
1e59de90 | 222 | |
20effc67 TL |
223 | #endif // !ROCKSDB_LITE |
224 | } // namespace ROCKSDB_NAMESPACE | |
225 | ||
226 | int main(int argc, char** argv) { | |
1e59de90 | 227 | ROCKSDB_NAMESPACE::port::InstallStackTraceHandler(); |
20effc67 TL |
228 | ::testing::InitGoogleTest(&argc, argv); |
229 | ||
230 | return RUN_ALL_TESTS(); | |
231 | } |