sync_point.h 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182
  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 <assert.h>
  7. #include <functional>
  8. #include <mutex>
  9. #include <string>
  10. #include <thread>
  11. #include <vector>
  12. #include "rocksdb/rocksdb_namespace.h"
  13. #include "rocksdb/slice.h"
  14. #ifdef NDEBUG
  15. // empty in release build
  16. #define TEST_KILL_RANDOM_WITH_WEIGHT(kill_point, rocksdb_kill_odds_weight)
  17. #define TEST_KILL_RANDOM(kill_point)
  18. #else
  19. namespace ROCKSDB_NAMESPACE {
  20. // To avoid crashing always at some frequently executed codepaths (during
  21. // kill random test), use this factor to reduce odds
  22. #define REDUCE_ODDS 2
  23. #define REDUCE_ODDS2 4
  24. // A class used to pass when a kill point is reached.
  25. struct KillPoint {
  26. public:
  27. // This is only set from db_stress.cc and for testing only.
  28. // If non-zero, kill at various points in source code with probability 1/this
  29. int rocksdb_kill_odds = 0;
  30. // If kill point has a prefix on this list, will skip killing.
  31. std::vector<std::string> rocksdb_kill_exclude_prefixes;
  32. // Kill the process with probability 1/odds for testing.
  33. void TestKillRandom(std::string kill_point, int odds,
  34. const std::string& srcfile, int srcline);
  35. static KillPoint* GetInstance();
  36. };
  37. #define TEST_KILL_RANDOM_WITH_WEIGHT(kill_point, rocksdb_kill_odds_weight) \
  38. { \
  39. KillPoint::GetInstance()->TestKillRandom( \
  40. kill_point, rocksdb_kill_odds_weight, __FILE__, __LINE__); \
  41. }
  42. #define TEST_KILL_RANDOM(kill_point) TEST_KILL_RANDOM_WITH_WEIGHT(kill_point, 1)
  43. } // namespace ROCKSDB_NAMESPACE
  44. #endif
  45. #ifdef NDEBUG
  46. #define TEST_SYNC_POINT(x)
  47. #define TEST_IDX_SYNC_POINT(x, index)
  48. #define TEST_SYNC_POINT_CALLBACK(x, y)
  49. #define INIT_SYNC_POINT_SINGLETONS()
  50. #else
  51. namespace ROCKSDB_NAMESPACE {
  52. // This class provides facility to reproduce race conditions deterministically
  53. // in unit tests.
  54. // Developer could specify sync points in the codebase via TEST_SYNC_POINT.
  55. // Each sync point represents a position in the execution stream of a thread.
  56. // In the unit test, 'Happens After' relationship among sync points could be
  57. // setup via SyncPoint::LoadDependency, to reproduce a desired interleave of
  58. // threads execution.
  59. // Refer to (DBTest,TransactionLogIteratorRace), for an example use case.
  60. class SyncPoint {
  61. public:
  62. static SyncPoint* GetInstance();
  63. SyncPoint(const SyncPoint&) = delete;
  64. SyncPoint& operator=(const SyncPoint&) = delete;
  65. ~SyncPoint();
  66. struct SyncPointPair {
  67. std::string predecessor;
  68. std::string successor;
  69. };
  70. // call once at the beginning of a test to setup the dependency between
  71. // sync points. Specifically, execution will not be allowed to proceed past
  72. // each successor until execution has reached the corresponding predecessor,
  73. // in any thread.
  74. void LoadDependency(const std::vector<SyncPointPair>& dependencies);
  75. // call once at the beginning of a test to setup the dependency between
  76. // sync points and setup markers indicating the successor is only enabled
  77. // when it is processed on the same thread as the predecessor.
  78. // When adding a marker, it implicitly adds a dependency for the marker pair.
  79. void LoadDependencyAndMarkers(const std::vector<SyncPointPair>& dependencies,
  80. const std::vector<SyncPointPair>& markers);
  81. // The argument to the callback is passed through from
  82. // TEST_SYNC_POINT_CALLBACK(); nullptr if TEST_SYNC_POINT or
  83. // TEST_IDX_SYNC_POINT was used.
  84. void SetCallBack(const std::string& point,
  85. const std::function<void(void*)>& callback);
  86. // Clear callback function by point
  87. void ClearCallBack(const std::string& point);
  88. // Clear all call back functions.
  89. void ClearAllCallBacks();
  90. // enable sync point processing (disabled on startup)
  91. void EnableProcessing();
  92. // disable sync point processing
  93. void DisableProcessing();
  94. // remove the execution trace of all sync points
  95. void ClearTrace();
  96. // triggered by TEST_SYNC_POINT, blocking execution until all predecessors
  97. // are executed.
  98. // And/or call registered callback function, with argument `cb_arg`
  99. void Process(const Slice& point, void* cb_arg = nullptr);
  100. // template gets length of const string at compile time,
  101. // avoiding strlen() at runtime
  102. template <size_t kLen>
  103. void Process(const char (&point)[kLen], void* cb_arg = nullptr) {
  104. static_assert(kLen > 0, "Must not be empty");
  105. assert(point[kLen - 1] == '\0');
  106. Process(Slice(point, kLen - 1), cb_arg);
  107. }
  108. // TODO: it might be useful to provide a function that blocks until all
  109. // sync points are cleared.
  110. // We want this to be public so we can
  111. // subclass the implementation
  112. struct Data;
  113. private:
  114. // Singleton
  115. SyncPoint();
  116. Data* impl_;
  117. };
  118. // Sets up sync points to mock direct IO instead of actually issuing direct IO
  119. // to the file system.
  120. void SetupSyncPointsToMockDirectIO();
  121. } // namespace ROCKSDB_NAMESPACE
  122. // Use TEST_SYNC_POINT to specify sync points inside code base.
  123. // Sync points can have happens-after dependency on other sync points,
  124. // configured at runtime via SyncPoint::LoadDependency. This could be
  125. // utilized to re-produce race conditions between threads.
  126. // See TransactionLogIteratorRace in db_test.cc for an example use case.
  127. // TEST_SYNC_POINT is no op in release build.
  128. #define TEST_SYNC_POINT(x) \
  129. ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->Process(x)
  130. #define TEST_IDX_SYNC_POINT(x, index) \
  131. ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->Process(x + \
  132. std::to_string(index))
  133. #define TEST_SYNC_POINT_CALLBACK(x, y) \
  134. ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->Process(x, y)
  135. #define INIT_SYNC_POINT_SINGLETONS() \
  136. (void)ROCKSDB_NAMESPACE::SyncPoint::GetInstance();
  137. #endif // NDEBUG
  138. // Callback sync point for any read IO errors that should be ignored by
  139. // the fault injection framework
  140. // Disable in release mode
  141. #ifdef NDEBUG
  142. #define IGNORE_STATUS_IF_ERROR(_status_)
  143. #else
  144. #define IGNORE_STATUS_IF_ERROR(_status_) \
  145. { \
  146. if (!_status_.ok()) { \
  147. TEST_SYNC_POINT("FaultInjectionIgnoreError"); \
  148. } \
  149. }
  150. #endif // NDEBUG