1 /*
2 Copyright (c) 2003, 2021, Oracle and/or its affiliates.
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License, version 2.0,
6 as published by the Free Software Foundation.
7
8 This program is also distributed with certain software (including
9 but not limited to OpenSSL) that is licensed under separate terms,
10 as designated in a particular file or component or in included license
11 documentation. The authors of MySQL hereby grant you an additional
12 permission to link the program and your derivative works with the
13 separately licensed software that they have included with MySQL.
14
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License, version 2.0, for more details.
19
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software
22 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
23 */
24
25 #ifndef __SAFE_COUNTER_HPP
26 #define __SAFE_COUNTER_HPP
27
28 /*************************************************************
29 *
30 * SafeCounter "automates" three way to node-fais safe protocols
31 * for "slave" failures. This is done by registing "fake" signals
32 * to be sent in case of nodefailure.
33 *
34 * init<SignalClass>(..., GSN, senderData);
35 *
36 * It is implemented so that one can replace SignalCounter with
37 * SafeCounter (SignalCounter should probably go away with time)
38 * methods:
39 * clearWaitingFor(nodeId);
40 * done();
41 * etc.
42 *
43 * If included in a new block method
44 * SafeCounterManager::execNODE_FAILREP must included in
45 * <block>::execNODE_FAILREP
46 *
47 * the SignalClass must have senderRef, senderData and errorCode
48 * and also ErrorCode::NF_FakeErrorREF, implemented
49 *
50 * SafeCounter consists of 3 parts:
51 * SafeCounterManager which keeps track of active "counters"
52 * SafeCounterHandle to store "i-value" in your "op record"
53 * SafeCounter as a temporary variable only to use on the stack
54 * for operation
55 *
56 */
57
58 #include <NodeBitmask.hpp>
59 #include "IntrusiveList.hpp"
60 #include "VMSignal.hpp"
61
62 #define JAM_FILE_ID 286
63
64
65 class SimulatedBlock;
66
67 /**
68 *
69 */
70 class SafeCounterManager {
71 friend class SafeCounter;
72 friend class SafeCounterHandle;
73 friend class SimulatedBlock;
74 public:
75 SafeCounterManager(class SimulatedBlock &);
76
77 bool setSize(Uint32 maxNoOfActiveMutexes, bool exit_on_error = true);
78 Uint32 getSize() const ;
79 Uint32 getNoOfFree() const;
80
81 void execNODE_FAILREP(Signal*);
82 void printNODE_FAILREP();
83
84 private:
85 struct ActiveCounter { /** sizeof = 7words = 28bytes */
86 public:
87 Uint32 m_senderData;
88 NdbNodeBitmask m_nodes;
89 struct SignalDesc {
90 public:
91 Uint16 m_gsn;
92 Uint16 m_block;
93 Uint8 m_senderRefOffset;
94 Uint8 m_senderDataOffset;
95 Uint8 m_errorCodeOffset;
96 Uint8 m_nodeFailErrorCode;
97 } m_signalDesc;
98 union {
99 Uint32 nextPool;
100 Uint32 nextList;
101 };
102 Uint32 prevList;
103 };
104
105 typedef Ptr<ActiveCounter> ActiveCounterPtr;
106
107 bool seize(ActiveCounterPtr& ptr);
108 void release(ActiveCounterPtr& ptr);
109 void getPtr(ActiveCounterPtr& ptr, Uint32 ptrI);
110
111 SimulatedBlock & m_block;
112 ArrayPool<ActiveCounter> m_counterPool;
113 DLList<ActiveCounter> m_activeCounters;
114
115 BlockReference reference() const;
116 void progError(int line, int err_code, const char* extra = 0);
117 };
118
119
120 class SafeCounterHandle {
121 friend class SafeCounter;
122 public:
123 SafeCounterHandle();
124
125 /**
126 * Return if done (no nodes set in bitmask)
127 */
128 bool clearWaitingFor(SafeCounterManager& mgr, Uint32 nodeId);
129
130 bool done() const;
131
132 private:
133 Uint32 m_activeCounterPtrI;
134 };
135
136 class SafeCounter {
137 friend class SafeCounterManager;
138 public:
139 SafeCounter(SafeCounterManager&, SafeCounterHandle&);
140
141 template<typename SignalClass>
142 bool init(Uint16 block, Uint16 GSN, Uint32 senderData);
143
144 template<typename SignalClass>
145 bool init(NodeReceiverGroup rg, Uint16 GSN, Uint32 senderData);
146
147 template<typename SignalClass>
148 bool init(NodeReceiverGroup rg, Uint32 senderData);
149
150 ~SafeCounter();
151
152 void clearWaitingFor();
153
154 /**
155 * When sending to different node
156 */
157 void setWaitingFor(Uint32 nodeId);
158 bool clearWaitingFor(Uint32 nodeId);
159 bool forceClearWaitingFor(Uint32 nodeId);
160
161 bool isWaitingFor(Uint32 nodeId) const;
162 bool done() const;
163
164 const char * getText() const; /* ? needed for, some portability issues */
165
166 SafeCounter& operator=(const NdbNodeBitmask&);
167 SafeCounter& operator=(const NodeReceiverGroup&);
168 private:
169 Uint32 m_count;
170 NdbNodeBitmask m_nodes;
171
172 SafeCounterManager & m_mgr;
173 SafeCounterManager::ActiveCounterPtr m_ptr;
174
175 Uint32 & m_activeCounterPtrI;
176 };
177
178 inline
SafeCounterHandle()179 SafeCounterHandle::SafeCounterHandle(){
180 m_activeCounterPtrI = RNIL;
181 }
182
183 inline
184 bool
done() const185 SafeCounterHandle::done() const {
186 return m_activeCounterPtrI == RNIL;
187 }
188
189 inline
SafeCounter(SafeCounterManager & mgr,SafeCounterHandle & handle)190 SafeCounter::SafeCounter(SafeCounterManager& mgr, SafeCounterHandle& handle)
191 : m_mgr(mgr),
192 m_activeCounterPtrI(handle.m_activeCounterPtrI)
193 {
194 m_ptr.i = handle.m_activeCounterPtrI;
195 if (m_ptr.i == RNIL) {
196 m_nodes.clear();
197 m_count = 0;
198 } else {
199 m_mgr.getPtr(m_ptr, m_ptr.i);
200 m_nodes = m_ptr.p->m_nodes;
201 m_count = m_nodes.count();
202 }
203 }
204
205 template<typename Ref>
206 inline
207 bool
init(Uint16 block,Uint16 GSN,Uint32 senderData)208 SafeCounter::init(Uint16 block, Uint16 GSN, Uint32 senderData){
209
210 SafeCounterManager::ActiveCounter::SignalDesc signalDesc;
211 signalDesc.m_gsn = GSN;
212 signalDesc.m_block = block;
213 signalDesc.m_errorCodeOffset = offsetof(Ref, errorCode) >> 2;
214 signalDesc.m_senderRefOffset = offsetof(Ref, senderRef) >> 2;
215 signalDesc.m_senderDataOffset = offsetof(Ref, senderData) >> 2;
216 signalDesc.m_nodeFailErrorCode = Ref::NF_FakeErrorREF;
217 assert(((Uint32)Ref::NF_FakeErrorREF) < 256);
218
219 if(m_ptr.i == RNIL){
220 SafeCounterManager::ActiveCounterPtr ptr;
221 if(m_mgr.seize(ptr)){
222 ptr.p->m_senderData = senderData;
223 ptr.p->m_signalDesc = signalDesc;
224 m_ptr = ptr;
225 return true;
226 }
227 return false;
228 }
229
230 if(m_count == 0){
231 m_ptr.p->m_senderData = senderData;
232 m_ptr.p->m_signalDesc = signalDesc;
233 return true;
234 }
235
236 ErrorReporter::handleAssert("SafeCounter::init twice", __FILE__, __LINE__);
237 return false;
238 }
239
240 template<typename Ref>
241 inline
242 bool
init(NodeReceiverGroup rg,Uint16 GSN,Uint32 senderData)243 SafeCounter::init(NodeReceiverGroup rg, Uint16 GSN, Uint32 senderData){
244
245 if (init<Ref>(rg.m_block, GSN, senderData))
246 {
247 m_nodes = rg.m_nodes;
248 m_count = m_nodes.count();
249
250 if (unlikely(m_count == 0))
251 {
252 ErrorReporter::handleAssert("SafeCounter::empty node list",
253 __FILE__, __LINE__);
254 }
255 return true;
256 }
257 return false;
258 }
259
260 template<typename Ref>
261 inline
262 bool
init(NodeReceiverGroup rg,Uint32 senderData)263 SafeCounter::init(NodeReceiverGroup rg, Uint32 senderData)
264 {
265 if (init<Ref>(rg.m_block, Ref::GSN, senderData))
266 {
267 m_nodes = rg.m_nodes;
268 m_count = m_nodes.count();
269
270 if (unlikely(m_count == 0))
271 {
272 ErrorReporter::handleAssert("SafeCounter::empty node list",
273 __FILE__, __LINE__);
274 }
275 return true;
276 }
277 return false;
278 }
279
280 inline
281 void
setWaitingFor(Uint32 nodeId)282 SafeCounter::setWaitingFor(Uint32 nodeId) {
283 if(!m_nodes.get(nodeId)){
284 m_nodes.set(nodeId);
285 m_count++;
286 return;
287 }
288 ErrorReporter::handleAssert("SafeCounter::set", __FILE__, __LINE__);
289 }
290
291 inline
292 bool
isWaitingFor(Uint32 nodeId) const293 SafeCounter::isWaitingFor(Uint32 nodeId) const {
294 return m_nodes.get(nodeId);
295 }
296
297 inline
298 bool
done() const299 SafeCounter::done() const {
300 return m_count == 0;
301 }
302
303 inline
304 bool
clearWaitingFor(Uint32 nodeId)305 SafeCounter::clearWaitingFor(Uint32 nodeId) {
306 if(m_count > 0 && m_nodes.get(nodeId)){
307 m_count--;
308 m_nodes.clear(nodeId);
309 return (m_count == 0);
310 }
311 ErrorReporter::handleAssert("SafeCounter::clear", __FILE__, __LINE__);
312 return false;
313 }
314
315 inline
316 void
clearWaitingFor()317 SafeCounter::clearWaitingFor(){
318 m_count = 0;
319 m_nodes.clear();
320 }
321
322 inline
323 bool
forceClearWaitingFor(Uint32 nodeId)324 SafeCounter::forceClearWaitingFor(Uint32 nodeId){
325 if(isWaitingFor(nodeId)){
326 return clearWaitingFor(nodeId);
327 }
328 return (m_count == 0);
329 }
330
331
332 #undef JAM_FILE_ID
333
334 #endif
335