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