]> git.proxmox.com Git - ceph.git/blob - ceph/src/rocksdb/db_stress_tool/db_stress_tool.cc
update ceph source to reef 18.1.2
[ceph.git] / ceph / src / rocksdb / db_stress_tool / db_stress_tool.cc
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 // The test uses an array to compare against values written to the database.
11 // Keys written to the array are in 1:1 correspondence to the actual values in
12 // the database according to the formula in the function GenerateValue.
13
14 // Space is reserved in the array from 0 to FLAGS_max_key and values are
15 // randomly written/deleted/read from those positions. During verification we
16 // compare all the positions in the array. To shorten/elongate the running
17 // time, you could change the settings: FLAGS_max_key, FLAGS_ops_per_thread,
18 // (sometimes also FLAGS_threads).
19 //
20 // NOTE that if FLAGS_test_batches_snapshots is set, the test will have
21 // different behavior. See comment of the flag for details.
22
23 #ifdef GFLAGS
24 #include "db_stress_tool/db_stress_common.h"
25 #include "db_stress_tool/db_stress_driver.h"
26 #include "rocksdb/convenience.h"
27 #include "utilities/fault_injection_fs.h"
28
29 namespace ROCKSDB_NAMESPACE {
30 namespace {
31 static std::shared_ptr<ROCKSDB_NAMESPACE::Env> env_guard;
32 static std::shared_ptr<ROCKSDB_NAMESPACE::DbStressEnvWrapper> env_wrapper_guard;
33 static std::shared_ptr<ROCKSDB_NAMESPACE::DbStressEnvWrapper>
34 dbsl_env_wrapper_guard;
35 static std::shared_ptr<CompositeEnvWrapper> fault_env_guard;
36 } // namespace
37
38 KeyGenContext key_gen_ctx;
39
40 int db_stress_tool(int argc, char** argv) {
41 SetUsageMessage(std::string("\nUSAGE:\n") + std::string(argv[0]) +
42 " [OPTIONS]...");
43 ParseCommandLineFlags(&argc, &argv, true);
44
45 SanitizeDoubleParam(&FLAGS_bloom_bits);
46 SanitizeDoubleParam(&FLAGS_memtable_prefix_bloom_size_ratio);
47 SanitizeDoubleParam(&FLAGS_max_bytes_for_level_multiplier);
48
49 #ifndef NDEBUG
50 if (FLAGS_mock_direct_io) {
51 SetupSyncPointsToMockDirectIO();
52 }
53 #endif
54 if (FLAGS_statistics) {
55 dbstats = ROCKSDB_NAMESPACE::CreateDBStatistics();
56 if (FLAGS_test_secondary) {
57 dbstats_secondaries = ROCKSDB_NAMESPACE::CreateDBStatistics();
58 }
59 }
60 compression_type_e = StringToCompressionType(FLAGS_compression_type.c_str());
61 bottommost_compression_type_e =
62 StringToCompressionType(FLAGS_bottommost_compression_type.c_str());
63 checksum_type_e = StringToChecksumType(FLAGS_checksum_type.c_str());
64
65 Env* raw_env;
66
67 int env_opts = !FLAGS_env_uri.empty() + !FLAGS_fs_uri.empty();
68 if (env_opts > 1) {
69 fprintf(stderr, "Error: --env_uri and --fs_uri are mutually exclusive\n");
70 exit(1);
71 }
72
73 Status s = Env::CreateFromUri(ConfigOptions(), FLAGS_env_uri, FLAGS_fs_uri,
74 &raw_env, &env_guard);
75 if (!s.ok()) {
76 fprintf(stderr, "Error Creating Env URI: %s: %s\n", FLAGS_env_uri.c_str(),
77 s.ToString().c_str());
78 exit(1);
79 }
80 dbsl_env_wrapper_guard = std::make_shared<DbStressEnvWrapper>(raw_env);
81 db_stress_listener_env = dbsl_env_wrapper_guard.get();
82
83 if (FLAGS_read_fault_one_in || FLAGS_sync_fault_injection ||
84 FLAGS_write_fault_one_in || FLAGS_open_metadata_write_fault_one_in ||
85 FLAGS_open_write_fault_one_in || FLAGS_open_read_fault_one_in) {
86 FaultInjectionTestFS* fs =
87 new FaultInjectionTestFS(raw_env->GetFileSystem());
88 fault_fs_guard.reset(fs);
89 if (FLAGS_write_fault_one_in) {
90 fault_fs_guard->SetFilesystemDirectWritable(false);
91 } else {
92 fault_fs_guard->SetFilesystemDirectWritable(true);
93 }
94 fault_env_guard =
95 std::make_shared<CompositeEnvWrapper>(raw_env, fault_fs_guard);
96 raw_env = fault_env_guard.get();
97 }
98
99 env_wrapper_guard = std::make_shared<DbStressEnvWrapper>(raw_env);
100 db_stress_env = env_wrapper_guard.get();
101
102 if (FLAGS_write_fault_one_in) {
103 // In the write injection case, we need to use the FS interface and returns
104 // the IOStatus with different error and flags. Therefore,
105 // DbStressEnvWrapper cannot be used which will swallow the FS
106 // implementations. We should directly use the raw_env which is the
107 // CompositeEnvWrapper of env and fault_fs.
108 db_stress_env = raw_env;
109 }
110
111 FLAGS_rep_factory = StringToRepFactory(FLAGS_memtablerep.c_str());
112
113 // The number of background threads should be at least as much the
114 // max number of concurrent compactions.
115 db_stress_env->SetBackgroundThreads(FLAGS_max_background_compactions,
116 ROCKSDB_NAMESPACE::Env::Priority::LOW);
117 db_stress_env->SetBackgroundThreads(FLAGS_num_bottom_pri_threads,
118 ROCKSDB_NAMESPACE::Env::Priority::BOTTOM);
119 if (FLAGS_prefixpercent > 0 && FLAGS_prefix_size < 0) {
120 fprintf(stderr,
121 "Error: prefixpercent is non-zero while prefix_size is "
122 "not positive!\n");
123 exit(1);
124 }
125 if (FLAGS_test_batches_snapshots && FLAGS_prefix_size <= 0) {
126 fprintf(stderr,
127 "Error: please specify prefix_size for "
128 "test_batches_snapshots test!\n");
129 exit(1);
130 }
131 if (FLAGS_memtable_prefix_bloom_size_ratio > 0.0 && FLAGS_prefix_size < 0 &&
132 !FLAGS_memtable_whole_key_filtering) {
133 fprintf(stderr,
134 "Error: please specify positive prefix_size or enable whole key "
135 "filtering in order to use memtable_prefix_bloom_size_ratio\n");
136 exit(1);
137 }
138 if ((FLAGS_readpercent + FLAGS_prefixpercent + FLAGS_writepercent +
139 FLAGS_delpercent + FLAGS_delrangepercent + FLAGS_iterpercent +
140 FLAGS_customopspercent) != 100) {
141 fprintf(
142 stderr,
143 "Error: "
144 "Read(-readpercent=%d)+Prefix(-prefixpercent=%d)+Write(-writepercent=%"
145 "d)+Delete(-delpercent=%d)+DeleteRange(-delrangepercent=%d)"
146 "+Iterate(-iterpercent=%d)+CustomOps(-customopspercent=%d) percents != "
147 "100!\n",
148 FLAGS_readpercent, FLAGS_prefixpercent, FLAGS_writepercent,
149 FLAGS_delpercent, FLAGS_delrangepercent, FLAGS_iterpercent,
150 FLAGS_customopspercent);
151 exit(1);
152 }
153 if (FLAGS_disable_wal == 1 && FLAGS_reopen > 0) {
154 fprintf(stderr, "Error: Db cannot reopen safely with disable_wal set!\n");
155 exit(1);
156 }
157 if ((unsigned)FLAGS_reopen >= FLAGS_ops_per_thread) {
158 fprintf(stderr,
159 "Error: #DB-reopens should be < ops_per_thread\n"
160 "Provided reopens = %d and ops_per_thread = %lu\n",
161 FLAGS_reopen, (unsigned long)FLAGS_ops_per_thread);
162 exit(1);
163 }
164 if (FLAGS_test_batches_snapshots && FLAGS_delrangepercent > 0) {
165 fprintf(stderr,
166 "Error: nonzero delrangepercent unsupported in "
167 "test_batches_snapshots mode\n");
168 exit(1);
169 }
170 if (FLAGS_active_width > FLAGS_max_key) {
171 fprintf(stderr, "Error: active_width can be at most max_key\n");
172 exit(1);
173 } else if (FLAGS_active_width == 0) {
174 FLAGS_active_width = FLAGS_max_key;
175 }
176 if (FLAGS_value_size_mult * kRandomValueMaxFactor > kValueMaxLen) {
177 fprintf(stderr, "Error: value_size_mult can be at most %d\n",
178 kValueMaxLen / kRandomValueMaxFactor);
179 exit(1);
180 }
181 if (FLAGS_use_merge && FLAGS_nooverwritepercent == 100) {
182 fprintf(
183 stderr,
184 "Error: nooverwritepercent must not be 100 when using merge operands");
185 exit(1);
186 }
187 if (FLAGS_ingest_external_file_one_in > 0 &&
188 FLAGS_nooverwritepercent == 100) {
189 fprintf(
190 stderr,
191 "Error: nooverwritepercent must not be 100 when using file ingestion");
192 exit(1);
193 }
194 if (FLAGS_clear_column_family_one_in > 0 && FLAGS_backup_one_in > 0) {
195 fprintf(stderr,
196 "Error: clear_column_family_one_in must be 0 when using backup\n");
197 exit(1);
198 }
199 if (FLAGS_test_cf_consistency && FLAGS_disable_wal) {
200 FLAGS_atomic_flush = true;
201 }
202
203 if (FLAGS_read_only) {
204 if (FLAGS_writepercent != 0 || FLAGS_delpercent != 0 ||
205 FLAGS_delrangepercent != 0) {
206 fprintf(stderr, "Error: updates are not supported in read only mode\n");
207 exit(1);
208 } else if (FLAGS_checkpoint_one_in > 0 &&
209 FLAGS_clear_column_family_one_in > 0) {
210 fprintf(stdout,
211 "Warn: checkpoint won't be validated since column families may "
212 "be dropped.\n");
213 }
214 }
215
216 // Choose a location for the test database if none given with --db=<path>
217 if (FLAGS_db.empty()) {
218 std::string default_db_path;
219 db_stress_env->GetTestDirectory(&default_db_path);
220 default_db_path += "/dbstress";
221 FLAGS_db = default_db_path;
222 }
223
224 if ((FLAGS_test_secondary || FLAGS_continuous_verification_interval > 0) &&
225 FLAGS_secondaries_base.empty()) {
226 std::string default_secondaries_path;
227 db_stress_env->GetTestDirectory(&default_secondaries_path);
228 default_secondaries_path += "/dbstress_secondaries";
229 s = db_stress_env->CreateDirIfMissing(default_secondaries_path);
230 if (!s.ok()) {
231 fprintf(stderr, "Failed to create directory %s: %s\n",
232 default_secondaries_path.c_str(), s.ToString().c_str());
233 exit(1);
234 }
235 FLAGS_secondaries_base = default_secondaries_path;
236 }
237
238 if (FLAGS_best_efforts_recovery && !FLAGS_skip_verifydb &&
239 !FLAGS_disable_wal) {
240 fprintf(stderr,
241 "With best-efforts recovery, either skip_verifydb or disable_wal "
242 "should be set to true.\n");
243 exit(1);
244 }
245 if (FLAGS_skip_verifydb) {
246 if (FLAGS_verify_db_one_in > 0) {
247 fprintf(stderr,
248 "Must set -verify_db_one_in=0 if skip_verifydb is true.\n");
249 exit(1);
250 }
251 if (FLAGS_continuous_verification_interval > 0) {
252 fprintf(stderr,
253 "Must set -continuous_verification_interval=0 if skip_verifydb "
254 "is true.\n");
255 exit(1);
256 }
257 }
258 if (FLAGS_enable_compaction_filter &&
259 (FLAGS_acquire_snapshot_one_in > 0 || FLAGS_compact_range_one_in > 0 ||
260 FLAGS_iterpercent > 0 || FLAGS_test_batches_snapshots ||
261 FLAGS_test_cf_consistency)) {
262 fprintf(
263 stderr,
264 "Error: acquire_snapshot_one_in, compact_range_one_in, iterpercent, "
265 "test_batches_snapshots must all be 0 when using compaction filter\n");
266 exit(1);
267 }
268 if (FLAGS_test_multi_ops_txns) {
269 CheckAndSetOptionsForMultiOpsTxnStressTest();
270 }
271
272 if (FLAGS_create_timestamped_snapshot_one_in > 0) {
273 if (!FLAGS_use_txn) {
274 fprintf(stderr, "timestamped snapshot supported only in TransactionDB\n");
275 exit(1);
276 } else if (FLAGS_txn_write_policy != 0) {
277 fprintf(stderr,
278 "timestamped snapshot supported only in write-committed\n");
279 exit(1);
280 }
281 }
282
283 if (FLAGS_preserve_unverified_changes && FLAGS_reopen != 0) {
284 fprintf(stderr,
285 "Reopen DB is incompatible with preserving unverified changes\n");
286 exit(1);
287 }
288
289 if (FLAGS_use_txn && FLAGS_sync_fault_injection &&
290 FLAGS_txn_write_policy != 0) {
291 fprintf(stderr,
292 "For TransactionDB, correctness testing with unsync data loss is "
293 "currently compatible with only write committed policy\n");
294 exit(1);
295 }
296
297 if (FLAGS_use_put_entity_one_in > 0 &&
298 (FLAGS_ingest_external_file_one_in > 0 || FLAGS_use_merge ||
299 FLAGS_use_full_merge_v1 || FLAGS_use_txn || FLAGS_test_multi_ops_txns ||
300 FLAGS_user_timestamp_size > 0)) {
301 fprintf(stderr,
302 "PutEntity is currently incompatible with SstFileWriter, Merge,"
303 " transactions, and user-defined timestamps\n");
304 exit(1);
305 }
306
307 #ifndef NDEBUG
308 KillPoint* kp = KillPoint::GetInstance();
309 kp->rocksdb_kill_odds = FLAGS_kill_random_test;
310 kp->rocksdb_kill_exclude_prefixes = SplitString(FLAGS_kill_exclude_prefixes);
311 #endif
312
313 unsigned int levels = FLAGS_max_key_len;
314 std::vector<std::string> weights;
315 uint64_t scale_factor = FLAGS_key_window_scale_factor;
316 key_gen_ctx.window = scale_factor * 100;
317 if (!FLAGS_key_len_percent_dist.empty()) {
318 weights = SplitString(FLAGS_key_len_percent_dist);
319 if (weights.size() != levels) {
320 fprintf(stderr,
321 "Number of weights in key_len_dist should be equal to"
322 " max_key_len");
323 exit(1);
324 }
325
326 uint64_t total_weight = 0;
327 for (std::string& weight : weights) {
328 uint64_t val = std::stoull(weight);
329 key_gen_ctx.weights.emplace_back(val * scale_factor);
330 total_weight += val;
331 }
332 if (total_weight != 100) {
333 fprintf(stderr, "Sum of all weights in key_len_dist should be 100");
334 exit(1);
335 }
336 } else {
337 uint64_t keys_per_level = key_gen_ctx.window / levels;
338 for (unsigned int level = 0; level + 1 < levels; ++level) {
339 key_gen_ctx.weights.emplace_back(keys_per_level);
340 }
341 key_gen_ctx.weights.emplace_back(key_gen_ctx.window -
342 keys_per_level * (levels - 1));
343 }
344
345 std::unique_ptr<ROCKSDB_NAMESPACE::StressTest> stress;
346 if (FLAGS_test_cf_consistency) {
347 stress.reset(CreateCfConsistencyStressTest());
348 } else if (FLAGS_test_batches_snapshots) {
349 stress.reset(CreateBatchedOpsStressTest());
350 } else if (FLAGS_test_multi_ops_txns) {
351 stress.reset(CreateMultiOpsTxnsStressTest());
352 } else {
353 stress.reset(CreateNonBatchedOpsStressTest());
354 }
355 // Initialize the Zipfian pre-calculated array
356 InitializeHotKeyGenerator(FLAGS_hot_key_alpha);
357 if (RunStressTest(stress.get())) {
358 return 0;
359 } else {
360 return 1;
361 }
362 }
363
364 } // namespace ROCKSDB_NAMESPACE
365 #endif // GFLAGS