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