db_iter_stress_test.cc 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654
  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. #include "db/db_iter.h"
  6. #include "db/dbformat.h"
  7. #include "rocksdb/comparator.h"
  8. #include "rocksdb/options.h"
  9. #include "rocksdb/slice.h"
  10. #include "test_util/testharness.h"
  11. #include "util/random.h"
  12. #include "util/string_util.h"
  13. #include "utilities/merge_operators.h"
  14. #ifdef GFLAGS
  15. #include "util/gflags_compat.h"
  16. using GFLAGS_NAMESPACE::ParseCommandLineFlags;
  17. DEFINE_bool(verbose, false,
  18. "Print huge, detailed trace. Intended for debugging failures.");
  19. #else
  20. void ParseCommandLineFlags(int*, char***, bool) {}
  21. bool FLAGS_verbose = false;
  22. #endif
  23. namespace ROCKSDB_NAMESPACE {
  24. class DBIteratorStressTest : public testing::Test {
  25. public:
  26. Env* env_;
  27. DBIteratorStressTest() : env_(Env::Default()) {}
  28. };
  29. namespace {
  30. struct Entry {
  31. std::string key;
  32. ValueType type; // kTypeValue, kTypeDeletion, kTypeMerge
  33. uint64_t sequence;
  34. std::string ikey; // internal key, made from `key`, `sequence` and `type`
  35. std::string value;
  36. // If false, we'll pretend that this entry doesn't exist.
  37. bool visible = true;
  38. bool operator<(const Entry& e) const {
  39. if (key != e.key) return key < e.key;
  40. return std::tie(sequence, type) > std::tie(e.sequence, e.type);
  41. }
  42. };
  43. struct Data {
  44. std::vector<Entry> entries;
  45. // Indices in `entries` with `visible` = false.
  46. std::vector<size_t> hidden;
  47. // Keys of entries whose `visible` changed since the last seek of iterators.
  48. std::set<std::string> recently_touched_keys;
  49. };
  50. struct StressTestIterator : public InternalIterator {
  51. Data* data;
  52. Random64* rnd;
  53. InternalKeyComparator cmp;
  54. // Each operation will return error with this probability...
  55. double error_probability = 0;
  56. // ... and add/remove entries with this probability.
  57. double mutation_probability = 0;
  58. // The probability of adding vs removing entries will be chosen so that the
  59. // amount of removed entries stays somewhat close to this number.
  60. double target_hidden_fraction = 0;
  61. // If true, print all mutations to stdout for debugging.
  62. bool trace = false;
  63. int iter = -1;
  64. Status status_;
  65. StressTestIterator(Data* _data, Random64* _rnd, const Comparator* _cmp)
  66. : data(_data), rnd(_rnd), cmp(_cmp) {}
  67. bool Valid() const override {
  68. if (iter >= 0 && iter < (int)data->entries.size()) {
  69. assert(status_.ok());
  70. return true;
  71. }
  72. return false;
  73. }
  74. Status status() const override { return status_; }
  75. bool MaybeFail() {
  76. if (rnd->Next() >=
  77. std::numeric_limits<uint64_t>::max() * error_probability) {
  78. return false;
  79. }
  80. if (rnd->Next() % 2) {
  81. status_ = Status::Incomplete("test");
  82. } else {
  83. status_ = Status::IOError("test");
  84. }
  85. if (trace) {
  86. std::cout << "injecting " << status_.ToString() << std::endl;
  87. }
  88. iter = -1;
  89. return true;
  90. }
  91. void MaybeMutate() {
  92. if (rnd->Next() >=
  93. std::numeric_limits<uint64_t>::max() * mutation_probability) {
  94. return;
  95. }
  96. do {
  97. // If too many entries are hidden, hide less, otherwise hide more.
  98. double hide_probability =
  99. data->hidden.size() > data->entries.size() * target_hidden_fraction
  100. ? 1. / 3
  101. : 2. / 3;
  102. if (data->hidden.empty()) {
  103. hide_probability = 1;
  104. }
  105. bool do_hide =
  106. rnd->Next() < std::numeric_limits<uint64_t>::max() * hide_probability;
  107. if (do_hide) {
  108. // Hide a random entry.
  109. size_t idx = rnd->Next() % data->entries.size();
  110. Entry& e = data->entries[idx];
  111. if (e.visible) {
  112. if (trace) {
  113. std::cout << "hiding idx " << idx << std::endl;
  114. }
  115. e.visible = false;
  116. data->hidden.push_back(idx);
  117. data->recently_touched_keys.insert(e.key);
  118. } else {
  119. // Already hidden. Let's go unhide something instead, just because
  120. // it's easy and it doesn't really matter what we do.
  121. do_hide = false;
  122. }
  123. }
  124. if (!do_hide) {
  125. // Unhide a random entry.
  126. size_t hi = rnd->Next() % data->hidden.size();
  127. size_t idx = data->hidden[hi];
  128. if (trace) {
  129. std::cout << "unhiding idx " << idx << std::endl;
  130. }
  131. Entry& e = data->entries[idx];
  132. assert(!e.visible);
  133. e.visible = true;
  134. data->hidden[hi] = data->hidden.back();
  135. data->hidden.pop_back();
  136. data->recently_touched_keys.insert(e.key);
  137. }
  138. } while (rnd->Next() % 3 != 0); // do 3 mutations on average
  139. }
  140. void SkipForward() {
  141. while (iter < (int)data->entries.size() && !data->entries[iter].visible) {
  142. ++iter;
  143. }
  144. }
  145. void SkipBackward() {
  146. while (iter >= 0 && !data->entries[iter].visible) {
  147. --iter;
  148. }
  149. }
  150. void SeekToFirst() override {
  151. if (MaybeFail()) return;
  152. MaybeMutate();
  153. status_ = Status::OK();
  154. iter = 0;
  155. SkipForward();
  156. }
  157. void SeekToLast() override {
  158. if (MaybeFail()) return;
  159. MaybeMutate();
  160. status_ = Status::OK();
  161. iter = (int)data->entries.size() - 1;
  162. SkipBackward();
  163. }
  164. void Seek(const Slice& target) override {
  165. if (MaybeFail()) return;
  166. MaybeMutate();
  167. status_ = Status::OK();
  168. // Binary search.
  169. auto it = std::partition_point(
  170. data->entries.begin(), data->entries.end(),
  171. [&](const Entry& e) { return cmp.Compare(e.ikey, target) < 0; });
  172. iter = (int)(it - data->entries.begin());
  173. SkipForward();
  174. }
  175. void SeekForPrev(const Slice& target) override {
  176. if (MaybeFail()) return;
  177. MaybeMutate();
  178. status_ = Status::OK();
  179. // Binary search.
  180. auto it = std::partition_point(
  181. data->entries.begin(), data->entries.end(),
  182. [&](const Entry& e) { return cmp.Compare(e.ikey, target) <= 0; });
  183. iter = (int)(it - data->entries.begin());
  184. --iter;
  185. SkipBackward();
  186. }
  187. void Next() override {
  188. assert(Valid());
  189. if (MaybeFail()) return;
  190. MaybeMutate();
  191. ++iter;
  192. SkipForward();
  193. }
  194. void Prev() override {
  195. assert(Valid());
  196. if (MaybeFail()) return;
  197. MaybeMutate();
  198. --iter;
  199. SkipBackward();
  200. }
  201. Slice key() const override {
  202. assert(Valid());
  203. return data->entries[iter].ikey;
  204. }
  205. Slice value() const override {
  206. assert(Valid());
  207. return data->entries[iter].value;
  208. }
  209. bool IsKeyPinned() const override { return true; }
  210. bool IsValuePinned() const override { return true; }
  211. };
  212. // A small reimplementation of DBIter, supporting only some of the features,
  213. // and doing everything in O(log n).
  214. // Skips all keys that are in recently_touched_keys.
  215. struct ReferenceIterator {
  216. Data* data;
  217. uint64_t sequence; // ignore entries with sequence number below this
  218. bool valid = false;
  219. std::string key;
  220. std::string value;
  221. ReferenceIterator(Data* _data, uint64_t _sequence)
  222. : data(_data), sequence(_sequence) {}
  223. bool Valid() const { return valid; }
  224. // Finds the first entry with key
  225. // greater/less/greater-or-equal/less-or-equal than `key`, depending on
  226. // arguments: if `skip`, inequality is strict; if `forward`, it's
  227. // greater/greater-or-equal, otherwise less/less-or-equal.
  228. // Sets `key` to the result.
  229. // If no such key exists, returns false. Doesn't check `visible`.
  230. bool FindNextKey(bool skip, bool forward) {
  231. valid = false;
  232. auto it = std::partition_point(data->entries.begin(), data->entries.end(),
  233. [&](const Entry& e) {
  234. if (forward != skip) {
  235. return e.key < key;
  236. } else {
  237. return e.key <= key;
  238. }
  239. });
  240. if (forward) {
  241. if (it != data->entries.end()) {
  242. key = it->key;
  243. return true;
  244. }
  245. } else {
  246. if (it != data->entries.begin()) {
  247. --it;
  248. key = it->key;
  249. return true;
  250. }
  251. }
  252. return false;
  253. }
  254. bool FindValueForCurrentKey() {
  255. if (data->recently_touched_keys.count(key)) {
  256. return false;
  257. }
  258. // Find the first entry for the key. The caller promises that it exists.
  259. auto it = std::partition_point(data->entries.begin(), data->entries.end(),
  260. [&](const Entry& e) {
  261. if (e.key != key) {
  262. return e.key < key;
  263. }
  264. return e.sequence > sequence;
  265. });
  266. // Find the first visible entry.
  267. for (;; ++it) {
  268. if (it == data->entries.end()) {
  269. return false;
  270. }
  271. Entry& e = *it;
  272. if (e.key != key) {
  273. return false;
  274. }
  275. assert(e.sequence <= sequence);
  276. if (!e.visible) continue;
  277. if (e.type == kTypeDeletion) {
  278. return false;
  279. }
  280. if (e.type == kTypeValue) {
  281. value = e.value;
  282. valid = true;
  283. return true;
  284. }
  285. assert(e.type == kTypeMerge);
  286. break;
  287. }
  288. // Collect merge operands.
  289. std::vector<Slice> operands;
  290. for (; it != data->entries.end(); ++it) {
  291. Entry& e = *it;
  292. if (e.key != key) {
  293. break;
  294. }
  295. assert(e.sequence <= sequence);
  296. if (!e.visible) continue;
  297. if (e.type == kTypeDeletion) {
  298. break;
  299. }
  300. operands.push_back(e.value);
  301. if (e.type == kTypeValue) {
  302. break;
  303. }
  304. }
  305. // Do a merge.
  306. value = operands.back().ToString();
  307. for (int i = (int)operands.size() - 2; i >= 0; --i) {
  308. value.append(",");
  309. value.append(operands[i].data(), operands[i].size());
  310. }
  311. valid = true;
  312. return true;
  313. }
  314. // Start at `key` and move until we encounter a valid value.
  315. // `forward` defines the direction of movement.
  316. // If `skip` is true, we're looking for key not equal to `key`.
  317. void DoTheThing(bool skip, bool forward) {
  318. while (FindNextKey(skip, forward) && !FindValueForCurrentKey()) {
  319. skip = true;
  320. }
  321. }
  322. void Seek(const Slice& target) {
  323. key = target.ToString();
  324. DoTheThing(false, true);
  325. }
  326. void SeekForPrev(const Slice& target) {
  327. key = target.ToString();
  328. DoTheThing(false, false);
  329. }
  330. void SeekToFirst() { Seek(""); }
  331. void SeekToLast() {
  332. key = data->entries.back().key;
  333. DoTheThing(false, false);
  334. }
  335. void Next() {
  336. assert(Valid());
  337. DoTheThing(true, true);
  338. }
  339. void Prev() {
  340. assert(Valid());
  341. DoTheThing(true, false);
  342. }
  343. };
  344. } // namespace
  345. // Use an internal iterator that sometimes returns errors and sometimes
  346. // adds/removes entries on the fly. Do random operations on a DBIter and
  347. // check results.
  348. // TODO: can be improved for more coverage:
  349. // * Override IsKeyPinned() and IsValuePinned() to actually use
  350. // PinnedIteratorManager and check that there's no use-after free.
  351. // * Try different combinations of prefix_extractor, total_order_seek,
  352. // prefix_same_as_start, iterate_lower_bound, iterate_upper_bound.
  353. TEST_F(DBIteratorStressTest, StressTest) {
  354. // We use a deterministic RNG, and everything happens in a single thread.
  355. Random64 rnd(826909345792864532ll);
  356. auto gen_key = [&](int max_key) {
  357. assert(max_key > 0);
  358. int len = 0;
  359. int a = max_key;
  360. while (a) {
  361. a /= 10;
  362. ++len;
  363. }
  364. std::string s = ToString(rnd.Next() % static_cast<uint64_t>(max_key));
  365. s.insert(0, len - (int)s.size(), '0');
  366. return s;
  367. };
  368. Options options;
  369. options.merge_operator = MergeOperators::CreateFromStringId("stringappend");
  370. ReadOptions ropt;
  371. size_t num_matching = 0;
  372. size_t num_at_end = 0;
  373. size_t num_not_ok = 0;
  374. size_t num_recently_removed = 0;
  375. // Number of iterations for each combination of parameters
  376. // (there are ~250 of those).
  377. // Tweak this to change the test run time.
  378. // As of the time of writing, the test takes ~4 seconds for value of 5000.
  379. const int num_iterations = 5000;
  380. // Enable this to print all the operations for debugging.
  381. bool trace = FLAGS_verbose;
  382. for (int num_entries : {5, 10, 100}) {
  383. for (double key_space : {0.1, 1.0, 3.0}) {
  384. for (ValueType prevalent_entry_type :
  385. {kTypeValue, kTypeDeletion, kTypeMerge}) {
  386. for (double error_probability : {0.01, 0.1}) {
  387. for (double mutation_probability : {0.01, 0.5}) {
  388. for (double target_hidden_fraction : {0.1, 0.5}) {
  389. std::string trace_str =
  390. "entries: " + ToString(num_entries) +
  391. ", key_space: " + ToString(key_space) +
  392. ", error_probability: " + ToString(error_probability) +
  393. ", mutation_probability: " + ToString(mutation_probability) +
  394. ", target_hidden_fraction: " +
  395. ToString(target_hidden_fraction);
  396. SCOPED_TRACE(trace_str);
  397. if (trace) {
  398. std::cout << trace_str << std::endl;
  399. }
  400. // Generate data.
  401. Data data;
  402. int max_key = (int)(num_entries * key_space) + 1;
  403. for (int i = 0; i < num_entries; ++i) {
  404. Entry e;
  405. e.key = gen_key(max_key);
  406. if (rnd.Next() % 10 != 0) {
  407. e.type = prevalent_entry_type;
  408. } else {
  409. const ValueType types[] = {kTypeValue, kTypeDeletion,
  410. kTypeMerge};
  411. e.type =
  412. types[rnd.Next() % (sizeof(types) / sizeof(types[0]))];
  413. }
  414. e.sequence = i;
  415. e.value = "v" + ToString(i);
  416. ParsedInternalKey internal_key(e.key, e.sequence, e.type);
  417. AppendInternalKey(&e.ikey, internal_key);
  418. data.entries.push_back(e);
  419. }
  420. std::sort(data.entries.begin(), data.entries.end());
  421. if (trace) {
  422. std::cout << "entries:";
  423. for (size_t i = 0; i < data.entries.size(); ++i) {
  424. Entry& e = data.entries[i];
  425. std::cout
  426. << "\n idx " << i << ": \"" << e.key << "\": \""
  427. << e.value << "\" seq: " << e.sequence << " type: "
  428. << (e.type == kTypeValue
  429. ? "val"
  430. : e.type == kTypeDeletion ? "del" : "merge");
  431. }
  432. std::cout << std::endl;
  433. }
  434. std::unique_ptr<Iterator> db_iter;
  435. std::unique_ptr<ReferenceIterator> ref_iter;
  436. for (int iteration = 0; iteration < num_iterations; ++iteration) {
  437. SCOPED_TRACE(iteration);
  438. // Create a new iterator every ~30 operations.
  439. if (db_iter == nullptr || rnd.Next() % 30 == 0) {
  440. uint64_t sequence = rnd.Next() % (data.entries.size() + 2);
  441. ref_iter.reset(new ReferenceIterator(&data, sequence));
  442. if (trace) {
  443. std::cout << "new iterator, seq: " << sequence << std::endl;
  444. }
  445. auto internal_iter =
  446. new StressTestIterator(&data, &rnd, BytewiseComparator());
  447. internal_iter->error_probability = error_probability;
  448. internal_iter->mutation_probability = mutation_probability;
  449. internal_iter->target_hidden_fraction =
  450. target_hidden_fraction;
  451. internal_iter->trace = trace;
  452. db_iter.reset(NewDBIterator(
  453. env_, ropt, ImmutableCFOptions(options),
  454. MutableCFOptions(options), BytewiseComparator(),
  455. internal_iter, sequence,
  456. options.max_sequential_skip_in_iterations,
  457. nullptr /*read_callback*/));
  458. }
  459. // Do a random operation. It's important to do it on ref_it
  460. // later than on db_iter to make sure ref_it sees the correct
  461. // recently_touched_keys.
  462. std::string old_key;
  463. bool forward = rnd.Next() % 2 > 0;
  464. // Do Next()/Prev() ~90% of the time.
  465. bool seek = !ref_iter->Valid() || rnd.Next() % 10 == 0;
  466. if (trace) {
  467. std::cout << iteration << ": ";
  468. }
  469. if (!seek) {
  470. assert(db_iter->Valid());
  471. old_key = ref_iter->key;
  472. if (trace) {
  473. std::cout << (forward ? "Next" : "Prev") << std::endl;
  474. }
  475. if (forward) {
  476. db_iter->Next();
  477. ref_iter->Next();
  478. } else {
  479. db_iter->Prev();
  480. ref_iter->Prev();
  481. }
  482. } else {
  483. data.recently_touched_keys.clear();
  484. // Do SeekToFirst less often than Seek.
  485. if (rnd.Next() % 4 == 0) {
  486. if (trace) {
  487. std::cout << (forward ? "SeekToFirst" : "SeekToLast")
  488. << std::endl;
  489. }
  490. if (forward) {
  491. old_key = "";
  492. db_iter->SeekToFirst();
  493. ref_iter->SeekToFirst();
  494. } else {
  495. old_key = data.entries.back().key;
  496. db_iter->SeekToLast();
  497. ref_iter->SeekToLast();
  498. }
  499. } else {
  500. old_key = gen_key(max_key);
  501. if (trace) {
  502. std::cout << (forward ? "Seek" : "SeekForPrev") << " \""
  503. << old_key << '"' << std::endl;
  504. }
  505. if (forward) {
  506. db_iter->Seek(old_key);
  507. ref_iter->Seek(old_key);
  508. } else {
  509. db_iter->SeekForPrev(old_key);
  510. ref_iter->SeekForPrev(old_key);
  511. }
  512. }
  513. }
  514. // Check the result.
  515. if (db_iter->Valid()) {
  516. ASSERT_TRUE(db_iter->status().ok());
  517. if (data.recently_touched_keys.count(
  518. db_iter->key().ToString())) {
  519. // Ended on a key that may have been mutated during the
  520. // operation. Reference iterator skips such keys, so we
  521. // can't check the exact result.
  522. // Check that the key moved in the right direction.
  523. if (forward) {
  524. if (seek)
  525. ASSERT_GE(db_iter->key().ToString(), old_key);
  526. else
  527. ASSERT_GT(db_iter->key().ToString(), old_key);
  528. } else {
  529. if (seek)
  530. ASSERT_LE(db_iter->key().ToString(), old_key);
  531. else
  532. ASSERT_LT(db_iter->key().ToString(), old_key);
  533. }
  534. if (ref_iter->Valid()) {
  535. // Check that DBIter didn't miss any non-mutated key.
  536. if (forward) {
  537. ASSERT_LT(db_iter->key().ToString(), ref_iter->key);
  538. } else {
  539. ASSERT_GT(db_iter->key().ToString(), ref_iter->key);
  540. }
  541. }
  542. // Tell the next iteration of the loop to reseek the
  543. // iterators.
  544. ref_iter->valid = false;
  545. ++num_recently_removed;
  546. } else {
  547. ASSERT_TRUE(ref_iter->Valid());
  548. ASSERT_EQ(ref_iter->key, db_iter->key().ToString());
  549. ASSERT_EQ(ref_iter->value, db_iter->value());
  550. ++num_matching;
  551. }
  552. } else if (db_iter->status().ok()) {
  553. ASSERT_FALSE(ref_iter->Valid());
  554. ++num_at_end;
  555. } else {
  556. // Non-ok status. Nothing to check here.
  557. // Tell the next iteration of the loop to reseek the
  558. // iterators.
  559. ref_iter->valid = false;
  560. ++num_not_ok;
  561. }
  562. }
  563. }
  564. }
  565. }
  566. }
  567. }
  568. }
  569. // Check that all cases were hit many times.
  570. EXPECT_GT(num_matching, 10000);
  571. EXPECT_GT(num_at_end, 10000);
  572. EXPECT_GT(num_not_ok, 10000);
  573. EXPECT_GT(num_recently_removed, 10000);
  574. std::cout << "stats:\n exact matches: " << num_matching
  575. << "\n end reached: " << num_at_end
  576. << "\n non-ok status: " << num_not_ok
  577. << "\n mutated on the fly: " << num_recently_removed << std::endl;
  578. }
  579. } // namespace ROCKSDB_NAMESPACE
  580. int main(int argc, char** argv) {
  581. ::testing::InitGoogleTest(&argc, argv);
  582. ParseCommandLineFlags(&argc, &argv, true);
  583. return RUN_ALL_TESTS();
  584. }