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