db_stress_tool.cc 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252
  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. namespace ROCKSDB_NAMESPACE {
  25. namespace {
  26. static std::shared_ptr<ROCKSDB_NAMESPACE::Env> env_guard;
  27. static std::shared_ptr<ROCKSDB_NAMESPACE::DbStressEnvWrapper> env_wrapper_guard;
  28. } // namespace
  29. KeyGenContext key_gen_ctx;
  30. int db_stress_tool(int argc, char** argv) {
  31. SetUsageMessage(std::string("\nUSAGE:\n") + std::string(argv[0]) +
  32. " [OPTIONS]...");
  33. ParseCommandLineFlags(&argc, &argv, true);
  34. SanitizeDoubleParam(&FLAGS_bloom_bits);
  35. SanitizeDoubleParam(&FLAGS_memtable_prefix_bloom_size_ratio);
  36. SanitizeDoubleParam(&FLAGS_max_bytes_for_level_multiplier);
  37. if (FLAGS_statistics) {
  38. dbstats = ROCKSDB_NAMESPACE::CreateDBStatistics();
  39. if (FLAGS_test_secondary) {
  40. dbstats_secondaries = ROCKSDB_NAMESPACE::CreateDBStatistics();
  41. }
  42. }
  43. compression_type_e = StringToCompressionType(FLAGS_compression_type.c_str());
  44. bottommost_compression_type_e =
  45. StringToCompressionType(FLAGS_bottommost_compression_type.c_str());
  46. checksum_type_e = StringToChecksumType(FLAGS_checksum_type.c_str());
  47. Env* raw_env;
  48. if (!FLAGS_hdfs.empty()) {
  49. if (!FLAGS_env_uri.empty()) {
  50. fprintf(stderr, "Cannot specify both --hdfs and --env_uri.\n");
  51. exit(1);
  52. }
  53. raw_env = new ROCKSDB_NAMESPACE::HdfsEnv(FLAGS_hdfs);
  54. } else if (!FLAGS_env_uri.empty()) {
  55. Status s = Env::LoadEnv(FLAGS_env_uri, &raw_env, &env_guard);
  56. if (raw_env == nullptr) {
  57. fprintf(stderr, "No Env registered for URI: %s\n", FLAGS_env_uri.c_str());
  58. exit(1);
  59. }
  60. } else {
  61. raw_env = Env::Default();
  62. }
  63. env_wrapper_guard = std::make_shared<DbStressEnvWrapper>(raw_env);
  64. db_stress_env = env_wrapper_guard.get();
  65. FLAGS_rep_factory = StringToRepFactory(FLAGS_memtablerep.c_str());
  66. // The number of background threads should be at least as much the
  67. // max number of concurrent compactions.
  68. db_stress_env->SetBackgroundThreads(FLAGS_max_background_compactions,
  69. ROCKSDB_NAMESPACE::Env::Priority::LOW);
  70. db_stress_env->SetBackgroundThreads(FLAGS_num_bottom_pri_threads,
  71. ROCKSDB_NAMESPACE::Env::Priority::BOTTOM);
  72. if (FLAGS_prefixpercent > 0 && FLAGS_prefix_size < 0) {
  73. fprintf(stderr,
  74. "Error: prefixpercent is non-zero while prefix_size is "
  75. "not positive!\n");
  76. exit(1);
  77. }
  78. if (FLAGS_test_batches_snapshots && FLAGS_prefix_size <= 0) {
  79. fprintf(stderr,
  80. "Error: please specify prefix_size for "
  81. "test_batches_snapshots test!\n");
  82. exit(1);
  83. }
  84. if (FLAGS_memtable_prefix_bloom_size_ratio > 0.0 && FLAGS_prefix_size < 0) {
  85. fprintf(stderr,
  86. "Error: please specify positive prefix_size in order to use "
  87. "memtable_prefix_bloom_size_ratio\n");
  88. exit(1);
  89. }
  90. if ((FLAGS_readpercent + FLAGS_prefixpercent + FLAGS_writepercent +
  91. FLAGS_delpercent + FLAGS_delrangepercent + FLAGS_iterpercent) != 100) {
  92. fprintf(stderr,
  93. "Error: Read+Prefix+Write+Delete+DeleteRange+Iterate percents != "
  94. "100!\n");
  95. exit(1);
  96. }
  97. if (FLAGS_disable_wal == 1 && FLAGS_reopen > 0) {
  98. fprintf(stderr, "Error: Db cannot reopen safely with disable_wal set!\n");
  99. exit(1);
  100. }
  101. if ((unsigned)FLAGS_reopen >= FLAGS_ops_per_thread) {
  102. fprintf(stderr,
  103. "Error: #DB-reopens should be < ops_per_thread\n"
  104. "Provided reopens = %d and ops_per_thread = %lu\n",
  105. FLAGS_reopen, (unsigned long)FLAGS_ops_per_thread);
  106. exit(1);
  107. }
  108. if (FLAGS_test_batches_snapshots && FLAGS_delrangepercent > 0) {
  109. fprintf(stderr,
  110. "Error: nonzero delrangepercent unsupported in "
  111. "test_batches_snapshots mode\n");
  112. exit(1);
  113. }
  114. if (FLAGS_active_width > FLAGS_max_key) {
  115. fprintf(stderr, "Error: active_width can be at most max_key\n");
  116. exit(1);
  117. } else if (FLAGS_active_width == 0) {
  118. FLAGS_active_width = FLAGS_max_key;
  119. }
  120. if (FLAGS_value_size_mult * kRandomValueMaxFactor > kValueMaxLen) {
  121. fprintf(stderr, "Error: value_size_mult can be at most %d\n",
  122. kValueMaxLen / kRandomValueMaxFactor);
  123. exit(1);
  124. }
  125. if (FLAGS_use_merge && FLAGS_nooverwritepercent == 100) {
  126. fprintf(
  127. stderr,
  128. "Error: nooverwritepercent must not be 100 when using merge operands");
  129. exit(1);
  130. }
  131. if (FLAGS_ingest_external_file_one_in > 0 && FLAGS_nooverwritepercent > 0) {
  132. fprintf(stderr,
  133. "Error: nooverwritepercent must be 0 when using file ingestion\n");
  134. exit(1);
  135. }
  136. if (FLAGS_clear_column_family_one_in > 0 && FLAGS_backup_one_in > 0) {
  137. fprintf(stderr,
  138. "Error: clear_column_family_one_in must be 0 when using backup\n");
  139. exit(1);
  140. }
  141. if (FLAGS_test_cf_consistency && FLAGS_disable_wal) {
  142. FLAGS_atomic_flush = true;
  143. }
  144. if (FLAGS_read_only) {
  145. if (FLAGS_writepercent != 0 || FLAGS_delpercent != 0 ||
  146. FLAGS_delrangepercent != 0) {
  147. fprintf(stderr, "Error: updates are not supported in read only mode\n");
  148. exit(1);
  149. } else if (FLAGS_checkpoint_one_in > 0 &&
  150. FLAGS_clear_column_family_one_in > 0) {
  151. fprintf(stdout,
  152. "Warn: checkpoint won't be validated since column families may "
  153. "be dropped.\n");
  154. }
  155. }
  156. // Choose a location for the test database if none given with --db=<path>
  157. if (FLAGS_db.empty()) {
  158. std::string default_db_path;
  159. db_stress_env->GetTestDirectory(&default_db_path);
  160. default_db_path += "/dbstress";
  161. FLAGS_db = default_db_path;
  162. }
  163. if ((FLAGS_test_secondary || FLAGS_continuous_verification_interval > 0) &&
  164. FLAGS_secondaries_base.empty()) {
  165. std::string default_secondaries_path;
  166. db_stress_env->GetTestDirectory(&default_secondaries_path);
  167. default_secondaries_path += "/dbstress_secondaries";
  168. ROCKSDB_NAMESPACE::Status s =
  169. db_stress_env->CreateDirIfMissing(default_secondaries_path);
  170. if (!s.ok()) {
  171. fprintf(stderr, "Failed to create directory %s: %s\n",
  172. default_secondaries_path.c_str(), s.ToString().c_str());
  173. exit(1);
  174. }
  175. FLAGS_secondaries_base = default_secondaries_path;
  176. }
  177. if (!FLAGS_test_secondary && FLAGS_secondary_catch_up_one_in > 0) {
  178. fprintf(
  179. stderr,
  180. "Must set -test_secondary=true if secondary_catch_up_one_in > 0.\n");
  181. exit(1);
  182. }
  183. rocksdb_kill_odds = FLAGS_kill_random_test;
  184. rocksdb_kill_prefix_blacklist = SplitString(FLAGS_kill_prefix_blacklist);
  185. unsigned int levels = FLAGS_max_key_len;
  186. std::vector<std::string> weights;
  187. uint64_t scale_factor = FLAGS_key_window_scale_factor;
  188. key_gen_ctx.window = scale_factor * 100;
  189. if (!FLAGS_key_len_percent_dist.empty()) {
  190. weights = SplitString(FLAGS_key_len_percent_dist);
  191. if (weights.size() != levels) {
  192. fprintf(stderr,
  193. "Number of weights in key_len_dist should be equal to"
  194. " max_key_len");
  195. exit(1);
  196. }
  197. uint64_t total_weight = 0;
  198. for (std::string& weight : weights) {
  199. uint64_t val = std::stoull(weight);
  200. key_gen_ctx.weights.emplace_back(val * scale_factor);
  201. total_weight += val;
  202. }
  203. if (total_weight != 100) {
  204. fprintf(stderr, "Sum of all weights in key_len_dist should be 100");
  205. exit(1);
  206. }
  207. } else {
  208. uint64_t keys_per_level = key_gen_ctx.window / levels;
  209. for (unsigned int level = 0; level < levels - 1; ++level) {
  210. key_gen_ctx.weights.emplace_back(keys_per_level);
  211. }
  212. key_gen_ctx.weights.emplace_back(key_gen_ctx.window -
  213. keys_per_level * (levels - 1));
  214. }
  215. std::unique_ptr<ROCKSDB_NAMESPACE::StressTest> stress;
  216. if (FLAGS_test_cf_consistency) {
  217. stress.reset(CreateCfConsistencyStressTest());
  218. } else if (FLAGS_test_batches_snapshots) {
  219. stress.reset(CreateBatchedOpsStressTest());
  220. } else {
  221. stress.reset(CreateNonBatchedOpsStressTest());
  222. }
  223. // Initialize the Zipfian pre-calculated array
  224. InitializeHotKeyGenerator(FLAGS_hot_key_alpha);
  225. if (RunStressTest(stress.get())) {
  226. return 0;
  227. } else {
  228. return 1;
  229. }
  230. }
  231. } // namespace ROCKSDB_NAMESPACE
  232. #endif // GFLAGS