]>
Commit | Line | Data |
---|---|---|
20effc67 TL |
1 | // Copyright (c) 2011-present, Facebook, Inc. All rights reserved. |
2 | // This source code is licensed under both the GPLv2 (found in the | |
3 | // COPYING file in the root directory) and Apache 2.0 License | |
4 | // (found in the LICENSE.Apache file in the root directory). | |
5 | ||
6 | #include "db/periodic_work_scheduler.h" | |
7 | ||
8 | #include "db/db_test_util.h" | |
9 | ||
10 | namespace ROCKSDB_NAMESPACE { | |
11 | ||
12 | #ifndef ROCKSDB_LITE | |
13 | class PeriodicWorkSchedulerTest : public DBTestBase { | |
14 | public: | |
15 | PeriodicWorkSchedulerTest() | |
16 | : DBTestBase("/periodic_work_scheduler_test", /*env_do_fsync=*/true) { | |
17 | mock_env_.reset(new MockTimeEnv(env_)); | |
18 | } | |
19 | ||
20 | protected: | |
21 | std::unique_ptr<MockTimeEnv> mock_env_; | |
22 | ||
23 | void SetUp() override { | |
24 | mock_env_->InstallTimedWaitFixCallback(); | |
25 | SyncPoint::GetInstance()->SetCallBack( | |
26 | "DBImpl::StartPeriodicWorkScheduler:Init", [&](void* arg) { | |
27 | auto* periodic_work_scheduler_ptr = | |
28 | reinterpret_cast<PeriodicWorkScheduler**>(arg); | |
29 | *periodic_work_scheduler_ptr = | |
30 | PeriodicWorkTestScheduler::Default(mock_env_.get()); | |
31 | }); | |
32 | } | |
33 | }; | |
34 | ||
35 | TEST_F(PeriodicWorkSchedulerTest, Basic) { | |
36 | constexpr unsigned int kPeriodSec = | |
37 | PeriodicWorkScheduler::kDefaultFlushInfoLogPeriodSec; | |
38 | Close(); | |
39 | Options options; | |
40 | options.stats_dump_period_sec = kPeriodSec; | |
41 | options.stats_persist_period_sec = kPeriodSec; | |
42 | options.create_if_missing = true; | |
43 | options.env = mock_env_.get(); | |
44 | ||
45 | int dump_st_counter = 0; | |
46 | SyncPoint::GetInstance()->SetCallBack("DBImpl::DumpStats:StartRunning", | |
47 | [&](void*) { dump_st_counter++; }); | |
48 | ||
49 | int pst_st_counter = 0; | |
50 | SyncPoint::GetInstance()->SetCallBack("DBImpl::PersistStats:StartRunning", | |
51 | [&](void*) { pst_st_counter++; }); | |
52 | ||
53 | int flush_info_log_counter = 0; | |
54 | SyncPoint::GetInstance()->SetCallBack( | |
55 | "DBImpl::FlushInfoLog:StartRunning", | |
56 | [&](void*) { flush_info_log_counter++; }); | |
57 | SyncPoint::GetInstance()->EnableProcessing(); | |
58 | ||
59 | Reopen(options); | |
60 | ||
61 | ASSERT_EQ(kPeriodSec, dbfull()->GetDBOptions().stats_dump_period_sec); | |
62 | ASSERT_EQ(kPeriodSec, dbfull()->GetDBOptions().stats_persist_period_sec); | |
63 | ||
64 | ASSERT_GT(kPeriodSec, 1u); | |
65 | dbfull()->TEST_WaitForStatsDumpRun([&] { | |
66 | mock_env_->MockSleepForSeconds(static_cast<int>(kPeriodSec) - 1); | |
67 | }); | |
68 | ||
69 | auto scheduler = dbfull()->TEST_GetPeriodicWorkScheduler(); | |
70 | ASSERT_NE(nullptr, scheduler); | |
71 | ASSERT_EQ(3, scheduler->TEST_GetValidTaskNum()); | |
72 | ||
73 | ASSERT_EQ(1, dump_st_counter); | |
74 | ASSERT_EQ(1, pst_st_counter); | |
75 | ASSERT_EQ(1, flush_info_log_counter); | |
76 | ||
77 | dbfull()->TEST_WaitForStatsDumpRun( | |
78 | [&] { mock_env_->MockSleepForSeconds(static_cast<int>(kPeriodSec)); }); | |
79 | ||
80 | ASSERT_EQ(2, dump_st_counter); | |
81 | ASSERT_EQ(2, pst_st_counter); | |
82 | ASSERT_EQ(2, flush_info_log_counter); | |
83 | ||
84 | dbfull()->TEST_WaitForStatsDumpRun( | |
85 | [&] { mock_env_->MockSleepForSeconds(static_cast<int>(kPeriodSec)); }); | |
86 | ||
87 | ASSERT_EQ(3, dump_st_counter); | |
88 | ASSERT_EQ(3, pst_st_counter); | |
89 | ASSERT_EQ(3, flush_info_log_counter); | |
90 | ||
91 | // Disable scheduler with SetOption | |
92 | ASSERT_OK(dbfull()->SetDBOptions( | |
93 | {{"stats_dump_period_sec", "0"}, {"stats_persist_period_sec", "0"}})); | |
94 | ASSERT_EQ(0u, dbfull()->GetDBOptions().stats_dump_period_sec); | |
95 | ASSERT_EQ(0u, dbfull()->GetDBOptions().stats_persist_period_sec); | |
96 | ||
97 | // Info log flush should still run. | |
98 | dbfull()->TEST_WaitForStatsDumpRun( | |
99 | [&] { mock_env_->MockSleepForSeconds(static_cast<int>(kPeriodSec)); }); | |
100 | ASSERT_EQ(3, dump_st_counter); | |
101 | ASSERT_EQ(3, pst_st_counter); | |
102 | ASSERT_EQ(4, flush_info_log_counter); | |
103 | ||
104 | scheduler = dbfull()->TEST_GetPeriodicWorkScheduler(); | |
105 | ASSERT_EQ(1u, scheduler->TEST_GetValidTaskNum()); | |
106 | ||
107 | // Re-enable one task | |
108 | ASSERT_OK(dbfull()->SetDBOptions({{"stats_dump_period_sec", "5"}})); | |
109 | ASSERT_EQ(5u, dbfull()->GetDBOptions().stats_dump_period_sec); | |
110 | ASSERT_EQ(0u, dbfull()->GetDBOptions().stats_persist_period_sec); | |
111 | ||
112 | scheduler = dbfull()->TEST_GetPeriodicWorkScheduler(); | |
113 | ASSERT_NE(nullptr, scheduler); | |
114 | ASSERT_EQ(2, scheduler->TEST_GetValidTaskNum()); | |
115 | ||
116 | dbfull()->TEST_WaitForStatsDumpRun( | |
117 | [&] { mock_env_->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); | |
121 | ||
122 | Close(); | |
123 | } | |
124 | ||
125 | TEST_F(PeriodicWorkSchedulerTest, MultiInstances) { | |
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]); | |
152 | auto scheduler = dbi->TEST_GetPeriodicWorkScheduler(); | |
153 | ASSERT_EQ(kInstanceNum * 3, scheduler->TEST_GetValidTaskNum()); | |
154 | ||
155 | int expected_run = kInstanceNum; | |
156 | dbi->TEST_WaitForStatsDumpRun( | |
157 | [&] { mock_env_->MockSleepForSeconds(kPeriodSec - 1); }); | |
158 | ASSERT_EQ(expected_run, dump_st_counter); | |
159 | ASSERT_EQ(expected_run, pst_st_counter); | |
160 | ||
161 | expected_run += kInstanceNum; | |
162 | dbi->TEST_WaitForStatsDumpRun( | |
163 | [&] { mock_env_->MockSleepForSeconds(kPeriodSec); }); | |
164 | ASSERT_EQ(expected_run, dump_st_counter); | |
165 | ASSERT_EQ(expected_run, pst_st_counter); | |
166 | ||
167 | expected_run += kInstanceNum; | |
168 | dbi->TEST_WaitForStatsDumpRun( | |
169 | [&] { mock_env_->MockSleepForSeconds(kPeriodSec); }); | |
170 | ASSERT_EQ(expected_run, dump_st_counter); | |
171 | ASSERT_EQ(expected_run, pst_st_counter); | |
172 | ||
173 | int half = kInstanceNum / 2; | |
174 | for (int i = 0; i < half; i++) { | |
175 | delete dbs[i]; | |
176 | } | |
177 | ||
178 | expected_run += (kInstanceNum - half) * 2; | |
179 | ||
180 | dbi->TEST_WaitForStatsDumpRun( | |
181 | [&] { mock_env_->MockSleepForSeconds(kPeriodSec); }); | |
182 | dbi->TEST_WaitForStatsDumpRun( | |
183 | [&] { mock_env_->MockSleepForSeconds(kPeriodSec); }); | |
184 | ASSERT_EQ(expected_run, dump_st_counter); | |
185 | ASSERT_EQ(expected_run, pst_st_counter); | |
186 | ||
187 | for (int i = half; i < kInstanceNum; i++) { | |
188 | dbs[i]->Close(); | |
189 | delete dbs[i]; | |
190 | } | |
191 | } | |
192 | ||
193 | TEST_F(PeriodicWorkSchedulerTest, MultiEnv) { | |
194 | constexpr int kDumpPeriodSec = 5; | |
195 | constexpr int kPersistPeriodSec = 10; | |
196 | Close(); | |
197 | Options options1; | |
198 | options1.stats_dump_period_sec = kDumpPeriodSec; | |
199 | options1.stats_persist_period_sec = kPersistPeriodSec; | |
200 | options1.create_if_missing = true; | |
201 | options1.env = mock_env_.get(); | |
202 | ||
203 | Reopen(options1); | |
204 | ||
205 | std::unique_ptr<MockTimeEnv> mock_env2(new MockTimeEnv(Env::Default())); | |
206 | Options options2; | |
207 | options2.stats_dump_period_sec = kDumpPeriodSec; | |
208 | options2.stats_persist_period_sec = kPersistPeriodSec; | |
209 | options2.create_if_missing = true; | |
210 | options1.env = mock_env2.get(); | |
211 | ||
212 | std::string dbname = test::PerThreadDBPath("multi_env_test"); | |
213 | DB* db; | |
214 | ASSERT_OK(DB::Open(options2, dbname, &db)); | |
215 | DBImpl* dbi = static_cast_with_check<DBImpl>(db); | |
216 | ||
217 | ASSERT_EQ(dbi->TEST_GetPeriodicWorkScheduler(), | |
218 | dbfull()->TEST_GetPeriodicWorkScheduler()); | |
219 | ||
220 | db->Close(); | |
221 | delete db; | |
222 | Close(); | |
223 | } | |
224 | #endif // !ROCKSDB_LITE | |
225 | } // namespace ROCKSDB_NAMESPACE | |
226 | ||
227 | int main(int argc, char** argv) { | |
228 | ::testing::InitGoogleTest(&argc, argv); | |
229 | ||
230 | return RUN_ALL_TESTS(); | |
231 | } |