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 #include "API.hpp"
26 
27 void
checkFailedNode()28 Ndb::checkFailedNode()
29 {
30   DBUG_ENTER("Ndb::checkFailedNode");
31   Uint32 *the_release_ind= theImpl->the_release_ind;
32   if (the_release_ind[0] == 0)
33   {
34     DBUG_VOID_RETURN;
35   }
36   Uint32 tNoOfDbNodes = theImpl->theNoOfDBnodes;
37   Uint8 *theDBnodes= theImpl->theDBnodes;
38 
39   DBUG_PRINT("enter", ("theNoOfDBnodes: %d", tNoOfDbNodes));
40 
41   assert(tNoOfDbNodes < MAX_NDB_NODES);
42   for (Uint32 i = 0; i < tNoOfDbNodes; i++){
43     const NodeId node_id = theDBnodes[i];
44     DBUG_PRINT("info", ("i: %d, node_id: %d", i, node_id));
45 
46     assert(node_id < MAX_NDB_NODES);
47     if (the_release_ind[node_id] == 1){
48 
49       /**
50        * Release all connections in idle list (for node)
51        */
52       NdbTransaction * tNdbCon = theConnectionArray[node_id];
53       theConnectionArray[node_id] = NULL;
54       theConnectionArrayLast[node_id] = NULL;
55       while (tNdbCon != NULL) {
56         NdbTransaction* tempNdbCon = tNdbCon;
57         tNdbCon = tNdbCon->next();
58         releaseNdbCon(tempNdbCon);
59       }
60       the_release_ind[node_id] = 0;
61     }
62   }
63   DBUG_VOID_RETURN;
64 }
65 
66 /***************************************************************************
67  * int createConIdleList(int aNrOfCon);
68  *
69  * Return Value:   Return the number of created connection object
70  *                 if createConIdleList was succesful
71  *                 Return -1: In all other case.
72  * Parameters:     aNrOfCon : Number of connections offered to the application.
73  * Remark:         Create connection idlelist with NdbTransaction objects.
74  ***************************************************************************/
75 int
createConIdleList(int aNrOfCon)76 Ndb::createConIdleList(int aNrOfCon)
77 {
78   if (theImpl->theConIdleList.fill(this, aNrOfCon))
79   {
80     return -1;
81   }
82   return aNrOfCon;
83 }
84 
85 /***************************************************************************
86  * int createOpIdleList(int aNrOfOp);
87  *
88  * Return Value:   Return the number of created operation object if
89  *                 createOpIdleList was succesful.
90  *                 Return -1: In all other case.
91  * Parameters:     aNrOfOp:  Number of operations offered to the application.
92  * Remark:         Create  operation idlelist with NdbOperation objects..
93  ***************************************************************************/
94 int
createOpIdleList(int aNrOfOp)95 Ndb::createOpIdleList(int aNrOfOp)
96 {
97   if (theImpl->theOpIdleList.fill(this, aNrOfOp))
98   {
99     return -1;
100   }
101   return aNrOfOp;
102 }
103 
104 /***************************************************************************
105  * NdbBranch* NdbBranch();
106  *
107  * Return Value:   Return a NdbBranch if the  getNdbBranch was successful.
108  *                Return NULL : In all other case.
109  * Remark:         Get a NdbBranch from theBranchList and return the object .
110  ***************************************************************************/
111 NdbBranch*
getNdbBranch()112 Ndb::getNdbBranch()
113 {
114   return theImpl->theBranchList.seize(this);
115 }
116 
117 /***************************************************************************
118  * NdbCall* NdbCall();
119  *
120  * Return Value:   Return a NdbCall if the  getNdbCall was successful.
121  *                Return NULL : In all other case.
122  * Remark:         Get a NdbCall from theCallList and return the object .
123  ***************************************************************************/
124 NdbCall*
getNdbCall()125 Ndb::getNdbCall()
126 {
127   return theImpl->theCallList.seize(this);
128 }
129 
130 /***************************************************************************
131  * NdbTransaction* getNdbCon();
132  *
133  * Return Value:   Return a connection if the  getNdbCon was successful.
134  *                Return NULL : In all other case.
135  * Remark:         Get a connection from theConIdleList and return the object .
136  ***************************************************************************/
137 NdbTransaction*
getNdbCon()138 Ndb::getNdbCon()
139 {
140   NdbTransaction* tNdbCon = theImpl->theConIdleList.seize(this);
141   tNdbCon->theMagicNumber = tNdbCon->getMagicNumber();
142   return tNdbCon;
143 }
144 
145 /***************************************************************************
146  * NdbLabel* getNdbLabel();
147  *
148  * Return Value:   Return a NdbLabel if the  getNdbLabel was successful.
149  *                 Return NULL : In all other case.
150  * Remark:         Get a NdbLabel from theLabelList and return the object .
151  ***************************************************************************/
152 NdbLabel*
getNdbLabel()153 Ndb::getNdbLabel()
154 {
155   return theImpl->theLabelList.seize(this);
156 }
157 
158 /***************************************************************************
159  * NdbScanReceiver* getNdbScanRec()
160  *
161  * Return Value:  Return a NdbScanReceiver
162  *                Return NULL : In all other case.
163  * Remark:        Get a NdbScanReceiver from theScanRecList and return the
164  *                object .
165  ****************************************************************************/
166 NdbReceiver*
getNdbScanRec()167 Ndb::getNdbScanRec()
168 {
169   return theImpl->theScanList.seize(this);
170 }
171 
172 /***************************************************************************
173  * NdbSubroutine* getNdbSubroutine();
174  *
175  * Return Value: Return a NdbSubroutine if the  getNdbSubroutine was successful.
176  *                Return NULL : In all other case.
177  * Remark:    Get a NdbSubroutine from theSubroutineList and return the object .
178  ***************************************************************************/
179 NdbSubroutine*
getNdbSubroutine()180 Ndb::getNdbSubroutine()
181 {
182   return theImpl->theSubroutineList.seize(this);
183 }
184 
185 /***************************************************************************
186 NdbOperation* getOperation();
187 
188 Return Value:   Return theOpList : if the  getOperation was succesful.
189                 Return NULL : In all other case.
190 Remark:         Get an operation from theOpIdleList and return the object .
191 ***************************************************************************/
192 NdbOperation*
getOperation()193 Ndb::getOperation()
194 {
195   return theImpl->theOpIdleList.seize(this);
196 }
197 
198 /***************************************************************************
199 NdbScanOperation* getScanOperation();
200 
201 Return Value:   Return theOpList : if the  getScanOperation was succesful.
202                 Return NULL : In all other case.
203 Remark:         Get an operation from theScanOpIdleList and return the object .
204 ***************************************************************************/
205 NdbIndexScanOperation*
getScanOperation()206 Ndb::getScanOperation()
207 {
208   return theImpl->theScanOpIdleList.seize(this);
209 }
210 
211 /***************************************************************************
212 NdbIndexOperation* getIndexOperation();
213 
214 Return Value:   Return theOpList : if the  getIndexOperation was succesful.
215                 Return NULL : In all other case.
216 Remark:         Get an operation from theIndexOpIdleList and return the object .
217 ***************************************************************************/
218 NdbIndexOperation*
getIndexOperation()219 Ndb::getIndexOperation()
220 {
221   return theImpl->theIndexOpIdleList.seize(this);
222 }
223 
224 /***************************************************************************
225 NdbRecAttr* getRecAttr();
226 
227 Return Value:   Return a reference to a receive attribute object.
228                 Return NULL if it's not possible to get a receive attribute object.
229 ***************************************************************************/
230 NdbRecAttr*
getRecAttr()231 Ndb::getRecAttr()
232 {
233   NdbRecAttr* tRecAttr = theImpl->theRecAttrIdleList.seize(this);
234   if (tRecAttr != NULL)
235   {
236     tRecAttr->init();
237     return tRecAttr;
238   }
239 
240   return NULL;
241 }
242 
243 /***************************************************************************
244 NdbApiSignal* getSignal();
245 
246 Return Value:   Return a reference to a signal object.
247                 Return NULL if not possible to get a signal object.
248 ***************************************************************************/
249 NdbApiSignal*
getSignal()250 Ndb::getSignal()
251 {
252   return theImpl->theSignalIdleList.seize(this);
253 }
254 
255 NdbBlob*
getNdbBlob()256 Ndb::getNdbBlob()
257 {
258   NdbBlob* tBlob = theImpl->theNdbBlobIdleList.seize(this);
259   if(tBlob)
260   {
261     tBlob->init();
262   }
263   return tBlob;
264 }
265 
266 NdbLockHandle*
getLockHandle()267 Ndb::getLockHandle()
268 {
269   NdbLockHandle* lh = theImpl->theLockHandleList.seize(this);
270   if (lh)
271   {
272     lh->init();
273   }
274 
275   return lh;
276 }
277 
278 /***************************************************************************
279 void releaseNdbBranch(NdbBranch* aNdbBranch);
280 
281 Parameters:     NdbBranch: The NdbBranch object.
282 Remark:         Add a NdbBranch object into the Branch idlelist.
283 ***************************************************************************/
284 void
releaseNdbBranch(NdbBranch * aNdbBranch)285 Ndb::releaseNdbBranch(NdbBranch* aNdbBranch)
286 {
287   theImpl->theBranchList.release(aNdbBranch);
288 }
289 
290 /***************************************************************************
291 void releaseNdbCall(NdbCall* aNdbCall);
292 
293 Parameters:     NdbBranch: The NdbBranch object.
294 Remark:         Add a NdbBranch object into the Branch idlelist.
295 ***************************************************************************/
296 void
releaseNdbCall(NdbCall * aNdbCall)297 Ndb::releaseNdbCall(NdbCall* aNdbCall)
298 {
299   theImpl->theCallList.release(aNdbCall);
300 }
301 
302 /***************************************************************************
303 void releaseNdbCon(NdbTransaction* aNdbCon);
304 
305 Parameters:     aNdbCon: The NdbTransaction object.
306 Remark:         Add a Connection object into the signal idlelist.
307 ***************************************************************************/
308 void
releaseNdbCon(NdbTransaction * aNdbCon)309 Ndb::releaseNdbCon(NdbTransaction* aNdbCon)
310 {
311   aNdbCon->theMagicNumber = 0xFE11DD;
312   theImpl->theConIdleList.release(aNdbCon);
313 }
314 
315 /***************************************************************************
316 void releaseNdbLabel(NdbLabel* aNdbLabel);
317 
318 Parameters:     NdbLabel: The NdbLabel object.
319 Remark:         Add a NdbLabel object into the Label idlelist.
320 ***************************************************************************/
321 void
releaseNdbLabel(NdbLabel * aNdbLabel)322 Ndb::releaseNdbLabel(NdbLabel* aNdbLabel)
323 {
324   theImpl->theLabelList.release(aNdbLabel);
325 }
326 
327 /***************************************************************************
328 void releaseNdbScanRec(NdbScanReceiver* aNdbScanRec);
329 
330 Parameters:     aNdbScanRec: The NdbScanReceiver object.
331 Remark:         Add a NdbScanReceiver object into the Scan idlelist.
332 ***************************************************************************/
333 void
releaseNdbScanRec(NdbReceiver * aNdbScanRec)334 Ndb::releaseNdbScanRec(NdbReceiver* aNdbScanRec)
335 {
336   theImpl->theScanList.release(aNdbScanRec);
337 }
338 
339 /***************************************************************************
340 void releaseNdbSubroutine(NdbSubroutine* aNdbSubroutine);
341 
342 Parameters:     NdbSubroutine: The NdbSubroutine object.
343 Remark:         Add a NdbSubroutine object into theSubroutine idlelist.
344 ***************************************************************************/
345 void
releaseNdbSubroutine(NdbSubroutine * aNdbSubroutine)346 Ndb::releaseNdbSubroutine(NdbSubroutine* aNdbSubroutine)
347 {
348   theImpl->theSubroutineList.release(aNdbSubroutine);
349 }
350 
351 /***************************************************************************
352 void releaseOperation(NdbOperation* anOperation);
353 
354 Parameters:     anOperation : The released NdbOperation object.
355 Remark:         Add a NdbOperation object into the signal idlelist.
356 ***************************************************************************/
357 void
releaseOperation(NdbOperation * anOperation)358 Ndb::releaseOperation(NdbOperation* anOperation)
359 {
360   if(anOperation->m_tcReqGSN == GSN_TCKEYREQ){
361     anOperation->theNdbCon = NULL;
362     anOperation->theMagicNumber = 0xFE11D0;
363     theImpl->theOpIdleList.release(anOperation);
364   } else {
365     assert(anOperation->m_tcReqGSN == GSN_TCINDXREQ);
366     anOperation->theNdbCon = NULL;
367     anOperation->theMagicNumber = 0xFE11D1;
368     theImpl->theIndexOpIdleList.release((NdbIndexOperation*)anOperation);
369   }
370 }
371 
372 /***************************************************************************
373 void releaseScanOperation(NdbScanOperation* aScanOperation);
374 
375 Parameters:     aScanOperation : The released NdbScanOperation object.
376 Remark:         Add a NdbScanOperation object into the signal idlelist.
377 ***************************************************************************/
378 void
releaseScanOperation(NdbIndexScanOperation * aScanOperation)379 Ndb::releaseScanOperation(NdbIndexScanOperation* aScanOperation)
380 {
381   DBUG_ENTER("Ndb::releaseScanOperation");
382   DBUG_PRINT("enter", ("op: 0x%lx", (long) aScanOperation));
383 #ifdef ndb_release_check_dup
384   { NdbIndexScanOperation* tOp = theScanOpIdleList;
385     while (tOp != NULL) {
386       assert(tOp != aScanOperation);
387       tOp = (NdbIndexScanOperation*)tOp->theNext;
388     }
389   }
390 #endif
391   aScanOperation->theNdbCon = NULL;
392   aScanOperation->theMagicNumber = 0xFE11D2;
393   theImpl->theScanOpIdleList.release(aScanOperation);
394   DBUG_VOID_RETURN;
395 }
396 
397 /***************************************************************************
398 void releaseRecAttr(NdbRecAttr* aRecAttr);
399 
400 Parameters:     aRecAttr : The released NdbRecAttr object.
401 Remark:         Add a NdbRecAttr object into the RecAtt idlelist.
402 ***************************************************************************/
403 void
releaseRecAttr(NdbRecAttr * aRecAttr)404 Ndb::releaseRecAttr(NdbRecAttr* aRecAttr)
405 {
406   aRecAttr->release();
407   theImpl->theRecAttrIdleList.release(aRecAttr);
408 }
409 
410 /***************************************************************************
411 void releaseSignal(NdbApiSignal* aSignal);
412 
413 Parameters:     aSignal : The released NdbApiSignal object.
414 Remark:         Add a NdbApiSignal object into the signal idlelist.
415 ***************************************************************************/
416 void
releaseSignal(NdbApiSignal * aSignal)417 Ndb::releaseSignal(NdbApiSignal* aSignal)
418 {
419 #if defined VM_TRACE
420   // Check that signal is not null
421   assert(aSignal != NULL);
422 #if 0
423   // Check that signal is not already in list
424   NdbApiSignal* tmp = theSignalIdleList;
425   while (tmp != NULL){
426     assert(tmp != aSignal);
427     tmp = tmp->next();
428   }
429 #endif
430 #endif
431 #ifdef POORMANSPURIFY
432   creleaseSignals++;
433 #endif
434   theImpl->theSignalIdleList.release(aSignal);
435 }
436 
437 void
releaseSignals(Uint32 cnt,NdbApiSignal * head,NdbApiSignal * tail)438 Ndb::releaseSignals(Uint32 cnt, NdbApiSignal* head, NdbApiSignal* tail)
439 {
440 #ifdef POORMANSPURIFY
441   creleaseSignals += cnt;
442 #endif
443   theImpl->theSignalIdleList.release(cnt, head, tail);
444 }
445 
446 void
releaseSignalsInList(NdbApiSignal ** pList)447 Ndb::releaseSignalsInList(NdbApiSignal** pList){
448   NdbApiSignal* tmp;
449   while (*pList != NULL){
450     tmp = *pList;
451     *pList = (*pList)->next();
452     releaseSignal(tmp);
453   }
454 }
455 
456 void
releaseNdbBlob(NdbBlob * aBlob)457 Ndb::releaseNdbBlob(NdbBlob* aBlob)
458 {
459   aBlob->release();
460   theImpl->theNdbBlobIdleList.release(aBlob);
461 }
462 
463 void
releaseLockHandle(NdbLockHandle * lh)464 Ndb::releaseLockHandle(NdbLockHandle* lh)
465 {
466   lh->release(this);
467   theImpl->theLockHandleList.release(lh);
468 };
469 
470 /****************************************************************************
471 int releaseConnectToNdb(NdbTransaction* aConnectConnection);
472 
473 Return Value:   -1 if error
474 Parameters:     aConnectConnection : Seized schema connection to DBTC
475 Remark:         Release and disconnect from DBTC a connection and seize it to theConIdleList.
476 *****************************************************************************/
477 void
releaseConnectToNdb(NdbTransaction * a_con)478 Ndb::releaseConnectToNdb(NdbTransaction* a_con)
479 {
480   DBUG_ENTER("Ndb::releaseConnectToNdb");
481   NdbApiSignal          tSignal(theMyRef);
482   int                   tConPtr;
483 
484 // I need to close the connection irrespective of whether I
485 // manage to reach NDB or not.
486 
487   if (a_con == NULL)
488     DBUG_VOID_RETURN;
489 
490   Uint32 node_id = a_con->getConnectedNodeId();
491   Uint32 conn_seq = a_con->theNodeSequence;
492   tSignal.setSignal(GSN_TCRELEASEREQ, refToBlock(a_con->m_tcRef));
493   tSignal.setData((tConPtr = a_con->getTC_ConnectPtr()), 1);
494   tSignal.setData(theMyRef, 2);
495   tSignal.setData(a_con->ptr2int(), 3);
496   a_con->Status(NdbTransaction::DisConnecting);
497   a_con->theMagicNumber = a_con->getMagicNumber();
498   int ret_code = sendRecSignal(node_id,
499                                WAIT_TC_RELEASE,
500                                &tSignal,
501                                conn_seq);
502   if (ret_code == 0) {
503     ;
504   } else if (ret_code == -1) {
505     TRACE_DEBUG("Time-out when TCRELEASE sent");
506   } else if (ret_code == -2) {
507     TRACE_DEBUG("Node failed when TCRELEASE sent");
508   } else if (ret_code == -3) {
509     TRACE_DEBUG("Send failed when TCRELEASE sent");
510   } else if (ret_code == -4) {
511     TRACE_DEBUG("Send buffer full when TCRELEASE sent");
512   } else if (ret_code == -5) {
513     TRACE_DEBUG("Node stopping when TCRELEASE sent");
514   } else {
515     ndbout << "Impossible return from sendRecSignal when TCRELEASE" << endl;
516     abort();
517   }//if
518   releaseNdbCon(a_con);
519   DBUG_VOID_RETURN;
520 }
521 
522 template<class T>
523 static
524 Ndb::Free_list_usage*
update(Ndb::Free_list_usage * curr,Ndb_free_list_t<T> & list,const char * name)525 update(Ndb::Free_list_usage* curr,
526        Ndb_free_list_t<T> & list,
527        const char * name)
528 {
529   curr->m_name = name;
530   curr->m_created = list.m_alloc_cnt;
531   curr->m_free = list.m_free_cnt;
532   curr->m_sizeof = sizeof(T);
533   return curr;
534 }
535 
536 Ndb::Free_list_usage*
get_free_list_usage(Ndb::Free_list_usage * curr)537 Ndb::get_free_list_usage(Ndb::Free_list_usage* curr)
538 {
539   if (curr == 0)
540   {
541     return 0;
542   }
543 
544   if(curr->m_name == 0)
545   {
546     update(curr, theImpl->theConIdleList, "NdbTransaction");
547   }
548   else if(!strcmp(curr->m_name, "NdbTransaction"))
549   {
550     update(curr, theImpl->theOpIdleList, "NdbOperation");
551   }
552   else if(!strcmp(curr->m_name, "NdbOperation"))
553   {
554     update(curr, theImpl->theScanOpIdleList, "NdbIndexScanOperation");
555   }
556   else if(!strcmp(curr->m_name, "NdbIndexScanOperation"))
557   {
558     update(curr, theImpl->theIndexOpIdleList, "NdbIndexOperation");
559   }
560   else if(!strcmp(curr->m_name, "NdbIndexOperation"))
561   {
562     update(curr, theImpl->theRecAttrIdleList, "NdbRecAttr");
563   }
564   else if(!strcmp(curr->m_name, "NdbRecAttr"))
565   {
566     update(curr, theImpl->theSignalIdleList, "NdbApiSignal");
567   }
568   else if(!strcmp(curr->m_name, "NdbApiSignal"))
569   {
570     update(curr, theImpl->theLabelList, "NdbLabel");
571   }
572   else if(!strcmp(curr->m_name, "NdbLabel"))
573   {
574     update(curr, theImpl->theBranchList, "NdbBranch");
575   }
576   else if(!strcmp(curr->m_name, "NdbBranch"))
577   {
578     update(curr, theImpl->theSubroutineList, "NdbSubroutine");
579   }
580   else if(!strcmp(curr->m_name, "NdbSubroutine"))
581   {
582     update(curr, theImpl->theCallList, "NdbCall");
583   }
584   else if(!strcmp(curr->m_name, "NdbCall"))
585   {
586     update(curr, theImpl->theNdbBlobIdleList, "NdbBlob");
587   }
588   else if(!strcmp(curr->m_name, "NdbBlob"))
589   {
590     update(curr, theImpl->theScanList, "NdbReceiver");
591   }
592   else if(!strcmp(curr->m_name, "NdbReceiver"))
593   {
594     update(curr, theImpl->theLockHandleList, "NdbLockHandle");
595   }
596   else if(!strcmp(curr->m_name, "NdbLockHandle"))
597   {
598     return 0;
599   }
600   else
601   {
602     update(curr, theImpl->theConIdleList, "NdbTransaction");
603   }
604 
605   return curr;
606 }
607 
608 #define TI(T) \
609  template Ndb::Free_list_usage* \
610  update(Ndb::Free_list_usage*, Ndb_free_list_t<T> &, const char * name);\
611  template struct Ndb_free_list_t<T>
612 
613 TI(NdbBlob);
614 TI(NdbCall);
615 TI(NdbLabel);
616 TI(NdbBranch);
617 TI(NdbSubroutine);
618 TI(NdbApiSignal);
619 TI(NdbRecAttr);
620 TI(NdbOperation);
621 TI(NdbReceiver);
622 TI(NdbConnection);
623 TI(NdbIndexOperation);
624 TI(NdbIndexScanOperation);
625 TI(NdbLockHandle);
626