cf_consistency_stress.cc 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583
  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. #ifdef GFLAGS
  10. #include "db_stress_tool/db_stress_common.h"
  11. namespace ROCKSDB_NAMESPACE {
  12. class CfConsistencyStressTest : public StressTest {
  13. public:
  14. CfConsistencyStressTest() : batch_id_(0) {}
  15. ~CfConsistencyStressTest() override {}
  16. Status TestPut(ThreadState* thread, WriteOptions& write_opts,
  17. const ReadOptions& /* read_opts */,
  18. const std::vector<int>& rand_column_families,
  19. const std::vector<int64_t>& rand_keys, char (&value)[100],
  20. std::unique_ptr<MutexLock>& /* lock */) override {
  21. std::string key_str = Key(rand_keys[0]);
  22. Slice key = key_str;
  23. uint64_t value_base = batch_id_.fetch_add(1);
  24. size_t sz =
  25. GenerateValue(static_cast<uint32_t>(value_base), value, sizeof(value));
  26. Slice v(value, sz);
  27. WriteBatch batch;
  28. for (auto cf : rand_column_families) {
  29. ColumnFamilyHandle* cfh = column_families_[cf];
  30. if (FLAGS_use_merge) {
  31. batch.Merge(cfh, key, v);
  32. } else { /* !FLAGS_use_merge */
  33. batch.Put(cfh, key, v);
  34. }
  35. }
  36. Status s = db_->Write(write_opts, &batch);
  37. if (!s.ok()) {
  38. fprintf(stderr, "multi put or merge error: %s\n", s.ToString().c_str());
  39. thread->stats.AddErrors(1);
  40. } else {
  41. auto num = static_cast<long>(rand_column_families.size());
  42. thread->stats.AddBytesForWrites(num, (sz + 1) * num);
  43. }
  44. return s;
  45. }
  46. Status TestDelete(ThreadState* thread, WriteOptions& write_opts,
  47. const std::vector<int>& rand_column_families,
  48. const std::vector<int64_t>& rand_keys,
  49. std::unique_ptr<MutexLock>& /* lock */) override {
  50. std::string key_str = Key(rand_keys[0]);
  51. Slice key = key_str;
  52. WriteBatch batch;
  53. for (auto cf : rand_column_families) {
  54. ColumnFamilyHandle* cfh = column_families_[cf];
  55. batch.Delete(cfh, key);
  56. }
  57. Status s = db_->Write(write_opts, &batch);
  58. if (!s.ok()) {
  59. fprintf(stderr, "multidel error: %s\n", s.ToString().c_str());
  60. thread->stats.AddErrors(1);
  61. } else {
  62. thread->stats.AddDeletes(static_cast<long>(rand_column_families.size()));
  63. }
  64. return s;
  65. }
  66. Status TestDeleteRange(ThreadState* thread, WriteOptions& write_opts,
  67. const std::vector<int>& rand_column_families,
  68. const std::vector<int64_t>& rand_keys,
  69. std::unique_ptr<MutexLock>& /* lock */) override {
  70. int64_t rand_key = rand_keys[0];
  71. auto shared = thread->shared;
  72. int64_t max_key = shared->GetMaxKey();
  73. if (rand_key > max_key - FLAGS_range_deletion_width) {
  74. rand_key =
  75. thread->rand.Next() % (max_key - FLAGS_range_deletion_width + 1);
  76. }
  77. std::string key_str = Key(rand_key);
  78. Slice key = key_str;
  79. std::string end_key_str = Key(rand_key + FLAGS_range_deletion_width);
  80. Slice end_key = end_key_str;
  81. WriteBatch batch;
  82. for (auto cf : rand_column_families) {
  83. ColumnFamilyHandle* cfh = column_families_[rand_column_families[cf]];
  84. batch.DeleteRange(cfh, key, end_key);
  85. }
  86. Status s = db_->Write(write_opts, &batch);
  87. if (!s.ok()) {
  88. fprintf(stderr, "multi del range error: %s\n", s.ToString().c_str());
  89. thread->stats.AddErrors(1);
  90. } else {
  91. thread->stats.AddRangeDeletions(
  92. static_cast<long>(rand_column_families.size()));
  93. }
  94. return s;
  95. }
  96. void TestIngestExternalFile(
  97. ThreadState* /* thread */,
  98. const std::vector<int>& /* rand_column_families */,
  99. const std::vector<int64_t>& /* rand_keys */,
  100. std::unique_ptr<MutexLock>& /* lock */) override {
  101. assert(false);
  102. fprintf(stderr,
  103. "CfConsistencyStressTest does not support TestIngestExternalFile "
  104. "because it's not possible to verify the result\n");
  105. std::terminate();
  106. }
  107. Status TestGet(ThreadState* thread, const ReadOptions& readoptions,
  108. const std::vector<int>& rand_column_families,
  109. const std::vector<int64_t>& rand_keys) override {
  110. std::string key_str = Key(rand_keys[0]);
  111. Slice key = key_str;
  112. Status s;
  113. bool is_consistent = true;
  114. if (thread->rand.OneIn(2)) {
  115. // 1/2 chance, does a random read from random CF
  116. auto cfh =
  117. column_families_[rand_column_families[thread->rand.Next() %
  118. rand_column_families.size()]];
  119. std::string from_db;
  120. s = db_->Get(readoptions, cfh, key, &from_db);
  121. } else {
  122. // 1/2 chance, comparing one key is the same across all CFs
  123. const Snapshot* snapshot = db_->GetSnapshot();
  124. ReadOptions readoptionscopy = readoptions;
  125. readoptionscopy.snapshot = snapshot;
  126. std::string value0;
  127. s = db_->Get(readoptionscopy, column_families_[rand_column_families[0]],
  128. key, &value0);
  129. if (s.ok() || s.IsNotFound()) {
  130. bool found = s.ok();
  131. for (size_t i = 1; i < rand_column_families.size(); i++) {
  132. std::string value1;
  133. s = db_->Get(readoptionscopy,
  134. column_families_[rand_column_families[i]], key, &value1);
  135. if (!s.ok() && !s.IsNotFound()) {
  136. break;
  137. }
  138. if (!found && s.ok()) {
  139. fprintf(stderr, "Get() return different results with key %s\n",
  140. Slice(key_str).ToString(true).c_str());
  141. fprintf(stderr, "CF %s is not found\n",
  142. column_family_names_[0].c_str());
  143. fprintf(stderr, "CF %s returns value %s\n",
  144. column_family_names_[i].c_str(),
  145. Slice(value1).ToString(true).c_str());
  146. is_consistent = false;
  147. } else if (found && s.IsNotFound()) {
  148. fprintf(stderr, "Get() return different results with key %s\n",
  149. Slice(key_str).ToString(true).c_str());
  150. fprintf(stderr, "CF %s returns value %s\n",
  151. column_family_names_[0].c_str(),
  152. Slice(value0).ToString(true).c_str());
  153. fprintf(stderr, "CF %s is not found\n",
  154. column_family_names_[i].c_str());
  155. is_consistent = false;
  156. } else if (s.ok() && value0 != value1) {
  157. fprintf(stderr, "Get() return different results with key %s\n",
  158. Slice(key_str).ToString(true).c_str());
  159. fprintf(stderr, "CF %s returns value %s\n",
  160. column_family_names_[0].c_str(),
  161. Slice(value0).ToString(true).c_str());
  162. fprintf(stderr, "CF %s returns value %s\n",
  163. column_family_names_[i].c_str(),
  164. Slice(value1).ToString(true).c_str());
  165. is_consistent = false;
  166. }
  167. if (!is_consistent) {
  168. break;
  169. }
  170. }
  171. }
  172. db_->ReleaseSnapshot(snapshot);
  173. }
  174. if (!is_consistent) {
  175. fprintf(stderr, "TestGet error: is_consistent is false\n");
  176. thread->stats.AddErrors(1);
  177. // Fail fast to preserve the DB state.
  178. thread->shared->SetVerificationFailure();
  179. } else if (s.ok()) {
  180. thread->stats.AddGets(1, 1);
  181. } else if (s.IsNotFound()) {
  182. thread->stats.AddGets(1, 0);
  183. } else {
  184. fprintf(stderr, "TestGet error: %s\n", s.ToString().c_str());
  185. thread->stats.AddErrors(1);
  186. }
  187. return s;
  188. }
  189. std::vector<Status> TestMultiGet(
  190. ThreadState* thread, const ReadOptions& read_opts,
  191. const std::vector<int>& rand_column_families,
  192. const std::vector<int64_t>& rand_keys) override {
  193. size_t num_keys = rand_keys.size();
  194. std::vector<std::string> key_str;
  195. std::vector<Slice> keys;
  196. keys.reserve(num_keys);
  197. key_str.reserve(num_keys);
  198. std::vector<PinnableSlice> values(num_keys);
  199. std::vector<Status> statuses(num_keys);
  200. ColumnFamilyHandle* cfh = column_families_[rand_column_families[0]];
  201. for (size_t i = 0; i < num_keys; ++i) {
  202. key_str.emplace_back(Key(rand_keys[i]));
  203. keys.emplace_back(key_str.back());
  204. }
  205. db_->MultiGet(read_opts, cfh, num_keys, keys.data(), values.data(),
  206. statuses.data());
  207. for (auto s : statuses) {
  208. if (s.ok()) {
  209. // found case
  210. thread->stats.AddGets(1, 1);
  211. } else if (s.IsNotFound()) {
  212. // not found case
  213. thread->stats.AddGets(1, 0);
  214. } else {
  215. // errors case
  216. fprintf(stderr, "MultiGet error: %s\n", s.ToString().c_str());
  217. thread->stats.AddErrors(1);
  218. }
  219. }
  220. return statuses;
  221. }
  222. Status TestPrefixScan(ThreadState* thread, const ReadOptions& readoptions,
  223. const std::vector<int>& rand_column_families,
  224. const std::vector<int64_t>& rand_keys) override {
  225. size_t prefix_to_use =
  226. (FLAGS_prefix_size < 0) ? 7 : static_cast<size_t>(FLAGS_prefix_size);
  227. std::string key_str = Key(rand_keys[0]);
  228. Slice key = key_str;
  229. Slice prefix = Slice(key.data(), prefix_to_use);
  230. std::string upper_bound;
  231. Slice ub_slice;
  232. ReadOptions ro_copy = readoptions;
  233. // Get the next prefix first and then see if we want to set upper bound.
  234. // We'll use the next prefix in an assertion later on
  235. if (GetNextPrefix(prefix, &upper_bound) && thread->rand.OneIn(2)) {
  236. ub_slice = Slice(upper_bound);
  237. ro_copy.iterate_upper_bound = &ub_slice;
  238. }
  239. auto cfh =
  240. column_families_[rand_column_families[thread->rand.Next() %
  241. rand_column_families.size()]];
  242. Iterator* iter = db_->NewIterator(ro_copy, cfh);
  243. unsigned long count = 0;
  244. for (iter->Seek(prefix); iter->Valid() && iter->key().starts_with(prefix);
  245. iter->Next()) {
  246. ++count;
  247. }
  248. assert(prefix_to_use == 0 ||
  249. count <= GetPrefixKeyCount(prefix.ToString(), upper_bound));
  250. Status s = iter->status();
  251. if (s.ok()) {
  252. thread->stats.AddPrefixes(1, count);
  253. } else {
  254. fprintf(stderr, "TestPrefixScan error: %s\n", s.ToString().c_str());
  255. thread->stats.AddErrors(1);
  256. }
  257. delete iter;
  258. return s;
  259. }
  260. ColumnFamilyHandle* GetControlCfh(ThreadState* thread,
  261. int /*column_family_id*/
  262. ) override {
  263. // All column families should contain the same data. Randomly pick one.
  264. return column_families_[thread->rand.Next() % column_families_.size()];
  265. }
  266. #ifdef ROCKSDB_LITE
  267. Status TestCheckpoint(ThreadState* /* thread */,
  268. const std::vector<int>& /* rand_column_families */,
  269. const std::vector<int64_t>& /* rand_keys */) override {
  270. assert(false);
  271. fprintf(stderr,
  272. "RocksDB lite does not support "
  273. "TestCheckpoint\n");
  274. std::terminate();
  275. }
  276. #else
  277. Status TestCheckpoint(ThreadState* thread,
  278. const std::vector<int>& /* rand_column_families */,
  279. const std::vector<int64_t>& /* rand_keys */) override {
  280. std::string checkpoint_dir =
  281. FLAGS_db + "/.checkpoint" + ToString(thread->tid);
  282. // We need to clear DB including manifest files, so make a copy
  283. Options opt_copy = options_;
  284. opt_copy.env = db_stress_env->target();
  285. DestroyDB(checkpoint_dir, opt_copy);
  286. Checkpoint* checkpoint = nullptr;
  287. Status s = Checkpoint::Create(db_, &checkpoint);
  288. if (s.ok()) {
  289. s = checkpoint->CreateCheckpoint(checkpoint_dir);
  290. }
  291. std::vector<ColumnFamilyHandle*> cf_handles;
  292. DB* checkpoint_db = nullptr;
  293. if (s.ok()) {
  294. delete checkpoint;
  295. checkpoint = nullptr;
  296. Options options(options_);
  297. options.listeners.clear();
  298. std::vector<ColumnFamilyDescriptor> cf_descs;
  299. // TODO(ajkr): `column_family_names_` is not safe to access here when
  300. // `clear_column_family_one_in != 0`. But we can't easily switch to
  301. // `ListColumnFamilies` to get names because it won't necessarily give
  302. // the same order as `column_family_names_`.
  303. if (FLAGS_clear_column_family_one_in == 0) {
  304. for (const auto& name : column_family_names_) {
  305. cf_descs.emplace_back(name, ColumnFamilyOptions(options));
  306. }
  307. s = DB::OpenForReadOnly(DBOptions(options), checkpoint_dir, cf_descs,
  308. &cf_handles, &checkpoint_db);
  309. }
  310. }
  311. if (checkpoint_db != nullptr) {
  312. for (auto cfh : cf_handles) {
  313. delete cfh;
  314. }
  315. cf_handles.clear();
  316. delete checkpoint_db;
  317. checkpoint_db = nullptr;
  318. }
  319. DestroyDB(checkpoint_dir, opt_copy);
  320. if (!s.ok()) {
  321. fprintf(stderr, "A checkpoint operation failed with: %s\n",
  322. s.ToString().c_str());
  323. }
  324. return s;
  325. }
  326. #endif // !ROCKSDB_LITE
  327. void VerifyDb(ThreadState* thread) const override {
  328. ReadOptions options(FLAGS_verify_checksum, true);
  329. // We must set total_order_seek to true because we are doing a SeekToFirst
  330. // on a column family whose memtables may support (by default) prefix-based
  331. // iterator. In this case, NewIterator with options.total_order_seek being
  332. // false returns a prefix-based iterator. Calling SeekToFirst using this
  333. // iterator causes the iterator to become invalid. That means we cannot
  334. // iterate the memtable using this iterator any more, although the memtable
  335. // contains the most up-to-date key-values.
  336. options.total_order_seek = true;
  337. const auto ss_deleter = [this](const Snapshot* ss) {
  338. db_->ReleaseSnapshot(ss);
  339. };
  340. std::unique_ptr<const Snapshot, decltype(ss_deleter)> snapshot_guard(
  341. db_->GetSnapshot(), ss_deleter);
  342. options.snapshot = snapshot_guard.get();
  343. assert(thread != nullptr);
  344. auto shared = thread->shared;
  345. std::vector<std::unique_ptr<Iterator>> iters(column_families_.size());
  346. for (size_t i = 0; i != column_families_.size(); ++i) {
  347. iters[i].reset(db_->NewIterator(options, column_families_[i]));
  348. }
  349. for (auto& iter : iters) {
  350. iter->SeekToFirst();
  351. }
  352. size_t num = column_families_.size();
  353. assert(num == iters.size());
  354. std::vector<Status> statuses(num, Status::OK());
  355. do {
  356. if (shared->HasVerificationFailedYet()) {
  357. break;
  358. }
  359. size_t valid_cnt = 0;
  360. size_t idx = 0;
  361. for (auto& iter : iters) {
  362. if (iter->Valid()) {
  363. ++valid_cnt;
  364. } else {
  365. statuses[idx] = iter->status();
  366. }
  367. ++idx;
  368. }
  369. if (valid_cnt == 0) {
  370. Status status;
  371. for (size_t i = 0; i != num; ++i) {
  372. const auto& s = statuses[i];
  373. if (!s.ok()) {
  374. status = s;
  375. fprintf(stderr, "Iterator on cf %s has error: %s\n",
  376. column_families_[i]->GetName().c_str(),
  377. s.ToString().c_str());
  378. shared->SetVerificationFailure();
  379. }
  380. }
  381. break;
  382. } else if (valid_cnt != iters.size()) {
  383. shared->SetVerificationFailure();
  384. for (size_t i = 0; i != num; ++i) {
  385. if (!iters[i]->Valid()) {
  386. if (statuses[i].ok()) {
  387. fprintf(stderr, "Finished scanning cf %s\n",
  388. column_families_[i]->GetName().c_str());
  389. } else {
  390. fprintf(stderr, "Iterator on cf %s has error: %s\n",
  391. column_families_[i]->GetName().c_str(),
  392. statuses[i].ToString().c_str());
  393. }
  394. } else {
  395. fprintf(stderr, "cf %s has remaining data to scan\n",
  396. column_families_[i]->GetName().c_str());
  397. }
  398. }
  399. break;
  400. }
  401. if (shared->HasVerificationFailedYet()) {
  402. break;
  403. }
  404. // If the program reaches here, then all column families' iterators are
  405. // still valid.
  406. if (shared->PrintingVerificationResults()) {
  407. continue;
  408. }
  409. Slice key;
  410. Slice value;
  411. int num_mismatched_cfs = 0;
  412. for (size_t i = 0; i != num; ++i) {
  413. if (i == 0) {
  414. key = iters[i]->key();
  415. value = iters[i]->value();
  416. } else {
  417. int cmp = key.compare(iters[i]->key());
  418. if (cmp != 0) {
  419. ++num_mismatched_cfs;
  420. if (1 == num_mismatched_cfs) {
  421. fprintf(stderr, "Verification failed\n");
  422. fprintf(stderr, "Latest Sequence Number: %" PRIu64 "\n",
  423. db_->GetLatestSequenceNumber());
  424. fprintf(stderr, "[%s] %s => %s\n",
  425. column_families_[0]->GetName().c_str(),
  426. key.ToString(true /* hex */).c_str(),
  427. value.ToString(true /* hex */).c_str());
  428. }
  429. fprintf(stderr, "[%s] %s => %s\n",
  430. column_families_[i]->GetName().c_str(),
  431. iters[i]->key().ToString(true /* hex */).c_str(),
  432. iters[i]->value().ToString(true /* hex */).c_str());
  433. #ifndef ROCKSDB_LITE
  434. Slice begin_key;
  435. Slice end_key;
  436. if (cmp < 0) {
  437. begin_key = key;
  438. end_key = iters[i]->key();
  439. } else {
  440. begin_key = iters[i]->key();
  441. end_key = key;
  442. }
  443. std::vector<KeyVersion> versions;
  444. const size_t kMaxNumIKeys = 8;
  445. const auto print_key_versions = [&](ColumnFamilyHandle* cfh) {
  446. Status s = GetAllKeyVersions(db_, cfh, begin_key, end_key,
  447. kMaxNumIKeys, &versions);
  448. if (!s.ok()) {
  449. fprintf(stderr, "%s\n", s.ToString().c_str());
  450. return;
  451. }
  452. assert(nullptr != cfh);
  453. fprintf(stderr,
  454. "Internal keys in CF '%s', [%s, %s] (max %" ROCKSDB_PRIszt
  455. ")\n",
  456. cfh->GetName().c_str(),
  457. begin_key.ToString(true /* hex */).c_str(),
  458. end_key.ToString(true /* hex */).c_str(), kMaxNumIKeys);
  459. for (const KeyVersion& kv : versions) {
  460. fprintf(stderr, " key %s seq %" PRIu64 " type %d\n",
  461. Slice(kv.user_key).ToString(true).c_str(), kv.sequence,
  462. kv.type);
  463. }
  464. };
  465. if (1 == num_mismatched_cfs) {
  466. print_key_versions(column_families_[0]);
  467. }
  468. print_key_versions(column_families_[i]);
  469. #endif // ROCKSDB_LITE
  470. shared->SetVerificationFailure();
  471. }
  472. }
  473. }
  474. shared->FinishPrintingVerificationResults();
  475. for (auto& iter : iters) {
  476. iter->Next();
  477. }
  478. } while (true);
  479. }
  480. #ifndef ROCKSDB_LITE
  481. void ContinuouslyVerifyDb(ThreadState* thread) const override {
  482. assert(thread);
  483. Status status;
  484. DB* db_ptr = cmp_db_ ? cmp_db_ : db_;
  485. const auto& cfhs = cmp_db_ ? cmp_cfhs_ : column_families_;
  486. const auto ss_deleter = [&](const Snapshot* ss) {
  487. db_ptr->ReleaseSnapshot(ss);
  488. };
  489. std::unique_ptr<const Snapshot, decltype(ss_deleter)> snapshot_guard(
  490. db_ptr->GetSnapshot(), ss_deleter);
  491. if (cmp_db_) {
  492. status = cmp_db_->TryCatchUpWithPrimary();
  493. }
  494. SharedState* shared = thread->shared;
  495. assert(shared);
  496. if (!status.ok()) {
  497. shared->SetShouldStopTest();
  498. return;
  499. }
  500. assert(cmp_db_ || snapshot_guard.get());
  501. const auto checksum_column_family = [](Iterator* iter,
  502. uint32_t* checksum) -> Status {
  503. assert(nullptr != checksum);
  504. uint32_t ret = 0;
  505. for (iter->SeekToFirst(); iter->Valid(); iter->Next()) {
  506. ret = crc32c::Extend(ret, iter->key().data(), iter->key().size());
  507. ret = crc32c::Extend(ret, iter->value().data(), iter->value().size());
  508. }
  509. *checksum = ret;
  510. return iter->status();
  511. };
  512. ReadOptions ropts;
  513. ropts.total_order_seek = true;
  514. ropts.snapshot = snapshot_guard.get();
  515. uint32_t crc = 0;
  516. {
  517. // Compute crc for all key-values of default column family.
  518. std::unique_ptr<Iterator> it(db_ptr->NewIterator(ropts));
  519. status = checksum_column_family(it.get(), &crc);
  520. }
  521. uint32_t tmp_crc = 0;
  522. if (status.ok()) {
  523. for (ColumnFamilyHandle* cfh : cfhs) {
  524. if (cfh == db_ptr->DefaultColumnFamily()) {
  525. continue;
  526. }
  527. std::unique_ptr<Iterator> it(db_ptr->NewIterator(ropts, cfh));
  528. status = checksum_column_family(it.get(), &tmp_crc);
  529. if (!status.ok() || tmp_crc != crc) {
  530. break;
  531. }
  532. }
  533. }
  534. if (!status.ok() || tmp_crc != crc) {
  535. shared->SetShouldStopTest();
  536. }
  537. }
  538. #endif // !ROCKSDB_LITE
  539. std::vector<int> GenerateColumnFamilies(
  540. const int /* num_column_families */,
  541. int /* rand_column_family */) const override {
  542. std::vector<int> ret;
  543. int num = static_cast<int>(column_families_.size());
  544. int k = 0;
  545. std::generate_n(back_inserter(ret), num, [&k]() -> int { return k++; });
  546. return ret;
  547. }
  548. private:
  549. std::atomic<int64_t> batch_id_;
  550. };
  551. StressTest* CreateCfConsistencyStressTest() {
  552. return new CfConsistencyStressTest();
  553. }
  554. } // namespace ROCKSDB_NAMESPACE
  555. #endif // GFLAGS