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