]>
Commit | Line | Data |
---|---|---|
f67539c2 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 | // Copyright (c) 2011 The LevelDB Authors. All rights reserved. | |
7 | // Use of this source code is governed by a BSD-style license that can be | |
8 | // found in the LICENSE file. See the AUTHORS file for names of contributors. | |
9 | ||
10 | #ifdef GFLAGS | |
11 | #pragma once | |
1e59de90 | 12 | |
f67539c2 TL |
13 | #include "db_stress_tool/db_stress_common.h" |
14 | #include "db_stress_tool/db_stress_shared_state.h" | |
15 | ||
16 | namespace ROCKSDB_NAMESPACE { | |
1e59de90 | 17 | class SystemClock; |
f67539c2 TL |
18 | class Transaction; |
19 | class TransactionDB; | |
1e59de90 | 20 | struct TransactionDBOptions; |
f67539c2 TL |
21 | |
22 | class StressTest { | |
23 | public: | |
24 | StressTest(); | |
25 | ||
26 | virtual ~StressTest(); | |
27 | ||
1e59de90 TL |
28 | std::shared_ptr<Cache> NewCache(size_t capacity, int32_t num_shard_bits); |
29 | ||
30 | static std::vector<std::string> GetBlobCompressionTags(); | |
f67539c2 TL |
31 | |
32 | bool BuildOptionsTable(); | |
33 | ||
1e59de90 | 34 | void InitDb(SharedState*); |
20effc67 TL |
35 | // The initialization work is split into two parts to avoid a circular |
36 | // dependency with `SharedState`. | |
1e59de90 TL |
37 | virtual void FinishInitDb(SharedState*); |
38 | void TrackExpectedState(SharedState* shared); | |
f67539c2 TL |
39 | void OperateDb(ThreadState* thread); |
40 | virtual void VerifyDb(ThreadState* thread) const = 0; | |
1e59de90 | 41 | virtual void ContinuouslyVerifyDb(ThreadState* /*thread*/) const = 0; |
f67539c2 TL |
42 | void PrintStatistics(); |
43 | ||
44 | protected: | |
45 | Status AssertSame(DB* db, ColumnFamilyHandle* cf, | |
46 | ThreadState::SnapshotState& snap_state); | |
47 | ||
48 | // Currently PreloadDb has to be single-threaded. | |
49 | void PreloadDbAndReopenAsReadOnly(int64_t number_of_keys, | |
50 | SharedState* shared); | |
51 | ||
52 | Status SetOptions(ThreadState* thread); | |
53 | ||
54 | #ifndef ROCKSDB_LITE | |
1e59de90 TL |
55 | // For transactionsDB, there can be txns prepared but not yet committeed |
56 | // right before previous stress run crash. | |
57 | // They will be recovered and processed through | |
58 | // ProcessRecoveredPreparedTxnsHelper on the start of current stress run. | |
59 | void ProcessRecoveredPreparedTxns(SharedState* shared); | |
60 | ||
61 | // Default implementation will first update ExpectedState to be | |
62 | // `SharedState::UNKNOWN` for each keys in `txn` and then randomly | |
63 | // commit or rollback `txn`. | |
64 | virtual void ProcessRecoveredPreparedTxnsHelper(Transaction* txn, | |
65 | SharedState* shared); | |
66 | ||
f67539c2 TL |
67 | Status NewTxn(WriteOptions& write_opts, Transaction** txn); |
68 | ||
1e59de90 | 69 | Status CommitTxn(Transaction* txn, ThreadState* thread = nullptr); |
f67539c2 TL |
70 | |
71 | Status RollbackTxn(Transaction* txn); | |
72 | #endif | |
73 | ||
74 | virtual void MaybeClearOneColumnFamily(ThreadState* /* thread */) {} | |
75 | ||
76 | virtual bool ShouldAcquireMutexOnKey() const { return false; } | |
77 | ||
1e59de90 TL |
78 | // Returns true if DB state is tracked by the stress test. |
79 | virtual bool IsStateTracked() const = 0; | |
80 | ||
f67539c2 TL |
81 | virtual std::vector<int> GenerateColumnFamilies( |
82 | const int /* num_column_families */, int rand_column_family) const { | |
83 | return {rand_column_family}; | |
84 | } | |
85 | ||
86 | virtual std::vector<int64_t> GenerateKeys(int64_t rand_key) const { | |
87 | return {rand_key}; | |
88 | } | |
89 | ||
90 | virtual Status TestGet(ThreadState* thread, const ReadOptions& read_opts, | |
91 | const std::vector<int>& rand_column_families, | |
92 | const std::vector<int64_t>& rand_keys) = 0; | |
93 | ||
94 | virtual std::vector<Status> TestMultiGet( | |
95 | ThreadState* thread, const ReadOptions& read_opts, | |
96 | const std::vector<int>& rand_column_families, | |
97 | const std::vector<int64_t>& rand_keys) = 0; | |
98 | ||
99 | virtual Status TestPrefixScan(ThreadState* thread, | |
100 | const ReadOptions& read_opts, | |
101 | const std::vector<int>& rand_column_families, | |
102 | const std::vector<int64_t>& rand_keys) = 0; | |
103 | ||
104 | virtual Status TestPut(ThreadState* thread, WriteOptions& write_opts, | |
105 | const ReadOptions& read_opts, | |
106 | const std::vector<int>& cf_ids, | |
1e59de90 TL |
107 | const std::vector<int64_t>& keys, |
108 | char (&value)[100]) = 0; | |
f67539c2 TL |
109 | |
110 | virtual Status TestDelete(ThreadState* thread, WriteOptions& write_opts, | |
111 | const std::vector<int>& rand_column_families, | |
1e59de90 | 112 | const std::vector<int64_t>& rand_keys) = 0; |
f67539c2 TL |
113 | |
114 | virtual Status TestDeleteRange(ThreadState* thread, WriteOptions& write_opts, | |
115 | const std::vector<int>& rand_column_families, | |
1e59de90 | 116 | const std::vector<int64_t>& rand_keys) = 0; |
f67539c2 TL |
117 | |
118 | virtual void TestIngestExternalFile( | |
119 | ThreadState* thread, const std::vector<int>& rand_column_families, | |
1e59de90 | 120 | const std::vector<int64_t>& rand_keys) = 0; |
f67539c2 TL |
121 | |
122 | // Issue compact range, starting with start_key, whose integer value | |
123 | // is rand_key. | |
124 | virtual void TestCompactRange(ThreadState* thread, int64_t rand_key, | |
125 | const Slice& start_key, | |
126 | ColumnFamilyHandle* column_family); | |
127 | ||
128 | // Calculate a hash value for all keys in range [start_key, end_key] | |
129 | // at a certain snapshot. | |
130 | uint32_t GetRangeHash(ThreadState* thread, const Snapshot* snapshot, | |
131 | ColumnFamilyHandle* column_family, | |
132 | const Slice& start_key, const Slice& end_key); | |
133 | ||
134 | // Return a column family handle that mirrors what is pointed by | |
135 | // `column_family_id`, which will be used to validate data to be correct. | |
136 | // By default, the column family itself will be returned. | |
137 | virtual ColumnFamilyHandle* GetControlCfh(ThreadState* /* thread*/, | |
138 | int column_family_id) { | |
139 | return column_families_[column_family_id]; | |
140 | } | |
141 | ||
142 | #ifndef ROCKSDB_LITE | |
143 | // Generated a list of keys that close to boundaries of SST keys. | |
144 | // If there isn't any SST file in the DB, return empty list. | |
145 | std::vector<std::string> GetWhiteBoxKeys(ThreadState* thread, DB* db, | |
146 | ColumnFamilyHandle* cfh, | |
147 | size_t num_keys); | |
148 | #else // !ROCKSDB_LITE | |
149 | std::vector<std::string> GetWhiteBoxKeys(ThreadState*, DB*, | |
150 | ColumnFamilyHandle*, size_t) { | |
151 | // Not supported in LITE mode. | |
152 | return {}; | |
153 | } | |
154 | #endif // !ROCKSDB_LITE | |
155 | ||
156 | // Given a key K, this creates an iterator which scans to K and then | |
157 | // does a random sequence of Next/Prev operations. | |
158 | virtual Status TestIterate(ThreadState* thread, const ReadOptions& read_opts, | |
159 | const std::vector<int>& rand_column_families, | |
160 | const std::vector<int64_t>& rand_keys); | |
161 | ||
1e59de90 TL |
162 | virtual Status TestIterateAgainstExpected( |
163 | ThreadState* /* thread */, const ReadOptions& /* read_opts */, | |
164 | const std::vector<int>& /* rand_column_families */, | |
165 | const std::vector<int64_t>& /* rand_keys */) { | |
166 | return Status::NotSupported(); | |
167 | } | |
168 | ||
f67539c2 TL |
169 | // Enum used by VerifyIterator() to identify the mode to validate. |
170 | enum LastIterateOp { | |
171 | kLastOpSeek, | |
172 | kLastOpSeekForPrev, | |
173 | kLastOpNextOrPrev, | |
174 | kLastOpSeekToFirst, | |
175 | kLastOpSeekToLast | |
176 | }; | |
177 | ||
178 | // Compare the two iterator, iter and cmp_iter are in the same position, | |
179 | // unless iter might be made invalidate or undefined because of | |
180 | // upper or lower bounds, or prefix extractor. | |
181 | // Will flag failure if the verification fails. | |
182 | // diverged = true if the two iterator is already diverged. | |
183 | // True if verification passed, false if not. | |
184 | // op_logs is the information to print when validation fails. | |
185 | void VerifyIterator(ThreadState* thread, ColumnFamilyHandle* cmp_cfh, | |
186 | const ReadOptions& ro, Iterator* iter, Iterator* cmp_iter, | |
187 | LastIterateOp op, const Slice& seek_key, | |
188 | const std::string& op_logs, bool* diverged); | |
189 | ||
190 | virtual Status TestBackupRestore(ThreadState* thread, | |
191 | const std::vector<int>& rand_column_families, | |
192 | const std::vector<int64_t>& rand_keys); | |
193 | ||
194 | virtual Status TestCheckpoint(ThreadState* thread, | |
195 | const std::vector<int>& rand_column_families, | |
196 | const std::vector<int64_t>& rand_keys); | |
197 | ||
198 | void TestCompactFiles(ThreadState* thread, ColumnFamilyHandle* column_family); | |
199 | ||
200 | Status TestFlush(const std::vector<int>& rand_column_families); | |
201 | ||
202 | Status TestPauseBackground(ThreadState* thread); | |
203 | ||
204 | void TestAcquireSnapshot(ThreadState* thread, int rand_column_family, | |
205 | const std::string& keystr, uint64_t i); | |
206 | ||
207 | Status MaybeReleaseSnapshots(ThreadState* thread, uint64_t i); | |
208 | #ifndef ROCKSDB_LITE | |
20effc67 TL |
209 | Status VerifyGetLiveFiles() const; |
210 | Status VerifyGetSortedWalFiles() const; | |
211 | Status VerifyGetCurrentWalFile() const; | |
212 | void TestGetProperty(ThreadState* thread) const; | |
213 | ||
f67539c2 TL |
214 | virtual Status TestApproximateSize( |
215 | ThreadState* thread, uint64_t iteration, | |
216 | const std::vector<int>& rand_column_families, | |
217 | const std::vector<int64_t>& rand_keys); | |
218 | #endif // !ROCKSDB_LITE | |
219 | ||
1e59de90 TL |
220 | virtual Status TestCustomOperations( |
221 | ThreadState* /*thread*/, | |
222 | const std::vector<int>& /*rand_column_families*/) { | |
223 | return Status::NotSupported("TestCustomOperations() must be overridden"); | |
224 | } | |
225 | ||
f67539c2 TL |
226 | void VerificationAbort(SharedState* shared, std::string msg, Status s) const; |
227 | ||
228 | void VerificationAbort(SharedState* shared, std::string msg, int cf, | |
229 | int64_t key) const; | |
230 | ||
1e59de90 TL |
231 | void VerificationAbort(SharedState* shared, std::string msg, int cf, |
232 | int64_t key, Slice value_from_db, | |
233 | Slice value_from_expected) const; | |
234 | ||
235 | void VerificationAbort(SharedState* shared, int cf, int64_t key, | |
236 | const Slice& value, const WideColumns& columns, | |
237 | const WideColumns& expected_columns) const; | |
238 | ||
239 | static std::string DebugString(const Slice& value, const WideColumns& columns, | |
240 | const WideColumns& expected_columns); | |
241 | ||
f67539c2 TL |
242 | void PrintEnv() const; |
243 | ||
1e59de90 | 244 | void Open(SharedState* shared); |
f67539c2 TL |
245 | |
246 | void Reopen(ThreadState* thread); | |
247 | ||
1e59de90 TL |
248 | virtual void RegisterAdditionalListeners() {} |
249 | ||
250 | #ifndef ROCKSDB_LITE | |
251 | virtual void PrepareTxnDbOptions(SharedState* /*shared*/, | |
252 | TransactionDBOptions& /*txn_db_opts*/) {} | |
253 | #endif | |
254 | ||
255 | // Returns whether the timestamp of read_opts is updated. | |
256 | bool MaybeUseOlderTimestampForPointLookup(ThreadState* thread, | |
257 | std::string& ts_str, | |
258 | Slice& ts_slice, | |
259 | ReadOptions& read_opts); | |
260 | ||
261 | void MaybeUseOlderTimestampForRangeScan(ThreadState* thread, | |
262 | std::string& ts_str, Slice& ts_slice, | |
263 | ReadOptions& read_opts); | |
264 | ||
f67539c2 TL |
265 | std::shared_ptr<Cache> cache_; |
266 | std::shared_ptr<Cache> compressed_cache_; | |
267 | std::shared_ptr<const FilterPolicy> filter_policy_; | |
268 | DB* db_; | |
269 | #ifndef ROCKSDB_LITE | |
270 | TransactionDB* txn_db_; | |
271 | #endif | |
1e59de90 TL |
272 | |
273 | // Currently only used in MultiOpsTxnsStressTest | |
274 | std::atomic<DB*> db_aptr_; | |
275 | ||
f67539c2 | 276 | Options options_; |
1e59de90 | 277 | SystemClock* clock_; |
f67539c2 TL |
278 | std::vector<ColumnFamilyHandle*> column_families_; |
279 | std::vector<std::string> column_family_names_; | |
280 | std::atomic<int> new_column_family_name_; | |
281 | int num_times_reopened_; | |
282 | std::unordered_map<std::string, std::vector<std::string>> options_table_; | |
283 | std::vector<std::string> options_index_; | |
284 | std::atomic<bool> db_preload_finished_; | |
285 | ||
f67539c2 TL |
286 | // Fields used for continuous verification from another thread |
287 | DB* cmp_db_; | |
288 | std::vector<ColumnFamilyHandle*> cmp_cfhs_; | |
1e59de90 | 289 | bool is_db_stopped_; |
f67539c2 TL |
290 | }; |
291 | ||
1e59de90 TL |
292 | // Load options from OPTIONS file and populate `options`. |
293 | extern bool InitializeOptionsFromFile(Options& options); | |
294 | ||
295 | // Initialize `options` using command line arguments. | |
296 | // When this function is called, `cache`, `block_cache_compressed`, | |
297 | // `filter_policy` have all been initialized. Therefore, we just pass them as | |
298 | // input arguments. | |
299 | extern void InitializeOptionsFromFlags( | |
300 | const std::shared_ptr<Cache>& cache, | |
301 | const std::shared_ptr<Cache>& block_cache_compressed, | |
302 | const std::shared_ptr<const FilterPolicy>& filter_policy, Options& options); | |
303 | ||
304 | // Initialize `options` on which `InitializeOptionsFromFile()` and | |
305 | // `InitializeOptionsFromFlags()` have both been called already. | |
306 | // There are two cases. | |
307 | // Case 1: OPTIONS file is not specified. Command line arguments have been used | |
308 | // to initialize `options`. InitializeOptionsGeneral() will use | |
309 | // `cache`, `block_cache_compressed` and `filter_policy` to initialize | |
310 | // corresponding fields of `options`. InitializeOptionsGeneral() will | |
311 | // also set up other fields of `options` so that stress test can run. | |
312 | // Examples include `create_if_missing` and | |
313 | // `create_missing_column_families`, etc. | |
314 | // Case 2: OPTIONS file is specified. It is possible that, after loading from | |
315 | // the given OPTIONS files, some shared object fields are still not | |
316 | // initialized because they are not set in the OPTIONS file. In this | |
317 | // case, if command line arguments indicate that the user wants to set | |
318 | // up such shared objects, e.g. block cache, compressed block cache, | |
319 | // row cache, filter policy, then InitializeOptionsGeneral() will honor | |
320 | // the user's choice, thus passing `cache`, `block_cache_compressed`, | |
321 | // `filter_policy` as input arguments. | |
322 | // | |
323 | // InitializeOptionsGeneral() must not overwrite fields of `options` loaded | |
324 | // from OPTIONS file. | |
325 | extern void InitializeOptionsGeneral( | |
326 | const std::shared_ptr<Cache>& cache, | |
327 | const std::shared_ptr<Cache>& block_cache_compressed, | |
328 | const std::shared_ptr<const FilterPolicy>& filter_policy, Options& options); | |
329 | ||
330 | // If no OPTIONS file is specified, set up `options` so that we can test | |
331 | // user-defined timestamp which requires `-user_timestamp_size=8`. | |
332 | // This function also checks for known (currently) incompatible features with | |
333 | // user-defined timestamp. | |
334 | extern void CheckAndSetOptionsForUserTimestamp(Options& options); | |
335 | ||
f67539c2 TL |
336 | } // namespace ROCKSDB_NAMESPACE |
337 | #endif // GFLAGS |