sync_point.h 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144
  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. // This is only set from db_stress.cc and for testing only.
  14. // If non-zero, kill at various points in source code with probability 1/this
  15. extern int rocksdb_kill_odds;
  16. // If kill point has a prefix on this list, will skip killing.
  17. extern std::vector<std::string> rocksdb_kill_prefix_blacklist;
  18. #ifdef NDEBUG
  19. // empty in release build
  20. #define TEST_KILL_RANDOM(kill_point, rocksdb_kill_odds)
  21. #else
  22. namespace ROCKSDB_NAMESPACE {
  23. // Kill the process with probability 1/odds for testing.
  24. extern void TestKillRandom(std::string kill_point, int odds,
  25. const std::string& srcfile, int srcline);
  26. // To avoid crashing always at some frequently executed codepaths (during
  27. // kill random test), use this factor to reduce odds
  28. #define REDUCE_ODDS 2
  29. #define REDUCE_ODDS2 4
  30. #define TEST_KILL_RANDOM(kill_point, rocksdb_kill_odds) \
  31. { \
  32. if (rocksdb_kill_odds > 0) { \
  33. TestKillRandom(kill_point, rocksdb_kill_odds, __FILE__, __LINE__); \
  34. } \
  35. }
  36. } // namespace ROCKSDB_NAMESPACE
  37. #endif
  38. #ifdef NDEBUG
  39. #define TEST_SYNC_POINT(x)
  40. #define TEST_IDX_SYNC_POINT(x, index)
  41. #define TEST_SYNC_POINT_CALLBACK(x, y)
  42. #define INIT_SYNC_POINT_SINGLETONS()
  43. #else
  44. namespace ROCKSDB_NAMESPACE {
  45. // This class provides facility to reproduce race conditions deterministically
  46. // in unit tests.
  47. // Developer could specify sync points in the codebase via TEST_SYNC_POINT.
  48. // Each sync point represents a position in the execution stream of a thread.
  49. // In the unit test, 'Happens After' relationship among sync points could be
  50. // setup via SyncPoint::LoadDependency, to reproduce a desired interleave of
  51. // threads execution.
  52. // Refer to (DBTest,TransactionLogIteratorRace), for an example use case.
  53. class SyncPoint {
  54. public:
  55. static SyncPoint* GetInstance();
  56. SyncPoint(const SyncPoint&) = delete;
  57. SyncPoint& operator=(const SyncPoint&) = delete;
  58. ~SyncPoint();
  59. struct SyncPointPair {
  60. std::string predecessor;
  61. std::string successor;
  62. };
  63. // call once at the beginning of a test to setup the dependency between
  64. // sync points
  65. void LoadDependency(const std::vector<SyncPointPair>& dependencies);
  66. // call once at the beginning of a test to setup the dependency between
  67. // sync points and setup markers indicating the successor is only enabled
  68. // when it is processed on the same thread as the predecessor.
  69. // When adding a marker, it implicitly adds a dependency for the marker pair.
  70. void LoadDependencyAndMarkers(const std::vector<SyncPointPair>& dependencies,
  71. const std::vector<SyncPointPair>& markers);
  72. // The argument to the callback is passed through from
  73. // TEST_SYNC_POINT_CALLBACK(); nullptr if TEST_SYNC_POINT or
  74. // TEST_IDX_SYNC_POINT was used.
  75. void SetCallBack(const std::string& point,
  76. const std::function<void(void*)>& callback);
  77. // Clear callback function by point
  78. void ClearCallBack(const std::string& point);
  79. // Clear all call back functions.
  80. void ClearAllCallBacks();
  81. // enable sync point processing (disabled on startup)
  82. void EnableProcessing();
  83. // disable sync point processing
  84. void DisableProcessing();
  85. // remove the execution trace of all sync points
  86. void ClearTrace();
  87. // triggered by TEST_SYNC_POINT, blocking execution until all predecessors
  88. // are executed.
  89. // And/or call registered callback function, with argument `cb_arg`
  90. void Process(const std::string& point, void* cb_arg = nullptr);
  91. // TODO: it might be useful to provide a function that blocks until all
  92. // sync points are cleared.
  93. // We want this to be public so we can
  94. // subclass the implementation
  95. struct Data;
  96. private:
  97. // Singleton
  98. SyncPoint();
  99. Data* impl_;
  100. };
  101. } // namespace ROCKSDB_NAMESPACE
  102. // Use TEST_SYNC_POINT to specify sync points inside code base.
  103. // Sync points can have happens-after depedency on other sync points,
  104. // configured at runtime via SyncPoint::LoadDependency. This could be
  105. // utilized to re-produce race conditions between threads.
  106. // See TransactionLogIteratorRace in db_test.cc for an example use case.
  107. // TEST_SYNC_POINT is no op in release build.
  108. #define TEST_SYNC_POINT(x) \
  109. ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->Process(x)
  110. #define TEST_IDX_SYNC_POINT(x, index) \
  111. ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->Process(x + \
  112. std::to_string(index))
  113. #define TEST_SYNC_POINT_CALLBACK(x, y) \
  114. ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->Process(x, y)
  115. #define INIT_SYNC_POINT_SINGLETONS() \
  116. (void)ROCKSDB_NAMESPACE::SyncPoint::GetInstance();
  117. #endif // NDEBUG