db_stress_tool.cc 14 KB

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