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