transaction_test_util.h 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145
  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. #pragma once
  6. #include "port/port.h"
  7. #include "rocksdb/options.h"
  8. #include "rocksdb/utilities/optimistic_transaction_db.h"
  9. #include "rocksdb/utilities/transaction_db.h"
  10. namespace ROCKSDB_NAMESPACE {
  11. class DB;
  12. class Random64;
  13. // Utility class for stress testing transactions. Can be used to write many
  14. // transactions in parallel and then validate that the data written is logically
  15. // consistent. This class assumes the input DB is initially empty.
  16. //
  17. // Each call to TransactionDBInsert()/OptimisticTransactionDBInsert() will
  18. // increment the value of a key in #num_sets sets of keys. Regardless of
  19. // whether the transaction succeeds, the total sum of values of keys in each
  20. // set is an invariant that should remain equal.
  21. //
  22. // After calling TransactionDBInsert()/OptimisticTransactionDBInsert() many
  23. // times, Verify() can be called to validate that the invariant holds.
  24. //
  25. // To test writing Transaction in parallel, multiple threads can create a
  26. // RandomTransactionInserter with similar arguments using the same DB.
  27. class RandomTransactionInserter {
  28. public:
  29. static bool RollbackDeletionTypeCallback(const Slice& key) {
  30. // These are hard-coded atm. See how RandomTransactionInserter::DoInsert()
  31. // determines whether to use SingleDelete or Delete for a key.
  32. assert(key.size() >= 4);
  33. const char* ptr = key.data();
  34. assert(ptr);
  35. while (ptr && ptr < key.data() + 4 && *ptr == '0') {
  36. ++ptr;
  37. }
  38. std::string prefix(ptr, 4 - (ptr - key.data()));
  39. unsigned long set_i = std::stoul(prefix);
  40. assert(set_i > 0);
  41. assert(set_i <= 9999);
  42. --set_i;
  43. return ((set_i % 4) != 0);
  44. }
  45. // num_keys is the number of keys in each set.
  46. // num_sets is the number of sets of keys.
  47. // cmt_delay_ms is the delay between prepare (if there is any) and commit
  48. // first_id is the id of the first transaction
  49. explicit RandomTransactionInserter(
  50. Random64* rand, const WriteOptions& write_options = WriteOptions(),
  51. const ReadOptions& read_options = ReadOptions(), uint64_t num_keys = 1000,
  52. uint16_t num_sets = 3, const uint64_t cmt_delay_ms = 0,
  53. const uint64_t first_id = 0);
  54. ~RandomTransactionInserter();
  55. // Increment a key in each set using a Transaction on a TransactionDB.
  56. //
  57. // Returns true if the transaction succeeded OR if any error encountered was
  58. // expected (eg a write-conflict). Error status may be obtained by calling
  59. // GetLastStatus();
  60. bool TransactionDBInsert(
  61. TransactionDB* db,
  62. const TransactionOptions& txn_options = TransactionOptions());
  63. // Increment a key in each set using a Transaction on an
  64. // OptimisticTransactionDB
  65. //
  66. // Returns true if the transaction succeeded OR if any error encountered was
  67. // expected (eg a write-conflict). Error status may be obtained by calling
  68. // GetLastStatus();
  69. bool OptimisticTransactionDBInsert(
  70. OptimisticTransactionDB* db,
  71. const OptimisticTransactionOptions& txn_options =
  72. OptimisticTransactionOptions());
  73. // Increment a key in each set without using a transaction. If this function
  74. // is called in parallel, then Verify() may fail.
  75. //
  76. // Returns true if the write succeeds.
  77. // Error status may be obtained by calling GetLastStatus().
  78. bool DBInsert(DB* db);
  79. // Get the ikey'th key from set set_i
  80. static Status DBGet(DB* db, Transaction* txn, ReadOptions& read_options,
  81. uint16_t set_i, uint64_t ikey, bool get_for_update,
  82. uint64_t* int_value, std::string* full_key,
  83. bool* unexpected_error);
  84. // Returns OK if Invariant is true.
  85. static Status Verify(DB* db, uint16_t num_sets, uint64_t num_keys_per_set = 0,
  86. bool take_snapshot = false, Random64* rand = nullptr,
  87. uint64_t delay_ms = 0);
  88. // Returns the status of the previous Insert operation
  89. Status GetLastStatus() { return last_status_; }
  90. // Returns the number of successfully written calls to
  91. // TransactionDBInsert/OptimisticTransactionDBInsert/DBInsert
  92. uint64_t GetSuccessCount() { return success_count_; }
  93. // Returns the number of calls to
  94. // TransactionDBInsert/OptimisticTransactionDBInsert/DBInsert that did not
  95. // write any data.
  96. uint64_t GetFailureCount() { return failure_count_; }
  97. // Returns the sum of user keys/values Put() to the DB.
  98. size_t GetBytesInserted() { return bytes_inserted_; }
  99. private:
  100. // Input options
  101. Random64* rand_;
  102. const WriteOptions write_options_;
  103. ReadOptions read_options_;
  104. const uint64_t num_keys_;
  105. const uint16_t num_sets_;
  106. // Number of successful insert batches performed
  107. uint64_t success_count_ = 0;
  108. // Number of failed insert batches attempted
  109. uint64_t failure_count_ = 0;
  110. size_t bytes_inserted_ = 0;
  111. // Status returned by most recent insert operation
  112. Status last_status_;
  113. // optimization: re-use allocated transaction objects.
  114. Transaction* txn_ = nullptr;
  115. Transaction* optimistic_txn_ = nullptr;
  116. uint64_t txn_id_;
  117. // The delay between ::Prepare and ::Commit
  118. const uint64_t cmt_delay_ms_;
  119. bool DoInsert(DB* db, Transaction* txn, bool is_optimistic);
  120. };
  121. } // namespace ROCKSDB_NAMESPACE