1 /* Copyright (c) 2003, 2021, Oracle and/or its affiliates.
2
3 This program is free software; you can redistribute it and/or modify
4 it under the terms of the GNU General Public License, version 2.0,
5 as published by the Free Software Foundation.
6
7 This program is also distributed with certain software (including
8 but not limited to OpenSSL) that is licensed under separate terms,
9 as designated in a particular file or component or in included license
10 documentation. The authors of MySQL hereby grant you an additional
11 permission to link the program and your derivative works with the
12 separately licensed software that they have included with MySQL.
13
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License, version 2.0, for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
22 */
23
24 #define DBTC_C
25
26 #include "Dbtc.hpp"
27 #include "md5_hash.hpp"
28 #include <RefConvert.hpp>
29 #include <ndb_limits.h>
30 #include <ndb_rand.h>
31
32 #include <signaldata/DiGetNodes.hpp>
33 #include <signaldata/EventReport.hpp>
34 #include <signaldata/TcKeyReq.hpp>
35 #include <signaldata/TcKeyConf.hpp>
36 #include <signaldata/TcKeyRef.hpp>
37 #include <signaldata/KeyInfo.hpp>
38 #include <signaldata/AttrInfo.hpp>
39 #include <signaldata/TransIdAI.hpp>
40 #include <signaldata/TcRollbackRep.hpp>
41 #include <signaldata/NodeFailRep.hpp>
42 #include <signaldata/ReadNodesConf.hpp>
43 #include <signaldata/NFCompleteRep.hpp>
44 #include <signaldata/LqhKey.hpp>
45 #include <signaldata/TcCommit.hpp>
46 #include <signaldata/TcContinueB.hpp>
47 #include <signaldata/TcKeyFailConf.hpp>
48 #include <signaldata/AbortAll.hpp>
49 #include <signaldata/DihScanTab.hpp>
50 #include <signaldata/ScanFrag.hpp>
51 #include <signaldata/ScanTab.hpp>
52 #include <signaldata/PrepDropTab.hpp>
53 #include <signaldata/DropTab.hpp>
54 #include <signaldata/AlterTab.hpp>
55 #include <signaldata/CreateTrig.hpp>
56 #include <signaldata/CreateTrigImpl.hpp>
57 #include <signaldata/DropTrig.hpp>
58 #include <signaldata/DropTrigImpl.hpp>
59 #include <signaldata/FireTrigOrd.hpp>
60 #include <signaldata/TrigAttrInfo.hpp>
61 #include <signaldata/CreateIndx.hpp>
62 #include <signaldata/CreateIndxImpl.hpp>
63 #include <signaldata/DropIndx.hpp>
64 #include <signaldata/DropIndxImpl.hpp>
65 #include <signaldata/AlterIndx.hpp>
66 #include <signaldata/AlterIndxImpl.hpp>
67 #include <signaldata/ScanTab.hpp>
68 #include <signaldata/SystemError.hpp>
69 #include <signaldata/DumpStateOrd.hpp>
70 #include <signaldata/DisconnectRep.hpp>
71 #include <signaldata/TcHbRep.hpp>
72
73 #include <signaldata/PrepDropTab.hpp>
74 #include <signaldata/DropTab.hpp>
75 #include <signaldata/TcIndx.hpp>
76 #include <signaldata/IndxKeyInfo.hpp>
77 #include <signaldata/IndxAttrInfo.hpp>
78 #include <signaldata/PackedSignal.hpp>
79 #include <signaldata/SignalDroppedRep.hpp>
80 #include <signaldata/LqhTransReq.hpp>
81 #include <AttributeHeader.hpp>
82 #include <signaldata/DictTabInfo.hpp>
83 #include <AttributeDescriptor.hpp>
84 #include <SectionReader.hpp>
85 #include <KeyDescriptor.hpp>
86
87 #include <NdbOut.hpp>
88 #include <DebuggerNames.hpp>
89 #include <signaldata/CheckNodeGroups.hpp>
90
91 #include <signaldata/RouteOrd.hpp>
92 #include <signaldata/GCP.hpp>
93
94 #include <signaldata/DbinfoScan.hpp>
95 #include <signaldata/TransIdAI.hpp>
96 #include <signaldata/CreateTab.hpp>
97
98 #include <TransporterRegistry.hpp> // error 8035
99 #include <EventLogger.hpp>
100
101 #include <signaldata/CreateFKImpl.hpp>
102 #include <signaldata/DropFKImpl.hpp>
103 #include <kernel/Interpreter.hpp>
104 #include <signaldata/TuxBound.hpp>
105
106 #define JAM_FILE_ID 353
107
108 #define TC_TIME_SIGNAL_DELAY 50
109
110 extern EventLogger * g_eventLogger;
111
112 // Use DEBUG to print messages that should be
113 // seen only when we debug the product
114 #ifdef VM_TRACE
115 #define DEBUG(x) ndbout << "DBTC: "<< x << endl;
116 #else
117 #define DEBUG(x)
118 #endif
119
120 #define INTERNAL_TRIGGER_TCKEYREQ_JBA 0
121
122 #ifdef VM_TRACE
123 NdbOut &
operator <<(NdbOut & out,Dbtc::ConnectionState state)124 operator<<(NdbOut& out, Dbtc::ConnectionState state){
125 switch(state){
126 case Dbtc::CS_CONNECTED: out << "CS_CONNECTED"; break;
127 case Dbtc::CS_DISCONNECTED: out << "CS_DISCONNECTED"; break;
128 case Dbtc::CS_STARTED: out << "CS_STARTED"; break;
129 case Dbtc::CS_RECEIVING: out << "CS_RECEIVING"; break;
130 case Dbtc::CS_RESTART: out << "CS_RESTART"; break;
131 case Dbtc::CS_ABORTING: out << "CS_ABORTING"; break;
132 case Dbtc::CS_COMPLETING: out << "CS_COMPLETING"; break;
133 case Dbtc::CS_COMPLETE_SENT: out << "CS_COMPLETE_SENT"; break;
134 case Dbtc::CS_PREPARE_TO_COMMIT: out << "CS_PREPARE_TO_COMMIT"; break;
135 case Dbtc::CS_COMMIT_SENT: out << "CS_COMMIT_SENT"; break;
136 case Dbtc::CS_START_COMMITTING: out << "CS_START_COMMITTING"; break;
137 case Dbtc::CS_COMMITTING: out << "CS_COMMITTING"; break;
138 case Dbtc::CS_REC_COMMITTING: out << "CS_REC_COMMITTING"; break;
139 case Dbtc::CS_WAIT_ABORT_CONF: out << "CS_WAIT_ABORT_CONF"; break;
140 case Dbtc::CS_WAIT_COMPLETE_CONF: out << "CS_WAIT_COMPLETE_CONF"; break;
141 case Dbtc::CS_WAIT_COMMIT_CONF: out << "CS_WAIT_COMMIT_CONF"; break;
142 case Dbtc::CS_FAIL_ABORTING: out << "CS_FAIL_ABORTING"; break;
143 case Dbtc::CS_FAIL_ABORTED: out << "CS_FAIL_ABORTED"; break;
144 case Dbtc::CS_FAIL_PREPARED: out << "CS_FAIL_PREPARED"; break;
145 case Dbtc::CS_FAIL_COMMITTING: out << "CS_FAIL_COMMITTING"; break;
146 case Dbtc::CS_FAIL_COMMITTED: out << "CS_FAIL_COMMITTED"; break;
147 case Dbtc::CS_FAIL_COMPLETED: out << "CS_FAIL_COMPLETED"; break;
148 case Dbtc::CS_START_SCAN: out << "CS_START_SCAN"; break;
149 default:
150 out << "Unknown: " << (int)state; break;
151 }
152 return out;
153 }
154 NdbOut &
operator <<(NdbOut & out,Dbtc::OperationState state)155 operator<<(NdbOut& out, Dbtc::OperationState state){
156 out << (int)state;
157 return out;
158 }
159 NdbOut &
operator <<(NdbOut & out,Dbtc::AbortState state)160 operator<<(NdbOut& out, Dbtc::AbortState state){
161 out << (int)state;
162 return out;
163 }
164 NdbOut &
operator <<(NdbOut & out,Dbtc::ReturnSignal state)165 operator<<(NdbOut& out, Dbtc::ReturnSignal state){
166 out << (int)state;
167 return out;
168 }
169 NdbOut &
operator <<(NdbOut & out,Dbtc::ScanRecord::ScanState state)170 operator<<(NdbOut& out, Dbtc::ScanRecord::ScanState state){
171 out << (int)state;
172 return out;
173 }
174 NdbOut &
operator <<(NdbOut & out,Dbtc::ScanFragRec::ScanFragState state)175 operator<<(NdbOut& out, Dbtc::ScanFragRec::ScanFragState state){
176 out << (int)state;
177 return out;
178 }
179 #endif
180
181 extern int ErrorSignalReceive;
182 extern int ErrorMaxSegmentsToSeize;
183
184 void
updateBuddyTimer(ApiConnectRecordPtr apiPtr)185 Dbtc::updateBuddyTimer(ApiConnectRecordPtr apiPtr)
186 {
187 if (apiPtr.p->buddyPtr != RNIL) {
188 jam();
189 ApiConnectRecordPtr buddyApiPtr;
190 buddyApiPtr.i = apiPtr.p->buddyPtr;
191 ptrCheckGuard(buddyApiPtr, capiConnectFilesize, apiConnectRecord);
192 if (getApiConTimer(buddyApiPtr.i) != 0) {
193 if ((apiPtr.p->transid[0] == buddyApiPtr.p->transid[0]) &&
194 (apiPtr.p->transid[1] == buddyApiPtr.p->transid[1])) {
195 jam();
196 setApiConTimer(buddyApiPtr.i, ctcTimer, __LINE__);
197 } else {
198 jam();
199 // Not a buddy anymore since not the same transid
200 apiPtr.p->buddyPtr = RNIL;
201 }//if
202 }//if
203 }//if
204 }
205
206 static
207 inline
208 bool
tc_testbit(Uint32 flags,Uint32 flag)209 tc_testbit(Uint32 flags, Uint32 flag)
210 {
211 return (flags & flag) != 0;
212 }
213
214 static
215 inline
216 void
tc_clearbit(Uint32 & flags,Uint32 flag)217 tc_clearbit(Uint32 & flags, Uint32 flag)
218 {
219 flags &= ~(Uint32)flag;
220 }
221
execCONTINUEB(Signal * signal)222 void Dbtc::execCONTINUEB(Signal* signal)
223 {
224 UintR tcase;
225
226 jamEntry();
227 tcase = signal->theData[0];
228 UintR Tdata0 = signal->theData[1];
229 UintR Tdata1 = signal->theData[2];
230 UintR Tdata2 = signal->theData[3];
231 UintR Tdata3 = signal->theData[4];
232 #ifdef ERROR_INSERT
233 UintR Tdata4 = signal->theData[5];
234 UintR Tdata5 = signal->theData[6];
235 #endif
236 switch (tcase) {
237 case TcContinueB::ZRETURN_FROM_QUEUED_DELIVERY:
238 jam();
239 ndbrequire(false);
240 return;
241 case TcContinueB::ZCOMPLETE_TRANS_AT_TAKE_OVER:
242 jam();
243 tcNodeFailptr.i = Tdata0;
244 ptrCheckGuard(tcNodeFailptr, 1, tcFailRecord);
245 completeTransAtTakeOverLab(signal, Tdata1);
246 return;
247 case TcContinueB::ZCONTINUE_TIME_OUT_CONTROL:
248 jam();
249 timeOutLoopStartLab(signal, Tdata0);
250 return;
251 case TcContinueB::ZNODE_TAKE_OVER_COMPLETED:
252 jam();
253 tcNodeFailptr.i = 0;
254 ptrAss(tcNodeFailptr, tcFailRecord);
255 nodeTakeOverCompletedLab(signal, Tdata0, 0);
256 return;
257 case TcContinueB::ZINITIALISE_RECORDS:
258 jam();
259 initialiseRecordsLab(signal, Tdata0, Tdata2, Tdata3);
260 return;
261 case TcContinueB::ZSEND_COMMIT_LOOP:
262 jam();
263 apiConnectptr.i = Tdata0;
264 ptrCheckGuard(apiConnectptr, capiConnectFilesize, apiConnectRecord);
265 tcConnectptr.i = Tdata1;
266 ptrCheckGuard(tcConnectptr, ctcConnectFilesize, tcConnectRecord);
267 commit020Lab(signal);
268 return;
269 case TcContinueB::ZSEND_COMPLETE_LOOP:
270 jam();
271 apiConnectptr.i = Tdata0;
272 ptrCheckGuard(apiConnectptr, capiConnectFilesize, apiConnectRecord);
273 tcConnectptr.i = Tdata1;
274 ptrCheckGuard(tcConnectptr, ctcConnectFilesize, tcConnectRecord);
275 complete010Lab(signal);
276 return;
277 case TcContinueB::ZHANDLE_FAILED_API_NODE:
278 jam();
279 handleFailedApiNode(signal, Tdata0, Tdata1);
280 return;
281 case TcContinueB::ZTRANS_EVENT_REP:
282 jam();
283 /* Send transaction counters report */
284 {
285 const Uint32 len = c_counters.build_event_rep(signal);
286 sendSignal(CMVMI_REF, GSN_EVENT_REP, signal, len, JBB);
287 }
288
289 {
290 const Uint32 report_interval = 5000;
291 const Uint32 len = c_counters.build_continueB(signal);
292 signal->theData[0] = TcContinueB::ZTRANS_EVENT_REP;
293 sendSignalWithDelay(cownref, GSN_CONTINUEB, signal, report_interval, len);
294 }
295 return;
296 case TcContinueB::ZCONTINUE_TIME_OUT_FRAG_CONTROL:
297 jam();
298 timeOutLoopStartFragLab(signal, Tdata0);
299 return;
300 case TcContinueB::ZABORT_BREAK:
301 jam();
302 tcConnectptr.i = Tdata0;
303 apiConnectptr.i = Tdata1;
304 ptrCheckGuard(apiConnectptr, capiConnectFilesize, apiConnectRecord);
305 apiConnectptr.p->counter--;
306 abort015Lab(signal);
307 return;
308 case TcContinueB::ZABORT_TIMEOUT_BREAK:
309 jam();
310 tcConnectptr.i = Tdata0;
311 apiConnectptr.i = Tdata1;
312 ptrCheckGuard(apiConnectptr, capiConnectFilesize, apiConnectRecord);
313 apiConnectptr.p->counter--;
314 sendAbortedAfterTimeout(signal, 1);
315 return;
316 case TcContinueB::ZHANDLE_FAILED_API_NODE_REMOVE_MARKERS:
317 jam();
318 removeMarkerForFailedAPI(signal, Tdata0, Tdata1);
319 return;
320 case TcContinueB::ZWAIT_ABORT_ALL:
321 jam();
322 checkAbortAllTimeout(signal, Tdata0);
323 return;
324 case TcContinueB::ZCHECK_SCAN_ACTIVE_FAILED_LQH:
325 jam();
326 checkScanActiveInFailedLqh(signal, Tdata0, Tdata1);
327 return;
328 case TcContinueB::ZNF_CHECK_TRANSACTIONS:
329 jam();
330 nodeFailCheckTransactions(signal, Tdata0, Tdata1);
331 return;
332 case TcContinueB::TRIGGER_PENDING:
333 {
334 jam();
335 ApiConnectRecordPtr transPtr;
336 transPtr.i = Tdata0;
337 ptrCheckGuard(transPtr, capiConnectFilesize, apiConnectRecord);
338 #ifdef ERROR_INSERT
339 if (ERROR_INSERTED(8082))
340 {
341 /* Max of 100000 TRIGGER_PENDING TcContinueBs to
342 * single ApiConnectRecord
343 * See testBlobs -bug 45768
344 */
345 if (++transPtr.p->continueBCount > 100000)
346 {
347 ndbrequire(false);
348 }
349 }
350 #endif
351 /* Check that ConnectRecord is for the same Trans Id */
352 if (likely((transPtr.p->transid[0] == Tdata1) &&
353 (transPtr.p->transid[1] == Tdata2)))
354 {
355 ndbrequire(tc_testbit(transPtr.p->m_flags,
356 ApiConnectRecord::TF_TRIGGER_PENDING));
357 tc_clearbit(transPtr.p->m_flags, ApiConnectRecord::TF_TRIGGER_PENDING);
358 /* Try executing triggers now */
359 executeTriggers(signal, &transPtr);
360 }
361 return;
362 }
363 case TcContinueB::DelayTCKEYCONF:
364 jam();
365 apiConnectptr.i = Tdata0;
366 ptrCheckGuard(apiConnectptr, capiConnectFilesize, apiConnectRecord);
367 sendtckeyconf(signal, Tdata1);
368 return;
369 case TcContinueB::ZSEND_FIRE_TRIG_REQ:
370 jam();
371 apiConnectptr.i = Tdata0;
372 ptrCheckGuard(apiConnectptr, capiConnectFilesize, apiConnectRecord);
373 if (unlikely(! (apiConnectptr.p->transid[0] == Tdata1 &&
374 apiConnectptr.p->transid[1] == Tdata2 &&
375 apiConnectptr.p->apiConnectstate == CS_SEND_FIRE_TRIG_REQ)))
376 {
377 warningReport(signal, 29);
378 return;
379 }
380 ndbrequire(apiConnectptr.p->lqhkeyreqrec > 0);
381 apiConnectptr.p->lqhkeyreqrec--; // UNDO: prevent early completion
382
383 sendFireTrigReq(signal, apiConnectptr,
384 signal->theData[4],
385 signal->theData[5]);
386 return;
387 case TcContinueB::ZSTART_FRAG_SCANS:
388 {
389 jam();
390 SectionHandle handle(this, signal);
391 startFragScansLab(signal, Tdata0, handle, Tdata1);
392 return;
393 }
394 #ifdef ERROR_INSERT
395 case TcContinueB::ZDEBUG_DELAYED_ABORT:
396 {
397 char buf[128];
398 BaseString::snprintf(buf, sizeof(buf), "Received CONTINUEB:ZDEBUG_DELAYED_ABORT");
399 warningEvent("%s", buf);
400
401 jam();
402 apiConnectptr.i = Tdata0;
403 ptrCheckGuard(apiConnectptr, capiConnectFilesize, apiConnectRecord);
404 apiConnectptr.p->returncode = Tdata3;
405 apiConnectptr.p->returnsignal = (Dbtc::ReturnSignal)Tdata4;
406 SET_ERROR_INSERT_VALUE(Tdata5);
407 abort010Lab(signal);
408 break;
409 }
410 case TcContinueB::ZDEBUG_DELAY_TCROLLBACKREP:
411 {
412 char buf[128];
413 BaseString::snprintf(buf, sizeof(buf), "Received CONTINUEB:ZDEBUG_DELAY_TCROLLBACKREP");
414 warningEvent("%s", buf);
415
416 jam();
417 if (ERROR_INSERTED(8101))
418 {
419 jam();
420 sendSignalWithDelay(reference(), GSN_CONTINUEB, signal, 100, 6);
421 }
422 else
423 {
424 TcRollbackRep * const tcRollbackRep =
425 (TcRollbackRep *) signal->getDataPtr();
426 Uint32 blockRef = Tdata5;
427
428 tcRollbackRep->connectPtr = Tdata0;
429 tcRollbackRep->transId[0] = Tdata1;
430 tcRollbackRep->transId[1] = Tdata2;
431 tcRollbackRep->returnCode = Tdata3;
432 tcRollbackRep->errorData = Tdata4;
433 sendSignal(blockRef, GSN_TCROLLBACKREP, signal,
434 TcRollbackRep::SignalLength, JBB);
435 }
436 break;
437 }
438 #endif
439 default:
440 ndbrequire(false);
441 }//switch
442 }
443
execDIGETNODESREF(Signal * signal)444 void Dbtc::execDIGETNODESREF(Signal* signal)
445 {
446 jamEntry();
447 terrorCode = signal->theData[1];
448 releaseAtErrorLab(signal);
449 }
450
execINCL_NODEREQ(Signal * signal)451 void Dbtc::execINCL_NODEREQ(Signal* signal)
452 {
453 jamEntry();
454 tblockref = signal->theData[0];
455 hostptr.i = signal->theData[1];
456 ptrCheckGuard(hostptr, chostFilesize, hostRecord);
457 hostptr.p->hostStatus = HS_ALIVE;
458 c_alive_nodes.set(hostptr.i);
459
460 signal->theData[0] = hostptr.i;
461 signal->theData[1] = cownref;
462
463 if (ERROR_INSERTED(8039))
464 {
465 CLEAR_ERROR_INSERT_VALUE;
466 Uint32 save = signal->theData[0];
467 signal->theData[0] = 9999;
468 sendSignal(numberToRef(CMVMI, hostptr.i),
469 GSN_NDB_TAMPER, signal, 1, JBB);
470 signal->theData[0] = save;
471 sendSignalWithDelay(tblockref, GSN_INCL_NODECONF, signal, 5000, 2);
472 return;
473 }
474
475 Uint32 Tnode = hostptr.i;
476
477 sendSignal(tblockref, GSN_INCL_NODECONF, signal, 2, JBB);
478
479 if (m_deferred_enabled)
480 {
481 jam();
482 if (!ndbd_deferred_unique_constraints(getNodeInfo(Tnode).m_version))
483 {
484 jam();
485 m_deferred_enabled = 0;
486 }
487 }
488 }
489
execREAD_NODESREF(Signal * signal)490 void Dbtc::execREAD_NODESREF(Signal* signal)
491 {
492 jamEntry();
493 ndbrequire(false);
494 }
495
496 // create table prepare
execTC_SCHVERREQ(Signal * signal)497 void Dbtc::execTC_SCHVERREQ(Signal* signal)
498 {
499 jamEntry();
500 if (! assembleFragments(signal)) {
501 jam();
502 return;
503 }
504 const TcSchVerReq* req = CAST_CONSTPTR(TcSchVerReq, signal->getDataPtr());
505 tabptr.i = req->tableId;
506 ptrCheckGuard(tabptr, ctabrecFilesize, tableRecord);
507 tabptr.p->currentSchemaVersion = req->tableVersion;
508 tabptr.p->m_flags = 0;
509 tabptr.p->set_storedTable((bool)req->tableLogged);
510 BlockReference retRef = req->senderRef;
511 tabptr.p->tableType = (Uint8)req->tableType;
512 BlockReference retPtr = req->senderData;
513 Uint32 noOfKeyAttr = req->noOfPrimaryKeys;
514 tabptr.p->singleUserMode = (Uint8)req->singleUserMode;
515 Uint32 userDefinedPartitioning = (Uint8)req->userDefinedPartition;
516 ndbrequire(noOfKeyAttr <= MAX_ATTRIBUTES_IN_INDEX);
517
518 const KeyDescriptor* desc = g_key_descriptor_pool.getPtr(tabptr.i);
519 ndbrequire(noOfKeyAttr == desc->noOfKeyAttr);
520
521 ndbrequire(tabptr.p->get_prepared() == false);
522 ndbrequire(tabptr.p->get_enabled() == false);
523 tabptr.p->set_prepared(true);
524 tabptr.p->set_enabled(false);
525 tabptr.p->set_dropping(false);
526 tabptr.p->noOfKeyAttr = desc->noOfKeyAttr;
527 tabptr.p->hasCharAttr = desc->hasCharAttr;
528 tabptr.p->noOfDistrKeys = desc->noOfDistrKeys;
529 tabptr.p->hasVarKeys = desc->noOfVarKeys > 0;
530 tabptr.p->set_user_defined_partitioning(userDefinedPartitioning);
531
532 TcSchVerConf * conf = (TcSchVerConf*)signal->getDataPtr();
533 conf->senderRef = reference();
534 conf->senderData = retPtr;
535 sendSignal(retRef, GSN_TC_SCHVERCONF, signal,
536 TcSchVerConf::SignalLength, JBB);
537 }//Dbtc::execTC_SCHVERREQ()
538
539 // create table commit
execTAB_COMMITREQ(Signal * signal)540 void Dbtc::execTAB_COMMITREQ(Signal* signal)
541 {
542 jamEntry();
543 Uint32 senderData = signal->theData[0];
544 Uint32 senderRef = signal->theData[1];
545 tabptr.i = signal->theData[2];
546 ptrCheckGuard(tabptr, ctabrecFilesize, tableRecord);
547
548 ndbrequire(tabptr.p->get_prepared() == true);
549 ndbrequire(tabptr.p->get_enabled() == false);
550 tabptr.p->set_enabled(true);
551 tabptr.p->set_prepared(false);
552 tabptr.p->set_dropping(false);
553
554 signal->theData[0] = senderData;
555 signal->theData[1] = reference();
556 signal->theData[2] = tabptr.i;
557 sendSignal(senderRef, GSN_TAB_COMMITCONF, signal, 3, JBB);
558 }
559
560 void
execPREP_DROP_TAB_REQ(Signal * signal)561 Dbtc::execPREP_DROP_TAB_REQ(Signal* signal)
562 {
563 jamEntry();
564
565 PrepDropTabReq* req = (PrepDropTabReq*)signal->getDataPtr();
566
567 TableRecordPtr tabPtr;
568 tabPtr.i = req->tableId;
569 ptrCheckGuard(tabPtr, ctabrecFilesize, tableRecord);
570
571 Uint32 senderRef = req->senderRef;
572 Uint32 senderData = req->senderData;
573
574 if(!tabPtr.p->get_enabled())
575 {
576 jam();
577 PrepDropTabRef* ref = (PrepDropTabRef*)signal->getDataPtrSend();
578 ref->senderRef = reference();
579 ref->senderData = senderData;
580 ref->tableId = tabPtr.i;
581 ref->errorCode = PrepDropTabRef::NoSuchTable;
582 sendSignal(senderRef, GSN_PREP_DROP_TAB_REF, signal,
583 PrepDropTabRef::SignalLength, JBB);
584 return;
585 }
586
587 if(tabPtr.p->get_dropping())
588 {
589 jam();
590 PrepDropTabRef* ref = (PrepDropTabRef*)signal->getDataPtrSend();
591 ref->senderRef = reference();
592 ref->senderData = senderData;
593 ref->tableId = tabPtr.i;
594 ref->errorCode = PrepDropTabRef::DropInProgress;
595 sendSignal(senderRef, GSN_PREP_DROP_TAB_REF, signal,
596 PrepDropTabRef::SignalLength, JBB);
597 return;
598 }
599
600 tabPtr.p->set_dropping(true);
601 tabPtr.p->set_prepared(false);
602
603 PrepDropTabConf* conf = (PrepDropTabConf*)signal->getDataPtrSend();
604 conf->tableId = tabPtr.i;
605 conf->senderRef = reference();
606 conf->senderData = senderData;
607 sendSignal(senderRef, GSN_PREP_DROP_TAB_CONF, signal,
608 PrepDropTabConf::SignalLength, JBB);
609 }
610
611 void
execDROP_TAB_REQ(Signal * signal)612 Dbtc::execDROP_TAB_REQ(Signal* signal)
613 {
614 jamEntry();
615
616 DropTabReq* req = (DropTabReq*)signal->getDataPtr();
617
618 TableRecordPtr tabPtr;
619 tabPtr.i = req->tableId;
620 ptrCheckGuard(tabPtr, ctabrecFilesize, tableRecord);
621
622 Uint32 senderRef = req->senderRef;
623 Uint32 senderData = req->senderData;
624 DropTabReq::RequestType rt = (DropTabReq::RequestType)req->requestType;
625
626 if(!tabPtr.p->get_enabled() && rt == DropTabReq::OnlineDropTab){
627 jam();
628 DropTabRef* ref = (DropTabRef*)signal->getDataPtrSend();
629 ref->senderRef = reference();
630 ref->senderData = senderData;
631 ref->tableId = tabPtr.i;
632 ref->errorCode = DropTabRef::NoSuchTable;
633 sendSignal(senderRef, GSN_DROP_TAB_REF, signal,
634 DropTabRef::SignalLength, JBB);
635 return;
636 }
637
638 if(!tabPtr.p->get_dropping() && rt == DropTabReq::OnlineDropTab){
639 jam();
640 DropTabRef* ref = (DropTabRef*)signal->getDataPtrSend();
641 ref->senderRef = reference();
642 ref->senderData = senderData;
643 ref->tableId = tabPtr.i;
644 ref->errorCode = DropTabRef::DropWoPrep;
645 sendSignal(senderRef, GSN_DROP_TAB_REF, signal,
646 DropTabRef::SignalLength, JBB);
647 return;
648 }
649
650 tabPtr.p->set_enabled(false);
651 tabPtr.p->set_prepared(false);
652 tabPtr.p->set_dropping(false);
653
654 DropTabConf * conf = (DropTabConf*)signal->getDataPtrSend();
655 conf->tableId = tabPtr.i;
656 conf->senderRef = reference();
657 conf->senderData = senderData;
658 sendSignal(senderRef, GSN_DROP_TAB_CONF, signal,
659 PrepDropTabConf::SignalLength, JBB);
660 }
661
execALTER_TAB_REQ(Signal * signal)662 void Dbtc::execALTER_TAB_REQ(Signal * signal)
663 {
664 const AlterTabReq* req = (const AlterTabReq*)signal->getDataPtr();
665 const Uint32 senderRef = req->senderRef;
666 const Uint32 senderData = req->senderData;
667 const Uint32 tableVersion = req->tableVersion;
668 const Uint32 newTableVersion = req->newTableVersion;
669 AlterTabReq::RequestType requestType =
670 (AlterTabReq::RequestType) req->requestType;
671
672 TableRecordPtr tabPtr;
673 tabPtr.i = req->tableId;
674 ptrCheckGuard(tabPtr, ctabrecFilesize, tableRecord);
675
676 switch (requestType) {
677 case AlterTabReq::AlterTablePrepare:
678 jam();
679 break;
680 case AlterTabReq::AlterTableRevert:
681 jam();
682 tabPtr.p->currentSchemaVersion = tableVersion;
683 break;
684 case AlterTabReq::AlterTableCommit:
685 jam();
686 tabPtr.p->currentSchemaVersion = newTableVersion;
687 break;
688 default:
689 ndbrequire(false);
690 break;
691 }
692
693 // Request handled successfully
694 AlterTabConf* conf = (AlterTabConf*)signal->getDataPtrSend();
695 conf->senderRef = reference();
696 conf->senderData = senderData;
697 conf->connectPtr = RNIL;
698 sendSignal(senderRef, GSN_ALTER_TAB_CONF, signal,
699 AlterTabConf::SignalLength, JBB);
700 }
701
702 /* ***************************************************************************/
703 /* START / RESTART */
704 /* ***************************************************************************/
execREAD_CONFIG_REQ(Signal * signal)705 void Dbtc::execREAD_CONFIG_REQ(Signal* signal)
706 {
707 const ReadConfigReq * req = (ReadConfigReq*)signal->getDataPtr();
708 Uint32 ref = req->senderRef;
709 Uint32 senderData = req->senderData;
710 ndbrequire(req->noOfParameters == 0);
711
712 jamEntry();
713
714 const ndb_mgm_configuration_iterator * p =
715 m_ctx.m_config.getOwnConfigIterator();
716 ndbrequire(p != 0);
717
718 initData();
719
720 UintR apiConnect;
721 UintR tcConnect;
722 UintR tables;
723 UintR localScan;
724 UintR tcScan;
725
726 ndbrequire(!ndb_mgm_get_int_parameter(p, CFG_TC_API_CONNECT, &apiConnect));
727 ndbrequire(!ndb_mgm_get_int_parameter(p, CFG_TC_TC_CONNECT, &tcConnect));
728 ndbrequire(!ndb_mgm_get_int_parameter(p, CFG_TC_TABLE, &tables));
729 ndbrequire(!ndb_mgm_get_int_parameter(p, CFG_TC_LOCAL_SCAN, &localScan));
730 ndbrequire(!ndb_mgm_get_int_parameter(p, CFG_TC_SCAN, &tcScan));
731
732 ccacheFilesize = (apiConnect/3) + 1;
733 capiConnectFilesize = apiConnect;
734 ctcConnectFilesize = tcConnect;
735 ctabrecFilesize = tables;
736 cscanrecFileSize = tcScan;
737 cscanFragrecFileSize = localScan;
738
739 initRecords();
740 initialiseRecordsLab(signal, 0, ref, senderData);
741
742 Uint32 val = 3000;
743 ndb_mgm_get_int_parameter(p, CFG_DB_TRANSACTION_DEADLOCK_TIMEOUT, &val);
744 set_timeout_value(val);
745
746 val = 1500;
747 ndb_mgm_get_int_parameter(p, CFG_DB_HEARTBEAT_INTERVAL, &val);
748 cDbHbInterval = (val < 10) ? 10 : val;
749
750 val = 3000;
751 ndb_mgm_get_int_parameter(p, CFG_DB_TRANSACTION_INACTIVE_TIMEOUT, &val);
752 set_appl_timeout_value(val);
753
754 val = 1;
755 //ndb_mgm_get_int_parameter(p, CFG_DB_PARALLEL_TRANSACTION_TAKEOVER, &val);
756 set_no_parallel_takeover(val);
757
758 val = ~(Uint32)0;
759 ndb_mgm_get_int_parameter(p, CFG_DB_MAX_DML_OPERATIONS_PER_TRANSACTION, &val);
760 m_max_writes_per_trans = val;
761
762 ctimeOutCheckDelay = 50; // 500ms
763 ctimeOutCheckDelayScan = 40; // 400ms
764
765 Pool_context pc;
766 pc.m_block = this;
767
768 c_fk_hash.setSize(16);
769 c_fk_pool.init(RT_DBDICT_FILE, pc); // TODO
770 }
771
execSTTOR(Signal * signal)772 void Dbtc::execSTTOR(Signal* signal)
773 {
774 Uint16 tphase;
775
776 jamEntry();
777 /* START CASE */
778 tphase = signal->theData[1];
779 csignalKey = signal->theData[6];
780 c_sttor_ref = signal->getSendersBlockRef();
781 switch (tphase) {
782 case ZSPH1:
783 jam();
784 startphase1x010Lab(signal);
785 return;
786 default:
787 jam();
788 sttorryLab(signal); /* START PHASE 255 */
789 return;
790 }//switch
791 }//Dbtc::execSTTOR()
792
sttorryLab(Signal * signal)793 void Dbtc::sttorryLab(Signal* signal)
794 {
795 signal->theData[0] = csignalKey;
796 signal->theData[1] = 3; /* BLOCK CATEGORY */
797 signal->theData[2] = 2; /* SIGNAL VERSION NUMBER */
798 signal->theData[3] = ZSPH1;
799 signal->theData[4] = 255;
800 sendSignal(c_sttor_ref, GSN_STTORRY, signal, 5, JBB);
801 }//Dbtc::sttorryLab()
802
803 /* ***************************************************************************/
804 /* INTERNAL START / RESTART */
805 /*****************************************************************************/
execNDB_STTOR(Signal * signal)806 void Dbtc::execNDB_STTOR(Signal* signal)
807 {
808 Uint16 tndbstartphase;
809 Uint16 tstarttype;
810
811 jamEntry();
812 tusersblkref = signal->theData[0];
813 NodeId nodeId = signal->theData[1];
814 tndbstartphase = signal->theData[2]; /* START PHASE */
815 tstarttype = signal->theData[3]; /* START TYPE */
816 c_sttor_ref = signal->getSendersBlockRef();
817 switch (tndbstartphase) {
818 case ZINTSPH1:
819 jam();
820 intstartphase1x010Lab(signal, nodeId);
821 return;
822 case ZINTSPH2:
823 jam();
824 ndbsttorry010Lab(signal);
825 return;
826 case ZINTSPH3:
827 {
828 jam();
829 intstartphase3x010Lab(signal);
830
831 /* Start transaction counters event reporting. */
832 const Uint32 len = c_counters.build_continueB(signal);
833 signal->theData[0] = TcContinueB::ZTRANS_EVENT_REP;
834 sendSignalWithDelay(cownref, GSN_CONTINUEB, signal, 10, len);
835 return;
836 }
837 case ZINTSPH6:
838 {
839 jam();
840 c_elapsed_time_millis = 0;
841 init_elapsed_time(signal, c_latestTIME_SIGNAL);
842 break;
843 }
844 default:
845 jam();
846 break;
847 }//switch
848 ndbsttorry010Lab(signal);
849 return;
850 }//Dbtc::execNDB_STTOR()
851
ndbsttorry010Lab(Signal * signal)852 void Dbtc::ndbsttorry010Lab(Signal* signal)
853 {
854 signal->theData[0] = cownref;
855 sendSignal(c_sttor_ref, GSN_NDB_STTORRY, signal, 1, JBB);
856 }//Dbtc::ndbsttorry010Lab()
857
858 void
set_timeout_value(Uint32 timeOut)859 Dbtc::set_timeout_value(Uint32 timeOut)
860 {
861 timeOut = timeOut / 10;
862 if (timeOut < 2) {
863 jam();
864 timeOut = 100;
865 }//if
866 ctimeOutValue = timeOut;
867 }
868
869 void
set_appl_timeout_value(Uint32 timeOut)870 Dbtc::set_appl_timeout_value(Uint32 timeOut)
871 {
872 if (timeOut)
873 {
874 timeOut /= 10;
875 if (timeOut < ctimeOutValue) {
876 jam();
877 c_appl_timeout_value = ctimeOutValue;
878 }//if
879 }
880 c_appl_timeout_value = timeOut;
881 }
882
883 void
set_no_parallel_takeover(Uint32 noParallelTakeOver)884 Dbtc::set_no_parallel_takeover(Uint32 noParallelTakeOver)
885 {
886 if (noParallelTakeOver == 0) {
887 jam();
888 noParallelTakeOver = 1;
889 } else if (noParallelTakeOver > MAX_NDB_NODES) {
890 jam();
891 noParallelTakeOver = MAX_NDB_NODES;
892 }//if
893 cnoParallelTakeOver = noParallelTakeOver;
894 }
895
896 /* ***************************************************************************/
897 /* S T A R T P H A S E 1 X */
898 /* INITIALISE BLOCKREF AND BLOCKNUMBERS */
899 /* ***************************************************************************/
startphase1x010Lab(Signal * signal)900 void Dbtc::startphase1x010Lab(Signal* signal)
901 {
902 ctimeOutCheckCounter = 0;
903 ctimeOutCheckFragCounter = 0;
904 ctimeOutMissedHeartbeats = 0;
905 ctimeOutCheckHeartbeat = 0;
906 ctimeOutCheckLastHeartbeat = 0;
907 ctimeOutMissedHeartbeatsScan = 0;
908 ctimeOutCheckHeartbeatScan = 0;
909 ctimeOutCheckLastHeartbeatScan = 0;
910 ctimeOutCheckActive = TOCS_FALSE;
911 ctimeOutCheckFragActive = TOCS_FALSE;
912 sttorryLab(signal);
913 }//Dbtc::startphase1x010Lab()
914
915 /*****************************************************************************/
916 /* I N T S T A R T P H A S E 1 X */
917 /* INITIALISE ALL RECORDS. */
918 /*****************************************************************************/
intstartphase1x010Lab(Signal * signal,NodeId nodeId)919 void Dbtc::intstartphase1x010Lab(Signal* signal, NodeId nodeId)
920 {
921 cownNodeid = nodeId;
922 cownref = reference();
923 clqhblockref = calcLqhBlockRef(cownNodeid);
924 cdihblockref = calcDihBlockRef(cownNodeid);
925 cdictblockref = calcDictBlockRef(cownNodeid);
926 cndbcntrblockref = calcNdbCntrBlockRef(cownNodeid);
927 cerrorBlockref = calcNdbCntrBlockRef(cownNodeid);
928 coperationsize = 0;
929 cfailure_nr = 0;
930 ndbsttorry010Lab(signal);
931 }//Dbtc::intstartphase1x010Lab()
932
933 /*****************************************************************************/
934 /* I N T S T A R T P H A S E 3 X */
935 /*****************************************************************************/
intstartphase3x010Lab(Signal * signal)936 void Dbtc::intstartphase3x010Lab(Signal* signal)
937 {
938 signal->theData[0] = cownref;
939 sendSignal(cndbcntrblockref, GSN_READ_NODESREQ, signal, 1, JBB);
940 }//Dbtc::intstartphase3x010Lab()
941
execREAD_NODESCONF(Signal * signal)942 void Dbtc::execREAD_NODESCONF(Signal* signal)
943 {
944 UintR guard0;
945
946 jamEntry();
947
948 ReadNodesConf * const readNodes = (ReadNodesConf *)&signal->theData[0];
949
950 csystemnodes = readNodes->noOfNodes;
951 cmasterNodeId = readNodes->masterNodeId;
952
953 con_lineNodes = 0;
954 arrGuard(csystemnodes, MAX_NDB_NODES);
955 guard0 = csystemnodes - 1;
956 arrGuard(guard0, MAX_NDB_NODES); // Check not zero nodes
957
958 for (unsigned i = 1; i < MAX_NDB_NODES; i++) {
959 jam();
960 if (NdbNodeBitmask::get(readNodes->allNodes, i)) {
961 hostptr.i = i;
962 ptrCheckGuard(hostptr, chostFilesize, hostRecord);
963
964 if (NdbNodeBitmask::get(readNodes->inactiveNodes, i)) {
965 jam();
966 hostptr.p->hostStatus = HS_DEAD;
967 } else {
968 jam();
969 con_lineNodes++;
970 hostptr.p->hostStatus = HS_ALIVE;
971 c_alive_nodes.set(i);
972 if (!ndbd_deferred_unique_constraints(getNodeInfo(i).m_version))
973 {
974 jam();
975 m_deferred_enabled = 0;
976 }
977 }//if
978 }//if
979 }//for
980 ndbsttorry010Lab(signal);
981 }//Dbtc::execREAD_NODESCONF()
982
983 /*****************************************************************************/
984 /* A P I _ F A I L R E Q */
985 // An API node has failed for some reason. We need to disconnect all API
986 // connections to the API node. This also includes
987 /*****************************************************************************/
execAPI_FAILREQ(Signal * signal)988 void Dbtc::execAPI_FAILREQ(Signal* signal)
989 {
990 /***************************************************************************
991 * Set the block reference to return API_FAILCONF to. Set the number of api
992 * connects currently closing to one to indicate that we are still in the
993 * process of going through the api connect records. Thus checking for zero
994 * can only be true after all api connect records have been checked.
995 **************************************************************************/
996 jamEntry();
997
998 if (ERROR_INSERTED(8056))
999 {
1000 CLEAR_ERROR_INSERT_VALUE;
1001 return;
1002 }
1003 #ifdef ERROR_INSERT
1004 if (ERROR_INSERTED(8078))
1005 {
1006 c_lastFailedApi = signal->theData[0];
1007 SET_ERROR_INSERT_VALUE(8079);
1008 }
1009 #endif
1010
1011 capiFailRef = signal->theData[1];
1012 arrGuard(signal->theData[0], MAX_NODES);
1013 capiConnectClosing[signal->theData[0]] = 1;
1014 handleFailedApiNode(signal, signal->theData[0], (UintR)0);
1015 }
1016
1017 void
handleFailedApiNode(Signal * signal,UintR TapiFailedNode,UintR TapiConnectPtr)1018 Dbtc::handleFailedApiNode(Signal* signal,
1019 UintR TapiFailedNode,
1020 UintR TapiConnectPtr)
1021 {
1022 UintR TloopCount = 0;
1023 arrGuard(TapiFailedNode, MAX_NODES);
1024 apiConnectptr.i = TapiConnectPtr;
1025 do {
1026 ptrCheckGuard(apiConnectptr, capiConnectFilesize, apiConnectRecord);
1027 const UintR TapiNode = refToNode(apiConnectptr.p->ndbapiBlockref);
1028 if (TapiNode == TapiFailedNode) {
1029 #ifdef VM_TRACE
1030 if (apiConnectptr.p->apiFailState != ZFALSE) {
1031 ndbout << "Error in previous API fail handling discovered" << endl
1032 << " apiConnectptr.i = " << apiConnectptr.i << endl
1033 << " apiConnectstate = " << apiConnectptr.p->apiConnectstate
1034 << endl
1035 << " ndbapiBlockref = " << hex
1036 << apiConnectptr.p->ndbapiBlockref << endl
1037 << " apiNode = " << refToNode(apiConnectptr.p->ndbapiBlockref)
1038 << endl;
1039 if (apiConnectptr.p->lastTcConnect != RNIL){
1040 jam();
1041 tcConnectptr.i = apiConnectptr.p->lastTcConnect;
1042 ptrCheckGuard(tcConnectptr, ctcConnectFilesize, tcConnectRecord);
1043 ndbout << " tcConnectptr.i = " << tcConnectptr.i << endl
1044 << " tcConnectstate = " << tcConnectptr.p->tcConnectstate
1045 << endl;
1046 }
1047 }//if
1048 #endif
1049
1050 apiConnectptr.p->returnsignal = RS_NO_RETURN;
1051 /***********************************************************************/
1052 // The connected node is the failed node.
1053 /**********************************************************************/
1054 switch(apiConnectptr.p->apiConnectstate) {
1055 case CS_DISCONNECTED:
1056 /*********************************************************************/
1057 // These states do not need any special handling.
1058 // Simply continue with the next.
1059 /*********************************************************************/
1060 jam();
1061 break;
1062 case CS_ABORTING:
1063 /*********************************************************************/
1064 // This could actually mean that the API connection is already
1065 // ready to release if the abortState is IDLE.
1066 /*********************************************************************/
1067 if (apiConnectptr.p->abortState == AS_IDLE) {
1068 jam();
1069 releaseApiCon(signal, apiConnectptr.i);
1070 } else {
1071 jam();
1072 capiConnectClosing[TapiFailedNode]++;
1073 apiConnectptr.p->apiFailState = ZTRUE;
1074 }//if
1075 break;
1076 case CS_WAIT_ABORT_CONF:
1077 case CS_WAIT_COMMIT_CONF:
1078 case CS_START_COMMITTING:
1079 case CS_PREPARE_TO_COMMIT:
1080 case CS_COMMITTING:
1081 case CS_COMMIT_SENT:
1082 /*********************************************************************/
1083 // These states indicate that an abort process or commit process is
1084 // already ongoing. We will set a state in the api record indicating
1085 // that the API node has failed.
1086 // Also we will increase the number of outstanding api records to
1087 // wait for before we can respond with API_FAILCONF.
1088 /*********************************************************************/
1089 jam();
1090 capiConnectClosing[TapiFailedNode]++;
1091 apiConnectptr.p->apiFailState = ZTRUE;
1092 break;
1093 case CS_START_SCAN:
1094 {
1095 /*********************************************************************/
1096 // The api record was performing a scan operation. We need to check
1097 // on the scan state. Since completing a scan process might involve
1098 // sending several signals we will increase the loop count by 64.
1099 /*********************************************************************/
1100 jam();
1101
1102 apiConnectptr.p->apiFailState = ZTRUE;
1103 capiConnectClosing[TapiFailedNode]++;
1104
1105 ScanRecordPtr scanPtr;
1106 scanPtr.i = apiConnectptr.p->apiScanRec;
1107 ptrCheckGuard(scanPtr, cscanrecFileSize, scanRecord);
1108 close_scan_req(signal, scanPtr, true);
1109
1110 TloopCount += 64;
1111 break;
1112 }
1113 case CS_CONNECTED:
1114 case CS_REC_COMMITTING:
1115 case CS_RECEIVING:
1116 case CS_STARTED:
1117 case CS_SEND_FIRE_TRIG_REQ:
1118 case CS_WAIT_FIRE_TRIG_REQ:
1119 /*********************************************************************/
1120 // The api record was in the process of performing a transaction but
1121 // had not yet sent all information.
1122 // We need to initiate an ABORT since the API will not provide any
1123 // more information.
1124 // Since the abort can send many signals we will insert a real-time
1125 // break after checking this record.
1126 /*********************************************************************/
1127 jam();
1128 apiConnectptr.p->apiFailState = ZTRUE;
1129 capiConnectClosing[TapiFailedNode]++;
1130 abort010Lab(signal);
1131 TloopCount = 256;
1132 break;
1133 case CS_RESTART:
1134 jam();
1135 case CS_COMPLETING:
1136 jam();
1137 case CS_COMPLETE_SENT:
1138 jam();
1139 case CS_WAIT_COMPLETE_CONF:
1140 jam();
1141 case CS_FAIL_ABORTING:
1142 jam();
1143 case CS_FAIL_ABORTED:
1144 jam();
1145 case CS_FAIL_PREPARED:
1146 jam();
1147 case CS_FAIL_COMMITTING:
1148 jam();
1149 case CS_FAIL_COMMITTED:
1150 /*********************************************************************/
1151 // These states are only valid on copy and fail API connections.
1152 /*********************************************************************/
1153 default:
1154 jam();
1155 jamLine(apiConnectptr.p->apiConnectstate);
1156 systemErrorLab(signal, __LINE__);
1157 break;
1158 }//switch
1159 } else {
1160 jam();
1161 }//if
1162 apiConnectptr.i++;
1163 if (apiConnectptr.i > ((capiConnectFilesize / 3) - 1)) {
1164 jam();
1165 /**
1166 * Finished with scanning connection record
1167 *
1168 * Now scan markers
1169 */
1170 removeMarkerForFailedAPI(signal, TapiFailedNode, 0);
1171 return;
1172 }//if
1173 } while (TloopCount++ < 256);
1174 signal->theData[0] = TcContinueB::ZHANDLE_FAILED_API_NODE;
1175 signal->theData[1] = TapiFailedNode;
1176 signal->theData[2] = apiConnectptr.i;
1177 sendSignal(cownref, GSN_CONTINUEB, signal, 3, JBB);
1178 }//Dbtc::handleFailedApiNode()
1179
1180 void
removeMarkerForFailedAPI(Signal * signal,NodeId nodeId,Uint32 startBucket)1181 Dbtc::removeMarkerForFailedAPI(Signal* signal,
1182 NodeId nodeId,
1183 Uint32 startBucket)
1184 {
1185 TcFailRecordPtr node_fail_ptr;
1186 node_fail_ptr.i = 0;
1187 ptrAss(node_fail_ptr, tcFailRecord);
1188 if(node_fail_ptr.p->failStatus != FS_IDLE) {
1189 jam();
1190 DEBUG("Restarting removeMarkerForFailedAPI");
1191 /**
1192 * TC take-over in progress
1193 * needs to restart as this
1194 * creates new markers
1195 */
1196 signal->theData[0] = TcContinueB::ZHANDLE_FAILED_API_NODE_REMOVE_MARKERS;
1197 signal->theData[1] = nodeId;
1198 signal->theData[2] = 0;
1199 sendSignalWithDelay(cownref, GSN_CONTINUEB, signal, 500, 3);
1200 return;
1201 }
1202
1203 CommitAckMarkerIterator iter;
1204 m_commitAckMarkerHash.next(startBucket, iter);
1205
1206 const Uint32 RT_BREAK = 256;
1207 for(Uint32 i = 0; i<RT_BREAK || iter.bucket == startBucket; i++){
1208 jam();
1209
1210 if(iter.curr.i == RNIL){
1211 jam();
1212 /**
1213 * Done with iteration
1214 */
1215 capiConnectClosing[nodeId]--;
1216 if (capiConnectClosing[nodeId] == 0) {
1217 jam();
1218
1219 /********************************************************************/
1220 // No outstanding ABORT or COMMIT's of this failed API node.
1221 // Perform SimulatedBlock level cleanup before sending
1222 // API_FAILCONF
1223 /********************************************************************/
1224 Callback cb = {safe_cast(&Dbtc::apiFailBlockCleanupCallback),
1225 nodeId};
1226 simBlockNodeFailure(signal, nodeId, cb);
1227 }
1228 return;
1229 }
1230
1231 if(iter.curr.p->apiNodeId == nodeId){
1232 jam();
1233
1234 /**
1235 * Check so that the record is not still in use
1236 *
1237 */
1238 ApiConnectRecordPtr apiConnectPtr;
1239 apiConnectPtr.i = iter.curr.p->apiConnectPtr;
1240 ptrCheckGuard(apiConnectPtr, capiConnectFilesize, apiConnectRecord);
1241 if(apiConnectPtr.p->commitAckMarker == iter.curr.i){
1242 jam();
1243 /**
1244 * The record is still active, this means that the transaction is
1245 * currentlygoing through the abort or commit process as started
1246 * in the API node failure handling, we have to wait until this
1247 * phase is completed until we continue with our processing of this.
1248 * If it goes through the aborting process the record will disappear
1249 * while we're waiting for it. If it goes through the commit process
1250 * it will eventually reach copyApi whereafter we can remove the
1251 * marker from LQH.
1252 *
1253 * Don't remove it, but continueb retry with a short delay
1254 */
1255 signal->theData[0] = TcContinueB::ZHANDLE_FAILED_API_NODE_REMOVE_MARKERS;
1256 signal->theData[1] = nodeId;
1257 signal->theData[2] = iter.bucket;
1258 sendSignalWithDelay(cownref, GSN_CONTINUEB, signal, 1, 3);
1259 return;
1260 }
1261 /**
1262 * This should only happen if we have done copyApi and the referred
1263 * apiConnect record have already moved on to the free connections or
1264 * to a new transaction. The commit ack marker is still around,
1265 * normally the API would then send TC_COMMIT_ACK, but this hasn't
1266 * happened here since the API have failed. So we need to remove the
1267 * marker on behalf of the failed API, the failed API will not be able
1268 * to communicate its hearing of the commit, so we can simply remove
1269 * the commit ack marker in LQH.
1270 */
1271 sendRemoveMarkers(signal, iter.curr.p, 1);
1272 m_commitAckMarkerHash.release(iter.curr);
1273
1274 break;
1275 }
1276 m_commitAckMarkerHash.next(iter);
1277 } // for (... i<RT_BREAK ...)
1278
1279 // Takes a RT-break to avoid starving other activity
1280 signal->theData[0] = TcContinueB::ZHANDLE_FAILED_API_NODE_REMOVE_MARKERS;
1281 signal->theData[1] = nodeId;
1282 signal->theData[2] = iter.bucket;
1283 sendSignal(cownref, GSN_CONTINUEB, signal, 3, JBB);
1284 }
1285
handleApiFailState(Signal * signal,UintR TapiConnectptr)1286 void Dbtc::handleApiFailState(Signal* signal, UintR TapiConnectptr)
1287 {
1288 ApiConnectRecordPtr TlocalApiConnectptr;
1289 UintR TfailedApiNode;
1290
1291 TlocalApiConnectptr.i = TapiConnectptr;
1292 ptrCheckGuard(TlocalApiConnectptr, capiConnectFilesize, apiConnectRecord);
1293 TfailedApiNode = refToNode(TlocalApiConnectptr.p->ndbapiBlockref);
1294 arrGuard(TfailedApiNode, MAX_NODES);
1295 capiConnectClosing[TfailedApiNode]--;
1296 releaseApiCon(signal, TapiConnectptr);
1297 TlocalApiConnectptr.p->apiFailState = ZFALSE;
1298 if (capiConnectClosing[TfailedApiNode] == 0)
1299 {
1300 jam();
1301
1302 /**
1303 * Perform block-level cleanups (e.g assembleFragments...)
1304 */
1305 Callback cb = {safe_cast(&Dbtc::apiFailBlockCleanupCallback),
1306 TfailedApiNode};
1307 simBlockNodeFailure(signal, TfailedApiNode, cb);
1308 }//if
1309 }//Dbtc::handleApiFailState()
1310
1311 /****************************************************************************
1312 * T C S E I Z E R E Q
1313 * THE APPLICATION SENDS A REQUEST TO SEIZE A CONNECT RECORD TO CARRY OUT A
1314 * TRANSACTION
1315 * TC BLOCK TAKE OUT A CONNECT RECORD FROM THE FREE LIST AND ESTABLISHES ALL
1316 * NECESSARY CONNECTION BEFORE REPLYING TO THE APPLICATION BLOCK
1317 ****************************************************************************/
execTCSEIZEREQ(Signal * signal)1318 void Dbtc::execTCSEIZEREQ(Signal* signal)
1319 {
1320 UintR tapiPointer;
1321 BlockReference tapiBlockref; /* SENDER BLOCK REFERENCE*/
1322
1323 jamEntry();
1324 tapiPointer = signal->theData[0]; /* REQUEST SENDERS CONNECT RECORD POINTER*/
1325 tapiBlockref = signal->theData[1]; /* SENDERS BLOCK REFERENCE*/
1326
1327 if (signal->getLength() > 2)
1328 {
1329 ndbassert(instance() == signal->theData[2]);
1330 }
1331
1332 const NodeState::StartLevel sl =
1333 (NodeState::StartLevel)getNodeState().startLevel;
1334
1335 const NodeId senderNodeId = refToNode(tapiBlockref);
1336 const bool local = senderNodeId == getOwnNodeId() || senderNodeId == 0;
1337
1338 {
1339 {
1340 if (!(sl == NodeState::SL_STARTED ||
1341 (sl == NodeState::SL_STARTING && local == true))) {
1342 jam();
1343
1344 Uint32 errCode = 0;
1345 if(!local)
1346 {
1347 switch(sl){
1348 case NodeState::SL_STARTING:
1349 errCode = ZSYSTEM_NOT_STARTED_ERROR;
1350 break;
1351 case NodeState::SL_STOPPING_1:
1352 case NodeState::SL_STOPPING_2:
1353 if (getNodeState().getSingleUserMode())
1354 break;
1355 case NodeState::SL_STOPPING_3:
1356 case NodeState::SL_STOPPING_4:
1357 if(getNodeState().stopping.systemShutdown)
1358 errCode = ZCLUSTER_SHUTDOWN_IN_PROGRESS;
1359 else
1360 errCode = ZNODE_SHUTDOWN_IN_PROGRESS;
1361 break;
1362 case NodeState::SL_SINGLEUSER:
1363 break;
1364 default:
1365 errCode = ZWRONG_STATE;
1366 break;
1367 }
1368 if (errCode)
1369 {
1370 ndbout << "error: " << errCode << " on " << tapiPointer << endl;
1371 signal->theData[0] = tapiPointer;
1372 signal->theData[1] = errCode;
1373 sendSignal(tapiBlockref, GSN_TCSEIZEREF, signal, 2, JBB);
1374 return;
1375 }
1376 }//if (!(sl == SL_SINGLEUSER))
1377 } //if
1378 }
1379 }
1380
1381 if (ERROR_INSERTED(8078) || ERROR_INSERTED(8079))
1382 {
1383 /* Clear testing of API_FAILREQ behaviour */
1384 CLEAR_ERROR_INSERT_VALUE;
1385 };
1386
1387 seizeApiConnect(signal);
1388 if (terrorCode == ZOK) {
1389 jam();
1390 apiConnectptr.p->ndbapiConnect = tapiPointer;
1391 apiConnectptr.p->ndbapiBlockref = tapiBlockref;
1392 signal->theData[0] = apiConnectptr.p->ndbapiConnect;
1393 signal->theData[1] = apiConnectptr.i;
1394 signal->theData[2] = reference();
1395 sendSignal(tapiBlockref, GSN_TCSEIZECONF, signal, 3, JBB);
1396 return;
1397 }
1398
1399 ndbout << "4006 on " << tapiPointer << endl;
1400 signal->theData[0] = tapiPointer;
1401 signal->theData[1] = terrorCode;
1402 sendSignal(tapiBlockref, GSN_TCSEIZEREF, signal, 2, JBB);
1403 }//Dbtc::execTCSEIZEREQ()
1404
1405 /****************************************************************************/
1406 /* T C R E L E A S E Q */
1407 /* REQUEST TO RELEASE A CONNECT RECORD */
1408 /****************************************************************************/
execTCRELEASEREQ(Signal * signal)1409 void Dbtc::execTCRELEASEREQ(Signal* signal)
1410 {
1411 UintR tapiPointer;
1412 BlockReference tapiBlockref; /* SENDER BLOCK REFERENCE*/
1413
1414 jamEntry();
1415 tapiPointer = signal->theData[0]; /* REQUEST SENDERS CONNECT RECORD POINTER*/
1416 tapiBlockref = signal->theData[1];/* SENDERS BLOCK REFERENCE*/
1417 tuserpointer = signal->theData[2];
1418 if (tapiPointer >= capiConnectFilesize) {
1419 jam();
1420 ndbassert(false);
1421 signal->theData[0] = tuserpointer;
1422 signal->theData[1] = ZINVALID_CONNECTION;
1423 signal->theData[2] = __LINE__;
1424 sendSignal(tapiBlockref, GSN_TCRELEASEREF, signal, 3, JBB);
1425 return;
1426 } else {
1427 jam();
1428 apiConnectptr.i = tapiPointer;
1429 }//if
1430 ptrAss(apiConnectptr, apiConnectRecord);
1431 if (apiConnectptr.p->apiConnectstate == CS_DISCONNECTED) {
1432 jam();
1433 signal->theData[0] = tuserpointer;
1434 sendSignal(tapiBlockref, GSN_TCRELEASECONF, signal, 1, JBB);
1435 } else {
1436 if (tapiBlockref == apiConnectptr.p->ndbapiBlockref) {
1437 if (apiConnectptr.p->apiConnectstate == CS_CONNECTED ||
1438 (apiConnectptr.p->apiConnectstate == CS_ABORTING &&
1439 apiConnectptr.p->abortState == AS_IDLE) ||
1440 (apiConnectptr.p->apiConnectstate == CS_STARTED &&
1441 apiConnectptr.p->firstTcConnect == RNIL))
1442 {
1443 jam(); /* JUST REPLY OK */
1444 apiConnectptr.p->m_transaction_nodes.clear();
1445 releaseApiCon(signal, apiConnectptr.i);
1446 signal->theData[0] = tuserpointer;
1447 sendSignal(tapiBlockref,
1448 GSN_TCRELEASECONF, signal, 1, JBB);
1449 } else {
1450 jam();
1451 ndbassert(false);
1452 signal->theData[0] = tuserpointer;
1453 signal->theData[1] = ZINVALID_CONNECTION;
1454 signal->theData[2] = __LINE__;
1455 signal->theData[3] = apiConnectptr.p->apiConnectstate;
1456 sendSignal(tapiBlockref,
1457 GSN_TCRELEASEREF, signal, 4, JBB);
1458 }
1459 } else {
1460 jam();
1461 ndbassert(false);
1462 signal->theData[0] = tuserpointer;
1463 signal->theData[1] = ZINVALID_CONNECTION;
1464 signal->theData[2] = __LINE__;
1465 signal->theData[3] = tapiBlockref;
1466 signal->theData[4] = apiConnectptr.p->ndbapiBlockref;
1467 sendSignal(tapiBlockref, GSN_TCRELEASEREF, signal, 5, JBB);
1468 }//if
1469 }//if
1470 }//Dbtc::execTCRELEASEREQ()
1471
1472 /****************************************************************************/
1473 // Error Handling for TCKEYREQ messages
1474 /****************************************************************************/
signalErrorRefuseLab(Signal * signal)1475 void Dbtc::signalErrorRefuseLab(Signal* signal)
1476 {
1477 ptrGuard(apiConnectptr);
1478 if (apiConnectptr.p->apiConnectstate != CS_DISCONNECTED) {
1479 jam();
1480 apiConnectptr.p->abortState = AS_IDLE;
1481 apiConnectptr.p->apiConnectstate = CS_ABORTING;
1482 }//if
1483 sendSignalErrorRefuseLab(signal);
1484 }//Dbtc::signalErrorRefuseLab()
1485
sendSignalErrorRefuseLab(Signal * signal)1486 void Dbtc::sendSignalErrorRefuseLab(Signal* signal)
1487 {
1488 ndbassert(false);
1489 ptrGuard(apiConnectptr);
1490 if (apiConnectptr.p->apiConnectstate != CS_DISCONNECTED) {
1491 jam();
1492 /* Force state print */
1493 printState(signal, 12, true);
1494 ndbrequire(false);
1495 signal->theData[0] = apiConnectptr.p->ndbapiConnect;
1496 signal->theData[1] = signal->theData[ttransid_ptr];
1497 signal->theData[2] = signal->theData[ttransid_ptr + 1];
1498 signal->theData[3] = ZSIGNAL_ERROR;
1499 sendSignal(apiConnectptr.p->ndbapiBlockref, GSN_TCROLLBACKREP,
1500 signal, 4, JBB);
1501 }
1502 }//Dbtc::sendSignalErrorRefuseLab()
1503
abortBeginErrorLab(Signal * signal)1504 void Dbtc::abortBeginErrorLab(Signal* signal)
1505 {
1506 apiConnectptr.p->transid[0] = signal->theData[ttransid_ptr];
1507 apiConnectptr.p->transid[1] = signal->theData[ttransid_ptr + 1];
1508 abortErrorLab(signal);
1509 }//Dbtc::abortBeginErrorLab()
1510
printState(Signal * signal,int place,bool force_trace)1511 void Dbtc::printState(Signal* signal, int place, bool force_trace)
1512 {
1513 /* Always give minimal ApiConnectState trace via jam */
1514 jam();
1515 jamLine(apiConnectptr.p->apiConnectstate);
1516 jam();
1517
1518 #ifdef VM_TRACE
1519 /* Always trace in debug mode */
1520 force_trace = true;
1521 #endif
1522
1523 if (!force_trace)
1524 return;
1525
1526 ndbout << "-- Dbtc::printState -- " << endl;
1527 ndbout << "Received from place = " << place
1528 << " apiConnectptr.i = " << apiConnectptr.i
1529 << " apiConnectstate = " << apiConnectptr.p->apiConnectstate << endl;
1530 ndbout << "ctcTimer = " << ctcTimer
1531 << " ndbapiBlockref = " << hex <<apiConnectptr.p->ndbapiBlockref
1532 << " Transid = " << apiConnectptr.p->transid[0]
1533 << " " << apiConnectptr.p->transid[1] << endl;
1534 ndbout << " apiTimer = " << getApiConTimer(apiConnectptr.i)
1535 << " counter = " << apiConnectptr.p->counter
1536 << " lqhkeyconfrec = " << apiConnectptr.p->lqhkeyconfrec
1537 << " lqhkeyreqrec = " << apiConnectptr.p->lqhkeyreqrec
1538 << " cascading_scans = " << apiConnectptr.p->cascading_scans_count << endl;
1539 ndbout << "abortState = " << apiConnectptr.p->abortState
1540 << " apiScanRec = " << apiConnectptr.p->apiScanRec
1541 << " returncode = " << apiConnectptr.p->returncode << endl;
1542 ndbout << "tckeyrec = " << apiConnectptr.p->tckeyrec
1543 << " returnsignal = " << apiConnectptr.p->returnsignal
1544 << " apiFailState = " << apiConnectptr.p->apiFailState << endl;
1545 if (apiConnectptr.p->cachePtr != RNIL) {
1546 jam();
1547 CacheRecord *localCacheRecord = cacheRecord;
1548 UintR TcacheFilesize = ccacheFilesize;
1549 UintR TcachePtr = apiConnectptr.p->cachePtr;
1550 if (TcachePtr < TcacheFilesize) {
1551 jam();
1552 CacheRecord * const regCachePtr = &localCacheRecord[TcachePtr];
1553 ndbout << "currReclenAi = " << regCachePtr->currReclenAi
1554 << " attrlength = " << regCachePtr->attrlength
1555 << " tableref = " << regCachePtr->tableref
1556 << " keylen = " << regCachePtr->keylen << endl;
1557 } else {
1558 jam();
1559 systemErrorLab(signal, __LINE__);
1560 }//if
1561 }//if
1562 return;
1563 }//Dbtc::printState()
1564
1565 void
TCKEY_abort(Signal * signal,int place)1566 Dbtc::TCKEY_abort(Signal* signal, int place)
1567 {
1568 switch (place) {
1569 case 0:
1570 jam();
1571 terrorCode = ZSTATE_ERROR;
1572 apiConnectptr.p->firstTcConnect = RNIL;
1573 printState(signal, 4);
1574 abortBeginErrorLab(signal);
1575 return;
1576 case 1:
1577 jam();
1578 printState(signal, 3);
1579 sendSignalErrorRefuseLab(signal);
1580 return;
1581 case 2:{
1582 printState(signal, 6);
1583 const TcKeyReq * const tcKeyReq = (TcKeyReq *)&signal->theData[0];
1584 const Uint32 t1 = tcKeyReq->transId1;
1585 const Uint32 t2 = tcKeyReq->transId2;
1586 signal->theData[0] = apiConnectptr.p->ndbapiConnect;
1587 signal->theData[1] = t1;
1588 signal->theData[2] = t2;
1589 signal->theData[3] = ZABORT_ERROR;
1590 ndbrequire(false);
1591 sendSignal(apiConnectptr.p->ndbapiBlockref, GSN_TCROLLBACKREP,
1592 signal, 4, JBB);
1593 return;
1594 }
1595 case 3:
1596 jam();
1597 printState(signal, 7);
1598 noFreeConnectionErrorLab(signal);
1599 return;
1600 case 4:
1601 jam();
1602 terrorCode = ZERO_KEYLEN_ERROR;
1603 releaseAtErrorLab(signal);
1604 return;
1605 case 5:
1606 jam();
1607 terrorCode = ZNO_AI_WITH_UPDATE;
1608 releaseAtErrorLab(signal);
1609 return;
1610 case 6:
1611 jam();
1612 warningHandlerLab(signal, __LINE__);
1613 return;
1614
1615 case 7:
1616 jam();
1617 tabStateErrorLab(signal);
1618 return;
1619
1620 case 8:
1621 jam();
1622 wrongSchemaVersionErrorLab(signal);
1623 return;
1624
1625 case 9:
1626 jam();
1627 terrorCode = ZSTATE_ERROR;
1628 releaseAtErrorLab(signal);
1629 return;
1630
1631 case 10:
1632 jam();
1633 systemErrorLab(signal, __LINE__);
1634 return;
1635
1636 case 11:
1637 jam();
1638 terrorCode = ZMORE_AI_IN_TCKEYREQ_ERROR;
1639 releaseAtErrorLab(signal);
1640 return;
1641
1642 case 12:
1643 jam();
1644 terrorCode = ZSIMPLE_READ_WITHOUT_AI;
1645 releaseAtErrorLab(signal);
1646 return;
1647
1648 case 13:
1649 jam();
1650 switch (tcConnectptr.p->tcConnectstate) {
1651 case OS_WAIT_KEYINFO:
1652 jam();
1653 printState(signal, 8);
1654 terrorCode = ZSTATE_ERROR;
1655 abortErrorLab(signal);
1656 return;
1657 default:
1658 jam();
1659 /********************************************************************/
1660 /* MISMATCH BETWEEN STATE ON API CONNECTION AND THIS */
1661 /* PARTICULAR TC CONNECT RECORD. THIS MUST BE CAUSED BY NDB */
1662 /* INTERNAL ERROR. */
1663 /********************************************************************/
1664 systemErrorLab(signal, __LINE__);
1665 return;
1666 }//switch
1667 return;
1668
1669 case 15:
1670 jam();
1671 terrorCode = ZSCAN_NODE_ERROR;
1672 releaseAtErrorLab(signal);
1673 return;
1674
1675 case 16:
1676 jam();
1677 systemErrorLab(signal, __LINE__);
1678 return;
1679
1680 case 17:
1681 jam();
1682 systemErrorLab(signal, __LINE__);
1683 return;
1684
1685 case 18:
1686 jam();
1687 warningHandlerLab(signal, __LINE__);
1688 return;
1689
1690 case 19:
1691 jam();
1692 return;
1693
1694 case 20:
1695 jam();
1696 warningHandlerLab(signal, __LINE__);
1697 return;
1698
1699 case 21:
1700 jam();
1701 systemErrorLab(signal, __LINE__);
1702 return;
1703
1704 case 22:
1705 jam();
1706 systemErrorLab(signal, __LINE__);
1707 return;
1708
1709 case 23:
1710 jam();
1711 systemErrorLab(signal, __LINE__);
1712 return;
1713
1714 case 24:
1715 jam();
1716 appendToSectionErrorLab(signal);
1717 return;
1718
1719 case 25:
1720 jam();
1721 warningHandlerLab(signal, __LINE__);
1722 return;
1723
1724 case 26:
1725 jam();
1726 return;
1727
1728 case 27:
1729 systemErrorLab(signal, __LINE__);
1730 jam();
1731 return;
1732
1733 case 28:
1734 jam();
1735 // NOT USED
1736 return;
1737
1738 case 29:
1739 jam();
1740 systemErrorLab(signal, __LINE__);
1741 return;
1742
1743 case 30:
1744 jam();
1745 systemErrorLab(signal, __LINE__);
1746 return;
1747
1748 case 31:
1749 jam();
1750 systemErrorLab(signal, __LINE__);
1751 return;
1752
1753 case 32:
1754 jam();
1755 systemErrorLab(signal, __LINE__);
1756 return;
1757
1758 case 33:
1759 jam();
1760 systemErrorLab(signal, __LINE__);
1761 return;
1762
1763 case 34:
1764 jam();
1765 systemErrorLab(signal, __LINE__);
1766 return;
1767
1768 case 35:
1769 jam();
1770 systemErrorLab(signal, __LINE__);
1771 return;
1772
1773 case 36:
1774 jam();
1775 systemErrorLab(signal, __LINE__);
1776 return;
1777
1778 case 37:
1779 jam();
1780 systemErrorLab(signal, __LINE__);
1781 return;
1782
1783 case 38:
1784 jam();
1785 systemErrorLab(signal, __LINE__);
1786 return;
1787
1788 case 39:
1789 jam();
1790 systemErrorLab(signal, __LINE__);
1791 return;
1792
1793 case 40:
1794 jam();
1795 systemErrorLab(signal, __LINE__);
1796 return;
1797
1798 case 41:
1799 jam();
1800 systemErrorLab(signal, __LINE__);
1801 return;
1802
1803 case 42:
1804 jam();
1805 systemErrorLab(signal, __LINE__);
1806 return;
1807
1808 case 43:
1809 jam();
1810 systemErrorLab(signal, __LINE__);
1811 return;
1812
1813 case 44:
1814 jam();
1815 systemErrorLab(signal, __LINE__);
1816 return;
1817
1818 case 45:
1819 jam();
1820 systemErrorLab(signal, __LINE__);
1821 return;
1822
1823 case 46:
1824 jam();
1825 systemErrorLab(signal, __LINE__);
1826 return;
1827
1828 case 47:
1829 jam();
1830 terrorCode = apiConnectptr.p->returncode;
1831 releaseAtErrorLab(signal);
1832 return;
1833
1834 case 48:
1835 jam();
1836 terrorCode = ZCOMMIT_TYPE_ERROR;
1837 releaseAtErrorLab(signal);
1838 return;
1839
1840 case 49:
1841 jam();
1842 abortErrorLab(signal);
1843 return;
1844
1845 case 50:
1846 jam();
1847 systemErrorLab(signal, __LINE__);
1848 return;
1849
1850 case 51:
1851 jam();
1852 abortErrorLab(signal);
1853 return;
1854
1855 case 52:
1856 jam();
1857 abortErrorLab(signal);
1858 return;
1859
1860 case 53:
1861 jam();
1862 abortErrorLab(signal);
1863 return;
1864
1865 case 54:
1866 jam();
1867 abortErrorLab(signal);
1868 return;
1869
1870 case 55:
1871 jam();
1872 printState(signal, 5);
1873 sendSignalErrorRefuseLab(signal);
1874 return;
1875
1876 case 56:{
1877 jam();
1878 terrorCode = ZNO_FREE_TC_MARKER;
1879 abortErrorLab(signal);
1880 return;
1881 }
1882 case 57:{
1883 jam();
1884 /**
1885 * Initialize object before starting error handling
1886 */
1887 initApiConnectRec(signal, apiConnectptr.p, true);
1888 start_failure:
1889 switch(getNodeState().startLevel){
1890 case NodeState::SL_STOPPING_2:
1891 if (getNodeState().getSingleUserMode())
1892 {
1893 terrorCode = ZCLUSTER_IN_SINGLEUSER_MODE;
1894 break;
1895 }
1896 case NodeState::SL_STOPPING_3:
1897 case NodeState::SL_STOPPING_4:
1898 if(getNodeState().stopping.systemShutdown)
1899 terrorCode = ZCLUSTER_SHUTDOWN_IN_PROGRESS;
1900 else
1901 terrorCode = ZNODE_SHUTDOWN_IN_PROGRESS;
1902 break;
1903 case NodeState::SL_SINGLEUSER:
1904 terrorCode = ZCLUSTER_IN_SINGLEUSER_MODE;
1905 break;
1906 case NodeState::SL_STOPPING_1:
1907 if (getNodeState().getSingleUserMode())
1908 {
1909 terrorCode = ZCLUSTER_IN_SINGLEUSER_MODE;
1910 break;
1911 }
1912 default:
1913 terrorCode = ZWRONG_STATE;
1914 break;
1915 }
1916 abortErrorLab(signal);
1917 return;
1918 }
1919
1920 case 58:{
1921 jam();
1922 releaseAtErrorLab(signal);
1923 return;
1924 }
1925
1926 case 59:{
1927 jam();
1928 terrorCode = ZABORTINPROGRESS;
1929 abortErrorLab(signal);
1930 return;
1931 }
1932
1933 case 60:
1934 {
1935 jam();
1936 initApiConnectRec(signal, apiConnectptr.p, true);
1937 apiConnectptr.p->m_flags |= ApiConnectRecord::TF_EXEC_FLAG;
1938 goto start_failure;
1939 }
1940 case 61:
1941 {
1942 jam();
1943 terrorCode = ZUNLOCKED_IVAL_TOO_HIGH;
1944 abortErrorLab(signal);
1945 return;
1946 }
1947 case 62:
1948 {
1949 jam();
1950 terrorCode = ZUNLOCKED_OP_HAS_BAD_STATE;
1951 abortErrorLab(signal);
1952 return;
1953 }
1954 case 63:
1955 {
1956 jam();
1957 /* Function not implemented yet */
1958 terrorCode = 4003;
1959 abortErrorLab(signal);
1960 return;
1961 }
1962 case 64:
1963 {
1964 jam();
1965 /* Invalid distribution key */
1966 terrorCode = ZBAD_DIST_KEY;
1967 abortErrorLab(signal);
1968 return;
1969 }
1970 case 65:
1971 {
1972 jam();
1973 terrorCode = ZTRANS_TOO_BIG;
1974 abortErrorLab(signal);
1975 return;
1976 }
1977 case 66:
1978 {
1979 jam();
1980 /* Function not implemented yet */
1981 terrorCode = 4003;
1982 abortErrorLab(signal);
1983 return;
1984 }
1985 case 67:
1986 {
1987 jam();
1988 terrorCode = ZNO_FREE_TC_MARKER_DATABUFFER;
1989 abortErrorLab(signal);
1990 return;
1991 }
1992 default:
1993 jam();
1994 systemErrorLab(signal, __LINE__);
1995 return;
1996 }//switch
1997 }
1998
1999 static
2000 inline
2001 bool
compare_transid(Uint32 * val0,Uint32 * val1)2002 compare_transid(Uint32* val0, Uint32* val1)
2003 {
2004 Uint32 tmp0 = val0[0] ^ val1[0];
2005 Uint32 tmp1 = val0[1] ^ val1[1];
2006 return (tmp0 | tmp1) == 0;
2007 }
2008
execKEYINFO(Signal * signal)2009 void Dbtc::execKEYINFO(Signal* signal)
2010 {
2011 jamEntry();
2012 apiConnectptr.i = signal->theData[0];
2013 tmaxData = 20;
2014 if (apiConnectptr.i >= capiConnectFilesize) {
2015 TCKEY_abort(signal, 18);
2016 return;
2017 }//if
2018 ptrAss(apiConnectptr, apiConnectRecord);
2019 ttransid_ptr = 1;
2020 if (compare_transid(apiConnectptr.p->transid, signal->theData+1) == false)
2021 {
2022 TCKEY_abort(signal, 19);
2023 return;
2024 }//if
2025 switch (apiConnectptr.p->apiConnectstate) {
2026 case CS_RECEIVING:
2027 case CS_REC_COMMITTING:
2028 case CS_START_SCAN:
2029 jam();
2030 /*empty*/;
2031 break;
2032 case CS_ABORTING:
2033 jam();
2034 return; /* IGNORE */
2035 case CS_CONNECTED:
2036 jam();
2037 /****************************************************************>*/
2038 /* MOST LIKELY CAUSED BY A MISSED SIGNAL. SEND REFUSE AND */
2039 /* SET STATE TO ABORTING. */
2040 /****************************************************************>*/
2041 printState(signal, 11);
2042 signalErrorRefuseLab(signal);
2043 return;
2044 case CS_STARTED:
2045 jam();
2046 /****************************************************************>*/
2047 /* MOST LIKELY CAUSED BY A MISSED SIGNAL. SEND REFUSE AND */
2048 /* SET STATE TO ABORTING. SINCE A TRANSACTION WAS STARTED */
2049 /* WE ALSO NEED TO ABORT THIS TRANSACTION. */
2050 /****************************************************************>*/
2051 terrorCode = ZSIGNAL_ERROR;
2052 printState(signal, 2);
2053 abortErrorLab(signal);
2054 return;
2055 default:
2056 jam();
2057 warningHandlerLab(signal, __LINE__);
2058 return;
2059 }//switch
2060
2061 CacheRecord *localCacheRecord = cacheRecord;
2062 UintR TcacheFilesize = ccacheFilesize;
2063 UintR TcachePtr = apiConnectptr.p->cachePtr;
2064 UintR TtcTimer = ctcTimer;
2065 CacheRecord * const regCachePtr = &localCacheRecord[TcachePtr];
2066 if (TcachePtr >= TcacheFilesize) {
2067 TCKEY_abort(signal, 42);
2068 return;
2069 }//if
2070 setApiConTimer(apiConnectptr.i, TtcTimer, __LINE__);
2071 cachePtr.i = TcachePtr;
2072 cachePtr.p = regCachePtr;
2073
2074 if (apiConnectptr.p->apiConnectstate == CS_START_SCAN)
2075 {
2076 jam();
2077 scanKeyinfoLab(signal);
2078 return;
2079 }
2080
2081 tcConnectptr.i = apiConnectptr.p->lastTcConnect;
2082 ptrCheckGuard(tcConnectptr, ctcConnectFilesize, tcConnectRecord);
2083 switch (tcConnectptr.p->tcConnectstate) {
2084 case OS_WAIT_KEYINFO:
2085 jam();
2086 tckeyreq020Lab(signal);
2087 return;
2088 default:
2089 jam();
2090 terrorCode = ZSTATE_ERROR;
2091 abortErrorLab(signal);
2092 return;
2093 }//switch
2094 }//Dbtc::execKEYINFO()
2095
2096 /**
2097 * sendKeyInfoTrain
2098 * Method to send a KeyInfo signal train from KeyInfo in the supplied
2099 * Section
2100 * KeyInfo will be taken from the section, starting at the supplied
2101 * offset
2102 */
sendKeyInfoTrain(Signal * signal,BlockReference TBRef,Uint32 connectPtr,Uint32 offset,Uint32 sectionIVal)2103 void Dbtc::sendKeyInfoTrain(Signal* signal,
2104 BlockReference TBRef,
2105 Uint32 connectPtr,
2106 Uint32 offset,
2107 Uint32 sectionIVal)
2108 {
2109 jam();
2110
2111 signal->theData[0] = connectPtr;
2112 signal->theData[1] = apiConnectptr.p->transid[0];
2113 signal->theData[2] = apiConnectptr.p->transid[1];
2114 Uint32 * dst = signal->theData + KeyInfo::HeaderLength;
2115
2116 ndbassert( sectionIVal != RNIL );
2117 SectionReader keyInfoReader(sectionIVal, getSectionSegmentPool());
2118
2119 Uint32 totalLen= keyInfoReader.getSize();
2120
2121 ndbassert( offset < totalLen );
2122
2123 keyInfoReader.step(offset);
2124 totalLen-= offset;
2125
2126 while(totalLen != 0)
2127 {
2128 Uint32 dataInSignal= MIN(KeyInfo::DataLength, totalLen);
2129 keyInfoReader.getWords(dst, dataInSignal);
2130 totalLen-= dataInSignal;
2131
2132 sendSignal(TBRef, GSN_KEYINFO, signal,
2133 KeyInfo::HeaderLength + dataInSignal, JBB);
2134 }
2135 }//Dbtc::sendKeyInfoTrain()
2136
2137 /**
2138 * tckeyreq020Lab
2139 * Handle received KEYINFO signal
2140 */
tckeyreq020Lab(Signal * signal)2141 void Dbtc::tckeyreq020Lab(Signal* signal)
2142 {
2143 CacheRecord * const regCachePtr = cachePtr.p;
2144 UintR TkeyLen = regCachePtr->keylen;
2145 UintR Tlen = regCachePtr->save1;
2146 UintR wordsInSignal= MIN(KeyInfo::DataLength,
2147 (TkeyLen - Tlen));
2148
2149 ndbassert(! regCachePtr->isLongTcKeyReq );
2150 ndbassert( regCachePtr->keyInfoSectionI != RNIL );
2151
2152 /* Add received KeyInfo data to the existing KeyInfo section */
2153 if (! appendToSection(regCachePtr->keyInfoSectionI,
2154 &signal->theData[KeyInfo::HeaderLength],
2155 wordsInSignal))
2156 {
2157 jam();
2158 appendToSectionErrorLab(signal);
2159 return;
2160 }
2161 Tlen+= wordsInSignal;
2162
2163 if (Tlen < TkeyLen)
2164 {
2165 /* More KeyInfo still to be read
2166 * Set timer and state and wait
2167 */
2168 jam();
2169 setApiConTimer(apiConnectptr.i, ctcTimer, __LINE__);
2170 regCachePtr->save1 = Tlen;
2171 tcConnectptr.p->tcConnectstate = OS_WAIT_KEYINFO;
2172 return;
2173 }
2174 else
2175 {
2176 /* Have all the KeyInfo ... continue processing
2177 * TCKEYREQ
2178 */
2179 jam();
2180 tckeyreq050Lab(signal);
2181 return;
2182 }
2183 }//Dbtc::tckeyreq020Lab()
2184
execATTRINFO(Signal * signal)2185 void Dbtc::execATTRINFO(Signal* signal)
2186 {
2187 UintR Tdata1 = signal->theData[0];
2188 UintR Tlength = signal->length();
2189 UintR TapiConnectFilesize = capiConnectFilesize;
2190 ApiConnectRecord *localApiConnectRecord = apiConnectRecord;
2191
2192 jamEntry();
2193 apiConnectptr.i = Tdata1;
2194 ttransid_ptr = 1;
2195 if (Tdata1 >= TapiConnectFilesize) {
2196 DEBUG("Drop ATTRINFO, wrong apiConnectptr");
2197 TCKEY_abort(signal, 18);
2198 return;
2199 }//if
2200
2201 ApiConnectRecord * const regApiPtr = &localApiConnectRecord[Tdata1];
2202 apiConnectptr.p = regApiPtr;
2203
2204 if (compare_transid(regApiPtr->transid, signal->theData+1) == false)
2205 {
2206 DEBUG("Drop ATTRINFO, wrong transid, lenght="<<Tlength
2207 << " transid("<<hex<<signal->theData[1]<<", "<<signal->theData[2]);
2208 TCKEY_abort(signal, 19);
2209 return;
2210 }//if
2211 if (Tlength < 4) {
2212 DEBUG("Drop ATTRINFO, wrong length = " << Tlength);
2213 TCKEY_abort(signal, 20);
2214 return;
2215 }
2216 Tlength -= AttrInfo::HeaderLength;
2217 UintR TcompREC_COMMIT = (regApiPtr->apiConnectstate == CS_REC_COMMITTING);
2218 UintR TcompRECEIVING = (regApiPtr->apiConnectstate == CS_RECEIVING);
2219 UintR TcompBOTH = TcompREC_COMMIT | TcompRECEIVING;
2220
2221 if (TcompBOTH) {
2222 jam();
2223 if (ERROR_INSERTED(8015)) {
2224 CLEAR_ERROR_INSERT_VALUE;
2225 return;
2226 }//if
2227 if (ERROR_INSERTED(8016)) {
2228 CLEAR_ERROR_INSERT_VALUE;
2229 return;
2230 }//if
2231 CacheRecord *localCacheRecord = cacheRecord;
2232 UintR TcacheFilesize = ccacheFilesize;
2233 UintR TcachePtr = regApiPtr->cachePtr;
2234 UintR TtcTimer = ctcTimer;
2235 CacheRecord * const regCachePtr = &localCacheRecord[TcachePtr];
2236 if (TcachePtr >= TcacheFilesize) {
2237 TCKEY_abort(signal, 43);
2238 return;
2239 }//if
2240
2241 /* Update TC global cache ptr */
2242 cachePtr.i= TcachePtr;
2243 cachePtr.p= regCachePtr;
2244
2245 regCachePtr->currReclenAi+= Tlength;
2246 int TattrlengthRemain = regCachePtr->attrlength -
2247 regCachePtr->currReclenAi;
2248
2249 /* Setup tcConnectptr to ensure that error handling etc.
2250 * can access required state
2251 */
2252 tcConnectptr.i = regApiPtr->lastTcConnect;
2253 ptrCheckGuard(tcConnectptr, ctcConnectFilesize, tcConnectRecord);
2254
2255 /* Add AttrInfo to any existing AttrInfo we have
2256 * Some short TCKEYREQ signals have no ATTRINFO in
2257 * the TCKEYREQ itself
2258 */
2259 if (! appendToSection(regCachePtr->attrInfoSectionI,
2260 &signal->theData[AttrInfo::HeaderLength],
2261 Tlength))
2262 {
2263 DEBUG("No more section segments available");
2264 appendToSectionErrorLab(signal);
2265 return;
2266 }//if
2267
2268 setApiConTimer(apiConnectptr.i, TtcTimer, __LINE__);
2269
2270 if (TattrlengthRemain == 0) {
2271 /****************************************************************>*/
2272 /* HERE WE HAVE FOUND THAT THE LAST SIGNAL BELONGING TO THIS */
2273 /* OPERATION HAVE BEEN RECEIVED. THIS MEANS THAT WE CAN NOW REUSE */
2274 /* THE API CONNECT RECORD. HOWEVER IF PREPARE OR COMMIT HAVE BEEN */
2275 /* RECEIVED THEN IT IS NOT ALLOWED TO RECEIVE ANY FURTHER */
2276 /* OPERATIONS. */
2277 /****************************************************************>*/
2278 if (TcompRECEIVING) {
2279 jam();
2280 regApiPtr->apiConnectstate = CS_STARTED;
2281 } else {
2282 jam();
2283 regApiPtr->apiConnectstate = CS_START_COMMITTING;
2284 }//if
2285 attrinfoDihReceivedLab(signal);
2286 } else if (TattrlengthRemain < 0) {
2287 jam();
2288 DEBUG("ATTRINFO wrong total length="<<Tlength
2289 <<", TattrlengthRemain="<<TattrlengthRemain
2290 <<", TattrLen="<< regCachePtr->attrlength
2291 <<", TcurrReclenAi="<< regCachePtr->currReclenAi);
2292 tcConnectptr.i = regApiPtr->lastTcConnect;
2293 ptrCheckGuard(tcConnectptr, ctcConnectFilesize, tcConnectRecord);
2294 aiErrorLab(signal);
2295 }//if
2296 return;
2297 } else if (regApiPtr->apiConnectstate == CS_START_SCAN) {
2298 jam();
2299 scanAttrinfoLab(signal, Tlength);
2300 return;
2301 } else {
2302 switch (regApiPtr->apiConnectstate) {
2303 case CS_ABORTING:
2304 jam();
2305 /* JUST IGNORE THE SIGNAL*/
2306 // DEBUG("Drop ATTRINFO, CS_ABORTING");
2307 return;
2308 case CS_CONNECTED:
2309 jam();
2310 /* MOST LIKELY CAUSED BY A MISSED SIGNAL.*/
2311 // DEBUG("Drop ATTRINFO, CS_CONNECTED");
2312 return;
2313 case CS_STARTED:
2314 jam();
2315 /****************************************************************>*/
2316 /* MOST LIKELY CAUSED BY A MISSED SIGNAL. SEND REFUSE AND */
2317 /* SET STATE TO ABORTING. SINCE A TRANSACTION WAS STARTED */
2318 /* WE ALSO NEED TO ABORT THIS TRANSACTION. */
2319 /****************************************************************>*/
2320 terrorCode = ZSIGNAL_ERROR;
2321 printState(signal, 1);
2322 abortErrorLab(signal);
2323 return;
2324 default:
2325 jam();
2326 /****************************************************************>*/
2327 /* SIGNAL RECEIVED IN AN UNEXPECTED STATE. WE IGNORE SIGNAL */
2328 /* SINCE WE DO NOT REALLY KNOW WHERE THE ERROR OCCURRED. */
2329 /****************************************************************>*/
2330 DEBUG("Drop ATTRINFO, illegal state="<<regApiPtr->apiConnectstate);
2331 printState(signal, 9);
2332 return;
2333 }//switch
2334 }//if
2335 }//Dbtc::execATTRINFO()
2336
2337 /* *********************************************************************>> */
2338 /* */
2339 /* MODULE: HASH MODULE */
2340 /* DESCRIPTION: CONTAINS THE HASH VALUE CALCULATION */
2341 /* *********************************************************************> */
hash(Signal * signal)2342 void Dbtc::hash(Signal* signal)
2343 {
2344 UintR* Tdata32;
2345
2346 CacheRecord * const regCachePtr = cachePtr.p;
2347 SegmentedSectionPtr keyInfoSection;
2348 UintR keylen = (UintR)regCachePtr->keylen;
2349 Uint32 distKey = regCachePtr->distributionKeyIndicator;
2350
2351 getSection(keyInfoSection, regCachePtr->keyInfoSectionI);
2352
2353 ndbassert( keyInfoSection.sz <= MAX_KEY_SIZE_IN_WORDS );
2354 ndbassert( keyInfoSection.sz == keylen );
2355 /* Copy KeyInfo section from segmented storage into linear storage
2356 * in signal->theData
2357 */
2358 if (keylen <= SectionSegment::DataLength)
2359 {
2360 /* No need to copy keyinfo into a linear space
2361 * Note that we require that the data in the section is
2362 * 64-bit aligned for md5_hash below
2363 */
2364 ndbassert( keyInfoSection.p != NULL );
2365
2366 Tdata32= &keyInfoSection.p->theData[0];
2367 }
2368 else
2369 {
2370 /* Copy segmented keyinfo into linear space in the signal */
2371 Tdata32= signal->theData;
2372 copy(Tdata32, keyInfoSection);
2373 }
2374
2375 Uint32 tmp[4];
2376 if(!regCachePtr->m_special_hash)
2377 {
2378 md5_hash(tmp, (Uint64*)&Tdata32[0], keylen);
2379 }
2380 else
2381 {
2382 if (regCachePtr->m_no_hash)
2383 {
2384 /* No need for tuple key hash at LQH */
2385 ndbassert(distKey); /* User must supply distkey */
2386 Uint32 zero[4] = {0, 0, 0, 0};
2387 *tmp = *zero;
2388 }
2389 else
2390 {
2391 handle_special_hash(tmp, Tdata32, keylen, regCachePtr->tableref, !distKey);
2392 }
2393 }
2394
2395 /* Primary key hash value is first word of hash on PK columns
2396 * Distribution key hash value is second word of hash on distribution
2397 * key columns, or a user defined value
2398 */
2399 thashValue = tmp[0];
2400 if (distKey){
2401 jam();
2402 tdistrHashValue = regCachePtr->distributionKey;
2403 } else {
2404 jam();
2405 tdistrHashValue = tmp[1];
2406 }//if
2407 }//Dbtc::hash()
2408
2409 bool
handle_special_hash(Uint32 dstHash[4],const Uint32 * src,Uint32 srcLen,Uint32 tabPtrI,bool distr)2410 Dbtc::handle_special_hash(Uint32 dstHash[4],
2411 const Uint32* src, Uint32 srcLen,
2412 Uint32 tabPtrI,
2413 bool distr)
2414 {
2415 const Uint32 MAX_KEY_SIZE_IN_LONG_WORDS=
2416 (MAX_KEY_SIZE_IN_WORDS + 1) / 2;
2417 Uint64 alignedWorkspace[MAX_KEY_SIZE_IN_LONG_WORDS * MAX_XFRM_MULTIPLY];
2418 Uint32* workspace= (Uint32*)alignedWorkspace;
2419 const TableRecord* tabPtrP = &tableRecord[tabPtrI];
2420 const bool hasVarKeys = tabPtrP->hasVarKeys;
2421 const bool hasCharAttr = tabPtrP->hasCharAttr;
2422 const bool compute_distkey = distr && (tabPtrP->noOfDistrKeys > 0);
2423
2424 const Uint32 *hashInput = workspace;
2425 Uint32 inputLen = 0;
2426 Uint32 keyPartLen[MAX_ATTRIBUTES_IN_INDEX];
2427 Uint32 * keyPartLenPtr;
2428
2429 /* Normalise KeyInfo into workspace if necessary */
2430 if(hasCharAttr || (compute_distkey && hasVarKeys))
2431 {
2432 keyPartLenPtr = keyPartLen;
2433 inputLen = xfrm_key(tabPtrI,
2434 src,
2435 workspace,
2436 sizeof(alignedWorkspace) >> 2,
2437 keyPartLenPtr);
2438 if (unlikely(inputLen == 0))
2439 {
2440 goto error;
2441 }
2442 }
2443 else
2444 {
2445 /* Keyinfo already suitable for hash */
2446 hashInput = src;
2447 inputLen = srcLen;
2448 keyPartLenPtr = 0;
2449 }
2450
2451 /* Calculate primary key hash */
2452 md5_hash(dstHash, (Uint64*)hashInput, inputLen);
2453
2454 /* If the distribution key != primary key then we have to
2455 * form a distribution key from the primary key and calculate
2456 * a separate distribution hash based on this
2457 */
2458 if(compute_distkey)
2459 {
2460 jam();
2461
2462 Uint32 distrKeyHash[4];
2463 /* Reshuffle primary key columns to get just distribution key */
2464 Uint32 len = create_distr_key(tabPtrI, hashInput, workspace, keyPartLenPtr);
2465 /* Calculate distribution key hash */
2466 md5_hash(distrKeyHash, (Uint64*) workspace, len);
2467
2468 /* Just one word used for distribution */
2469 dstHash[1] = distrKeyHash[1];
2470 }
2471 return true; // success
2472
2473 error:
2474 terrorCode = ZINVALID_KEY;
2475 return false;
2476 }
2477
2478 /*
2479 INIT_API_CONNECT_REC
2480 ---------------------------
2481 */
2482 /* ========================================================================= */
2483 /* ======= INIT_API_CONNECT_REC ======= */
2484 /* */
2485 /* ========================================================================= */
initApiConnectRec(Signal * signal,ApiConnectRecord * const regApiPtr,bool releaseIndexOperations)2486 void Dbtc::initApiConnectRec(Signal* signal,
2487 ApiConnectRecord * const regApiPtr,
2488 bool releaseIndexOperations)
2489 {
2490 const TcKeyReq * const tcKeyReq = (TcKeyReq *)&signal->theData[0];
2491 UintR TfailureNr = cfailure_nr;
2492 UintR Ttransid0 = tcKeyReq->transId1;
2493 UintR Ttransid1 = tcKeyReq->transId2;
2494
2495 tc_clearbit(regApiPtr->m_flags, ApiConnectRecord::TF_EXEC_FLAG);
2496 regApiPtr->returncode = 0;
2497 regApiPtr->returnsignal = RS_TCKEYCONF;
2498 ndbassert(regApiPtr->firstTcConnect == RNIL);
2499 regApiPtr->firstTcConnect = RNIL;
2500 regApiPtr->lastTcConnect = RNIL;
2501 regApiPtr->globalcheckpointid = 0;
2502 regApiPtr->lqhkeyconfrec = 0;
2503 regApiPtr->lqhkeyreqrec = 0;
2504 regApiPtr->tckeyrec = 0;
2505 regApiPtr->tcindxrec = 0;
2506 tc_clearbit(regApiPtr->m_flags,
2507 ApiConnectRecord::TF_COMMIT_ACK_MARKER_RECEIVED);
2508 regApiPtr->failureNr = TfailureNr;
2509 regApiPtr->transid[0] = Ttransid0;
2510 regApiPtr->transid[1] = Ttransid1;
2511 ndbrequire(regApiPtr->commitAckMarker == RNIL);
2512 ndbrequire(regApiPtr->num_commit_ack_markers == 0);
2513 /**
2514 * We wanted to verify those variables around commitAckMarkers,
2515 * So we have an ndbrequire around them, this means we can
2516 * remove the setting of them since we already verified that
2517 * they already have the correct value.
2518 * regApiPtr->num_commit_ack_markers = 0;
2519 * regApiPtr->commitAckMarker = RNIL;
2520 */
2521 regApiPtr->buddyPtr = RNIL;
2522 regApiPtr->currSavePointId = 0;
2523 regApiPtr->m_transaction_nodes.clear();
2524 regApiPtr->singleUserMode = 0;
2525 regApiPtr->m_pre_commit_pass = 0;
2526 regApiPtr->cascading_scans_count = 0;
2527 // FiredTriggers should have been released when previous transaction ended.
2528 ndbrequire(regApiPtr->theFiredTriggers.isEmpty());
2529 // Index data
2530 tc_clearbit(regApiPtr->m_flags,
2531 ApiConnectRecord::TF_INDEX_OP_RETURN);
2532 regApiPtr->noIndexOp = 0;
2533 if(releaseIndexOperations)
2534 releaseAllSeizedIndexOperations(regApiPtr);
2535 regApiPtr->immediateTriggerId = RNIL;
2536
2537 tc_clearbit(regApiPtr->m_flags,
2538 ApiConnectRecord::TF_DEFERRED_CONSTRAINTS);
2539 tc_clearbit(regApiPtr->m_flags,
2540 ApiConnectRecord::TF_DISABLE_FK_CONSTRAINTS);
2541 c_counters.ctransCount++;
2542
2543 #ifdef ERROR_INSERT
2544 regApiPtr->continueBCount = 0;
2545 #endif
2546
2547 regApiPtr->m_write_count = 0;
2548 }//Dbtc::initApiConnectRec()
2549
2550 int
seizeTcRecord(Signal * signal)2551 Dbtc::seizeTcRecord(Signal* signal)
2552 {
2553 ApiConnectRecord * const regApiPtr = apiConnectptr.p;
2554 TcConnectRecord *localTcConnectRecord = tcConnectRecord;
2555 UintR TfirstfreeTcConnect = cfirstfreeTcConnect;
2556 UintR TtcConnectFilesize = ctcConnectFilesize;
2557 tcConnectptr.i = TfirstfreeTcConnect;
2558 if (TfirstfreeTcConnect >= TtcConnectFilesize) {
2559 int place = 3;
2560 if (TfirstfreeTcConnect != RNIL) {
2561 place = 10;
2562 }//if
2563 TCKEY_abort(signal, place);
2564 return 1;
2565 }//if
2566 //--------------------------------------------------------------------------
2567 // Optimised version of ptrAss(tcConnectptr, tcConnectRecord)
2568 //--------------------------------------------------------------------------
2569 TcConnectRecord * const regTcPtr =
2570 &localTcConnectRecord[TfirstfreeTcConnect];
2571
2572 UintR TlastTcConnect = regApiPtr->lastTcConnect;
2573 UintR TtcConnectptrIndex = tcConnectptr.i;
2574 TcConnectRecordPtr tmpTcConnectptr;
2575
2576 cfirstfreeTcConnect = regTcPtr->nextTcConnect;
2577 tcConnectptr.p = regTcPtr;
2578
2579 c_counters.cconcurrentOp++;
2580
2581 regTcPtr->prevTcConnect = TlastTcConnect;
2582 regTcPtr->nextTcConnect = RNIL;
2583 regTcPtr->numFiredTriggers = 0;
2584 regTcPtr->numReceivedTriggers = 0;
2585 regTcPtr->triggerExecutionCount = 0;
2586 regTcPtr->triggeringOperation = RNIL;
2587 regTcPtr->m_special_op_flags = 0;
2588 regTcPtr->indexOp = RNIL;
2589 regTcPtr->currentTriggerId = RNIL;
2590 regTcPtr->tcConnectstate = OS_ABORTING;
2591 regTcPtr->noOfNodes = 0;
2592
2593 regApiPtr->lastTcConnect = TtcConnectptrIndex;
2594
2595 if (TlastTcConnect == RNIL) {
2596 jam();
2597 regApiPtr->firstTcConnect = TtcConnectptrIndex;
2598 } else {
2599 tmpTcConnectptr.i = TlastTcConnect;
2600 jam();
2601 ptrCheckGuard(tmpTcConnectptr, TtcConnectFilesize, localTcConnectRecord);
2602 tmpTcConnectptr.p->nextTcConnect = TtcConnectptrIndex;
2603 }//if
2604 return 0;
2605 }//Dbtc::seizeTcRecord()
2606
2607 int
seizeCacheRecord(Signal * signal)2608 Dbtc::seizeCacheRecord(Signal* signal)
2609 {
2610 ApiConnectRecord * const regApiPtr = apiConnectptr.p;
2611 UintR TfirstfreeCacheRec = cfirstfreeCacheRec;
2612 UintR TcacheFilesize = ccacheFilesize;
2613 CacheRecord *localCacheRecord = cacheRecord;
2614 if (TfirstfreeCacheRec >= TcacheFilesize) {
2615 TCKEY_abort(signal, 41);
2616 return 1;
2617 }//if
2618 CacheRecord * const regCachePtr = &localCacheRecord[TfirstfreeCacheRec];
2619
2620 regApiPtr->cachePtr = TfirstfreeCacheRec;
2621 cfirstfreeCacheRec = regCachePtr->nextCacheRec;
2622 cachePtr.i = TfirstfreeCacheRec;
2623 cachePtr.p = regCachePtr;
2624
2625 regCachePtr->currReclenAi = 0;
2626 regCachePtr->keyInfoSectionI = RNIL;
2627 regCachePtr->attrInfoSectionI = RNIL;
2628 return 0;
2629 }//Dbtc::seizeCacheRecord()
2630
2631 void
releaseCacheRecord(ApiConnectRecordPtr transPtr,CacheRecord * regCachePtr)2632 Dbtc::releaseCacheRecord(ApiConnectRecordPtr transPtr, CacheRecord* regCachePtr)
2633 {
2634 ApiConnectRecord * const regApiPtr = transPtr.p;
2635 UintR TfirstfreeCacheRec = cfirstfreeCacheRec;
2636 UintR TCacheIndex = transPtr.p->cachePtr;
2637 regCachePtr->nextCacheRec = TfirstfreeCacheRec;
2638 cfirstfreeCacheRec = TCacheIndex;
2639 regApiPtr->cachePtr = RNIL;
2640 }
2641
2642 void
dump_trans(ApiConnectRecordPtr transPtr)2643 Dbtc::dump_trans(ApiConnectRecordPtr transPtr)
2644 {
2645 printf("transid %u [ 0x%x 0x%x ] state: %u flags: 0x%x m_pre_commit_pass: %u\n",
2646 transPtr.i,
2647 transPtr.p->transid[0],
2648 transPtr.p->transid[1],
2649 transPtr.p->apiConnectstate,
2650 transPtr.p->m_flags,
2651 transPtr.p->m_pre_commit_pass);
2652
2653 Uint32 i = 0;
2654 tcConnectptr.i = transPtr.p->firstTcConnect;
2655 while (tcConnectptr.i != RNIL)
2656 {
2657 jam();
2658 ptrCheckGuard(tcConnectptr,
2659 ctcConnectFilesize, tcConnectRecord);
2660
2661 Ptr<TcDefinedTriggerData> trigPtr;
2662 if (tcConnectptr.p->currentTriggerId != RNIL)
2663 {
2664 c_theDefinedTriggers.getPtr(trigPtr, tcConnectptr.p->currentTriggerId);
2665 }
2666
2667 printf(" %u : opPtrI: 0x%x op: %u state: %u triggeringOperation: 0x%x flags: 0x%x triggerType: %u apiConnect: %u\n",
2668 i++,
2669 tcConnectptr.i,
2670 tcConnectptr.p->operation,
2671 tcConnectptr.p->tcConnectstate,
2672 tcConnectptr.p->triggeringOperation,
2673 tcConnectptr.p->m_special_op_flags,
2674 tcConnectptr.p->currentTriggerId == RNIL ? RNIL :
2675 (Uint32)trigPtr.p->triggerType,
2676 tcConnectptr.p->apiConnect);
2677
2678 tcConnectptr.i = tcConnectptr.p->nextTcConnect;
2679 }
2680 }
2681
2682 bool
hasOp(ApiConnectRecordPtr transPtr,Uint32 opPtrI)2683 Dbtc::hasOp(ApiConnectRecordPtr transPtr, Uint32 opPtrI)
2684 {
2685 TcConnectRecordPtr tcPtr;
2686 tcPtr.i = transPtr.p->firstTcConnect;
2687 while (tcPtr.i != RNIL)
2688 {
2689 jam();
2690 ptrCheckGuard(tcPtr,
2691 ctcConnectFilesize, tcConnectRecord);
2692 if (tcPtr.i == opPtrI)
2693 {
2694 return tcPtr.p->apiConnect == transPtr.i;
2695 }
2696
2697 tcPtr.i = tcPtr.p->nextTcConnect;
2698 }
2699
2700 return false;
2701 }
2702
2703 /*****************************************************************************/
2704 /* T C K E Y R E Q */
2705 /* AFTER HAVING ESTABLISHED THE CONNECT, THE APPLICATION BLOCK SENDS AN */
2706 /* OPERATION REQUEST TO TC. ALL NECESSARY INFORMATION TO CARRY OUT REQUEST */
2707 /* IS FURNISHED IN PARAMETERS. TC STORES THIS INFORMATION AND ENQUIRES */
2708 /* FROM DIH ABOUT THE NODES WHICH MAY HAVE THE REQUESTED DATA */
2709 /*****************************************************************************/
execTCKEYREQ(Signal * signal)2710 void Dbtc::execTCKEYREQ(Signal* signal)
2711 {
2712 Uint32 sendersNodeId = refToNode(signal->getSendersBlockRef());
2713 UintR compare_transid1, compare_transid2;
2714 const TcKeyReq * const tcKeyReq = (TcKeyReq *)signal->getDataPtr();
2715 UintR Treqinfo;
2716 SectionHandle handle(this, signal);
2717
2718 jamEntry();
2719 /*-------------------------------------------------------------------------
2720 * Common error routines are used for several signals, they need to know
2721 * where to find the transaction identifier in the signal.
2722 *-------------------------------------------------------------------------*/
2723 const UintR TapiIndex = tcKeyReq->apiConnectPtr;
2724 const UintR TapiMaxIndex = capiConnectFilesize;
2725 const UintR TtabIndex = tcKeyReq->tableId;
2726 const UintR TtabMaxIndex = ctabrecFilesize;
2727 ApiConnectRecord *localApiConnectRecord = apiConnectRecord;
2728
2729 ttransid_ptr = 6;
2730 apiConnectptr.i = TapiIndex;
2731 if (TapiIndex >= TapiMaxIndex) {
2732 releaseSections(handle);
2733 TCKEY_abort(signal, 6);
2734 return;
2735 }//if
2736 if (TtabIndex >= TtabMaxIndex) {
2737 releaseSections(handle);
2738 TCKEY_abort(signal, 7);
2739 return;
2740 }//if
2741
2742 #ifdef ERROR_INSERT
2743 if (ERROR_INSERTED(8079))
2744 {
2745 /* Test that no signals received after API_FAILREQ */
2746 if (sendersNodeId == c_lastFailedApi)
2747 {
2748 /* Signal from API node received *after* API_FAILREQ */
2749 ndbrequire(false);
2750 }
2751 }
2752 #endif
2753
2754 Treqinfo = tcKeyReq->requestInfo;
2755 //--------------------------------------------------------------------------
2756 // Optimised version of ptrAss(tabptr, tableRecord)
2757 // Optimised version of ptrAss(apiConnectptr, apiConnectRecord)
2758 //--------------------------------------------------------------------------
2759 ApiConnectRecord * const regApiPtr = &localApiConnectRecord[TapiIndex];
2760 apiConnectptr.i = TapiIndex;
2761 apiConnectptr.p = regApiPtr;
2762
2763 Uint32 TstartFlag = TcKeyReq::getStartFlag(Treqinfo);
2764 Uint32 TexecFlag =
2765 TcKeyReq::getExecuteFlag(Treqinfo) ? ApiConnectRecord::TF_EXEC_FLAG : 0;
2766
2767 Uint16 Tspecial_op_flags = regApiPtr->m_special_op_flags;
2768 bool isIndexOpReturn = tc_testbit(regApiPtr->m_flags,
2769 ApiConnectRecord::TF_INDEX_OP_RETURN);
2770 bool isExecutingTrigger = Tspecial_op_flags & TcConnectRecord::SOF_TRIGGER;
2771 regApiPtr->m_special_op_flags = 0; // Reset marker
2772 regApiPtr->m_flags |= TexecFlag;
2773 TableRecordPtr localTabptr;
2774 localTabptr.i = TtabIndex;
2775 localTabptr.p = &tableRecord[TtabIndex];
2776 switch (regApiPtr->apiConnectstate) {
2777 case CS_CONNECTED:{
2778 if (TstartFlag == 1 && getAllowStartTransaction(sendersNodeId, localTabptr.p->singleUserMode) == true){
2779 //---------------------------------------------------------------------
2780 // Initialise API connect record if transaction is started.
2781 //---------------------------------------------------------------------
2782 jam();
2783 initApiConnectRec(signal, regApiPtr);
2784 regApiPtr->m_flags |= TexecFlag;
2785 } else {
2786 releaseSections(handle);
2787 if(getAllowStartTransaction(sendersNodeId, localTabptr.p->singleUserMode) == true){
2788 /*------------------------------------------------------------------
2789 * WE EXPECTED A START TRANSACTION. SINCE NO OPERATIONS HAVE BEEN
2790 * RECEIVED WE INDICATE THIS BY SETTING FIRST_TC_CONNECT TO RNIL TO
2791 * ENSURE PROPER OPERATION OF THE COMMON ABORT HANDLING.
2792 *-----------------------------------------------------------------*/
2793 TCKEY_abort(signal, 0);
2794 return;
2795 } else {
2796 /**
2797 * getAllowStartTransaction(sendersNodeId) == false
2798 */
2799 TCKEY_abort(signal, TexecFlag ? 60 : 57);
2800 return;
2801 }//if
2802 }
2803 }
2804 break;
2805 case CS_STARTED:
2806 if(TstartFlag == 1 && regApiPtr->firstTcConnect == RNIL)
2807 {
2808 /**
2809 * If last operation in last transaction was a simple/dirty read
2810 * it does not have to be committed or rollbacked hence,
2811 * the state will be CS_STARTED
2812 */
2813 jam();
2814 if (unlikely(getNodeState().getSingleUserMode()) &&
2815 getNodeState().getSingleUserApi() != sendersNodeId &&
2816 !localTabptr.p->singleUserMode)
2817 {
2818 releaseSections(handle);
2819 TCKEY_abort(signal, TexecFlag ? 60 : 57);
2820 return;
2821 }
2822 initApiConnectRec(signal, regApiPtr);
2823 regApiPtr->m_flags |= TexecFlag;
2824 } else {
2825 //----------------------------------------------------------------------
2826 // Transaction is started already.
2827 // Check that the operation is on the same transaction.
2828 //-----------------------------------------------------------------------
2829 compare_transid1 = regApiPtr->transid[0] ^ tcKeyReq->transId1;
2830 compare_transid2 = regApiPtr->transid[1] ^ tcKeyReq->transId2;
2831 jam();
2832 compare_transid1 = compare_transid1 | compare_transid2;
2833 if (compare_transid1 != 0) {
2834 releaseSections(handle);
2835 TCKEY_abort(signal, 1);
2836 return;
2837 }//if
2838 }
2839 break;
2840 case CS_ABORTING:
2841 if (regApiPtr->abortState == AS_IDLE) {
2842 if (TstartFlag == 1) {
2843 if(getAllowStartTransaction(sendersNodeId, localTabptr.p->singleUserMode) == false){
2844 releaseSections(handle);
2845 TCKEY_abort(signal, TexecFlag ? 60 : 57);
2846 return;
2847 }
2848 //--------------------------------------------------------------------
2849 // Previous transaction had been aborted and the abort was completed.
2850 // It is then OK to start a new transaction again.
2851 //--------------------------------------------------------------------
2852 jam();
2853 initApiConnectRec(signal, regApiPtr);
2854 regApiPtr->m_flags |= TexecFlag;
2855 } else if(TexecFlag) {
2856 releaseSections(handle);
2857 TCKEY_abort(signal, 59);
2858 return;
2859 } else {
2860 //--------------------------------------------------------------------
2861 // The current transaction was aborted successfully.
2862 // We will not do anything before we receive an operation
2863 // with a start indicator. We will ignore this signal.
2864 //--------------------------------------------------------------------
2865 jam();
2866 DEBUG("Drop TCKEYREQ - apiConnectState=CS_ABORTING, ==AS_IDLE");
2867 releaseSections(handle);
2868 return;
2869 }//if
2870 } else {
2871 //----------------------------------------------------------------------
2872 // Previous transaction is still aborting
2873 //----------------------------------------------------------------------
2874 jam();
2875 releaseSections(handle);
2876 if (TstartFlag == 1) {
2877 //--------------------------------------------------------------------
2878 // If a new transaction tries to start while the old is
2879 // still aborting, we will report this to the starting API.
2880 //--------------------------------------------------------------------
2881 TCKEY_abort(signal, 2);
2882 return;
2883 } else if(TexecFlag) {
2884 TCKEY_abort(signal, 59);
2885 return;
2886 }
2887 //----------------------------------------------------------------------
2888 // Ignore signals without start indicator set when aborting transaction.
2889 //----------------------------------------------------------------------
2890 DEBUG("Drop TCKEYREQ - apiConnectState=CS_ABORTING, !=AS_IDLE");
2891 return;
2892 }//if
2893 break;
2894 case CS_START_COMMITTING:
2895 case CS_SEND_FIRE_TRIG_REQ:
2896 case CS_WAIT_FIRE_TRIG_REQ:
2897 jam();
2898 if(isIndexOpReturn || isExecutingTrigger){
2899 break;
2900 }
2901 default:
2902 jam();
2903 /*----------------------------------------------------------------------
2904 * IN THIS CASE THE NDBAPI IS AN UNTRUSTED ENTITY THAT HAS SENT A SIGNAL
2905 * WHEN IT WAS NOT EXPECTED TO.
2906 * WE MIGHT BE IN A PROCESS TO RECEIVE, PREPARE,
2907 * COMMIT OR COMPLETE AND OBVIOUSLY THIS IS NOT A DESIRED EVENT.
2908 * WE WILL ALWAYS COMPLETE THE ABORT HANDLING BEFORE WE ALLOW
2909 * ANYTHING TO HAPPEN ON THIS CONNECTION AGAIN.
2910 * THUS THERE IS NO ACTION FROM THE API THAT CAN SPEED UP THIS PROCESS.
2911 *---------------------------------------------------------------------*/
2912 releaseSections(handle);
2913 TCKEY_abort(signal, 55);
2914 return;
2915 }//switch
2916
2917 if (localTabptr.p->checkTable(tcKeyReq->tableSchemaVersion)) {
2918 ;
2919 } else {
2920 /*-----------------------------------------------------------------------*/
2921 /* THE API IS WORKING WITH AN OLD SCHEMA VERSION. IT NEEDS REPLACEMENT. */
2922 /* COULD ALSO BE THAT THE TABLE IS NOT DEFINED. */
2923 /*-----------------------------------------------------------------------*/
2924 releaseSections(handle);
2925 TCKEY_abort(signal, 8);
2926 return;
2927 }//if
2928
2929 //-------------------------------------------------------------------------
2930 // Error Insertion for testing purposes. Test to see what happens when no
2931 // more TC records available.
2932 //-------------------------------------------------------------------------
2933 if (ERROR_INSERTED(8032)) {
2934 releaseSections(handle);
2935 TCKEY_abort(signal, 3);
2936 return;
2937 }//if
2938
2939 if (seizeTcRecord(signal) != 0) {
2940 releaseSections(handle);
2941 return;
2942 }//if
2943
2944 if (seizeCacheRecord(signal) != 0) {
2945 releaseSections(handle);
2946 return;
2947 }//if
2948
2949 CRASH_INSERTION(8063);
2950
2951 TcConnectRecord * const regTcPtr = tcConnectptr.p;
2952 CacheRecord * const regCachePtr = cachePtr.p;
2953
2954 /*
2955 INIT_TC_CONNECT_REC
2956 -------------------------
2957 */
2958 /* ---------------------------------------------------------------------- */
2959 /* ------- INIT OPERATION RECORD WITH SIGNAL DATA AND RNILS ------- */
2960 /* */
2961 /* ---------------------------------------------------------------------- */
2962
2963 UintR Tlqhkeyreqrec = regApiPtr->lqhkeyreqrec;
2964 regApiPtr->lqhkeyreqrec = Tlqhkeyreqrec + 1;
2965
2966 /* If we have any sections at all then this is a long TCKEYREQ */
2967 regCachePtr->isLongTcKeyReq= ( handle.m_cnt != 0 );
2968
2969 UintR TapiConnectptrIndex = apiConnectptr.i;
2970 UintR TsenderData = tcKeyReq->senderData;
2971
2972 if (ERROR_INSERTED(8065))
2973 {
2974 ErrorSignalReceive= 1;
2975 ErrorMaxSegmentsToSeize= 10;
2976 }
2977 if (ERROR_INSERTED(8066))
2978 {
2979 ErrorSignalReceive= 1;
2980 ErrorMaxSegmentsToSeize= 1;
2981 }
2982 if (ERROR_INSERTED(8067))
2983 {
2984 ErrorSignalReceive= 1;
2985 ErrorMaxSegmentsToSeize= 0;
2986 }
2987 if (ERROR_INSERTED(8068))
2988 {
2989 ErrorSignalReceive= 0;
2990 ErrorMaxSegmentsToSeize= 0;
2991 CLEAR_ERROR_INSERT_VALUE;
2992 DEBUG("Max segments to seize cleared");
2993 }
2994 #ifdef ERROR_INSERT
2995 if (ErrorSignalReceive)
2996 DEBUG("Max segments to seize : "
2997 << ErrorMaxSegmentsToSeize);
2998 #endif
2999
3000 /* Key and attribute lengths are passed in the header for
3001 * short TCKEYREQ and passed as section lengths for long
3002 * TCKEYREQ
3003 */
3004 UintR TkeyLength = 0;
3005 UintR TattrLen = 0;
3006 UintR titcLenAiInTckeyreq = 0;
3007
3008 if (regCachePtr->isLongTcKeyReq)
3009 {
3010 SegmentedSectionPtr keyInfoSec;
3011 if (handle.getSection(keyInfoSec, TcKeyReq::KeyInfoSectionNum))
3012 TkeyLength= keyInfoSec.sz;
3013
3014 SegmentedSectionPtr attrInfoSec;
3015 if (handle.getSection(attrInfoSec, TcKeyReq::AttrInfoSectionNum))
3016 TattrLen= attrInfoSec.sz;
3017
3018 if (TcKeyReq::getDeferredConstraints(Treqinfo))
3019 {
3020 regApiPtr->m_flags |= ApiConnectRecord::TF_DEFERRED_CONSTRAINTS;
3021 }
3022
3023 if (TcKeyReq::getDisableFkConstraints(Treqinfo))
3024 {
3025 regApiPtr->m_flags |= ApiConnectRecord::TF_DISABLE_FK_CONSTRAINTS;
3026 }
3027 }
3028 else
3029 {
3030 TkeyLength = TcKeyReq::getKeyLength(Treqinfo);
3031 TattrLen= TcKeyReq::getAttrinfoLen(tcKeyReq->attrLen);
3032 titcLenAiInTckeyreq = TcKeyReq::getAIInTcKeyReq(Treqinfo);
3033 }
3034
3035 regCachePtr->keylen = TkeyLength;
3036 regCachePtr->lenAiInTckeyreq = titcLenAiInTckeyreq;
3037 regCachePtr->currReclenAi = titcLenAiInTckeyreq;
3038
3039 regTcPtr->apiConnect = TapiConnectptrIndex;
3040 regTcPtr->clientData = TsenderData;
3041 regTcPtr->commitAckMarker = RNIL;
3042 regTcPtr->m_special_op_flags = Tspecial_op_flags;
3043 regTcPtr->indexOp = regApiPtr->executingIndexOp;
3044 regTcPtr->savePointId = regApiPtr->currSavePointId;
3045 regApiPtr->executingIndexOp = RNIL;
3046
3047 regApiPtr->singleUserMode |= 1 << localTabptr.p->singleUserMode;
3048
3049 if (isExecutingTrigger)
3050 {
3051 // Save the TcOperationPtr for fireing operation
3052 regTcPtr->triggeringOperation = TsenderData;
3053 // ndbrequire(hasOp(apiConnectptr, TsenderData));
3054
3055 // Grab trigger Id from ApiConnectRecord
3056 ndbrequire(regApiPtr->immediateTriggerId != RNIL);
3057 regTcPtr->currentTriggerId= regApiPtr->immediateTriggerId;
3058 }
3059 ndbassert(isExecutingTrigger ||
3060 (regApiPtr->immediateTriggerId == RNIL));
3061
3062 if (TexecFlag){
3063 Uint32 currSPId = regApiPtr->currSavePointId;
3064 regApiPtr->currSavePointId = ++currSPId;
3065 }
3066
3067 regCachePtr->attrlength = TattrLen;
3068 c_counters.cattrinfoCount += TattrLen;
3069
3070 UintR TtabptrIndex = localTabptr.i;
3071 UintR TtableSchemaVersion = tcKeyReq->tableSchemaVersion;
3072 Uint8 TOperationType = TcKeyReq::getOperationType(Treqinfo);
3073 regCachePtr->tableref = TtabptrIndex;
3074 regCachePtr->schemaVersion = TtableSchemaVersion;
3075 regTcPtr->operation = TOperationType;
3076
3077 Uint8 TSimpleFlag = TcKeyReq::getSimpleFlag(Treqinfo);
3078 Uint8 TDirtyFlag = TcKeyReq::getDirtyFlag(Treqinfo);
3079 Uint8 TInterpretedFlag = TcKeyReq::getInterpretedFlag(Treqinfo);
3080 Uint8 TDistrKeyFlag = TcKeyReq::getDistributionKeyFlag(Treqinfo);
3081 Uint8 TNoDiskFlag = TcKeyReq::getNoDiskFlag(Treqinfo);
3082 Uint8 TexecuteFlag = TexecFlag;
3083 Uint8 Treorg = TcKeyReq::getReorgFlag(Treqinfo);
3084 const Uint8 TViaSPJFlag = TcKeyReq::getViaSPJFlag(Treqinfo);
3085 const Uint8 Tqueue = TcKeyReq::getQueueOnRedoProblemFlag(Treqinfo);
3086
3087 if (Treorg)
3088 {
3089 if (TOperationType == ZWRITE)
3090 regTcPtr->m_special_op_flags = TcConnectRecord::SOF_REORG_COPY;
3091 else if (TOperationType == ZDELETE)
3092 regTcPtr->m_special_op_flags = TcConnectRecord::SOF_REORG_DELETE;
3093 else
3094 {
3095 ndbassert(false);
3096 }
3097 }
3098
3099 regTcPtr->dirtyOp = TDirtyFlag;
3100 regTcPtr->opSimple = TSimpleFlag;
3101 regCachePtr->opExec = TInterpretedFlag;
3102 regCachePtr->distributionKeyIndicator = TDistrKeyFlag;
3103 regCachePtr->m_no_disk_flag = TNoDiskFlag;
3104 regCachePtr->viaSPJFlag = TViaSPJFlag;
3105 regCachePtr->m_op_queue = Tqueue;
3106
3107 //-------------------------------------------------------------
3108 // The next step is to read the upto three conditional words.
3109 //-------------------------------------------------------------
3110 Uint32 TkeyIndex;
3111 Uint32* TOptionalDataPtr = (Uint32*)&tcKeyReq->scanInfo;
3112 {
3113 Uint32 TDistrGHIndex = TcKeyReq::getScanIndFlag(Treqinfo);
3114 Uint32 TDistrKeyIndex = TDistrGHIndex;
3115
3116 Uint32 TscanInfo = TcKeyReq::getTakeOverScanInfo(TOptionalDataPtr[0]);
3117
3118 regCachePtr->scanTakeOverInd = TDistrGHIndex;
3119 regCachePtr->scanInfo = TscanInfo;
3120
3121 regCachePtr->distributionKey = TOptionalDataPtr[TDistrKeyIndex];
3122
3123 TkeyIndex = TDistrKeyIndex + TDistrKeyFlag;
3124 }
3125
3126 regCachePtr->m_no_hash = false;
3127
3128 if (TOperationType == ZUNLOCK)
3129 {
3130 /* Unlock op has distribution key containing
3131 * LQH nodeid and fragid
3132 */
3133 ndbassert( regCachePtr->distributionKeyIndicator );
3134 regCachePtr->m_no_hash = 1;
3135 regCachePtr->unlockNodeId = (regCachePtr->distributionKey >> 16);
3136 regCachePtr->distributionKey &= 0xffff;
3137 }
3138
3139 regCachePtr->m_special_hash =
3140 localTabptr.p->hasCharAttr |
3141 (localTabptr.p->noOfDistrKeys > 0) |
3142 regCachePtr->m_no_hash;
3143
3144 if (TkeyLength == 0)
3145 {
3146 releaseSections(handle);
3147 TCKEY_abort(signal, 4);
3148 return;
3149 }
3150
3151 if (unlikely(TViaSPJFlag &&
3152 /* Check that all nodes can handle SPJ requests. */
3153 !ndb_join_pushdown(getNodeVersionInfo().m_type[NodeInfo::DB]
3154 .m_min_version)))
3155 {
3156 jam();
3157 releaseSections(handle);
3158 TCKEY_abort(signal, 66);
3159 return;
3160 }
3161
3162 /* KeyInfo and AttrInfo are buffered in segmented sections
3163 * If they arrived in segmented sections then there's nothing to do
3164 * If they arrived in short signals then they are appended into
3165 * segmented sections
3166 */
3167 if (regCachePtr->isLongTcKeyReq)
3168 {
3169 ndbassert( titcLenAiInTckeyreq == 0);
3170 /* Long TcKeyReq - KI and AI already in sections */
3171 SegmentedSectionPtr keyInfoSection, attrInfoSection;
3172
3173 /* Store i value for first long section of KeyInfo
3174 * and AttrInfo in Cache Record
3175 */
3176 handle.getSection(keyInfoSection,
3177 TcKeyReq::KeyInfoSectionNum);
3178
3179 regCachePtr->keyInfoSectionI= keyInfoSection.i;
3180
3181 if (regCachePtr->attrlength != 0)
3182 {
3183 ndbassert( handle.m_cnt == 2 );
3184 handle.getSection(attrInfoSection,
3185 TcKeyReq::AttrInfoSectionNum);
3186 regCachePtr->attrInfoSectionI= attrInfoSection.i;
3187 }
3188 else
3189 {
3190 ndbassert( handle.m_cnt == 1 );
3191 }
3192
3193 /* Detach sections from the handle, we are now responsible
3194 * for always freeing them before returning
3195 * For a long TcKeyReq, they will be freed at the end
3196 * of the processing this signal.
3197 */
3198 handle.clear();
3199 }
3200 else
3201 {
3202 /* Short TcKeyReq - need to receive KI and AI into
3203 * segmented sections
3204 * We store any KI and AI from the TCKeyReq now and
3205 * will then wait for further signals if necessary
3206 */
3207 ndbassert( handle.m_cnt == 0 );
3208 Uint32 keyInfoInTCKeyReq= MIN(TkeyLength, TcKeyReq::MaxKeyInfo);
3209
3210 bool ok= appendToSection(regCachePtr->keyInfoSectionI,
3211 &TOptionalDataPtr[TkeyIndex],
3212 keyInfoInTCKeyReq);
3213 if (!ok)
3214 {
3215 jam();
3216 appendToSectionErrorLab(signal);
3217 return;
3218 }
3219
3220 if (titcLenAiInTckeyreq != 0)
3221 {
3222 Uint32 TAIDataIndex= TkeyIndex + keyInfoInTCKeyReq;
3223
3224 ok= appendToSection(regCachePtr->attrInfoSectionI,
3225 &TOptionalDataPtr[TAIDataIndex],
3226 titcLenAiInTckeyreq);
3227 if (!ok)
3228 {
3229 jam();
3230 appendToSectionErrorLab(signal);
3231 return;
3232 }
3233 }
3234 }
3235
3236 if (TOperationType == ZUNLOCK)
3237 {
3238 jam();
3239 // TODO : Consider adding counter for unlock operations
3240 }
3241 else if (TOperationType == ZREAD || TOperationType == ZREAD_EX) {
3242 jam();
3243 c_counters.creadCount++;
3244 }
3245 else
3246 {
3247 /**
3248 * Insert, Update, Write, Delete
3249 * Markers are created on all nodes in a nodegroup
3250 * (as changes affect all replicas)
3251 * Therefore any survivable node failure will have a live
3252 * node with a marker for any marked write transaction.
3253 * Therefore only need one nodegroup marked - after that
3254 * needn't bother.
3255 */
3256 if (!tc_testbit(regApiPtr->m_flags,
3257 ApiConnectRecord::TF_COMMIT_ACK_MARKER_RECEIVED))
3258 {
3259 if(regApiPtr->commitAckMarker != RNIL)
3260 regTcPtr->commitAckMarker = regApiPtr->commitAckMarker;
3261 else
3262 {
3263 jam();
3264 CommitAckMarkerPtr tmp;
3265 if (ERROR_INSERTED(8087))
3266 {
3267 CLEAR_ERROR_INSERT_VALUE;
3268 TCKEY_abort(signal, 56);
3269 return;
3270 }
3271
3272 if (!m_commitAckMarkerHash.seize(tmp))
3273 {
3274 TCKEY_abort(signal, 56);
3275 return;
3276 }
3277 else
3278 {
3279 regTcPtr->commitAckMarker = tmp.i;
3280 regApiPtr->commitAckMarker = tmp.i;
3281 new (tmp.p) CommitAckMarker();
3282 tmp.p->transid1 = tcKeyReq->transId1;
3283 tmp.p->transid2 = tcKeyReq->transId2;
3284 tmp.p->apiNodeId = refToNode(regApiPtr->ndbapiBlockref);
3285 tmp.p->apiConnectPtr = TapiIndex;
3286 #if defined VM_TRACE || defined ERROR_INSERT
3287 {
3288 CommitAckMarkerPtr check;
3289 ndbrequire(!m_commitAckMarkerHash.find(check, *tmp.p));
3290 }
3291 #endif
3292 m_commitAckMarkerHash.add(tmp);
3293 }
3294 }
3295 regApiPtr->num_commit_ack_markers++;
3296 }
3297
3298 UintR Toperationsize = coperationsize;
3299 /* --------------------------------------------------------------------
3300 * THIS IS A TEMPORARY TABLE, DON'T UPDATE coperationsize.
3301 * THIS VARIABLE CONTROLS THE INTERVAL BETWEEN LCP'S AND
3302 * TEMP TABLES DON'T PARTICIPATE.
3303 * -------------------------------------------------------------------- */
3304 if (localTabptr.p->get_storedTable()) {
3305 coperationsize = ((Toperationsize + TattrLen) + TkeyLength) + 17;
3306 }
3307 c_counters.cwriteCount++;
3308 switch (TOperationType) {
3309 case ZUPDATE:
3310 case ZINSERT:
3311 case ZDELETE:
3312 case ZWRITE:
3313 case ZREFRESH:
3314 jam();
3315 regApiPtr->m_write_count++;
3316 if (regApiPtr->m_flags & ApiConnectRecord::TF_DEFERRED_CONSTRAINTS)
3317 {
3318 /**
3319 * Allow slave applier to ignore m_max_writes_per_trans
3320 */
3321 break;
3322 }
3323
3324 if (unlikely(regApiPtr->m_write_count > m_max_writes_per_trans))
3325 {
3326 TCKEY_abort(signal, 65);
3327 return;
3328 }
3329 break;
3330 default:
3331 TCKEY_abort(signal, 9);
3332 return;
3333 }//switch
3334 }//if
3335
3336 Uint32 TabortOption = TcKeyReq::getAbortOption(Treqinfo);
3337 regTcPtr->m_execAbortOption = TabortOption;
3338
3339 /*-------------------------------------------------------------------------
3340 * Check error handling per operation
3341 * If CommitFlag is set state accordingly and check for early abort
3342 *------------------------------------------------------------------------*/
3343 if (TcKeyReq::getCommitFlag(Treqinfo) == 1) {
3344 ndbrequire(TexecuteFlag);
3345 regApiPtr->apiConnectstate = CS_REC_COMMITTING;
3346 } else {
3347 /* ---------------------------------------------------------------------
3348 * PREPARE TRANSACTION IS NOT IMPLEMENTED YET.
3349 * ---------------------------------------------------------------------
3350 * ELSIF (TREQINFO => 3) (*) 1 = 1 THEN
3351 * IF PREPARE TRANSACTION THEN
3352 * API_CONNECTPTR:API_CONNECTSTATE = REC_PREPARING
3353 * SET STATE TO PREPARING
3354 * --------------------------------------------------------------------- */
3355 if (regApiPtr->apiConnectstate == CS_START_COMMITTING) {
3356 jam();
3357 // Trigger execution at commit
3358 regApiPtr->apiConnectstate = CS_REC_COMMITTING;
3359 } else if (!regApiPtr->isExecutingDeferredTriggers()) {
3360 jam();
3361 regApiPtr->apiConnectstate = CS_RECEIVING;
3362 }//if
3363 }//if
3364
3365 if (regCachePtr->isLongTcKeyReq)
3366 {
3367 jam();
3368 /* Have all the KeyInfo (and AttrInfo), process now */
3369 tckeyreq050Lab(signal);
3370 }
3371 else if (TkeyLength <= TcKeyReq::MaxKeyInfo)
3372 {
3373 jam();
3374 /* Have all the KeyInfo, get any extra AttrInfo */
3375 tckeyreq050Lab(signal);
3376 }
3377 else
3378 {
3379 jam();
3380 /* --------------------------------------------------------------------
3381 * THE TCKEYREQ DIDN'T CONTAIN ALL KEY DATA,
3382 * SAVE STATE AND WAIT FOR KEYINFO
3383 * --------------------------------------------------------------------*/
3384 setApiConTimer(apiConnectptr.i, ctcTimer, __LINE__);
3385 regCachePtr->save1 = 8;
3386 regTcPtr->tcConnectstate = OS_WAIT_KEYINFO;
3387 return;
3388 }//if
3389
3390 return;
3391 }//Dbtc::execTCKEYREQ()
3392
3393 static
3394 void
handle_reorg_trigger(DiGetNodesConf * conf)3395 handle_reorg_trigger(DiGetNodesConf * conf)
3396 {
3397 if (conf->reqinfo & DiGetNodesConf::REORG_MOVING)
3398 {
3399 conf->fragId = conf->nodes[MAX_REPLICAS];
3400 conf->reqinfo = conf->nodes[MAX_REPLICAS+1];
3401 memcpy(conf->nodes, conf->nodes+MAX_REPLICAS+2,
3402 sizeof(Uint32)*MAX_REPLICAS);
3403 }
3404 else
3405 {
3406 conf->nodes[0] = 0; // Should not execute...
3407 }
3408 }
3409
3410 bool
isRefreshSupported() const3411 Dbtc::isRefreshSupported() const
3412 {
3413 const NodeVersionInfo& nvi = getNodeVersionInfo();
3414 const Uint32 minVer = nvi.m_type[NodeInfo::DB].m_min_version;
3415 const Uint32 maxVer = nvi.m_type[NodeInfo::DB].m_max_version;
3416
3417 if (likely (minVer == maxVer))
3418 {
3419 /* Normal case, use function */
3420 return ndb_refresh_tuple(minVer);
3421 }
3422
3423 /* As refresh feature was introduced across three minor versions
3424 * we check that all data nodes support it. This slow path
3425 * should only be hit during upgrades between versions
3426 */
3427 for (Uint32 i=1; i < MAX_NODES; i++)
3428 {
3429 const NodeInfo& nodeInfo = getNodeInfo(i);
3430 if ((nodeInfo.m_type == NODE_TYPE_DB) &&
3431 (nodeInfo.m_connected) &&
3432 (! ndb_refresh_tuple(nodeInfo.m_version)))
3433 return false;
3434 }
3435 return true;
3436 }
3437
3438 /**
3439 * tckeyreq050Lab
3440 * This method is executed once all KeyInfo has been obtained for
3441 * the TcKeyReq signal
3442 */
tckeyreq050Lab(Signal * signal)3443 void Dbtc::tckeyreq050Lab(Signal* signal)
3444 {
3445 UintR tnoOfBackup;
3446 UintR tnoOfStandby;
3447 UintR tnodeinfo;
3448
3449 terrorCode = 0;
3450
3451 hash(signal); /* NOW IT IS TIME TO CALCULATE THE HASH VALUE*/
3452
3453 CacheRecord * const regCachePtr = cachePtr.p;
3454 TcConnectRecord * const regTcPtr = tcConnectptr.p;
3455 ApiConnectRecord * const regApiPtr = apiConnectptr.p;
3456
3457 UintR TtcTimer = ctcTimer;
3458 UintR ThashValue = thashValue;
3459 UintR TdistrHashValue = tdistrHashValue;
3460 UintR Ttableref = regCachePtr->tableref;
3461 Uint16 Tspecial_op_flags = regTcPtr->m_special_op_flags;
3462
3463 TableRecordPtr localTabptr;
3464 localTabptr.i = Ttableref;
3465 localTabptr.p = &tableRecord[localTabptr.i];
3466 Uint32 schemaVersion = regCachePtr->schemaVersion;
3467 if(localTabptr.p->checkTable(schemaVersion)){
3468 ;
3469 } else {
3470 terrorCode = localTabptr.p->getErrorCode(schemaVersion);
3471 TCKEY_abort(signal, 58);
3472 return;
3473 }
3474
3475 setApiConTimer(apiConnectptr.i, TtcTimer, __LINE__);
3476 regCachePtr->hashValue = ThashValue;
3477
3478 ndbassert( signal->getNoOfSections() == 0 );
3479
3480 DiGetNodesReq * const req = (DiGetNodesReq *)&signal->theData[0];
3481 req->tableId = Ttableref;
3482 req->hashValue = TdistrHashValue;
3483 req->distr_key_indicator = regCachePtr->distributionKeyIndicator;
3484 req->jamBufferPtr = jamBuffer();
3485
3486 /*-------------------------------------------------------------*/
3487 /* FOR EFFICIENCY REASONS WE AVOID THE SIGNAL SENDING HERE AND */
3488 /* PROCEED IMMEDIATELY TO DIH. IN MULTI-THREADED VERSIONS WE */
3489 /* HAVE TO INSERT A MUTEX ON DIH TO ENSURE PROPER OPERATION. */
3490 /* SINCE THIS SIGNAL AND DIVERIFYREQ ARE THE ONLY SIGNALS SENT */
3491 /* TO DIH IN TRAFFIC IT SHOULD BE OK (3% OF THE EXECUTION TIME */
3492 /* IS SPENT IN DIH AND EVEN LESS IN REPLICATED NDB. */
3493 /*-------------------------------------------------------------*/
3494 EXECUTE_DIRECT(DBDIH, GSN_DIGETNODESREQ, signal,
3495 DiGetNodesReq::SignalLength, 0);
3496 DiGetNodesConf * conf = (DiGetNodesConf *)&signal->theData[0];
3497 UintR Tdata2 = conf->reqinfo;
3498 UintR TerrorIndicator = signal->theData[0];
3499 jamEntry();
3500 if (TerrorIndicator != 0) {
3501 execDIGETNODESREF(signal);
3502 return;
3503 }
3504
3505 if((ERROR_INSERTED(8071) || ERROR_INSERTED(8072)) &&
3506 (regTcPtr->m_special_op_flags & TcConnectRecord::SOF_INDEX_TABLE_READ) &&
3507 signal->theData[3] != getOwnNodeId())
3508 {
3509 ndbassert(false);
3510 signal->theData[1] = 626;
3511 execDIGETNODESREF(signal);
3512 return;
3513 }
3514
3515 if((ERROR_INSERTED(8050) || ERROR_INSERTED(8072)) &&
3516 refToBlock(regApiPtr->ndbapiBlockref) != DBUTIL &&
3517 regTcPtr->m_special_op_flags == 0 &&
3518 signal->theData[3] != getOwnNodeId())
3519 {
3520 ndbassert(false);
3521 signal->theData[1] = 626;
3522 execDIGETNODESREF(signal);
3523 return;
3524 }
3525
3526 /****************>>*/
3527 /* DIGETNODESCONF >*/
3528 /* ***************>*/
3529 if (Tspecial_op_flags & TcConnectRecord::SOF_REORG_TRIGGER_BASE)
3530 {
3531 jam();
3532 handle_reorg_trigger(conf);
3533 Tdata2 = conf->reqinfo;
3534 }
3535 else if (Tspecial_op_flags & TcConnectRecord::SOF_REORG_DELETE)
3536 {
3537 jam();
3538 handle_reorg_trigger(conf);
3539 Tdata2 = conf->reqinfo;
3540 }
3541 else if (Tdata2 & DiGetNodesConf::REORG_MOVING)
3542 {
3543 jam();
3544 regTcPtr->m_special_op_flags |= TcConnectRecord::SOF_REORG_MOVING;
3545 }
3546 else if (Tspecial_op_flags & TcConnectRecord::SOF_REORG_COPY)
3547 {
3548 jam();
3549 conf->nodes[0] = 0;
3550 }
3551
3552 UintR Tdata1 = conf->fragId;
3553 UintR Tdata3 = conf->nodes[0];
3554 UintR Tdata4 = conf->nodes[1];
3555 UintR Tdata5 = conf->nodes[2];
3556 UintR Tdata6 = conf->nodes[3];
3557
3558 regCachePtr->fragmentid = Tdata1;
3559 tnodeinfo = Tdata2;
3560
3561 regTcPtr->tcNodedata[0] = Tdata3;
3562 regTcPtr->tcNodedata[1] = Tdata4;
3563 regTcPtr->tcNodedata[2] = Tdata5;
3564 regTcPtr->tcNodedata[3] = Tdata6;
3565
3566 regTcPtr->lqhInstanceKey = (Tdata2 >> 24) & 127;// 1 bit used for reorg moving
3567
3568 Uint8 Toperation = regTcPtr->operation;
3569 Uint8 TopSimple = regTcPtr->opSimple;
3570 Uint8 TopDirty = regTcPtr->dirtyOp;
3571 tnoOfBackup = tnodeinfo & 3;
3572 tnoOfStandby = (tnodeinfo >> 8) & 3;
3573
3574 regCachePtr->fragmentDistributionKey = (tnodeinfo >> 16) & 255;
3575 if (Toperation == ZREAD || Toperation == ZREAD_EX)
3576 {
3577 regTcPtr->m_special_op_flags &= ~TcConnectRecord::SOF_REORG_MOVING;
3578 if (TopSimple == 1 && TopDirty == 0){
3579 jam();
3580 /*-------------------------------------------------------------*/
3581 /* A SIMPLE READ CAN SELECT ANY OF THE PRIMARY AND */
3582 /* BACKUP NODES TO READ. WE WILL TRY TO SELECT THIS */
3583 /* NODE IF POSSIBLE TO AVOID UNNECESSARY COMMUNICATION */
3584 /* WITH SIMPLE READS. */
3585 /*-------------------------------------------------------------*/
3586 arrGuard(tnoOfBackup, MAX_REPLICAS);
3587 UintR Tindex;
3588 UintR TownNode = cownNodeid;
3589 for (Tindex = 1; Tindex <= tnoOfBackup; Tindex++) {
3590 UintR Tnode = regTcPtr->tcNodedata[Tindex];
3591 jam();
3592 if (Tnode == TownNode) {
3593 jam();
3594 regTcPtr->tcNodedata[0] = Tnode;
3595 }//if
3596 }//for
3597 if(ERROR_INSERTED(8048) || ERROR_INSERTED(8049))
3598 {
3599 for (Tindex = 0; Tindex <= tnoOfBackup; Tindex++)
3600 {
3601 UintR Tnode = regTcPtr->tcNodedata[Tindex];
3602 jam();
3603 if (Tnode != TownNode) {
3604 jam();
3605 regTcPtr->tcNodedata[0] = Tnode;
3606 ndbout_c("Choosing %d", Tnode);
3607 }//if
3608 }//for
3609 }
3610 }//if
3611 jam();
3612 regTcPtr->lastReplicaNo = 0;
3613 regTcPtr->noOfNodes = 1;
3614
3615 if (regTcPtr->tcNodedata[0] == getOwnNodeId())
3616 c_counters.clocalReadCount++;
3617 }
3618 else if (Toperation == ZUNLOCK)
3619 {
3620 regTcPtr->m_special_op_flags &= ~TcConnectRecord::SOF_REORG_MOVING;
3621
3622 const Uint32 numNodes = tnoOfBackup + 1;
3623 /* Check that node from dist key is one of the nodes returned */
3624 bool found = false;
3625 for (Uint32 idx = 0; idx < numNodes; idx ++)
3626 {
3627 NodeId nodeId = regTcPtr->tcNodedata[ idx ];
3628 jam();
3629 if (nodeId == regCachePtr->unlockNodeId)
3630 {
3631 jam();
3632 found = true;
3633 break;
3634 }
3635 }
3636
3637 if (unlikely(!found))
3638 {
3639 /* DIH says the specified node does not store the fragment
3640 * requested
3641 */
3642 jam();
3643 TCKEY_abort(signal, 64);
3644 return;
3645 }
3646
3647 /* Check that the relevant LQH node can handle an unlock request */
3648 Uint32 lqhVersion = getNodeInfo(regCachePtr->unlockNodeId).m_version;
3649
3650 if (unlikely( lqhVersion < NDBD_UNLOCK_OP_SUPPORTED ))
3651 {
3652 TCKEY_abort(signal, 63);
3653 return;
3654 }
3655
3656 /* Select the specified node for the unlock op */
3657 regTcPtr->tcNodedata[0] = regCachePtr->unlockNodeId;
3658 regTcPtr->lastReplicaNo = 0;
3659 regTcPtr->noOfNodes = 1;
3660 }
3661 else {
3662 UintR TlastReplicaNo;
3663 jam();
3664 TlastReplicaNo = tnoOfBackup + tnoOfStandby;
3665 regTcPtr->lastReplicaNo = (Uint8)TlastReplicaNo;
3666 regTcPtr->noOfNodes = (Uint8)(TlastReplicaNo + 1);
3667 if (regTcPtr->tcNodedata[0] == getOwnNodeId())
3668 c_counters.clocalWriteCount++;
3669
3670 if (unlikely((Toperation == ZREFRESH) &&
3671 (! isRefreshSupported())))
3672 {
3673 /* Function not implemented yet */
3674 TCKEY_abort(signal,63);
3675 return;
3676 }
3677 }//if
3678
3679 if (regCachePtr->isLongTcKeyReq ||
3680 (regCachePtr->lenAiInTckeyreq == regCachePtr->attrlength)) {
3681 /****************************************************************>*/
3682 /* HERE WE HAVE FOUND THAT THE LAST SIGNAL BELONGING TO THIS */
3683 /* OPERATION HAVE BEEN RECEIVED. THIS MEANS THAT WE CAN NOW REUSE */
3684 /* THE API CONNECT RECORD. HOWEVER IF PREPARE OR COMMIT HAVE BEEN */
3685 /* RECEIVED THEN IT IS NOT ALLOWED TO RECEIVE ANY FURTHER */
3686 /* OPERATIONS. WE KNOW THAT WE WILL WAIT FOR DICT NEXT. IT IS NOT */
3687 /* POSSIBLE FOR THE TC CONNECTION TO BE READY YET. */
3688 /****************************************************************>*/
3689 switch (regApiPtr->apiConnectstate) {
3690 case CS_RECEIVING:
3691 jam();
3692 regApiPtr->apiConnectstate = CS_STARTED;
3693 break;
3694 case CS_REC_COMMITTING:
3695 jam();
3696 regApiPtr->apiConnectstate = CS_START_COMMITTING;
3697 break;
3698 case CS_SEND_FIRE_TRIG_REQ:
3699 case CS_WAIT_FIRE_TRIG_REQ:
3700 jam();
3701 break;
3702 default:
3703 jam();
3704 systemErrorLab(signal, __LINE__);
3705 return;
3706 }//switch
3707 attrinfoDihReceivedLab(signal);
3708 return;
3709 } else {
3710 if (regCachePtr->lenAiInTckeyreq < regCachePtr->attrlength) {
3711 TtcTimer = ctcTimer;
3712 jam();
3713 setApiConTimer(apiConnectptr.i, TtcTimer, __LINE__);
3714 regTcPtr->tcConnectstate = OS_WAIT_ATTR;
3715 return;
3716 } else {
3717 TCKEY_abort(signal, 11);
3718 return;
3719 }//if
3720 }//if
3721 return;
3722 }//Dbtc::tckeyreq050Lab()
3723
attrinfoDihReceivedLab(Signal * signal)3724 void Dbtc::attrinfoDihReceivedLab(Signal* signal)
3725 {
3726 CacheRecord * const regCachePtr = cachePtr.p;
3727 TcConnectRecord * const regTcPtr = tcConnectptr.p;
3728 ApiConnectRecord * const regApiPtr = apiConnectptr.p;
3729 Uint16 Tnode = regTcPtr->tcNodedata[0];
3730
3731 TableRecordPtr localTabptr;
3732 localTabptr.i = regCachePtr->tableref;
3733 localTabptr.p = &tableRecord[localTabptr.i];
3734
3735 if(localTabptr.p->checkTable(regCachePtr->schemaVersion)){
3736 ;
3737 } else {
3738 terrorCode = localTabptr.p->getErrorCode(regCachePtr->schemaVersion);
3739 TCKEY_abort(signal, 58);
3740 return;
3741 }
3742 if (Tnode != 0)
3743 {
3744 jam();
3745 arrGuard(Tnode, MAX_NDB_NODES);
3746 Uint32 instanceKey = regTcPtr->lqhInstanceKey;
3747 BlockReference lqhRef;
3748 if(regCachePtr->viaSPJFlag){
3749 //ndbout << "TC:Choosing SPJ." << endl;
3750 lqhRef = numberToRef(DBSPJ, instanceKey, Tnode);
3751 }else{
3752 //ndbout << "TC:Choosing LQH." << endl;
3753 lqhRef = numberToRef(DBLQH, instanceKey, Tnode);
3754 }
3755 packLqhkeyreq(signal, lqhRef);
3756 }
3757 else
3758 {
3759 /**
3760 * 1) This is when a reorg trigger fired...
3761 * but the tuple should *not* move
3762 * This should be prevent using the LqhKeyReq::setReorgFlag
3763 *
3764 * 2) This also happens during reorg copy, when a row should *not* be moved
3765 */
3766 jam();
3767 Uint32 trigOp = regTcPtr->triggeringOperation;
3768 Uint32 TclientData = regTcPtr->clientData;
3769 releaseKeys();
3770 releaseAttrinfo();
3771 regApiPtr->lqhkeyreqrec--;
3772 unlinkReadyTcCon(signal);
3773 clearCommitAckMarker(regApiPtr, regTcPtr);
3774 releaseTcCon();
3775
3776 if (trigOp != RNIL)
3777 {
3778 jam();
3779 //ndbassert(false); // see above
3780 TcConnectRecordPtr opPtr;
3781 opPtr.i = trigOp;
3782 ptrCheckGuard(opPtr, ctcConnectFilesize, tcConnectRecord);
3783 trigger_op_finished(signal, apiConnectptr, RNIL, opPtr.p, 0);
3784 return;
3785 }
3786 else
3787 {
3788 jam();
3789 Uint32 Ttckeyrec = regApiPtr->tckeyrec;
3790 regApiPtr->tcSendArray[Ttckeyrec] = TclientData;
3791 regApiPtr->tcSendArray[Ttckeyrec + 1] = 0;
3792 regApiPtr->tckeyrec = Ttckeyrec + 2;
3793 lqhKeyConf_checkTransactionState(signal, apiConnectptr);
3794 }
3795 }
3796 }//Dbtc::attrinfoDihReceivedLab()
3797
packLqhkeyreq(Signal * signal,BlockReference TBRef)3798 void Dbtc::packLqhkeyreq(Signal* signal,
3799 BlockReference TBRef)
3800 {
3801 CacheRecord * const regCachePtr = cachePtr.p;
3802 UintR Tkeylen = regCachePtr->keylen;
3803
3804 ndbassert( signal->getNoOfSections() == 0 );
3805
3806 sendlqhkeyreq(signal, TBRef);
3807
3808 /* Do we need to send a KeyInfo signal train? */
3809 if ((! regCachePtr->useLongLqhKeyReq) &&
3810 (Tkeylen > LqhKeyReq::MaxKeyInfo))
3811 {
3812 /* Build KeyInfo train from KeyInfo long signal section */
3813 sendKeyInfoTrain(signal,
3814 TBRef,
3815 tcConnectptr.i,
3816 LqhKeyReq::MaxKeyInfo,
3817 regCachePtr->keyInfoSectionI);
3818 }//if
3819
3820 if (tcConnectptr.p->triggeringOperation != RNIL &&
3821 tcConnectptr.p->currentTriggerId != RNIL)
3822 {
3823 jam();
3824 //NOTE: before packLqhkeyreq040Lab which might release operation...
3825 Ptr<TcDefinedTriggerData> trigPtr;
3826 c_theDefinedTriggers.getPtr(trigPtr, tcConnectptr.p->currentTriggerId);
3827 trigPtr.p->refCount++;
3828 }
3829
3830 /* Release key storage */
3831 releaseKeys();
3832 packLqhkeyreq040Lab(signal,
3833 TBRef);
3834 }//Dbtc::packLqhkeyreq()
3835
3836
sendlqhkeyreq(Signal * signal,BlockReference TBRef)3837 void Dbtc::sendlqhkeyreq(Signal* signal,
3838 BlockReference TBRef)
3839 {
3840 UintR tslrAttrLen;
3841 UintR Tdata10;
3842 TcConnectRecord * const regTcPtr = tcConnectptr.p;
3843 ApiConnectRecord * const regApiPtr = apiConnectptr.p;
3844 CacheRecord * const regCachePtr = cachePtr.p;
3845 Uint32 version = getNodeInfo(refToNode(TBRef)).m_version;
3846 UintR sig0, sig1, sig2, sig3, sig4, sig5, sig6;
3847 #ifdef ERROR_INSERT
3848 if (ERROR_INSERTED(8002)) {
3849 systemErrorLab(signal, __LINE__);
3850 }//if
3851 if (ERROR_INSERTED(8007)) {
3852 if (apiConnectptr.p->apiConnectstate == CS_STARTED) {
3853 CLEAR_ERROR_INSERT_VALUE;
3854 return;
3855 }//if
3856 }//if
3857 if (ERROR_INSERTED(8008)) {
3858 if (apiConnectptr.p->apiConnectstate == CS_START_COMMITTING) {
3859 CLEAR_ERROR_INSERT_VALUE;
3860 return;
3861 }//if
3862 }//if
3863 if (ERROR_INSERTED(8009)) {
3864 if (apiConnectptr.p->apiConnectstate == CS_STARTED) {
3865 return;
3866 }//if
3867 }//if
3868 if (ERROR_INSERTED(8010)) {
3869 if (apiConnectptr.p->apiConnectstate == CS_START_COMMITTING) {
3870 return;
3871 }//if
3872 }//if
3873 #endif
3874 Uint32 Tdeferred = tc_testbit(regApiPtr->m_flags,
3875 ApiConnectRecord::TF_DEFERRED_CONSTRAINTS);
3876 Uint32 Tdisable_fk = tc_testbit(regApiPtr->m_flags,
3877 ApiConnectRecord::TF_DISABLE_FK_CONSTRAINTS);
3878 Uint32 reorg = ScanFragReq::REORG_ALL;
3879 Uint32 Tspecial_op = regTcPtr->m_special_op_flags;
3880 if (Tspecial_op == 0)
3881 {
3882 }
3883 else if (Tspecial_op & (TcConnectRecord::SOF_REORG_TRIGGER_BASE |
3884 TcConnectRecord::SOF_REORG_DELETE))
3885 {
3886 reorg = ScanFragReq::REORG_NOT_MOVED;
3887 }
3888 else if (Tspecial_op & TcConnectRecord::SOF_REORG_MOVING)
3889 {
3890 reorg = ScanFragReq::REORG_MOVED;
3891 }
3892
3893 Uint32 inlineKeyLen= 0;
3894 Uint32 inlineAttrLen= 0;
3895
3896 /* We normally send long LQHKEYREQ unless the
3897 * destination cannot handle it or we are
3898 * testing
3899 */
3900 if (unlikely((version < NDBD_LONG_LQHKEYREQ) ||
3901 ERROR_INSERTED(8069)))
3902 {
3903 /* Short LQHKEYREQ, with some key/attr data inline */
3904 regCachePtr->useLongLqhKeyReq= 0;
3905 inlineKeyLen= regCachePtr->keylen;
3906 inlineAttrLen= regCachePtr->attrlength;
3907 }
3908 else
3909 /* Long LQHKEYREQ, with key/attr data in long sections */
3910 regCachePtr->useLongLqhKeyReq= 1;
3911
3912 tslrAttrLen = 0;
3913 LqhKeyReq::setAttrLen(tslrAttrLen, inlineAttrLen);
3914 /* ---------------------------------------------------------------------- */
3915 // Bit16 == 0 since StoredProcedures are not yet supported.
3916 /* ---------------------------------------------------------------------- */
3917 LqhKeyReq::setDistributionKey(tslrAttrLen, regCachePtr->fragmentDistributionKey);
3918 LqhKeyReq::setScanTakeOverFlag(tslrAttrLen, regCachePtr->scanTakeOverInd);
3919 LqhKeyReq::setReorgFlag(tslrAttrLen, reorg);
3920
3921 Tdata10 = 0;
3922 sig0 = regTcPtr->opSimple;
3923 sig1 = regTcPtr->operation;
3924 sig2 = regTcPtr->dirtyOp;
3925 bool dirtyRead = (sig1 == ZREAD && sig2 == ZTRUE);
3926 LqhKeyReq::setKeyLen(Tdata10, inlineKeyLen);
3927 LqhKeyReq::setLastReplicaNo(Tdata10, regTcPtr->lastReplicaNo);
3928 if (unlikely(version < NDBD_ROWID_VERSION))
3929 {
3930 Uint32 op = regTcPtr->operation;
3931 Uint32 lock = (Operation_t) op == ZREAD_EX ? ZUPDATE : (Operation_t) op == ZWRITE ? ZINSERT : (Operation_t) op;
3932 LqhKeyReq::setLockType(Tdata10, lock);
3933 }
3934 /* ---------------------------------------------------------------------- */
3935 // Indicate Application Reference is present in bit 15
3936 /* ---------------------------------------------------------------------- */
3937 LqhKeyReq::setApplicationAddressFlag(Tdata10, 1);
3938 LqhKeyReq::setDirtyFlag(Tdata10, sig2);
3939 LqhKeyReq::setInterpretedFlag(Tdata10, regCachePtr->opExec);
3940 LqhKeyReq::setSimpleFlag(Tdata10, sig0);
3941 LqhKeyReq::setOperation(Tdata10, sig1);
3942 LqhKeyReq::setNoDiskFlag(Tdata10, regCachePtr->m_no_disk_flag);
3943 LqhKeyReq::setQueueOnRedoProblemFlag(Tdata10, regCachePtr->m_op_queue);
3944 LqhKeyReq::setDeferredConstraints(Tdata10, (Tdeferred & m_deferred_enabled));
3945 LqhKeyReq::setDisableFkConstraints(Tdata10, Tdisable_fk);
3946
3947 /* -----------------------------------------------------------------------
3948 * If we are sending a short LQHKEYREQ, then there will be some AttrInfo
3949 * in the LQHKEYREQ.
3950 * Work out how much we'll send
3951 * ----------------------------------------------------------------------- */
3952 UintR aiInLqhKeyReq= 0;
3953
3954 if (! regCachePtr->useLongLqhKeyReq)
3955 {
3956 /* Short LQHKEYREQ :
3957 * Send max 5 words of AttrInfo in LQHKEYREQ
3958 */
3959 aiInLqhKeyReq= MIN(LqhKeyReq::MaxAttrInfo, regCachePtr->attrlength);
3960 }
3961
3962 LqhKeyReq::setAIInLqhKeyReq(Tdata10, aiInLqhKeyReq);
3963 /* -----------------------------------------------------------------------
3964 * Bit 27 == 0 since TC record is the same as the client record.
3965 * Bit 28 == 0 since readLenAi can only be set after reading in LQH.
3966 * ----------------------------------------------------------------------- */
3967 LqhKeyReq::setMarkerFlag(Tdata10, regTcPtr->commitAckMarker != RNIL ? 1 : 0);
3968
3969 if (regTcPtr->m_special_op_flags & TcConnectRecord::SOF_FK_READ_COMMITTED)
3970 {
3971 LqhKeyReq::setNormalProtocolFlag(Tdata10, 1);
3972 LqhKeyReq::setDirtyFlag(Tdata10, 1);
3973 }
3974 /* ************************************************************> */
3975 /* NO READ LENGTH SENT FROM TC. SEQUENTIAL NUMBER IS 1 AND IT */
3976 /* IS SENT TO A PRIMARY NODE. */
3977 /* ************************************************************> */
3978
3979 LqhKeyReq * const lqhKeyReq = (LqhKeyReq *)signal->getDataPtrSend();
3980
3981 sig0 = tcConnectptr.i;
3982 sig2 = regCachePtr->hashValue;
3983 sig4 = cownref;
3984 sig5 = regTcPtr->savePointId;
3985
3986 lqhKeyReq->clientConnectPtr = sig0;
3987 lqhKeyReq->attrLen = tslrAttrLen;
3988 lqhKeyReq->hashValue = sig2;
3989 lqhKeyReq->requestInfo = Tdata10;
3990 lqhKeyReq->tcBlockref = sig4;
3991 lqhKeyReq->savePointId = sig5;
3992
3993 sig0 = regCachePtr->tableref + ((regCachePtr->schemaVersion << 16) & 0xFFFF0000);
3994 sig1 = regCachePtr->fragmentid + (regTcPtr->tcNodedata[1] << 16);
3995 sig2 = regApiPtr->transid[0];
3996 sig3 = regApiPtr->transid[1];
3997 sig4 =
3998 (regTcPtr->m_special_op_flags & TcConnectRecord::SOF_INDEX_TABLE_READ) ?
3999 reference() : regApiPtr->ndbapiBlockref;
4000 sig5 = regTcPtr->clientData;
4001 sig6 = regCachePtr->scanInfo;
4002
4003 if (! dirtyRead)
4004 {
4005 regApiPtr->m_transaction_nodes.set(regTcPtr->tcNodedata[0]);
4006 regApiPtr->m_transaction_nodes.set(regTcPtr->tcNodedata[1]);
4007 regApiPtr->m_transaction_nodes.set(regTcPtr->tcNodedata[2]);
4008 regApiPtr->m_transaction_nodes.set(regTcPtr->tcNodedata[3]);
4009 }
4010
4011 lqhKeyReq->tableSchemaVersion = sig0;
4012 lqhKeyReq->fragmentData = sig1;
4013 lqhKeyReq->transId1 = sig2;
4014 lqhKeyReq->transId2 = sig3;
4015 lqhKeyReq->scanInfo = sig6;
4016
4017 lqhKeyReq->variableData[0] = sig4;
4018 lqhKeyReq->variableData[1] = sig5;
4019
4020 UintR nextPos = 2;
4021
4022 if (regTcPtr->lastReplicaNo > 1) {
4023 sig0 = (UintR)regTcPtr->tcNodedata[2] +
4024 (UintR)(regTcPtr->tcNodedata[3] << 16);
4025 lqhKeyReq->variableData[nextPos] = sig0;
4026 nextPos++;
4027 }//if
4028
4029 // Reset trigger count
4030 regTcPtr->numFiredTriggers = 0;
4031 regTcPtr->triggerExecutionCount = 0;
4032
4033 if (regCachePtr->useLongLqhKeyReq)
4034 {
4035 /* Build long LQHKeyReq using Key + AttrInfo sections */
4036 SectionHandle handle(this);
4037 SegmentedSectionPtr keyInfoSection;
4038
4039 getSection(keyInfoSection, regCachePtr->keyInfoSectionI);
4040
4041 handle.m_ptr[ LqhKeyReq::KeyInfoSectionNum ]= keyInfoSection;
4042 handle.m_cnt= 1;
4043
4044 if (regCachePtr->attrlength != 0)
4045 {
4046 SegmentedSectionPtr attrInfoSection;
4047
4048 ndbassert(regCachePtr->attrInfoSectionI != RNIL);
4049 getSection(attrInfoSection, regCachePtr->attrInfoSectionI);
4050
4051 handle.m_ptr[ LqhKeyReq::AttrInfoSectionNum ]= attrInfoSection;
4052 handle.m_cnt= 2;
4053 }
4054 sendSignal(TBRef, GSN_LQHKEYREQ, signal,
4055 nextPos + LqhKeyReq::FixedSignalLength, JBB,
4056 &handle);
4057
4058 /* Long sections were freed as part of sendSignal */
4059 ndbassert( handle.m_cnt == 0 );
4060 regCachePtr->keyInfoSectionI= RNIL;
4061 regCachePtr->attrInfoSectionI= RNIL;
4062 }
4063 else
4064 {
4065 /* Build short LQHKeyReq from Key + AttrInfo sections
4066 *
4067 * Read upto 4 words of KeyInfo from TCKEYREQ KeyInfo section into
4068 * LqhKeyReq signal
4069 */
4070 SegmentedSectionPtr keyInfoSection;
4071
4072 getSection(keyInfoSection, regCachePtr->keyInfoSectionI);
4073 SectionReader keyInfoReader(keyInfoSection, getSectionSegmentPool());
4074
4075 UintR keyLenInLqhKeyReq= MIN(LqhKeyReq::MaxKeyInfo, regCachePtr->keylen);
4076
4077 keyInfoReader.getWords(&lqhKeyReq->variableData[nextPos], keyLenInLqhKeyReq);
4078
4079 nextPos+= keyLenInLqhKeyReq;
4080
4081 if (aiInLqhKeyReq != 0)
4082 {
4083 /* Read upto 5 words of AttrInfo from TCKEYREQ KeyInfo section into
4084 * LqhKeyReq signal
4085 */
4086 SegmentedSectionPtr attrInfoSection;
4087
4088 ndbassert(regCachePtr->attrInfoSectionI != RNIL);
4089
4090 getSection(attrInfoSection, regCachePtr->attrInfoSectionI);
4091 SectionReader attrInfoReader(attrInfoSection, getSectionSegmentPool());
4092
4093 attrInfoReader.getWords(&lqhKeyReq->variableData[nextPos], aiInLqhKeyReq);
4094
4095 nextPos+= aiInLqhKeyReq;
4096 }
4097
4098 sendSignal(TBRef, GSN_LQHKEYREQ, signal,
4099 nextPos + LqhKeyReq::FixedSignalLength, JBB);
4100 }
4101 }//Dbtc::sendlqhkeyreq()
4102
packLqhkeyreq040Lab(Signal * signal,BlockReference TBRef)4103 void Dbtc::packLqhkeyreq040Lab(Signal* signal,
4104 BlockReference TBRef)
4105 {
4106 TcConnectRecord * const regTcPtr = tcConnectptr.p;
4107 CacheRecord * const regCachePtr = cachePtr.p;
4108 #ifdef ERROR_INSERT
4109 ApiConnectRecord * const regApiPtr = apiConnectptr.p;
4110
4111 if (ERROR_INSERTED(8009)) {
4112 if (regApiPtr->apiConnectstate == CS_STARTED) {
4113 CLEAR_ERROR_INSERT_VALUE;
4114 return;
4115 }//if
4116 }//if
4117 if (ERROR_INSERTED(8010)) {
4118 if (regApiPtr->apiConnectstate == CS_START_COMMITTING) {
4119 CLEAR_ERROR_INSERT_VALUE;
4120 return;
4121 }//if
4122 }//if
4123 #endif
4124
4125 /* Do we have an ATTRINFO train to send? */
4126 if (!regCachePtr->useLongLqhKeyReq)
4127 {
4128 /* Short LqhKeyReq */
4129 if (regCachePtr->attrlength > LqhKeyReq::MaxAttrInfo)
4130 {
4131 if (unlikely( !sendAttrInfoTrain(signal,
4132 TBRef,
4133 tcConnectptr.i,
4134 LqhKeyReq::MaxAttrInfo,
4135 regCachePtr->attrInfoSectionI)))
4136 {
4137 jam();
4138 TCKEY_abort(signal, 17);
4139 return;
4140 }
4141 }
4142 } // useLongLqhKeyReq
4143
4144 /* Release AttrInfo related storage, and the Cache Record */
4145 releaseAttrinfo();
4146
4147 UintR TtcTimer = ctcTimer;
4148 UintR Tread = (regTcPtr->operation == ZREAD);
4149 UintR Tdirty = (regTcPtr->dirtyOp == ZTRUE);
4150 UintR Tboth = Tread & Tdirty;
4151 setApiConTimer(apiConnectptr.i, TtcTimer, __LINE__);
4152 jam();
4153 /*--------------------------------------------------------------------
4154 * WE HAVE SENT ALL THE SIGNALS OF THIS OPERATION. SET STATE AND EXIT.
4155 *---------------------------------------------------------------------*/
4156 if (Tboth) {
4157 jam();
4158 releaseDirtyRead(signal, apiConnectptr, tcConnectptr.p);
4159 return;
4160 }//if
4161 regTcPtr->tcConnectstate = OS_OPERATING;
4162 return;
4163 }//Dbtc::packLqhkeyreq040Lab()
4164
4165 /* ========================================================================= */
4166 /* ------- RELEASE ALL ATTRINFO RECORDS IN AN OPERATION RECORD ------- */
4167 /* ========================================================================= */
releaseAttrinfo()4168 void Dbtc::releaseAttrinfo()
4169 {
4170 CacheRecord * const regCachePtr = cachePtr.p;
4171 Uint32 attrInfoSectionI= cachePtr.p->attrInfoSectionI;
4172
4173 /* Release AttrInfo section if there is one */
4174 releaseSection( attrInfoSectionI );
4175 cachePtr.p->attrInfoSectionI= RNIL;
4176
4177 //---------------------------------------------------
4178 // Now we will release the cache record at the same
4179 // time as releasing the attrinfo records.
4180 //---------------------------------------------------
4181 ApiConnectRecord * const regApiPtr = apiConnectptr.p;
4182 UintR TfirstfreeCacheRec = cfirstfreeCacheRec;
4183 UintR TCacheIndex = cachePtr.i;
4184 regCachePtr->nextCacheRec = TfirstfreeCacheRec;
4185 cfirstfreeCacheRec = TCacheIndex;
4186 regApiPtr->cachePtr = RNIL;
4187 return;
4188 }//Dbtc::releaseAttrinfo()
4189
4190 /* ========================================================================= */
4191 /* ------- RELEASE ALL RECORDS CONNECTED TO A DIRTY OPERATION ------- */
4192 /* ========================================================================= */
releaseDirtyRead(Signal * signal,ApiConnectRecordPtr regApiPtr,TcConnectRecord * regTcPtr)4193 void Dbtc::releaseDirtyRead(Signal* signal,
4194 ApiConnectRecordPtr regApiPtr,
4195 TcConnectRecord* regTcPtr)
4196 {
4197 Uint32 Ttckeyrec = regApiPtr.p->tckeyrec;
4198 Uint32 TclientData = regTcPtr->clientData;
4199 Uint32 Tnode = regTcPtr->tcNodedata[0];
4200 Uint32 Tlqhkeyreqrec = regApiPtr.p->lqhkeyreqrec;
4201 ConnectionState state = regApiPtr.p->apiConnectstate;
4202
4203 regApiPtr.p->tcSendArray[Ttckeyrec] = TclientData;
4204 regApiPtr.p->tcSendArray[Ttckeyrec + 1] = TcKeyConf::DirtyReadBit | Tnode;
4205 regApiPtr.p->tckeyrec = Ttckeyrec + 2;
4206
4207 unlinkReadyTcCon(signal);
4208 releaseTcCon();
4209
4210 /**
4211 * No LQHKEYCONF in Simple/Dirty read
4212 * Therefore decrese no LQHKEYCONF(REF) we are waiting for
4213 */
4214 c_counters.csimpleReadCount++;
4215 regApiPtr.p->lqhkeyreqrec = --Tlqhkeyreqrec;
4216
4217 if(Tlqhkeyreqrec == 0)
4218 {
4219 /**
4220 * Special case of lqhKeyConf_checkTransactionState:
4221 * - commit with zero operations: handle only for simple read
4222 */
4223 sendtckeyconf(signal, state == CS_START_COMMITTING);
4224 regApiPtr.p->apiConnectstate =
4225 (state == CS_START_COMMITTING ? CS_CONNECTED : state);
4226 setApiConTimer(regApiPtr.i, 0, __LINE__);
4227
4228 return;
4229 }
4230
4231 /**
4232 * Emulate LQHKEYCONF
4233 */
4234 lqhKeyConf_checkTransactionState(signal, regApiPtr);
4235 }//Dbtc::releaseDirtyRead()
4236
4237 /* ------------------------------------------------------------------------- */
4238 /* ------- CHECK IF ALL TC CONNECTIONS ARE COMPLETED ------- */
4239 /* ------------------------------------------------------------------------- */
unlinkReadyTcCon(Signal * signal)4240 void Dbtc::unlinkReadyTcCon(Signal* signal)
4241 {
4242 TcConnectRecordPtr urtTcConnectptr;
4243
4244 TcConnectRecord * const regTcPtr = tcConnectptr.p;
4245 TcConnectRecord *localTcConnectRecord = tcConnectRecord;
4246 UintR TtcConnectFilesize = ctcConnectFilesize;
4247 ApiConnectRecord * const regApiPtr = apiConnectptr.p;
4248 if (regTcPtr->prevTcConnect != RNIL) {
4249 jam();
4250 urtTcConnectptr.i = regTcPtr->prevTcConnect;
4251 ptrCheckGuard(urtTcConnectptr, TtcConnectFilesize, localTcConnectRecord);
4252 urtTcConnectptr.p->nextTcConnect = regTcPtr->nextTcConnect;
4253 } else {
4254 jam();
4255 regApiPtr->firstTcConnect = regTcPtr->nextTcConnect;
4256 }//if
4257 if (regTcPtr->nextTcConnect != RNIL) {
4258 jam();
4259 urtTcConnectptr.i = regTcPtr->nextTcConnect;
4260 ptrCheckGuard(urtTcConnectptr, TtcConnectFilesize, localTcConnectRecord);
4261 urtTcConnectptr.p->prevTcConnect = regTcPtr->prevTcConnect;
4262 } else {
4263 jam();
4264 regApiPtr->lastTcConnect = tcConnectptr.p->prevTcConnect;
4265 }//if
4266 }//Dbtc::unlinkReadyTcCon()
4267
releaseTcCon()4268 void Dbtc::releaseTcCon()
4269 {
4270 TcConnectRecord * const regTcPtr = tcConnectptr.p;
4271 UintR TfirstfreeTcConnect = cfirstfreeTcConnect;
4272 UintR TtcConnectptrIndex = tcConnectptr.i;
4273
4274 ndbrequire(regTcPtr->commitAckMarker == RNIL);
4275 regTcPtr->tcConnectstate = OS_CONNECTED;
4276 regTcPtr->nextTcConnect = TfirstfreeTcConnect;
4277 regTcPtr->apiConnect = RNIL;
4278 regTcPtr->m_special_op_flags = 0;
4279 regTcPtr->indexOp = RNIL;
4280 cfirstfreeTcConnect = TtcConnectptrIndex;
4281 c_counters.cconcurrentOp--;
4282
4283 if (regTcPtr->triggeringOperation != RNIL &&
4284 regTcPtr->currentTriggerId != RNIL)
4285 {
4286 jam();
4287 Ptr<TcDefinedTriggerData> trigPtr;
4288 c_theDefinedTriggers.getPtr(trigPtr, regTcPtr->currentTriggerId);
4289 ndbassert(trigPtr.p->refCount);
4290 if (trigPtr.p->refCount)
4291 {
4292 trigPtr.p->refCount--;
4293 }
4294 }
4295
4296 if (!regTcPtr->thePendingTriggers.isEmpty())
4297 {
4298 LocalDLFifoList<TcFiredTriggerData>
4299 list(c_theFiredTriggerPool, regTcPtr->thePendingTriggers);
4300 releaseFiredTriggerData(&list);
4301 }
4302
4303 ndbrequire(regTcPtr->thePendingTriggers.isEmpty());
4304
4305 }//Dbtc::releaseTcCon()
4306
execPACKED_SIGNAL(Signal * signal)4307 void Dbtc::execPACKED_SIGNAL(Signal* signal)
4308 {
4309 LqhKeyConf * const lqhKeyConf = (LqhKeyConf *)signal->getDataPtr();
4310
4311 UintR Ti;
4312 UintR Tstep = 0;
4313 UintR Tlength;
4314 UintR TpackedData[28];
4315 UintR Tdata1, Tdata2, Tdata3, Tdata4;
4316
4317 jamEntry();
4318 Tlength = signal->length();
4319 if (Tlength > 25) {
4320 jam();
4321 systemErrorLab(signal, __LINE__);
4322 return;
4323 }//if
4324 Uint32* TpackDataPtr;
4325 for (Ti = 0; Ti < Tlength; Ti += 4) {
4326 Uint32* TsigDataPtr = &signal->theData[Ti];
4327 Tdata1 = TsigDataPtr[0];
4328 Tdata2 = TsigDataPtr[1];
4329 Tdata3 = TsigDataPtr[2];
4330 Tdata4 = TsigDataPtr[3];
4331
4332 TpackDataPtr = &TpackedData[Ti];
4333 TpackDataPtr[0] = Tdata1;
4334 TpackDataPtr[1] = Tdata2;
4335 TpackDataPtr[2] = Tdata3;
4336 TpackDataPtr[3] = Tdata4;
4337 }//for
4338
4339 if (VERIFY_PACKED_RECEIVE)
4340 {
4341 ndbrequire(PackedSignal::verify(&TpackedData[0],
4342 Tlength,
4343 cownref,
4344 TC_RECEIVE_TYPES,
4345 0)); /* Irrelevant */
4346 }
4347 while (Tlength > Tstep) {
4348
4349 TpackDataPtr = &TpackedData[Tstep];
4350 Tdata1 = TpackDataPtr[0];
4351 Tdata2 = TpackDataPtr[1];
4352 Tdata3 = TpackDataPtr[2];
4353
4354 lqhKeyConf->connectPtr = Tdata1 & 0x0FFFFFFF;
4355 lqhKeyConf->opPtr = Tdata2;
4356 lqhKeyConf->userRef = Tdata3;
4357
4358 switch (Tdata1 >> 28) {
4359 case ZCOMMITTED:
4360 signal->header.theLength = 3;
4361 jamBuffer()->markEndOfSigExec();
4362 execCOMMITTED(signal);
4363 Tstep += 3;
4364 break;
4365 case ZCOMPLETED:
4366 signal->header.theLength = 3;
4367 jamBuffer()->markEndOfSigExec();
4368 execCOMPLETED(signal);
4369 Tstep += 3;
4370 break;
4371 case ZLQHKEYCONF:
4372 jam();
4373 Tdata1 = TpackDataPtr[3];
4374 Tdata2 = TpackDataPtr[4];
4375 Tdata3 = TpackDataPtr[5];
4376 Tdata4 = TpackDataPtr[6];
4377
4378 lqhKeyConf->readLen = Tdata1;
4379 lqhKeyConf->transId1 = Tdata2;
4380 lqhKeyConf->transId2 = Tdata3;
4381 lqhKeyConf->numFiredTriggers = Tdata4;
4382 signal->header.theLength = LqhKeyConf::SignalLength;
4383 jamBuffer()->markEndOfSigExec();
4384 execLQHKEYCONF(signal);
4385 Tstep += LqhKeyConf::SignalLength;
4386 break;
4387 case ZFIRE_TRIG_CONF:
4388 jam();
4389 signal->header.theLength = 4;
4390 signal->theData[3] = TpackDataPtr[3];
4391 jamBuffer()->markEndOfSigExec();
4392 execFIRE_TRIG_CONF(signal);
4393 Tstep += 4;
4394 break;
4395 default:
4396 systemErrorLab(signal, __LINE__);
4397 return;
4398 }//switch
4399 }//while
4400 return;
4401 }//Dbtc::execPACKED_SIGNAL()
4402
4403
execSIGNAL_DROPPED_REP(Signal * signal)4404 void Dbtc::execSIGNAL_DROPPED_REP(Signal* signal)
4405 {
4406 /* An incoming signal was dropped, handle it
4407 * Dropped signal really means that we ran out of
4408 * long signal buffering to store its sections
4409 */
4410 jamEntry();
4411
4412 if (!assembleDroppedFragments(signal))
4413 {
4414 jam();
4415 return;
4416 }
4417
4418 const SignalDroppedRep* rep = (SignalDroppedRep*) &signal->theData[0];
4419 Uint32 originalGSN= rep->originalGsn;
4420
4421 DEBUG("SignalDroppedRep received for GSN " << originalGSN);
4422
4423 switch(originalGSN) {
4424 case GSN_TCKEYREQ:
4425 jam();
4426 /* Fall through */
4427 case GSN_TCINDXREQ:
4428 {
4429 jam();
4430
4431 /* Get original signal data - unfortunately it may
4432 * have been truncated. We must not read beyond
4433 * word # 22
4434 * We will send an Abort to the Api using info from
4435 * the received signal and clean up our transaction
4436 * state
4437 */
4438 const TcKeyReq * const truncatedTcKeyReq =
4439 (TcKeyReq *) &rep->originalData[0];
4440
4441 const UintR apiIndex = truncatedTcKeyReq->apiConnectPtr;
4442
4443 if (apiIndex >= capiConnectFilesize)
4444 {
4445 jam();
4446 warningHandlerLab(signal, __LINE__);
4447 return;
4448 }
4449
4450 /* We have a valid Api ConnectPtr...
4451 * Ensure that we have the necessary information
4452 * to send a rollback to the client
4453 */
4454 apiConnectptr.i = apiIndex;
4455 ApiConnectRecord * const regApiPtr = &apiConnectRecord[apiIndex];
4456 apiConnectptr.p = regApiPtr;
4457 UintR transId1= truncatedTcKeyReq->transId1;
4458 UintR transId2= truncatedTcKeyReq->transId2;
4459
4460 /* Ensure that the apiConnectptr global is initialised
4461 * may not be in cases where we drop the first signal of
4462 * a transaction
4463 */
4464 apiConnectptr.p->transid[0] = transId1;
4465 apiConnectptr.p->transid[1] = transId2;
4466 apiConnectptr.p->returncode = ZGET_DATAREC_ERROR;
4467
4468 /* Set m_exec_flag according to the dropped request */
4469 apiConnectptr.p->m_flags |=
4470 TcKeyReq::getExecuteFlag(truncatedTcKeyReq->requestInfo) ?
4471 ApiConnectRecord::TF_EXEC_FLAG : 0;
4472
4473 DEBUG(" Execute flag set to " << tc_testbit(apiConnectptr.p->m_flags,
4474 ApiConnectRecord::TF_EXEC_FLAG)
4475 );
4476
4477 abortErrorLab(signal);
4478
4479 break;
4480 }
4481 case GSN_SCAN_TABREQ:
4482 {
4483 jam();
4484 /* Get information necessary to send SCAN_TABREF back to client */
4485 // TODO : Handle dropped signal fragments
4486 const ScanTabReq * const truncatedScanTabReq =
4487 (ScanTabReq *) &rep->originalData[0];
4488
4489 Uint32 apiConnectPtr= truncatedScanTabReq->apiConnectPtr;
4490 Uint32 transId1= truncatedScanTabReq->transId1;
4491 Uint32 transId2= truncatedScanTabReq->transId2;
4492
4493 if (apiConnectPtr >= capiConnectFilesize)
4494 {
4495 jam();
4496 warningHandlerLab(signal, __LINE__);
4497 return;
4498 }//if
4499
4500 apiConnectptr.i = apiConnectPtr;
4501 ptrAss(apiConnectptr, apiConnectRecord);
4502 ApiConnectRecord * transP = apiConnectptr.p;
4503
4504 /* Now send the SCAN_TABREF */
4505 ScanTabRef* ref= (ScanTabRef*)&signal->theData[0];
4506 ref->apiConnectPtr = transP->ndbapiConnect;
4507 ref->transId1= transId1;
4508 ref->transId2= transId2;
4509 ref->errorCode= ZGET_ATTRBUF_ERROR;
4510 ref->closeNeeded= 0;
4511
4512 sendSignal(transP->ndbapiBlockref, GSN_SCAN_TABREF,
4513 signal, ScanTabRef::SignalLength, JBB);
4514 break;
4515 }
4516 default:
4517 jam();
4518 /* Don't expect dropped signals for other GSNs,
4519 * default handling
4520 * TODO : Can TC get long TRANSID_AI as part of
4521 * Unique index operations?
4522 */
4523 SimulatedBlock::execSIGNAL_DROPPED_REP(signal);
4524 };
4525
4526 return;
4527 }
4528
4529 bool
insert_in_commit_ack_marker(Dbtc * tc,Uint32 instanceKey,NodeId node_id)4530 Dbtc::CommitAckMarker::insert_in_commit_ack_marker(Dbtc *tc,
4531 Uint32 instanceKey,
4532 NodeId node_id)
4533 {
4534 const NodeInfo& nodeInfo = tc->getNodeInfo(node_id);
4535 Uint32 workers = nodeInfo.m_lqh_workers;
4536 assert(instanceKey != 0);
4537 Uint32 instanceNo = workers == 0 ? 0 : 1 + (instanceKey - 1) % workers;
4538 Uint32 item = instanceNo + (node_id << 16);
4539 CommitAckMarkerBuffer::DataBufferPool & pool =
4540 tc->c_theCommitAckMarkerBufferPool;
4541 // check for duplicate (todo DataBuffer method find-or-append)
4542 {
4543 LocalDataBuffer<5> tmp(pool, this->theDataBuffer);
4544 CommitAckMarkerBuffer::Iterator iter;
4545 bool next_flag = tmp.first(iter);
4546 while (next_flag)
4547 {
4548 Uint32 dataWord = *iter.data;
4549 if (dataWord == item)
4550 {
4551 return true;
4552 }
4553 next_flag = tmp.next(iter, 1);
4554 }
4555 }
4556 LocalDataBuffer<5> tmp(pool, this->theDataBuffer);
4557 return tmp.append(&item, (Uint32)1);
4558 }
4559 bool
insert_in_commit_ack_marker_all(Dbtc * tc,NodeId node_id)4560 Dbtc::CommitAckMarker::insert_in_commit_ack_marker_all(Dbtc *tc,
4561 NodeId node_id)
4562 {
4563 for (Uint32 ikey = 1; ikey <= MAX_NDBMT_LQH_THREADS; ikey++)
4564 {
4565 if (!insert_in_commit_ack_marker(tc, ikey, node_id))
4566 return false;
4567 }
4568 return true;
4569 }
4570
execLQHKEYCONF(Signal * signal)4571 void Dbtc::execLQHKEYCONF(Signal* signal)
4572 {
4573 const LqhKeyConf * lqhKeyConf = CAST_CONSTPTR(LqhKeyConf,
4574 signal->getDataPtr());
4575 #ifdef UNUSED
4576 ndbout << "TC: Received LQHKEYCONF"
4577 << " transId1=" << lqhKeyConf-> transId1
4578 << " transId2=" << lqhKeyConf-> transId2
4579 << endl;
4580 #endif /*UNUSED*/
4581 UintR compare_transid1, compare_transid2;
4582 BlockReference tlastLqhBlockref;
4583 UintR tlastLqhConnect;
4584 UintR treadlenAi;
4585 UintR TtcConnectptrIndex;
4586 UintR TtcConnectFilesize = ctcConnectFilesize;
4587
4588 tlastLqhConnect = lqhKeyConf->connectPtr;
4589 TtcConnectptrIndex = lqhKeyConf->opPtr;
4590 tlastLqhBlockref = lqhKeyConf->userRef;
4591 treadlenAi = lqhKeyConf->readLen;
4592 TcConnectRecord *localTcConnectRecord = tcConnectRecord;
4593
4594 /*------------------------------------------------------------------------
4595 * NUMBER OF EXTERNAL TRIGGERS FIRED IN DATA[6]
4596 * OPERATION IS NOW COMPLETED. CHECK FOR CORRECT OPERATION POINTER
4597 * TO ENSURE NO CRASHES BECAUSE OF ERRONEUS NODES. CHECK STATE OF
4598 * OPERATION. THEN SET OPERATION STATE AND RETRIEVE ALL POINTERS
4599 * OF THIS OPERATION. PUT COMPLETED OPERATION IN LIST OF COMPLETED
4600 * OPERATIONS ON THE LQH CONNECT RECORD.
4601 *------------------------------------------------------------------------
4602 * THIS SIGNAL ALWAYS ARRIVE BEFORE THE ABORTED SIGNAL ARRIVES SINCE IT USES
4603 * THE SAME PATH BACK TO TC AS THE ABORTED SIGNAL DO. WE DO HOWEVER HAVE A
4604 * PROBLEM WHEN WE ENCOUNTER A TIME-OUT WAITING FOR THE ABORTED SIGNAL.
4605 * THEN THIS SIGNAL MIGHT ARRIVE WHEN THE TC CONNECT RECORD HAVE BEEN REUSED
4606 * BY OTHER TRANSACTION THUS WE CHECK THE TRANSACTION ID OF THE SIGNAL
4607 * BEFORE ACCEPTING THIS SIGNAL.
4608 * Due to packing of LQHKEYCONF the ABORTED signal can now arrive before
4609 * this.
4610 * This is more reason to ignore the signal if not all states are correct.
4611 *------------------------------------------------------------------------*/
4612 if (TtcConnectptrIndex >= TtcConnectFilesize) {
4613 TCKEY_abort(signal, 25);
4614 return;
4615 }//if
4616 TcConnectRecord* const regTcPtr = &localTcConnectRecord[TtcConnectptrIndex];
4617 OperationState TtcConnectstate = regTcPtr->tcConnectstate;
4618 tcConnectptr.i = TtcConnectptrIndex;
4619 tcConnectptr.p = regTcPtr;
4620 if (TtcConnectstate != OS_OPERATING) {
4621 warningReport(signal, 23);
4622 return;
4623 }//if
4624 ApiConnectRecord *localApiConnectRecord = apiConnectRecord;
4625 UintR TapiConnectptrIndex = regTcPtr->apiConnect;
4626 UintR TapiConnectFilesize = capiConnectFilesize;
4627 UintR Ttrans1 = lqhKeyConf->transId1;
4628 UintR Ttrans2 = lqhKeyConf->transId2;
4629 Uint32 numFired = LqhKeyConf::getFiredCount(lqhKeyConf->numFiredTriggers);
4630 Uint32 deferreduk = LqhKeyConf::getDeferredUKBit(lqhKeyConf->numFiredTriggers);
4631 Uint32 deferredfk = LqhKeyConf::getDeferredFKBit(lqhKeyConf->numFiredTriggers);
4632
4633 if (TapiConnectptrIndex >= TapiConnectFilesize) {
4634 TCKEY_abort(signal, 29);
4635 return;
4636 }//if
4637 Ptr<ApiConnectRecord> regApiPtr;
4638 regApiPtr.i = TapiConnectptrIndex;
4639 regApiPtr.p = &localApiConnectRecord[TapiConnectptrIndex];
4640 apiConnectptr.i = TapiConnectptrIndex;
4641 apiConnectptr.p = regApiPtr.p;
4642 compare_transid1 = regApiPtr.p->transid[0] ^ Ttrans1;
4643 compare_transid2 = regApiPtr.p->transid[1] ^ Ttrans2;
4644 compare_transid1 = compare_transid1 | compare_transid2;
4645 if (compare_transid1 != 0) {
4646 warningReport(signal, 24);
4647 return;
4648 }//if
4649
4650 #ifdef ERROR_INSERT
4651 if (ERROR_INSERTED(8029)) {
4652 systemErrorLab(signal, __LINE__);
4653 }//if
4654 if (ERROR_INSERTED(8003)) {
4655 if (regApiPtr.p->apiConnectstate == CS_STARTED) {
4656 CLEAR_ERROR_INSERT_VALUE;
4657 return;
4658 }//if
4659 }//if
4660 if (ERROR_INSERTED(8004)) {
4661 if (regApiPtr.p->apiConnectstate == CS_RECEIVING) {
4662 CLEAR_ERROR_INSERT_VALUE;
4663 return;
4664 }//if
4665 }//if
4666 if (ERROR_INSERTED(8005)) {
4667 if (regApiPtr.p->apiConnectstate == CS_REC_COMMITTING) {
4668 CLEAR_ERROR_INSERT_VALUE;
4669 return;
4670 }//if
4671 }//if
4672 if (ERROR_INSERTED(8006)) {
4673 if (regApiPtr.p->apiConnectstate == CS_START_COMMITTING) {
4674 CLEAR_ERROR_INSERT_VALUE;
4675 return;
4676 }//if
4677 }//if
4678 if (ERROR_INSERTED(8023)) {
4679 SET_ERROR_INSERT_VALUE(8024);
4680 return;
4681 }//if
4682 if (ERROR_INSERTED(8107))
4683 {
4684 jam();
4685 ndbout_c("Error 8107, timing out transaction");
4686 timeOutFoundLab(signal, apiConnectptr.i, ZTIME_OUT_ERROR);
4687 return;
4688 }
4689
4690 #endif
4691 UintR TtcTimer = ctcTimer;
4692 regTcPtr->lastLqhCon = tlastLqhConnect;
4693 regTcPtr->lastLqhNodeId = refToNode(tlastLqhBlockref);
4694 regTcPtr->numFiredTriggers = numFired;
4695 regTcPtr->m_special_op_flags |=
4696 ((deferreduk) ? TcConnectRecord::SOF_DEFERRED_UK_TRIGGER : 0 ) |
4697 ((deferredfk) ? TcConnectRecord::SOF_DEFERRED_FK_TRIGGER : 0 );
4698 regApiPtr.p->m_flags |=
4699 ((deferreduk) ? ApiConnectRecord::TF_DEFERRED_UK_TRIGGERS : 0) |
4700 ((deferredfk) ? ApiConnectRecord::TF_DEFERRED_FK_TRIGGERS : 0);
4701
4702 UintR Ttckeyrec = (UintR)regApiPtr.p->tckeyrec;
4703 UintR TclientData = regTcPtr->clientData;
4704 UintR TdirtyOp = regTcPtr->dirtyOp;
4705 Uint32 TopSimple = regTcPtr->opSimple;
4706 Uint32 Toperation = regTcPtr->operation;
4707 ConnectionState TapiConnectstate = regApiPtr.p->apiConnectstate;
4708
4709 if (TapiConnectstate == CS_ABORTING) {
4710 warningReport(signal, 27);
4711 return;
4712 }//if
4713
4714 Uint32 lockingOpI = RNIL;
4715 if (Toperation == ZUNLOCK)
4716 {
4717 /* For unlock operations readlen in TCKEYCONF carries
4718 * the locking operation TC reference
4719 */
4720 lockingOpI = treadlenAi;
4721 treadlenAi = 0;
4722 }
4723
4724 /* Handle case where LQHKEYREQ requested an LQH CommitAckMarker */
4725 Uint32 commitAckMarker = regTcPtr->commitAckMarker;
4726 setApiConTimer(apiConnectptr.i, TtcTimer, __LINE__);
4727 if (commitAckMarker != RNIL)
4728 {
4729 /* Update TC CommitAckMarker record to track LQH CommitAckMarkers */
4730 const Uint32 noOfLqhs = regTcPtr->noOfNodes;
4731 CommitAckMarker * tmp = m_commitAckMarkerHash.getPtr(commitAckMarker);
4732 jam();
4733 /**
4734 * Now that we have a marker in all nodes in at least one nodegroup,
4735 * don't need to request any more for this transaction
4736 */
4737 regApiPtr.p->m_flags |= ApiConnectRecord::TF_COMMIT_ACK_MARKER_RECEIVED;
4738
4739 /**
4740 * Populate LQH array
4741 */
4742 for(Uint32 i = 0; i < noOfLqhs; i++)
4743 {
4744 jam();
4745 if (ERROR_INSERTED(8096) && i+1 == noOfLqhs)
4746 {
4747 CLEAR_ERROR_INSERT_VALUE;
4748 TCKEY_abort(signal, 67);
4749 return;
4750 }
4751 if (!tmp->insert_in_commit_ack_marker(this,
4752 regTcPtr->lqhInstanceKey,
4753 regTcPtr->tcNodedata[i]))
4754 {
4755 TCKEY_abort(signal, 67);
4756 return;
4757 }
4758 }
4759 }
4760 if (regTcPtr->isIndexOp(regTcPtr->m_special_op_flags)) {
4761 jam();
4762 // This was an internal TCKEYREQ
4763 // will be returned unpacked
4764 regTcPtr->attrInfoLen = treadlenAi;
4765 } else {
4766 if (numFired == 0 && regTcPtr->triggeringOperation == RNIL) {
4767 jam();
4768
4769 if (Ttckeyrec > (ZTCOPCONF_SIZE - 2)) {
4770 TCKEY_abort(signal, 30);
4771 return;
4772 }
4773
4774 /*
4775 * Skip counting triggering operations the first round
4776 * since they will enter execLQHKEYCONF a second time
4777 * Skip counting internally generated TcKeyReq
4778 */
4779 regApiPtr.p->tcSendArray[Ttckeyrec] = TclientData;
4780 regApiPtr.p->tcSendArray[Ttckeyrec + 1] = treadlenAi;
4781 regApiPtr.p->tckeyrec = Ttckeyrec + 2;
4782 }//if
4783 }//if
4784 if (TdirtyOp == ZTRUE)
4785 {
4786 UintR Tlqhkeyreqrec = regApiPtr.p->lqhkeyreqrec;
4787 jam();
4788 releaseDirtyWrite(signal);
4789 regApiPtr.p->lqhkeyreqrec = Tlqhkeyreqrec - 1;
4790 }
4791 else if (Toperation == ZREAD && TopSimple)
4792 {
4793 UintR Tlqhkeyreqrec = regApiPtr.p->lqhkeyreqrec;
4794 jam();
4795 unlinkReadyTcCon(signal);
4796 releaseTcCon();
4797 regApiPtr.p->lqhkeyreqrec = Tlqhkeyreqrec - 1;
4798 }
4799 else if (Toperation == ZUNLOCK)
4800 {
4801 jam();
4802 /* We've unlocked and released a read operation in LQH
4803 * The readLenAi member contains the TC OP reference
4804 * for the unlocked operation.
4805 * So here we :
4806 * 1) Validate the TC OP reference
4807 * 2) Release the referenced TC op
4808 * 3) Send TCKEYCONF back to the user
4809 * 4) Release our own TC op
4810 */
4811 Uint32 unlockOpI = tcConnectptr.i;
4812
4813 ndbrequire( numFired == 0 );
4814 ndbrequire( regTcPtr->triggeringOperation == RNIL );
4815
4816 /* Switch to the original locking operation */
4817 if (unlikely( lockingOpI >= ctcConnectFilesize ))
4818 {
4819 jam();
4820 TCKEY_abort(signal, 61);
4821 return;
4822 }
4823 tcConnectptr.i = lockingOpI;
4824 ptrCheckGuard(tcConnectptr, ctcConnectFilesize, tcConnectRecord);
4825
4826 const TcConnectRecord * regLockTcPtr = tcConnectptr.p;
4827
4828 /* Validate the locking operation's state */
4829 bool locking_op_ok =
4830 ( ( regLockTcPtr->apiConnect == regTcPtr->apiConnect ) &&
4831 ( ( regLockTcPtr->operation == ZREAD ) ||
4832 ( regLockTcPtr->operation == ZREAD_EX ) ) &&
4833 ( regLockTcPtr->tcConnectstate == OS_PREPARED ) &&
4834 ( ! regLockTcPtr->dirtyOp ) &&
4835 ( ! regLockTcPtr->opSimple ) &&
4836 ( ! TcConnectRecord::isIndexOp(regLockTcPtr->m_special_op_flags) ) &&
4837 ( regLockTcPtr->commitAckMarker == RNIL ) );
4838
4839 if (unlikely (! locking_op_ok ))
4840 {
4841 jam();
4842 TCKEY_abort(signal, 63);
4843 return;
4844 }
4845
4846 /* Ok, all checks passed, release the original locking op */
4847 unlinkReadyTcCon(signal);
4848 releaseTcCon();
4849
4850 /* Remove record of original locking op's LQHKEYREQ/CONF
4851 * etc.
4852 */
4853 ndbrequire( regApiPtr.p->lqhkeyreqrec );
4854 ndbrequire( regApiPtr.p->lqhkeyconfrec );
4855 regApiPtr.p->lqhkeyreqrec -= 1;
4856 regApiPtr.p->lqhkeyconfrec -= 1;
4857
4858 /* Switch back to the unlock operation */
4859 tcConnectptr.i = unlockOpI;
4860 ptrCheckGuard(tcConnectptr, ctcConnectFilesize, tcConnectRecord);
4861
4862 /* Release the unlock operation */
4863 unlinkReadyTcCon(signal);
4864 releaseTcCon();
4865
4866 /* Remove record of unlock op's LQHKEYREQ */
4867 ndbrequire( regApiPtr.p->lqhkeyreqrec );
4868 regApiPtr.p->lqhkeyreqrec -= 1;
4869
4870 /* TCKEYCONF sent below */
4871 }
4872 else
4873 {
4874 jam();
4875 if (numFired == 0) {
4876 jam();
4877 // No triggers to execute
4878 UintR Tlqhkeyconfrec = regApiPtr.p->lqhkeyconfrec;
4879 regApiPtr.p->lqhkeyconfrec = Tlqhkeyconfrec + 1;
4880 regTcPtr->tcConnectstate = OS_PREPARED;
4881 }
4882 }//if
4883
4884 /**
4885 * And now decide what to do next
4886 * 1) First check if there are fired triggers
4887 * 2) Then check if it's a index-table read
4888 * 3) Then check if op was created by trigger
4889 * 4) Else it's a normal op
4890 *
4891 * - trigger op, can cause new trigger ops (cascade)
4892 * - trigger op can be using uk
4893 */
4894 if (numFired)
4895 {
4896 // We have fired triggers
4897 jam();
4898 saveTriggeringOpState(signal, regTcPtr);
4899 if (regTcPtr->numReceivedTriggers == numFired)
4900 {
4901 // We have received all data
4902 jam();
4903 regApiPtr.p->theFiredTriggers.appendList(regTcPtr->thePendingTriggers);
4904 executeTriggers(signal, ®ApiPtr);
4905 }
4906 // else wait for more trigger data
4907 }
4908 else if (regTcPtr->isIndexOp(regTcPtr->m_special_op_flags))
4909 {
4910 // This is a index-table read
4911 jam();
4912 setupIndexOpReturn(regApiPtr.p, regTcPtr);
4913 lqhKeyConf_checkTransactionState(signal, regApiPtr);
4914 }
4915 else if (regTcPtr->triggeringOperation == RNIL)
4916 {
4917 // This is "normal" path
4918 jam();
4919 lqhKeyConf_checkTransactionState(signal, regApiPtr);
4920 }
4921 else
4922 {
4923 jam();
4924 /**
4925 * This operation was created by a trigger executing operation
4926 * Thus no need to handle the operation any further, return to
4927 * the original operation instead. There can be many triggering
4928 * operations waiting on each other here.
4929 *
4930 * Restart the original operation if we have executed all it's
4931 * triggers.
4932 */
4933 TcConnectRecordPtr opPtr;
4934
4935 opPtr.i = regTcPtr->triggeringOperation;
4936 ptrCheckGuard(opPtr, ctcConnectFilesize, localTcConnectRecord);
4937 trigger_op_finished(signal, regApiPtr, regTcPtr->currentTriggerId,
4938 opPtr.p, 0);
4939 }
4940 }//Dbtc::execLQHKEYCONF()
4941
setupIndexOpReturn(ApiConnectRecord * regApiPtr,TcConnectRecord * regTcPtr)4942 void Dbtc::setupIndexOpReturn(ApiConnectRecord* regApiPtr,
4943 TcConnectRecord* regTcPtr)
4944 {
4945 regApiPtr->m_flags |= ApiConnectRecord::TF_INDEX_OP_RETURN;
4946 regApiPtr->indexOp = regTcPtr->indexOp;
4947 TcIndexOperationPtr indexOpPtr;
4948 indexOpPtr.i = regApiPtr->indexOp;
4949 TcIndexOperation* indexOp = c_theIndexOperationPool.getPtr(indexOpPtr.i);
4950 if (tc_testbit(indexOp->savedFlags,
4951 ApiConnectRecord::TF_DEFERRED_CONSTRAINTS))
4952 {
4953 regApiPtr->m_flags |= ApiConnectRecord::TF_DEFERRED_CONSTRAINTS;
4954 }
4955
4956 if (tc_testbit(indexOp->savedFlags,
4957 ApiConnectRecord::TF_DISABLE_FK_CONSTRAINTS))
4958 {
4959 regApiPtr->m_flags |= ApiConnectRecord::TF_DISABLE_FK_CONSTRAINTS;
4960 }
4961 regApiPtr->clientData = regTcPtr->clientData;
4962 regApiPtr->attrInfoLen = regTcPtr->attrInfoLen;
4963 }
4964
4965 /**
4966 * lqhKeyConf_checkTransactionState
4967 *
4968 * This functions checks state variables, and
4969 * decides if it should wait for more LQHKEYCONF signals
4970 * or if it should start commiting
4971 */
4972 void
lqhKeyConf_checkTransactionState(Signal * signal,Ptr<ApiConnectRecord> regApiPtr)4973 Dbtc::lqhKeyConf_checkTransactionState(Signal * signal,
4974 Ptr<ApiConnectRecord> regApiPtr)
4975 {
4976 /*---------------------------------------------------------------*/
4977 /* IF THE COMMIT FLAG IS SET IN SIGNAL TCKEYREQ THEN DBTC HAS TO */
4978 /* SEND TCKEYCONF FOR ALL OPERATIONS EXCEPT THE LAST ONE. WHEN */
4979 /* THE TRANSACTION THEN IS COMMITTED TCKEYCONF IS SENT FOR THE */
4980 /* WHOLE TRANSACTION */
4981 /* IF THE COMMIT FLAG IS NOT RECECIVED DBTC WILL SEND TCKEYCONF */
4982 /* FOR ALL OPERATIONS, AND THEN WAIT FOR THE API TO CONCLUDE THE */
4983 /* TRANSACTION */
4984 /*---------------------------------------------------------------*/
4985 ConnectionState TapiConnectstate = regApiPtr.p->apiConnectstate;
4986 UintR Tlqhkeyconfrec = regApiPtr.p->lqhkeyconfrec;
4987 UintR Tlqhkeyreqrec = regApiPtr.p->lqhkeyreqrec;
4988 int TnoOfOutStanding = Tlqhkeyreqrec - Tlqhkeyconfrec;
4989
4990 apiConnectptr = regApiPtr;
4991 switch (TapiConnectstate) {
4992 case CS_START_COMMITTING:
4993 if (TnoOfOutStanding == 0) {
4994 jam();
4995 diverify010Lab(signal);
4996 return;
4997 } else if (TnoOfOutStanding > 0) {
4998 if (regApiPtr.p->tckeyrec == ZTCOPCONF_SIZE) {
4999 jam();
5000 sendtckeyconf(signal, 0);
5001 return;
5002 }
5003 else if (tc_testbit(regApiPtr.p->m_flags,
5004 ApiConnectRecord::TF_INDEX_OP_RETURN))
5005 {
5006 jam();
5007 sendtckeyconf(signal, 0);
5008 return;
5009 }//if
5010 jam();
5011 return;
5012 } else {
5013 TCKEY_abort(signal, 44);
5014 return;
5015 }//if
5016 return;
5017 case CS_STARTED:
5018 case CS_RECEIVING:
5019 if (TnoOfOutStanding == 0) {
5020 jam();
5021 sendtckeyconf(signal, 2);
5022 return;
5023 } else {
5024 if (regApiPtr.p->tckeyrec == ZTCOPCONF_SIZE) {
5025 jam();
5026 sendtckeyconf(signal, 0);
5027 return;
5028 }
5029 else if (tc_testbit(regApiPtr.p->m_flags,
5030 ApiConnectRecord::TF_INDEX_OP_RETURN))
5031 {
5032 jam();
5033 sendtckeyconf(signal, 0);
5034 return;
5035 }//if
5036 jam();
5037 }//if
5038 return;
5039 case CS_REC_COMMITTING:
5040 if (TnoOfOutStanding > 0) {
5041 if (regApiPtr.p->tckeyrec == ZTCOPCONF_SIZE) {
5042 jam();
5043 sendtckeyconf(signal, 0);
5044 return;
5045 }
5046 else if (tc_testbit(regApiPtr.p->m_flags,
5047 ApiConnectRecord::TF_INDEX_OP_RETURN))
5048 {
5049 jam();
5050 sendtckeyconf(signal, 0);
5051 return;
5052 }//if
5053 jam();
5054 return;
5055 }//if
5056 TCKEY_abort(signal, 45);
5057 return;
5058 case CS_CONNECTED:
5059 jam();
5060 /*---------------------------------------------------------------*/
5061 /* WE HAVE CONCLUDED THE TRANSACTION SINCE IT WAS ONLY */
5062 /* CONSISTING OF DIRTY WRITES AND ALL OF THOSE WERE */
5063 /* COMPLETED. ENSURE TCKEYREC IS ZERO TO PREVENT ERRORS. */
5064 /*---------------------------------------------------------------*/
5065 regApiPtr.p->tckeyrec = 0;
5066 return;
5067 case CS_SEND_FIRE_TRIG_REQ:
5068 return;
5069 case CS_WAIT_FIRE_TRIG_REQ:
5070 if (tc_testbit(regApiPtr.p->m_flags,
5071 ApiConnectRecord::TF_INDEX_OP_RETURN))
5072 {
5073 jam();
5074 sendtckeyconf(signal, 0);
5075 return;
5076 }
5077 else if (TnoOfOutStanding == 0 && regApiPtr.p->pendingTriggers == 0)
5078 {
5079 jam();
5080 regApiPtr.p->apiConnectstate = CS_START_COMMITTING;
5081 diverify010Lab(signal);
5082 return;
5083 }
5084 return;
5085 default:
5086 TCKEY_abort(signal, 46);
5087 return;
5088 }//switch
5089 }//Dbtc::lqhKeyConf_checkTransactionState()
5090
sendtckeyconf(Signal * signal,UintR TcommitFlag)5091 void Dbtc::sendtckeyconf(Signal* signal, UintR TcommitFlag)
5092 {
5093 if(ERROR_INSERTED(8049)){
5094 CLEAR_ERROR_INSERT_VALUE;
5095 signal->theData[0] = TcContinueB::DelayTCKEYCONF;
5096 signal->theData[1] = apiConnectptr.i;
5097 signal->theData[2] = TcommitFlag;
5098 sendSignalWithDelay(cownref, GSN_CONTINUEB, signal, 3000, 3);
5099 return;
5100 }
5101
5102 HostRecordPtr localHostptr;
5103 ApiConnectRecord * const regApiPtr = apiConnectptr.p;
5104 const UintR TopWords = (UintR)regApiPtr->tckeyrec;
5105 localHostptr.i = refToNode(regApiPtr->ndbapiBlockref);
5106 const Uint32 type = getNodeInfo(localHostptr.i).m_type;
5107 const bool is_api = (type >= NodeInfo::API && type <= NodeInfo::MGM);
5108 const BlockNumber TblockNum = refToBlock(regApiPtr->ndbapiBlockref);
5109 const Uint32 Tmarker = (regApiPtr->commitAckMarker == RNIL) ? 0 : 1;
5110 ptrAss(localHostptr, hostRecord);
5111 struct PackedWordsContainer * container = &localHostptr.p->packTCKEYCONF;
5112 UintR TcurrLen = container->noOfPackedWords;
5113 UintR confInfo = 0;
5114 TcKeyConf::setCommitFlag(confInfo, TcommitFlag == 1);
5115 TcKeyConf::setMarkerFlag(confInfo, Tmarker);
5116 const UintR TpacketLen = 6 + TopWords;
5117 regApiPtr->tckeyrec = 0;
5118
5119 if (tc_testbit(regApiPtr->m_flags, ApiConnectRecord::TF_INDEX_OP_RETURN))
5120 {
5121 jam();
5122 // Return internally generated TCKEY
5123 TcKeyConf * const tcKeyConf = (TcKeyConf *)signal->getDataPtrSend();
5124 TcKeyConf::setNoOfOperations(confInfo, 1);
5125 tcKeyConf->apiConnectPtr = regApiPtr->indexOp;
5126 tcKeyConf->gci_hi = Uint32(regApiPtr->globalcheckpointid >> 32);
5127 Uint32* gci_lo = (Uint32*)&tcKeyConf->operations[1];
5128 * gci_lo = Uint32(regApiPtr->globalcheckpointid);
5129 tcKeyConf->confInfo = confInfo;
5130 tcKeyConf->transId1 = regApiPtr->transid[0];
5131 tcKeyConf->transId2 = regApiPtr->transid[1];
5132 tcKeyConf->operations[0].apiOperationPtr = regApiPtr->clientData;
5133 tcKeyConf->operations[0].attrInfoLen = regApiPtr->attrInfoLen;
5134 Uint32 sigLen = 1 /** gci_lo */ +
5135 TcKeyConf::StaticLength + TcKeyConf::OperationLength;
5136 EXECUTE_DIRECT(DBTC, GSN_TCKEYCONF, signal, sigLen);
5137 tc_clearbit(regApiPtr->m_flags, ApiConnectRecord::TF_INDEX_OP_RETURN);
5138 if (TopWords == 0) {
5139 jam();
5140 return; // No queued TcKeyConf
5141 }//if
5142 }//if
5143 if(TcommitFlag){
5144 jam();
5145 tc_clearbit(regApiPtr->m_flags, ApiConnectRecord::TF_EXEC_FLAG);
5146 }
5147 TcKeyConf::setNoOfOperations(confInfo, (TopWords >> 1));
5148 if ((TpacketLen + 1 /** gci_lo */ > 25) ||!is_api){
5149 TcKeyConf * const tcKeyConf = (TcKeyConf *)signal->getDataPtrSend();
5150
5151 jam();
5152 tcKeyConf->apiConnectPtr = regApiPtr->ndbapiConnect;
5153 tcKeyConf->gci_hi = Uint32(regApiPtr->globalcheckpointid >> 32);
5154 Uint32* gci_lo = (Uint32*)&tcKeyConf->operations[TopWords >> 1];
5155 tcKeyConf->confInfo = confInfo;
5156 tcKeyConf->transId1 = regApiPtr->transid[0];
5157 tcKeyConf->transId2 = regApiPtr->transid[1];
5158 copyFromToLen(®ApiPtr->tcSendArray[0],
5159 (UintR*)&tcKeyConf->operations,
5160 (UintR)ZTCOPCONF_SIZE);
5161 * gci_lo = Uint32(regApiPtr->globalcheckpointid);
5162 sendSignal(regApiPtr->ndbapiBlockref,
5163 GSN_TCKEYCONF, signal, (TpacketLen - 1) + 1 /** gci_lo */, JBB);
5164 return;
5165 } else if (((TcurrLen + TpacketLen + 1 /** gci_lo */) > 25) &&
5166 (TcurrLen > 0)) {
5167 jam();
5168 sendPackedTCKEYCONF(signal, localHostptr.p, localHostptr.i);
5169 TcurrLen = 0;
5170 } else {
5171 jam();
5172 updatePackedList(signal, localHostptr.p, localHostptr.i);
5173 }//if
5174 // -------------------------------------------------------------------------
5175 // The header contains the block reference of receiver plus the real signal
5176 // length - 3, since we have the real signal length plus one additional word
5177 // for the header we have to do - 4.
5178 // -------------------------------------------------------------------------
5179 container->noOfPackedWords = TcurrLen + TpacketLen + 1 /** gci_lo */;
5180
5181 UintR Tpack0 = (TblockNum << 16) + (TpacketLen - 4 + 1 /** gci_lo */);
5182 UintR Tpack1 = regApiPtr->ndbapiConnect;
5183 UintR Tpack2 = Uint32(regApiPtr->globalcheckpointid >> 32);
5184 UintR Tpack3 = confInfo;
5185 UintR Tpack4 = regApiPtr->transid[0];
5186 UintR Tpack5 = regApiPtr->transid[1];
5187 UintR Tpack6 = Uint32(regApiPtr->globalcheckpointid);
5188
5189 container->packedWords[TcurrLen + 0] = Tpack0;
5190 container->packedWords[TcurrLen + 1] = Tpack1;
5191 container->packedWords[TcurrLen + 2] = Tpack2;
5192 container->packedWords[TcurrLen + 3] = Tpack3;
5193 container->packedWords[TcurrLen + 4] = Tpack4;
5194 container->packedWords[TcurrLen + 5] = Tpack5;
5195
5196 container->packedWords[TcurrLen + TpacketLen] = Tpack6;
5197
5198 for (Uint32 Ti = 6; Ti < TpacketLen; Ti++) {
5199 container->packedWords[TcurrLen + Ti] = regApiPtr->tcSendArray[Ti - 6];
5200 }//for
5201
5202 if (unlikely(!ndb_check_micro_gcp(getNodeInfo(localHostptr.i).m_version)))
5203 {
5204 jam();
5205 ndbassert(Tpack6 == 0 ||
5206 getNodeInfo(localHostptr.i).m_version == 0); // Disconnected
5207 }
5208 }//Dbtc::sendtckeyconf()
5209
copyFromToLen(UintR * sourceBuffer,UintR * destBuffer,UintR Tlen)5210 void Dbtc::copyFromToLen(UintR* sourceBuffer, UintR* destBuffer, UintR Tlen)
5211 {
5212 UintR Tindex = 0;
5213 UintR Ti;
5214 while (Tlen >= 4) {
5215 UintR Tdata0 = sourceBuffer[Tindex + 0];
5216 UintR Tdata1 = sourceBuffer[Tindex + 1];
5217 UintR Tdata2 = sourceBuffer[Tindex + 2];
5218 UintR Tdata3 = sourceBuffer[Tindex + 3];
5219 Tlen -= 4;
5220 destBuffer[Tindex + 0] = Tdata0;
5221 destBuffer[Tindex + 1] = Tdata1;
5222 destBuffer[Tindex + 2] = Tdata2;
5223 destBuffer[Tindex + 3] = Tdata3;
5224 Tindex += 4;
5225 }//while
5226 for (Ti = 0; Ti < Tlen; Ti++, Tindex++) {
5227 destBuffer[Tindex] = sourceBuffer[Tindex];
5228 }//for
5229 }//Dbtc::copyFromToLen()
5230
execSEND_PACKED(Signal * signal)5231 void Dbtc::execSEND_PACKED(Signal* signal)
5232 {
5233 HostRecordPtr Thostptr;
5234 HostRecord *localHostRecord = hostRecord;
5235 UintR i;
5236 UintR TpackedListIndex = cpackedListIndex;
5237 jamEntry();
5238 for (i = 0; i < TpackedListIndex; i++) {
5239 jam();
5240 Thostptr.i = cpackedList[i];
5241 ptrAss(Thostptr, localHostRecord);
5242 arrGuard(Thostptr.i - 1, MAX_NODES - 1);
5243 for (Uint32 j = 0; j < NDB_ARRAY_SIZE(Thostptr.p->lqh_pack); j++)
5244 {
5245 struct PackedWordsContainer * container = &Thostptr.p->lqh_pack[j];
5246 jam();
5247 if (container->noOfPackedWords > 0) {
5248 jam();
5249 sendPackedSignal(signal, container);
5250 }
5251 }
5252 struct PackedWordsContainer * container = &Thostptr.p->packTCKEYCONF;
5253 if (container->noOfPackedWords > 0) {
5254 jam();
5255 sendPackedTCKEYCONF(signal, Thostptr.p, (Uint32)Thostptr.i);
5256 }//if
5257 Thostptr.p->inPackedList = false;
5258 }//for
5259 cpackedListIndex = 0;
5260 return;
5261 }//Dbtc::execSEND_PACKED()
5262
5263 void
updatePackedList(Signal * signal,HostRecord * ahostptr,Uint16 ahostIndex)5264 Dbtc::updatePackedList(Signal* signal, HostRecord* ahostptr, Uint16 ahostIndex)
5265 {
5266 if (ahostptr->inPackedList == false) {
5267 UintR TpackedListIndex = cpackedListIndex;
5268 jam();
5269 ahostptr->inPackedList = true;
5270 cpackedList[TpackedListIndex] = ahostIndex;
5271 cpackedListIndex = TpackedListIndex + 1;
5272 }//if
5273 }//Dbtc::updatePackedList()
5274
sendPackedSignal(Signal * signal,struct PackedWordsContainer * container)5275 void Dbtc::sendPackedSignal(Signal* signal,
5276 struct PackedWordsContainer * container)
5277 {
5278 UintR TnoOfWords = container->noOfPackedWords;
5279 ndbassert(TnoOfWords <= 25);
5280 container->noOfPackedWords = 0;
5281 memcpy(&signal->theData[0], &container->packedWords[0], 4 * TnoOfWords);
5282 if (VERIFY_PACKED_SEND)
5283 {
5284 ndbrequire(refToMain(container->hostBlockRef) == DBLQH);
5285 ndbrequire(PackedSignal::verify(&signal->theData[0],
5286 TnoOfWords,
5287 container->hostBlockRef,
5288 LQH_RECEIVE_TYPES,
5289 5)); /* Commit signal length */
5290 }
5291 sendSignal(container->hostBlockRef,
5292 GSN_PACKED_SIGNAL,
5293 signal,
5294 TnoOfWords,
5295 JBB);
5296 }//Dbtc::sendPackedSignal()
5297
sendPackedTCKEYCONF(Signal * signal,HostRecord * ahostptr,UintR hostId)5298 void Dbtc::sendPackedTCKEYCONF(Signal* signal,
5299 HostRecord * ahostptr,
5300 UintR hostId)
5301 {
5302 struct PackedWordsContainer * container = &ahostptr->packTCKEYCONF;
5303 UintR TnoOfWords = container->noOfPackedWords;
5304 ndbassert(TnoOfWords <= 25);
5305 container->noOfPackedWords = 0;
5306 BlockReference TBref = numberToRef(API_PACKED, hostId);
5307 memcpy(&signal->theData[0], &container->packedWords[0], 4 * TnoOfWords);
5308 sendSignal(TBref, GSN_TCKEYCONF, signal, TnoOfWords, JBB);
5309 }//Dbtc::sendPackedTCKEYCONF()
5310
5311 void
startSendFireTrigReq(Signal * signal,Ptr<ApiConnectRecord> regApiPtr)5312 Dbtc::startSendFireTrigReq(Signal* signal, Ptr<ApiConnectRecord> regApiPtr)
5313 {
5314 const Uint32 pass = regApiPtr.p->m_pre_commit_pass;
5315 const Uint32 step = pass & Uint32(TriggerPreCommitPass::TPCP_PASS_MAX);
5316 regApiPtr.p->pendingTriggers = 0;
5317 if (tc_testbit(regApiPtr.p->m_flags,
5318 ApiConnectRecord::TF_DEFERRED_UK_TRIGGERS))
5319 {
5320 jam();
5321 if (step == TriggerPreCommitPass::UK_PASS_1)
5322 {
5323 jam();
5324 // clear on second pass...
5325 tc_clearbit(regApiPtr.p->m_flags,
5326 ApiConnectRecord::TF_DEFERRED_UK_TRIGGERS);
5327 }
5328 }
5329 else
5330 {
5331 ndbassert(tc_testbit(regApiPtr.p->m_flags,
5332 ApiConnectRecord::TF_DEFERRED_FK_TRIGGERS));
5333 tc_clearbit(regApiPtr.p->m_flags,
5334 ApiConnectRecord::TF_DEFERRED_FK_TRIGGERS);
5335
5336 Uint32 newpass = pass;
5337 newpass = newpass & ~Uint32(TriggerPreCommitPass::TPCP_PASS_MAX);
5338 newpass = newpass + TriggerPreCommitPass::FK_PASS_0;
5339 regApiPtr.p->m_pre_commit_pass = newpass;
5340 }
5341 sendFireTrigReq(signal, regApiPtr,
5342 regApiPtr.p->firstTcConnect,
5343 regApiPtr.p->lastTcConnect);
5344 }
5345
5346 /*
5347 4.3.11 DIVERIFY
5348 ---------------
5349 */
5350 /*****************************************************************************/
5351 /* D I V E R I F Y */
5352 /* */
5353 /*****************************************************************************/
diverify010Lab(Signal * signal)5354 void Dbtc::diverify010Lab(Signal* signal)
5355 {
5356 UintR TfirstfreeApiConnectCopy = cfirstfreeApiConnectCopy;
5357 ApiConnectRecord * const regApiPtr = apiConnectptr.p;
5358 signal->theData[0] = apiConnectptr.i;
5359 signal->theData[1] = instance() ? instance() - 1 : 0;
5360 if (ERROR_INSERTED(8022)) {
5361 jam();
5362 systemErrorLab(signal, __LINE__);
5363 }//if
5364
5365 if (tc_testbit(regApiPtr->m_flags,
5366 (ApiConnectRecord::TF_DEFERRED_UK_TRIGGERS +
5367 ApiConnectRecord::TF_DEFERRED_FK_TRIGGERS)))
5368 {
5369 /**
5370 * If trans has deferred triggers, let them fire just before
5371 * transaction starts to commit
5372 */
5373 startSendFireTrigReq(signal, apiConnectptr);
5374 return;
5375 }
5376
5377 if (regApiPtr->lqhkeyreqrec)
5378 {
5379 if (TfirstfreeApiConnectCopy != RNIL) {
5380 seizeApiConnectCopy(signal);
5381 regApiPtr->apiConnectstate = CS_PREPARE_TO_COMMIT;
5382 /*-----------------------------------------------------------------------
5383 * WE COME HERE ONLY IF THE TRANSACTION IS PREPARED ON ALL TC CONNECTIONS
5384 * THUS WE CAN START THE COMMIT PHASE BY SENDING DIVERIFY ON ALL TC
5385 * CONNECTIONS AND THEN WHEN ALL DIVERIFYCONF HAVE BEEN RECEIVED THE
5386 * COMMIT MESSAGE CAN BE SENT TO ALL INVOLVED PARTS.
5387 *---------------------------------------------------------------------*/
5388 * (EmulatedJamBuffer**)(signal->theData+2) = jamBuffer();
5389 EXECUTE_DIRECT(DBDIH, GSN_DIVERIFYREQ, signal,
5390 2 + sizeof(void*)/sizeof(Uint32), 0);
5391 if (signal->theData[3] == 0) {
5392 execDIVERIFYCONF(signal);
5393 }
5394 return;
5395 } else {
5396 /*-----------------------------------------------------------------------
5397 * There were no free copy connections available. We must abort the
5398 * transaction since otherwise we will have a problem with the report
5399 * to the application.
5400 * This should more or less not happen but if it happens we do
5401 * not want to crash and we do not want to create code to handle it
5402 * properly since it is difficult to test it and will be complex to
5403 * handle a problem more or less not occurring.
5404 *---------------------------------------------------------------------*/
5405 terrorCode = ZSEIZE_API_COPY_ERROR;
5406 abortErrorLab(signal);
5407 return;
5408 }
5409 }
5410 else
5411 {
5412 jam();
5413 sendtckeyconf(signal, 1);
5414 regApiPtr->apiConnectstate = CS_CONNECTED;
5415 regApiPtr->m_transaction_nodes.clear();
5416 setApiConTimer(apiConnectptr.i, 0,__LINE__);
5417 }
5418 }//Dbtc::diverify010Lab()
5419
5420 /* ------------------------------------------------------------------------- */
5421 /* ------- SEIZE_API_CONNECT ------- */
5422 /* SEIZE CONNECT RECORD FOR A REQUEST */
5423 /* ------------------------------------------------------------------------- */
seizeApiConnectCopy(Signal * signal)5424 void Dbtc::seizeApiConnectCopy(Signal* signal)
5425 {
5426 ApiConnectRecordPtr locApiConnectptr;
5427
5428 ApiConnectRecord *localApiConnectRecord = apiConnectRecord;
5429 UintR TapiConnectFilesize = capiConnectFilesize;
5430 ApiConnectRecord * const regApiPtr = apiConnectptr.p;
5431
5432 locApiConnectptr.i = cfirstfreeApiConnectCopy;
5433 ptrCheckGuard(locApiConnectptr, TapiConnectFilesize, localApiConnectRecord);
5434 cfirstfreeApiConnectCopy = locApiConnectptr.p->nextApiConnect;
5435 locApiConnectptr.p->nextApiConnect = RNIL;
5436 ndbassert(regApiPtr->apiCopyRecord == RNIL);
5437 regApiPtr->apiCopyRecord = locApiConnectptr.i;
5438 tc_clearbit(regApiPtr->m_flags,
5439 ApiConnectRecord::TF_TRIGGER_PENDING);
5440 regApiPtr->m_special_op_flags = 0;
5441 }//Dbtc::seizeApiConnectCopy()
5442
execDIVERIFYCONF(Signal * signal)5443 void Dbtc::execDIVERIFYCONF(Signal* signal)
5444 {
5445 UintR TapiConnectptrIndex = signal->theData[0];
5446 UintR TapiConnectFilesize = capiConnectFilesize;
5447 UintR Tgci_hi = signal->theData[1];
5448 UintR Tgci_lo = signal->theData[2];
5449 Uint64 Tgci = Tgci_lo | (Uint64(Tgci_hi) << 32);
5450 ApiConnectRecord *localApiConnectRecord = apiConnectRecord;
5451
5452 jamEntry();
5453 if (ERROR_INSERTED(8017)) {
5454 CLEAR_ERROR_INSERT_VALUE;
5455 return;
5456 }//if
5457 if (TapiConnectptrIndex >= TapiConnectFilesize) {
5458 TCKEY_abort(signal, 31);
5459 return;
5460 }//if
5461 ApiConnectRecord * const regApiPtr =
5462 &localApiConnectRecord[TapiConnectptrIndex];
5463 ConnectionState TapiConnectstate = regApiPtr->apiConnectstate;
5464 UintR TApifailureNr = regApiPtr->failureNr;
5465 UintR Tfailure_nr = cfailure_nr;
5466 apiConnectptr.i = TapiConnectptrIndex;
5467 apiConnectptr.p = regApiPtr;
5468 if (TapiConnectstate != CS_PREPARE_TO_COMMIT) {
5469 TCKEY_abort(signal, 32);
5470 return;
5471 }//if
5472 /*--------------------------------------------------------------------------
5473 * THIS IS THE COMMIT POINT. IF WE ARRIVE HERE THE TRANSACTION IS COMMITTED
5474 * UNLESS EVERYTHING CRASHES BEFORE WE HAVE BEEN ABLE TO REPORT THE COMMIT
5475 * DECISION. THERE IS NO TURNING BACK FROM THIS DECISION FROM HERE ON.
5476 * WE WILL INSERT THE TRANSACTION INTO ITS PROPER QUEUE OF
5477 * TRANSACTIONS FOR ITS GLOBAL CHECKPOINT.
5478 *-------------------------------------------------------------------------*/
5479 if (TApifailureNr != Tfailure_nr ||
5480 ERROR_INSERTED(8094)) {
5481 jam();
5482 DIVER_node_fail_handling(signal, Tgci);
5483 return;
5484 }//if
5485 commitGciHandling(signal, Tgci);
5486
5487 /**************************************************************************
5488 * C O M M I T
5489 * THE TRANSACTION HAVE NOW BEEN VERIFIED AND NOW THE COMMIT PHASE CAN START
5490 **************************************************************************/
5491
5492 UintR TtcConnectptrIndex = regApiPtr->firstTcConnect;
5493 UintR TtcConnectFilesize = ctcConnectFilesize;
5494 TcConnectRecord *localTcConnectRecord = tcConnectRecord;
5495
5496 regApiPtr->counter = regApiPtr->lqhkeyconfrec;
5497 regApiPtr->apiConnectstate = CS_COMMITTING;
5498 if (TtcConnectptrIndex >= TtcConnectFilesize) {
5499 TCKEY_abort(signal, 33);
5500 return;
5501 }//if
5502 TcConnectRecord* const regTcPtr = &localTcConnectRecord[TtcConnectptrIndex];
5503 tcConnectptr.i = TtcConnectptrIndex;
5504 tcConnectptr.p = regTcPtr;
5505 commit020Lab(signal);
5506 }//Dbtc::execDIVERIFYCONF()
5507
5508 /*--------------------------------------------------------------------------*/
5509 /* COMMIT_GCI_HANDLING */
5510 /* SET UP GLOBAL CHECKPOINT DATA STRUCTURE AT THE COMMIT POINT. */
5511 /*--------------------------------------------------------------------------*/
commitGciHandling(Signal * signal,Uint64 Tgci)5512 void Dbtc::commitGciHandling(Signal* signal, Uint64 Tgci)
5513 {
5514 GcpRecordPtr localGcpPointer;
5515
5516 UintR TgcpFilesize = cgcpFilesize;
5517 UintR Tfirstgcp = cfirstgcp;
5518 Ptr<ApiConnectRecord> regApiPtr = apiConnectptr;
5519 GcpRecord *localGcpRecord = gcpRecord;
5520
5521 regApiPtr.p->globalcheckpointid = Tgci;
5522 if (Tfirstgcp != RNIL) {
5523 /* IF THIS GLOBAL CHECKPOINT ALREADY EXISTS */
5524 localGcpPointer.i = Tfirstgcp;
5525 ptrCheckGuard(localGcpPointer, TgcpFilesize, localGcpRecord);
5526 do {
5527 if (regApiPtr.p->globalcheckpointid == localGcpPointer.p->gcpId) {
5528 jam();
5529 linkApiToGcp(localGcpPointer, regApiPtr);
5530 return;
5531 } else {
5532 if (unlikely(! (regApiPtr.p->globalcheckpointid > localGcpPointer.p->gcpId)))
5533 {
5534 ndbout_c("%u/%u %u/%u",
5535 Uint32(regApiPtr.p->globalcheckpointid >> 32),
5536 Uint32(regApiPtr.p->globalcheckpointid),
5537 Uint32(localGcpPointer.p->gcpId >> 32),
5538 Uint32(localGcpPointer.p->gcpId));
5539 crash_gcp(__LINE__);
5540 }
5541 localGcpPointer.i = localGcpPointer.p->nextGcp;
5542 jam();
5543 if (localGcpPointer.i != RNIL) {
5544 jam();
5545 ptrCheckGuard(localGcpPointer, TgcpFilesize, localGcpRecord);
5546 continue;
5547 }//if
5548 }//if
5549 seizeGcp(localGcpPointer, Tgci);
5550 linkApiToGcp(localGcpPointer, regApiPtr);
5551 return;
5552 } while (1);
5553 } else {
5554 jam();
5555 seizeGcp(localGcpPointer, Tgci);
5556 linkApiToGcp(localGcpPointer, regApiPtr);
5557 }//if
5558 }//Dbtc::commitGciHandling()
5559
5560 /* --------------------------------------------------------------------------*/
5561 /* -LINK AN API CONNECT RECORD IN STATE PREPARED INTO THE LIST WITH GLOBAL - */
5562 /* CHECKPOINTS. WHEN THE TRANSACTION I COMPLETED THE API CONNECT RECORD IS */
5563 /* LINKED OUT OF THE LIST. */
5564 /*---------------------------------------------------------------------------*/
linkApiToGcp(Ptr<GcpRecord> regGcpPtr,Ptr<ApiConnectRecord> regApiPtr)5565 void Dbtc::linkApiToGcp(Ptr<GcpRecord> regGcpPtr,
5566 Ptr<ApiConnectRecord> regApiPtr)
5567 {
5568 ApiConnectRecordPtr localApiConnectptr;
5569 ApiConnectRecord *localApiConnectRecord = apiConnectRecord;
5570
5571 regApiPtr.p->nextGcpConnect = RNIL;
5572 if (regGcpPtr.p->firstApiConnect == RNIL) {
5573 regGcpPtr.p->firstApiConnect = regApiPtr.i;
5574 jam();
5575 } else {
5576 UintR TapiConnectFilesize = capiConnectFilesize;
5577 localApiConnectptr.i = regGcpPtr.p->lastApiConnect;
5578 jam();
5579 ptrCheckGuard(localApiConnectptr,
5580 TapiConnectFilesize, localApiConnectRecord);
5581 localApiConnectptr.p->nextGcpConnect = regApiPtr.i;
5582 }//if
5583 UintR TlastApiConnect = regGcpPtr.p->lastApiConnect;
5584 regApiPtr.p->gcpPointer = regGcpPtr.i;
5585 regApiPtr.p->prevGcpConnect = TlastApiConnect;
5586 regGcpPtr.p->lastApiConnect = regApiPtr.i;
5587 }//Dbtc::linkApiToGcp()
5588
5589 void
crash_gcp(Uint32 line)5590 Dbtc::crash_gcp(Uint32 line)
5591 {
5592 GcpRecordPtr localGcpPointer;
5593
5594 localGcpPointer.i = cfirstgcp;
5595
5596 while (localGcpPointer.i != RNIL)
5597 {
5598 ptrCheckGuard(localGcpPointer, cgcpFilesize, gcpRecord);
5599 ndbout_c("%u : %u/%u nomoretrans: %u api %u %u next: %u",
5600 localGcpPointer.i,
5601 Uint32(localGcpPointer.p->gcpId >> 32),
5602 Uint32(localGcpPointer.p->gcpId),
5603 localGcpPointer.p->gcpNomoretransRec,
5604 localGcpPointer.p->firstApiConnect,
5605 localGcpPointer.p->lastApiConnect,
5606 localGcpPointer.p->nextGcp);
5607 localGcpPointer.i = localGcpPointer.p->nextGcp;
5608 }
5609 progError(line, NDBD_EXIT_NDBREQUIRE);
5610 ndbrequire(false);
5611 }
5612
seizeGcp(Ptr<GcpRecord> & dst,Uint64 Tgci)5613 void Dbtc::seizeGcp(Ptr<GcpRecord> & dst, Uint64 Tgci)
5614 {
5615 GcpRecordPtr tmpGcpPointer;
5616 GcpRecordPtr localGcpPointer;
5617
5618 UintR Tfirstgcp = cfirstgcp;
5619 UintR TgcpFilesize = cgcpFilesize;
5620 GcpRecord *localGcpRecord = gcpRecord;
5621
5622 localGcpPointer.i = cfirstfreeGcp;
5623 if (unlikely(localGcpPointer.i > TgcpFilesize))
5624 {
5625 ndbout_c("%u/%u", Uint32(Tgci >> 32), Uint32(Tgci));
5626 crash_gcp(__LINE__);
5627 }
5628 ptrCheckGuard(localGcpPointer, TgcpFilesize, localGcpRecord);
5629 UintR TfirstfreeGcp = localGcpPointer.p->nextGcp;
5630 localGcpPointer.p->gcpId = Tgci;
5631 localGcpPointer.p->nextGcp = RNIL;
5632 localGcpPointer.p->firstApiConnect = RNIL;
5633 localGcpPointer.p->lastApiConnect = RNIL;
5634 localGcpPointer.p->gcpNomoretransRec = ZFALSE;
5635 cfirstfreeGcp = TfirstfreeGcp;
5636
5637 if (Tfirstgcp == RNIL) {
5638 jam();
5639 cfirstgcp = localGcpPointer.i;
5640 } else {
5641 tmpGcpPointer.i = clastgcp;
5642 jam();
5643 ptrCheckGuard(tmpGcpPointer, TgcpFilesize, localGcpRecord);
5644 tmpGcpPointer.p->nextGcp = localGcpPointer.i;
5645 }//if
5646 clastgcp = localGcpPointer.i;
5647 dst = localGcpPointer;
5648 }//Dbtc::seizeGcp()
5649
5650 /*---------------------------------------------------------------------------*/
5651 // Send COMMIT messages to all LQH operations involved in the transaction.
5652 /*---------------------------------------------------------------------------*/
commit020Lab(Signal * signal)5653 void Dbtc::commit020Lab(Signal* signal)
5654 {
5655 TcConnectRecordPtr localTcConnectptr;
5656 ApiConnectRecord * const regApiPtr = apiConnectptr.p;
5657 UintR TtcConnectFilesize = ctcConnectFilesize;
5658 TcConnectRecord *localTcConnectRecord = tcConnectRecord;
5659
5660 localTcConnectptr.p = tcConnectptr.p;
5661 setApiConTimer(apiConnectptr.i, ctcTimer, __LINE__);
5662 UintR Tcount = 0;
5663 do {
5664 /*-----------------------------------------------------------------------
5665 * WE ARE NOW READY TO RELEASE ALL OPERATIONS ON THE LQH
5666 *-----------------------------------------------------------------------*/
5667 /* *********< */
5668 /* COMMIT < */
5669 /* *********< */
5670 localTcConnectptr.i = localTcConnectptr.p->nextTcConnect;
5671 /* Clear per-operation record CommitAckMarker ref if necessary */
5672 if (localTcConnectptr.p->commitAckMarker != RNIL)
5673 {
5674 ndbassert(regApiPtr->commitAckMarker != RNIL);
5675 ndbrequire(regApiPtr->num_commit_ack_markers--);
5676 localTcConnectptr.p->commitAckMarker = RNIL;
5677 }
5678 localTcConnectptr.p->tcConnectstate = OS_COMMITTING;
5679 Tcount += sendCommitLqh(signal, localTcConnectptr.p);
5680
5681 if (localTcConnectptr.i != RNIL) {
5682 if (Tcount < 16 &&
5683 ! (ERROR_INSERTED(8057) ||
5684 ERROR_INSERTED(8073) ||
5685 ERROR_INSERTED(8089)))
5686 {
5687 ptrCheckGuard(localTcConnectptr,
5688 TtcConnectFilesize, localTcConnectRecord);
5689 jam();
5690 continue;
5691 } else {
5692 jam();
5693 if (ERROR_INSERTED(8014)) {
5694 CLEAR_ERROR_INSERT_VALUE;
5695 return;
5696 }//if
5697
5698 if (ERROR_INSERTED(8073))
5699 {
5700 execSEND_PACKED(signal);
5701 signal->theData[0] = 9999;
5702 sendSignalWithDelay(CMVMI_REF, GSN_NDB_TAMPER, signal, 100, 1);
5703 return;
5704 }
5705 signal->theData[0] = TcContinueB::ZSEND_COMMIT_LOOP;
5706 signal->theData[1] = apiConnectptr.i;
5707 signal->theData[2] = localTcConnectptr.i;
5708 if (ERROR_INSERTED(8089))
5709 {
5710 sendSignalWithDelay(cownref, GSN_CONTINUEB, signal, 100, 3);
5711 return;
5712 }
5713 sendSignal(cownref, GSN_CONTINUEB, signal, 3, JBB);
5714 return;
5715 }//if
5716 } else {
5717 jam();
5718 if (ERROR_INSERTED(8057))
5719 CLEAR_ERROR_INSERT_VALUE;
5720
5721 if (ERROR_INSERTED(8089))
5722 CLEAR_ERROR_INSERT_VALUE;
5723
5724 regApiPtr->apiConnectstate = CS_COMMIT_SENT;
5725 ndbrequire(regApiPtr->num_commit_ack_markers == 0);
5726 return;
5727 }//if
5728 } while (1);
5729 }//Dbtc::commit020Lab()
5730
5731 Uint32
sendCommitLqh(Signal * signal,TcConnectRecord * const regTcPtr)5732 Dbtc::sendCommitLqh(Signal* signal,
5733 TcConnectRecord * const regTcPtr)
5734 {
5735 HostRecordPtr Thostptr;
5736 UintR ThostFilesize = chostFilesize;
5737 Uint32 instanceKey = regTcPtr->lqhInstanceKey;
5738 ApiConnectRecord * const regApiPtr = apiConnectptr.p;
5739 Thostptr.i = regTcPtr->lastLqhNodeId;
5740 ptrCheckGuard(Thostptr, ThostFilesize, hostRecord);
5741
5742 Uint32 Tnode = Thostptr.i;
5743 Uint32 self = getOwnNodeId();
5744 Uint32 ret = (Tnode == self) ? 4 : 1;
5745
5746 Uint32 Tdata[5];
5747 Tdata[0] = regTcPtr->lastLqhCon;
5748 Tdata[1] = Uint32(regApiPtr->globalcheckpointid >> 32);
5749 Tdata[2] = regApiPtr->transid[0];
5750 Tdata[3] = regApiPtr->transid[1];
5751 Tdata[4] = Uint32(regApiPtr->globalcheckpointid);
5752 Uint32 len = 5;
5753
5754 if (unlikely(!ndb_check_micro_gcp(getNodeInfo(Thostptr.i).m_version)))
5755 {
5756 jam();
5757 ndbassert(Tdata[4] == 0 || getNodeInfo(Thostptr.i).m_version == 0);
5758 len = 4;
5759 }
5760 if (instanceKey > MAX_NDBMT_LQH_THREADS) {
5761 memcpy(&signal->theData[0], &Tdata[0], len << 2);
5762 BlockReference lqhRef = numberToRef(DBLQH, instanceKey, Tnode);
5763 sendSignal(lqhRef, GSN_COMMIT, signal, len, JBB);
5764 return ret;
5765 }
5766
5767 struct PackedWordsContainer * container = &Thostptr.p->lqh_pack[instanceKey];
5768
5769 if (container->noOfPackedWords > 25 - len) {
5770 jam();
5771 sendPackedSignal(signal, container);
5772 } else {
5773 jam();
5774 ret = 1;
5775 updatePackedList(signal, Thostptr.p, Thostptr.i);
5776 }
5777
5778 Tdata[0] |= (ZCOMMIT << 28);
5779 UintR Tindex = container->noOfPackedWords;
5780 container->noOfPackedWords = Tindex + len;
5781 UintR* TDataPtr = &container->packedWords[Tindex];
5782 memcpy(TDataPtr, &Tdata[0], len << 2);
5783 return ret;
5784 }
5785
5786 void
DIVER_node_fail_handling(Signal * signal,Uint64 Tgci)5787 Dbtc::DIVER_node_fail_handling(Signal* signal, Uint64 Tgci)
5788 {
5789 /*------------------------------------------------------------------------
5790 * AT LEAST ONE NODE HAS FAILED DURING THE TRANSACTION. WE NEED TO CHECK IF
5791 * THIS IS SO SERIOUS THAT WE NEED TO ABORT THE TRANSACTION. IN BOTH THE
5792 * ABORT AND THE COMMIT CASES WE NEED TO SET-UP THE DATA FOR THE
5793 * ABORT/COMMIT/COMPLETE HANDLING AS ALSO USED BY TAKE OVER FUNCTIONALITY.
5794 *------------------------------------------------------------------------*/
5795 tabortInd = ZFALSE;
5796 setupFailData(signal);
5797 if (false && tabortInd == ZFALSE) {
5798 jam();
5799 commitGciHandling(signal, Tgci);
5800 toCommitHandlingLab(signal);
5801 } else {
5802 jam();
5803 apiConnectptr.p->returnsignal = RS_TCROLLBACKREP;
5804 apiConnectptr.p->returncode = ZNODEFAIL_BEFORE_COMMIT;
5805 toAbortHandlingLab(signal);
5806 }//if
5807 return;
5808 }//Dbtc::DIVER_node_fail_handling()
5809
5810
5811 /* ------------------------------------------------------------------------- */
5812 /* ------- ENTER COMMITTED ------- */
5813 /* */
5814 /* ------------------------------------------------------------------------- */
execCOMMITTED(Signal * signal)5815 void Dbtc::execCOMMITTED(Signal* signal)
5816 {
5817 TcConnectRecordPtr localTcConnectptr;
5818 ApiConnectRecordPtr localApiConnectptr;
5819 ApiConnectRecordPtr localCopyPtr;
5820
5821 UintR TtcConnectFilesize = ctcConnectFilesize;
5822 UintR TapiConnectFilesize = capiConnectFilesize;
5823 TcConnectRecord *localTcConnectRecord = tcConnectRecord;
5824 ApiConnectRecord *localApiConnectRecord = apiConnectRecord;
5825
5826 #ifdef ERROR_INSERT
5827 if (ERROR_INSERTED(8018)) {
5828 CLEAR_ERROR_INSERT_VALUE;
5829 return;
5830 }//if
5831 CRASH_INSERTION(8030);
5832 if (ERROR_INSERTED(8025)) {
5833 SET_ERROR_INSERT_VALUE(8026);
5834 return;
5835 }//if
5836 if (ERROR_INSERTED(8041)) {
5837 CLEAR_ERROR_INSERT_VALUE;
5838 sendSignalWithDelay(cownref, GSN_COMMITTED, signal, 2000, 3);
5839 return;
5840 }//if
5841 if (ERROR_INSERTED(8042)) {
5842 SET_ERROR_INSERT_VALUE(8046);
5843 sendSignalWithDelay(cownref, GSN_COMMITTED, signal, 2000, 4);
5844 return;
5845 }//if
5846 #endif
5847 localTcConnectptr.i = signal->theData[0];
5848 jamEntry();
5849 ptrCheckGuard(localTcConnectptr, TtcConnectFilesize, localTcConnectRecord);
5850 localApiConnectptr.i = localTcConnectptr.p->apiConnect;
5851 if (localTcConnectptr.p->tcConnectstate != OS_COMMITTING) {
5852 warningReport(signal, 4);
5853 return;
5854 }//if
5855 ptrCheckGuard(localApiConnectptr, TapiConnectFilesize,
5856 localApiConnectRecord);
5857 UintR Tcounter = localApiConnectptr.p->counter - 1;
5858 ConnectionState TapiConnectstate = localApiConnectptr.p->apiConnectstate;
5859 UintR Tdata1 = localApiConnectptr.p->transid[0] - signal->theData[1];
5860 UintR Tdata2 = localApiConnectptr.p->transid[1] - signal->theData[2];
5861 Tdata1 = Tdata1 | Tdata2;
5862 bool TcheckCondition =
5863 (TapiConnectstate != CS_COMMIT_SENT) || (Tcounter != 0);
5864
5865 setApiConTimer(localApiConnectptr.i, ctcTimer, __LINE__);
5866 localApiConnectptr.p->counter = Tcounter;
5867 localTcConnectptr.p->tcConnectstate = OS_COMMITTED;
5868 if (Tdata1 != 0) {
5869 warningReport(signal, 5);
5870 return;
5871 }//if
5872 if (TcheckCondition) {
5873 jam();
5874 /*-------------------------------------------------------*/
5875 // We have not sent all COMMIT requests yet. We could be
5876 // in the state that all sent are COMMITTED but we are
5877 // still waiting for a CONTINUEB to send the rest of the
5878 // COMMIT requests.
5879 /*-------------------------------------------------------*/
5880 return;
5881 }//if
5882 if (ERROR_INSERTED(8020)) {
5883 jam();
5884 systemErrorLab(signal, __LINE__);
5885 }//if
5886 /*-------------------------------------------------------*/
5887 /* THE ENTIRE TRANSACTION IS NOW COMMITED */
5888 /* NOW WE NEED TO SEND THE RESPONSE TO THE APPLICATION. */
5889 /* THE APPLICATION CAN THEN REUSE THE API CONNECTION AND */
5890 /* THEREFORE WE NEED TO MOVE THE API CONNECTION TO A */
5891 /* NEW API CONNECT RECORD. */
5892 /*-------------------------------------------------------*/
5893
5894 apiConnectptr = localApiConnectptr;
5895 localCopyPtr = sendApiCommit(signal);
5896
5897 localTcConnectptr.i = localCopyPtr.p->firstTcConnect;
5898 UintR Tlqhkeyconfrec = localCopyPtr.p->lqhkeyconfrec;
5899 ptrCheckGuard(localTcConnectptr, TtcConnectFilesize, localTcConnectRecord);
5900 localCopyPtr.p->counter = Tlqhkeyconfrec;
5901
5902 apiConnectptr = localCopyPtr;
5903 tcConnectptr = localTcConnectptr;
5904 complete010Lab(signal);
5905 return;
5906
5907 }//Dbtc::execCOMMITTED()
5908
5909 /*-------------------------------------------------------*/
5910 /* SEND_API_COMMIT */
5911 /* SEND COMMIT DECISION TO THE API. */
5912 /*-------------------------------------------------------*/
5913 Ptr<Dbtc::ApiConnectRecord>
sendApiCommit(Signal * signal)5914 Dbtc::sendApiCommit(Signal* signal)
5915 {
5916 ApiConnectRecordPtr regApiPtr = apiConnectptr;
5917
5918 if (ERROR_INSERTED(8055))
5919 {
5920 /**
5921 * 1) Kill self
5922 * 2) Disconnect API
5923 * 3) Prevent execAPI_FAILREQ from handling trans...
5924 */
5925 signal->theData[0] = 9999;
5926 sendSignalWithDelay(CMVMI_REF, GSN_NDB_TAMPER, signal, 1000, 1);
5927 Uint32 node = refToNode(regApiPtr.p->ndbapiBlockref);
5928 signal->theData[0] = node;
5929 sendSignal(QMGR_REF, GSN_API_FAILREQ, signal, 1, JBB);
5930
5931 SET_ERROR_INSERT_VALUE(8056);
5932
5933 goto err8055;
5934 }
5935
5936 if (regApiPtr.p->returnsignal == RS_TCKEYCONF)
5937 {
5938 if (ERROR_INSERTED(8054))
5939 {
5940 signal->theData[0] = 9999;
5941 sendSignalWithDelay(CMVMI_REF, GSN_NDB_TAMPER, signal, 5000, 1);
5942 }
5943 else
5944 {
5945 sendtckeyconf(signal, 1);
5946 }
5947 }
5948 else if (regApiPtr.p->returnsignal == RS_TC_COMMITCONF)
5949 {
5950 jam();
5951 TcCommitConf * const commitConf = (TcCommitConf *)&signal->theData[0];
5952 if(regApiPtr.p->commitAckMarker == RNIL)
5953 {
5954 jam();
5955 commitConf->apiConnectPtr = regApiPtr.p->ndbapiConnect;
5956 }
5957 else
5958 {
5959 jam();
5960 commitConf->apiConnectPtr = regApiPtr.p->ndbapiConnect | 1;
5961 }
5962 commitConf->transId1 = regApiPtr.p->transid[0];
5963 commitConf->transId2 = regApiPtr.p->transid[1];
5964 commitConf->gci_hi = Uint32(regApiPtr.p->globalcheckpointid >> 32);
5965 commitConf->gci_lo = Uint32(regApiPtr.p->globalcheckpointid);
5966
5967 if (!ERROR_INSERTED(8054) && !ERROR_INSERTED(8108))
5968 {
5969 sendSignal(regApiPtr.p->ndbapiBlockref, GSN_TC_COMMITCONF, signal,
5970 TcCommitConf::SignalLength, JBB);
5971 }
5972 }
5973 else if (regApiPtr.p->returnsignal == RS_NO_RETURN)
5974 {
5975 jam();
5976 }
5977 else
5978 {
5979 TCKEY_abort(signal, 37);
5980 return regApiPtr;
5981 }//if
5982
5983 err8055:
5984 Ptr<ApiConnectRecord> copyPtr;
5985 UintR TapiConnectFilesize = capiConnectFilesize;
5986 /**
5987 * Unlink copy connect record from main connect record to allow main record
5988 * re-use.
5989 */
5990 copyPtr.i = regApiPtr.p->apiCopyRecord;
5991 regApiPtr.p->apiCopyRecord = RNIL;
5992 UintR TapiFailState = regApiPtr.p->apiFailState;
5993 ApiConnectRecord *localApiConnectRecord = apiConnectRecord;
5994
5995 c_counters.ccommitCount++;
5996 ptrCheckGuard(copyPtr, TapiConnectFilesize, localApiConnectRecord);
5997 copyApi(copyPtr, regApiPtr);
5998 if (TapiFailState != ZTRUE) {
5999 return copyPtr;
6000 } else {
6001 jam();
6002 handleApiFailState(signal, regApiPtr.i);
6003 return copyPtr;
6004 }//if
6005 }//Dbtc::sendApiCommit()
6006
6007 /* ========================================================================= */
6008 /* ======= COPY_API ======= */
6009 /* COPY API RECORD ALSO RESET THE OLD API RECORD SO THAT IT */
6010 /* IS PREPARED TO RECEIVE A NEW TRANSACTION. */
6011 /*===========================================================================*/
copyApi(ApiConnectRecordPtr copyPtr,ApiConnectRecordPtr regApiPtr)6012 void Dbtc::copyApi(ApiConnectRecordPtr copyPtr, ApiConnectRecordPtr regApiPtr)
6013 {
6014 UintR TndbapiConnect = regApiPtr.p->ndbapiConnect;
6015 UintR TfirstTcConnect = regApiPtr.p->firstTcConnect;
6016 UintR Ttransid1 = regApiPtr.p->transid[0];
6017 UintR Ttransid2 = regApiPtr.p->transid[1];
6018 UintR Tlqhkeyconfrec = regApiPtr.p->lqhkeyconfrec;
6019 UintR TgcpPointer = regApiPtr.p->gcpPointer;
6020 UintR TgcpFilesize = cgcpFilesize;
6021 NdbNodeBitmask Tnodes = regApiPtr.p->m_transaction_nodes;
6022 GcpRecord *localGcpRecord = gcpRecord;
6023
6024 copyPtr.p->ndbapiBlockref = regApiPtr.p->ndbapiBlockref;
6025 copyPtr.p->ndbapiConnect = TndbapiConnect;
6026 copyPtr.p->firstTcConnect = TfirstTcConnect;
6027 copyPtr.p->apiConnectstate = CS_COMPLETING;
6028 copyPtr.p->transid[0] = Ttransid1;
6029 copyPtr.p->transid[1] = Ttransid2;
6030 copyPtr.p->lqhkeyconfrec = Tlqhkeyconfrec;
6031 copyPtr.p->commitAckMarker = RNIL;
6032 copyPtr.p->m_transaction_nodes = Tnodes;
6033 copyPtr.p->num_commit_ack_markers = 0;
6034 copyPtr.p->singleUserMode = 0;
6035
6036 Ptr<GcpRecord> gcpPtr;
6037 gcpPtr.i = TgcpPointer;
6038 ptrCheckGuard(gcpPtr, TgcpFilesize, localGcpRecord);
6039 unlinkApiConnect(gcpPtr, regApiPtr);
6040 linkApiToGcp(gcpPtr, copyPtr);
6041 setApiConTimer(regApiPtr.i, 0, __LINE__);
6042 regApiPtr.p->apiConnectstate = CS_CONNECTED;
6043 regApiPtr.p->commitAckMarker = RNIL;
6044 regApiPtr.p->firstTcConnect = RNIL;
6045 regApiPtr.p->lastTcConnect = RNIL;
6046 regApiPtr.p->m_transaction_nodes.clear();
6047 regApiPtr.p->singleUserMode = 0;
6048 regApiPtr.p->num_commit_ack_markers = 0;
6049 releaseAllSeizedIndexOperations(regApiPtr.p);
6050 }//Dbtc::copyApi()
6051
unlinkApiConnect(Ptr<GcpRecord> gcpPtr,Ptr<ApiConnectRecord> regApiPtr)6052 void Dbtc::unlinkApiConnect(Ptr<GcpRecord> gcpPtr,
6053 Ptr<ApiConnectRecord> regApiPtr)
6054 {
6055 ApiConnectRecordPtr localApiConnectptr;
6056 UintR TapiConnectFilesize = capiConnectFilesize;
6057 UintR TprevGcpConnect = regApiPtr.p->prevGcpConnect;
6058 UintR TnextGcpConnect = regApiPtr.p->nextGcpConnect;
6059 ApiConnectRecord *localApiConnectRecord = apiConnectRecord;
6060
6061 if (TprevGcpConnect == RNIL) {
6062 gcpPtr.p->firstApiConnect = TnextGcpConnect;
6063 jam();
6064 } else {
6065 localApiConnectptr.i = TprevGcpConnect;
6066 jam();
6067 ptrCheckGuard(localApiConnectptr,
6068 TapiConnectFilesize, localApiConnectRecord);
6069 localApiConnectptr.p->nextGcpConnect = TnextGcpConnect;
6070 }//if
6071 if (TnextGcpConnect == RNIL) {
6072 gcpPtr.p->lastApiConnect = TprevGcpConnect;
6073 jam();
6074 } else {
6075 localApiConnectptr.i = TnextGcpConnect;
6076 jam();
6077 ptrCheckGuard(localApiConnectptr,
6078 TapiConnectFilesize, localApiConnectRecord);
6079 localApiConnectptr.p->prevGcpConnect = TprevGcpConnect;
6080 }//if
6081 }//Dbtc::unlinkApiConnect()
6082
complete010Lab(Signal * signal)6083 void Dbtc::complete010Lab(Signal* signal)
6084 {
6085 TcConnectRecordPtr localTcConnectptr;
6086 ApiConnectRecord * const regApiPtr = apiConnectptr.p;
6087 UintR TtcConnectFilesize = ctcConnectFilesize;
6088 TcConnectRecord *localTcConnectRecord = tcConnectRecord;
6089
6090 localTcConnectptr.p = tcConnectptr.p;
6091 setApiConTimer(apiConnectptr.i, ctcTimer, __LINE__);
6092 UintR TapiConnectptrIndex = apiConnectptr.i;
6093 UintR Tcount = 0;
6094 do {
6095 localTcConnectptr.p->apiConnect = TapiConnectptrIndex;
6096 localTcConnectptr.p->tcConnectstate = OS_COMPLETING;
6097
6098 /* ************ */
6099 /* COMPLETE < */
6100 /* ************ */
6101 const Uint32 nextTcConnect = localTcConnectptr.p->nextTcConnect;
6102 Tcount += sendCompleteLqh(signal, localTcConnectptr.p);
6103 localTcConnectptr.i = nextTcConnect;
6104 if (localTcConnectptr.i != RNIL) {
6105 if (Tcount < 16) {
6106 ptrCheckGuard(localTcConnectptr,
6107 TtcConnectFilesize, localTcConnectRecord);
6108 jam();
6109 continue;
6110 } else {
6111 jam();
6112 if (ERROR_INSERTED(8013)) {
6113 CLEAR_ERROR_INSERT_VALUE;
6114 return;
6115 }//if
6116 signal->theData[0] = TcContinueB::ZSEND_COMPLETE_LOOP;
6117 signal->theData[1] = apiConnectptr.i;
6118 signal->theData[2] = localTcConnectptr.i;
6119 sendSignal(cownref, GSN_CONTINUEB, signal, 3, JBB);
6120 return;
6121 }//if
6122 } else {
6123 jam();
6124 regApiPtr->apiConnectstate = CS_COMPLETE_SENT;
6125 return;
6126 }//if
6127 } while (1);
6128 }//Dbtc::complete010Lab()
6129
6130 Uint32
sendCompleteLqh(Signal * signal,TcConnectRecord * const regTcPtr)6131 Dbtc::sendCompleteLqh(Signal* signal,
6132 TcConnectRecord * const regTcPtr)
6133 {
6134 HostRecordPtr Thostptr;
6135 UintR ThostFilesize = chostFilesize;
6136 Uint32 instanceKey = regTcPtr->lqhInstanceKey;
6137 ApiConnectRecord * const regApiPtr = apiConnectptr.p;
6138 Thostptr.i = regTcPtr->lastLqhNodeId;
6139 ptrCheckGuard(Thostptr, ThostFilesize, hostRecord);
6140
6141 Uint32 Tnode = Thostptr.i;
6142 Uint32 self = getOwnNodeId();
6143 Uint32 ret = (Tnode == self) ? 4 : 1;
6144
6145 Uint32 Tdata[3];
6146 Tdata[0] = regTcPtr->lastLqhCon;
6147 Tdata[1] = regApiPtr->transid[0];
6148 Tdata[2] = regApiPtr->transid[1];
6149 Uint32 len = 3;
6150
6151 if (instanceKey > MAX_NDBMT_LQH_THREADS) {
6152 memcpy(&signal->theData[0], &Tdata[0], len << 2);
6153 BlockReference lqhRef = numberToRef(DBLQH, instanceKey, Tnode);
6154 sendSignal(lqhRef, GSN_COMPLETE, signal, 3, JBB);
6155 return ret;
6156 }
6157
6158 struct PackedWordsContainer * container = &Thostptr.p->lqh_pack[instanceKey];
6159
6160 if (container->noOfPackedWords > 22) {
6161 jam();
6162 sendPackedSignal(signal, container);
6163 } else {
6164 jam();
6165 ret = 1;
6166 updatePackedList(signal, Thostptr.p, Thostptr.i);
6167 }
6168
6169 Tdata[0] |= (ZCOMPLETE << 28);
6170 UintR Tindex = container->noOfPackedWords;
6171 container->noOfPackedWords = Tindex + len;
6172 UintR* TDataPtr = &container->packedWords[Tindex];
6173 memcpy(TDataPtr, &Tdata[0], len << 2);
6174 return ret;
6175 }
6176
6177 static
6178 inline
6179 Uint32
getTcConnectRecordDeferredFlag(Uint32 pass)6180 getTcConnectRecordDeferredFlag(Uint32 pass)
6181 {
6182 switch(pass & TriggerPreCommitPass::TPCP_PASS_MAX){
6183 case TriggerPreCommitPass::UK_PASS_0:
6184 case TriggerPreCommitPass::UK_PASS_1:
6185 return Dbtc::TcConnectRecord::SOF_DEFERRED_UK_TRIGGER;
6186 case TriggerPreCommitPass::FK_PASS_0:
6187 return Dbtc::TcConnectRecord::SOF_DEFERRED_FK_TRIGGER;
6188 }
6189 assert(false);
6190 return 0;
6191 }
6192
6193 static
6194 inline
6195 Uint8
getNextDeferredPass(Uint32 pass)6196 getNextDeferredPass(Uint32 pass)
6197 {
6198 Uint32 loop = (pass & ~Uint32(TriggerPreCommitPass::TPCP_PASS_MAX));
6199 switch(pass & TriggerPreCommitPass::TPCP_PASS_MAX){
6200 case TriggerPreCommitPass::UK_PASS_0:
6201 return loop + TriggerPreCommitPass::UK_PASS_1;
6202 case TriggerPreCommitPass::UK_PASS_1:
6203 return loop + TriggerPreCommitPass::FK_PASS_0;
6204 case TriggerPreCommitPass::FK_PASS_0:
6205 return loop + Uint32(TriggerPreCommitPass::TPCP_PASS_MAX) + 1;
6206 }
6207 assert(false);
6208 return 255;
6209 }
6210
6211 void
sendFireTrigReq(Signal * signal,Ptr<ApiConnectRecord> regApiPtr,Uint32 TopPtrI,Uint32 TlastOpPtrI)6212 Dbtc::sendFireTrigReq(Signal* signal,
6213 Ptr<ApiConnectRecord> regApiPtr,
6214 Uint32 TopPtrI,
6215 Uint32 TlastOpPtrI)
6216 {
6217 UintR TtcConnectFilesize = ctcConnectFilesize;
6218 TcConnectRecord *localTcConnectRecord = tcConnectRecord;
6219 TcConnectRecordPtr localTcConnectptr;
6220
6221 setApiConTimer(regApiPtr.i, ctcTimer, __LINE__);
6222 regApiPtr.p->apiConnectstate = CS_SEND_FIRE_TRIG_REQ;
6223
6224 localTcConnectptr.i = TopPtrI;
6225 ndbassert(TopPtrI != RNIL);
6226 Uint32 Tlqhkeyreqrec = regApiPtr.p->lqhkeyreqrec;
6227 const Uint32 pass = regApiPtr.p->m_pre_commit_pass;
6228 const Uint32 passflag = getTcConnectRecordDeferredFlag(pass);
6229 Uint32 prevOpPtrI = RNIL;
6230 #if defined VM_TRACE || defined ERROR_INSERT
6231 const Uint32 LIMIT = 1 + rand() % 15;
6232 #else
6233 const Uint32 LIMIT = 16;
6234 #endif
6235 for (Uint32 i = 0; prevOpPtrI != TlastOpPtrI && i < LIMIT; i++)
6236 {
6237 ptrCheckGuard(localTcConnectptr,
6238 TtcConnectFilesize, localTcConnectRecord);
6239
6240 const Uint32 nextTcConnect = localTcConnectptr.p->nextTcConnect;
6241 Uint32 flags = localTcConnectptr.p->m_special_op_flags;
6242 if (flags & passflag)
6243 {
6244 jam();
6245 tc_clearbit(flags, passflag);
6246 if (unlikely(! (localTcConnectptr.p->tcConnectstate == OS_PREPARED)))
6247 {
6248 ndbout_c("op: 0x%x trans [ 0x%.8x 0x%.8x ] state: %u (TopPtrI: %x)",
6249 localTcConnectptr.i,
6250 regApiPtr.p->transid[0],
6251 regApiPtr.p->transid[1],
6252 localTcConnectptr.p->tcConnectstate,
6253 TopPtrI);
6254 dump_trans(regApiPtr);
6255 }
6256
6257 ndbrequire(localTcConnectptr.p->tcConnectstate == OS_PREPARED);
6258 localTcConnectptr.p->tcConnectstate = OS_FIRE_TRIG_REQ;
6259 localTcConnectptr.p->m_special_op_flags = flags;
6260 i += sendFireTrigReqLqh(signal, localTcConnectptr, pass);
6261 Tlqhkeyreqrec++;
6262 }
6263
6264 prevOpPtrI = localTcConnectptr.i;
6265 localTcConnectptr.i = nextTcConnect;
6266 }
6267
6268 regApiPtr.p->lqhkeyreqrec = Tlqhkeyreqrec;
6269 if (prevOpPtrI == TlastOpPtrI)
6270 {
6271 /**
6272 * Now wait for FIRE_TRIG_CONF
6273 */
6274 jam();
6275 regApiPtr.p->apiConnectstate = CS_WAIT_FIRE_TRIG_REQ;
6276 ndbrequire(pass < 255);
6277 regApiPtr.p->m_pre_commit_pass = getNextDeferredPass(pass);
6278
6279 /**
6280 * Check if we are already finished...
6281 */
6282 if (regApiPtr.p->lqhkeyreqrec == regApiPtr.p->lqhkeyconfrec &&
6283 regApiPtr.p->pendingTriggers == 0)
6284 {
6285 jam();
6286 lqhKeyConf_checkTransactionState(signal, regApiPtr);
6287 }
6288 return;
6289 }
6290 else
6291 {
6292 jam();
6293 regApiPtr.p->lqhkeyreqrec++; // prevent early completion
6294 signal->theData[0] = TcContinueB::ZSEND_FIRE_TRIG_REQ;
6295 signal->theData[1] = regApiPtr.i;
6296 signal->theData[2] = regApiPtr.p->transid[0];
6297 signal->theData[3] = regApiPtr.p->transid[1];
6298 signal->theData[4] = localTcConnectptr.i;
6299 signal->theData[5] = TlastOpPtrI;
6300 if (ERROR_INSERTED_CLEAR(8090))
6301 {
6302 sendSignalWithDelay(cownref, GSN_CONTINUEB, signal, 5000, 6);
6303 }
6304 else
6305 {
6306 sendSignal(cownref, GSN_CONTINUEB, signal, 6, JBB);
6307 }
6308 }
6309 }
6310
6311 Uint32
sendFireTrigReqLqh(Signal * signal,Ptr<TcConnectRecord> regTcPtr,Uint32 pass)6312 Dbtc::sendFireTrigReqLqh(Signal* signal,
6313 Ptr<TcConnectRecord> regTcPtr,
6314 Uint32 pass)
6315 {
6316 HostRecordPtr Thostptr;
6317 UintR ThostFilesize = chostFilesize;
6318 Uint32 instanceKey = regTcPtr.p->lqhInstanceKey;
6319 ApiConnectRecord * const regApiPtr = apiConnectptr.p;
6320 Thostptr.i = regTcPtr.p->tcNodedata[0];
6321 ptrCheckGuard(Thostptr, ThostFilesize, hostRecord);
6322
6323 Uint32 Tnode = Thostptr.i;
6324 Uint32 self = getOwnNodeId();
6325 Uint32 ret = (Tnode == self) ? 4 : 1;
6326
6327 Uint32 Tdata[FireTrigReq::SignalLength];
6328 FireTrigReq * req = CAST_PTR(FireTrigReq, Tdata);
6329 req->tcOpRec = regTcPtr.i;
6330 req->transId[0] = regApiPtr->transid[0];
6331 req->transId[1] = regApiPtr->transid[1];
6332 req->pass = pass;
6333 Uint32 len = FireTrigReq::SignalLength;
6334
6335 if (instanceKey > MAX_NDBMT_LQH_THREADS) {
6336 memcpy(signal->theData, Tdata, len << 2);
6337 BlockReference lqhRef = numberToRef(DBLQH, instanceKey, Tnode);
6338 sendSignal(lqhRef, GSN_FIRE_TRIG_REQ, signal, len, JBB);
6339 return ret;
6340 }
6341
6342 struct PackedWordsContainer * container = &Thostptr.p->lqh_pack[instanceKey];
6343
6344 if (container->noOfPackedWords > 25 - len) {
6345 jam();
6346 sendPackedSignal(signal, container);
6347 } else {
6348 jam();
6349 ret = 1;
6350 updatePackedList(signal, Thostptr.p, Thostptr.i);
6351 }
6352
6353 Tdata[0] |= (ZFIRE_TRIG_REQ << 28);
6354 UintR Tindex = container->noOfPackedWords;
6355 container->noOfPackedWords = Tindex + len;
6356 UintR* TDataPtr = &container->packedWords[Tindex];
6357 memcpy(TDataPtr, Tdata, len << 2);
6358 return ret;
6359 }
6360
6361 void
execFIRE_TRIG_CONF(Signal * signal)6362 Dbtc::execFIRE_TRIG_CONF(Signal* signal)
6363 {
6364 TcConnectRecordPtr localTcConnectptr;
6365 ApiConnectRecordPtr regApiPtr;
6366
6367 UintR TtcConnectFilesize = ctcConnectFilesize;
6368 UintR TapiConnectFilesize = capiConnectFilesize;
6369 TcConnectRecord *localTcConnectRecord = tcConnectRecord;
6370 ApiConnectRecord *localApiConnectRecord = apiConnectRecord;
6371
6372 const FireTrigConf * conf = CAST_CONSTPTR(FireTrigConf, signal->theData);
6373 localTcConnectptr.i = conf->tcOpRec;
6374 jamEntry();
6375 ptrCheckGuard(localTcConnectptr, TtcConnectFilesize, localTcConnectRecord);
6376 regApiPtr.i = localTcConnectptr.p->apiConnect;
6377 if (localTcConnectptr.p->tcConnectstate != OS_FIRE_TRIG_REQ)
6378 {
6379 warningReport(signal, 28);
6380 return;
6381 }//if
6382 ptrCheckGuard(regApiPtr, TapiConnectFilesize,
6383 localApiConnectRecord);
6384
6385 Uint32 Tlqhkeyreqrec = regApiPtr.p->lqhkeyreqrec;
6386 Uint32 TapiConnectstate = regApiPtr.p->apiConnectstate;
6387 UintR Tdata1 = regApiPtr.p->transid[0] - conf->transId[0];
6388 UintR Tdata2 = regApiPtr.p->transid[1] - conf->transId[1];
6389 Uint32 TcheckCondition =
6390 (TapiConnectstate != CS_SEND_FIRE_TRIG_REQ) &&
6391 (TapiConnectstate != CS_WAIT_FIRE_TRIG_REQ);
6392
6393 Tdata1 = Tdata1 | Tdata2 | TcheckCondition;
6394
6395 if (Tdata1 != 0) {
6396 warningReport(signal, 28);
6397 return;
6398 }//if
6399
6400 if (ERROR_INSERTED_CLEAR(8091))
6401 {
6402 jam();
6403 return;
6404 }
6405
6406 CRASH_INSERTION(8092);
6407
6408 setApiConTimer(regApiPtr.i, ctcTimer, __LINE__);
6409 ndbassert(Tlqhkeyreqrec > 0);
6410 regApiPtr.p->lqhkeyreqrec = Tlqhkeyreqrec - 1;
6411 localTcConnectptr.p->tcConnectstate = OS_PREPARED;
6412
6413 Uint32 numFired = FireTrigConf::getFiredCount(conf->numFiredTriggers);
6414 Uint32 deferreduk = FireTrigConf::getDeferredUKBit(conf->numFiredTriggers);
6415 Uint32 deferredfk = FireTrigConf::getDeferredFKBit(conf->numFiredTriggers);
6416
6417 regApiPtr.p->pendingTriggers += numFired;
6418 regApiPtr.p->m_flags |=
6419 ((deferreduk) ? ApiConnectRecord::TF_DEFERRED_UK_TRIGGERS : 0) |
6420 ((deferredfk) ? ApiConnectRecord::TF_DEFERRED_FK_TRIGGERS : 0);
6421 localTcConnectptr.p->m_special_op_flags |=
6422 ((deferreduk) ? TcConnectRecord::SOF_DEFERRED_UK_TRIGGER : 0) |
6423 ((deferredfk) ? TcConnectRecord::SOF_DEFERRED_FK_TRIGGER : 0);
6424
6425 if (regApiPtr.p->pendingTriggers == 0)
6426 {
6427 jam();
6428 lqhKeyConf_checkTransactionState(signal, regApiPtr);
6429 }
6430 }
6431
6432 void
execFIRE_TRIG_REF(Signal * signal)6433 Dbtc::execFIRE_TRIG_REF(Signal* signal)
6434 {
6435 TcConnectRecordPtr localTcConnectptr;
6436 ApiConnectRecordPtr regApiPtr;
6437
6438 UintR TtcConnectFilesize = ctcConnectFilesize;
6439 UintR TapiConnectFilesize = capiConnectFilesize;
6440 TcConnectRecord *localTcConnectRecord = tcConnectRecord;
6441 ApiConnectRecord *localApiConnectRecord = apiConnectRecord;
6442
6443 const FireTrigRef * ref = CAST_CONSTPTR(FireTrigRef, signal->theData);
6444 localTcConnectptr.i = ref->tcOpRec;
6445 jamEntry();
6446 ptrCheckGuard(localTcConnectptr, TtcConnectFilesize, localTcConnectRecord);
6447 regApiPtr.i = localTcConnectptr.p->apiConnect;
6448 if (localTcConnectptr.p->tcConnectstate != OS_FIRE_TRIG_REQ)
6449 {
6450 warningReport(signal, 28);
6451 return;
6452 }//if
6453 ptrCheckGuard(regApiPtr, TapiConnectFilesize,
6454 localApiConnectRecord);
6455
6456 apiConnectptr = regApiPtr;
6457
6458 UintR Tdata1 = regApiPtr.p->transid[0] - ref->transId[0];
6459 UintR Tdata2 = regApiPtr.p->transid[1] - ref->transId[1];
6460 Tdata1 = Tdata1 | Tdata2;
6461 if (Tdata1 != 0) {
6462 warningReport(signal, 28);
6463 return;
6464 }//if
6465
6466 if (regApiPtr.p->apiConnectstate != CS_SEND_FIRE_TRIG_REQ &&
6467 regApiPtr.p->apiConnectstate != CS_WAIT_FIRE_TRIG_REQ)
6468 {
6469 jam();
6470 warningReport(signal, 28);
6471 return;
6472 }
6473
6474 terrorCode = ref->errCode;
6475 abortErrorLab(signal);
6476 }
6477
6478 /**
6479 * The NDB API has now reported that it has heard about the commit of
6480 * transaction, this means that we're ready to remove the commit ack
6481 * markers, both here in DBTC and in all the participating DBLQH's.
6482 */
6483 void
execTC_COMMIT_ACK(Signal * signal)6484 Dbtc::execTC_COMMIT_ACK(Signal* signal){
6485 jamEntry();
6486
6487 CommitAckMarker key;
6488 key.transid1 = signal->theData[0];
6489 key.transid2 = signal->theData[1];
6490
6491 CommitAckMarkerPtr removedMarker;
6492 m_commitAckMarkerHash.remove(removedMarker, key);
6493 if (removedMarker.i == RNIL) {
6494 jam();
6495 warningHandlerLab(signal, __LINE__);
6496 return;
6497 }//if
6498 sendRemoveMarkers(signal, removedMarker.p, 0);
6499 m_commitAckMarkerPool.release(removedMarker);
6500 }
6501
6502 void
sendRemoveMarkers(Signal * signal,CommitAckMarker * marker,Uint32 removed_by_fail_api)6503 Dbtc::sendRemoveMarkers(Signal* signal,
6504 CommitAckMarker * marker,
6505 Uint32 removed_by_fail_api)
6506 {
6507 jam();
6508 const Uint32 transId1 = marker->transid1;
6509 const Uint32 transId2 = marker->transid2;
6510
6511 CommitAckMarkerBuffer::DataBufferPool & pool =
6512 c_theCommitAckMarkerBufferPool;
6513 LocalDataBuffer<5> commitAckMarkers(pool, marker->theDataBuffer);
6514 CommitAckMarkerBuffer::DataBufferIterator iter;
6515 bool next_flag = commitAckMarkers.first(iter);
6516 while (next_flag)
6517 {
6518 jam();
6519 Uint32 dataWord = *iter.data;
6520 NodeId nodeId = dataWord >> 16;
6521 Uint32 instanceKey = dataWord & 0xFFFF;
6522 sendRemoveMarker(signal,
6523 nodeId,
6524 instanceKey,
6525 transId1,
6526 transId2,
6527 removed_by_fail_api);
6528 next_flag = commitAckMarkers.next(iter, 1);
6529 }
6530 commitAckMarkers.release();
6531 }
6532
6533 void
sendRemoveMarker(Signal * signal,NodeId nodeId,Uint32 instanceKey,Uint32 transid1,Uint32 transid2,Uint32 removed_by_fail_api)6534 Dbtc::sendRemoveMarker(Signal* signal,
6535 NodeId nodeId,
6536 Uint32 instanceKey,
6537 Uint32 transid1,
6538 Uint32 transid2,
6539 Uint32 removed_by_fail_api){
6540 /**
6541 * Seize host ptr
6542 */
6543 HostRecordPtr hostPtr;
6544 const UintR ThostFilesize = chostFilesize;
6545 hostPtr.i = nodeId;
6546 ptrCheckGuard(hostPtr, ThostFilesize, hostRecord);
6547
6548 Uint32 Tdata[3];
6549 Tdata[0] = removed_by_fail_api;
6550 Tdata[1] = transid1;
6551 Tdata[2] = transid2;
6552 Uint32 len = 3;
6553
6554 if (instanceKey > MAX_NDBMT_LQH_THREADS) {
6555 jam();
6556 // first word omitted
6557 memcpy(&signal->theData[0], &Tdata[1], (len - 1) << 2);
6558 Uint32 Tnode = hostPtr.i;
6559 BlockReference ref = numberToRef(DBLQH, instanceKey, Tnode);
6560 sendSignal(ref, GSN_REMOVE_MARKER_ORD, signal, len - 1, JBB);
6561 return;
6562 }
6563
6564 struct PackedWordsContainer * container = &hostPtr.p->lqh_pack[instanceKey];
6565
6566 if (container->noOfPackedWords > (25 - 3)){
6567 jam();
6568 sendPackedSignal(signal, container);
6569 } else {
6570 jam();
6571 updatePackedList(signal, hostPtr.p, hostPtr.i);
6572 }
6573
6574 UintR numWord = container->noOfPackedWords;
6575 UintR* dataPtr = &container->packedWords[numWord];
6576
6577 container->noOfPackedWords = numWord + len;
6578 Tdata[0] |= (ZREMOVE_MARKER << 28);
6579 memcpy(dataPtr, &Tdata[0], len << 2);
6580 }
6581
execCOMPLETED(Signal * signal)6582 void Dbtc::execCOMPLETED(Signal* signal)
6583 {
6584 TcConnectRecordPtr localTcConnectptr;
6585 ApiConnectRecordPtr localApiConnectptr;
6586
6587 UintR TtcConnectFilesize = ctcConnectFilesize;
6588 UintR TapiConnectFilesize = capiConnectFilesize;
6589 TcConnectRecord *localTcConnectRecord = tcConnectRecord;
6590 ApiConnectRecord *localApiConnectRecord = apiConnectRecord;
6591
6592 #ifdef ERROR_INSERT
6593 if (ERROR_INSERTED(8031)) {
6594 systemErrorLab(signal, __LINE__);
6595 }//if
6596 if (ERROR_INSERTED(8019)) {
6597 CLEAR_ERROR_INSERT_VALUE;
6598 return;
6599 }//if
6600 if (ERROR_INSERTED(8027)) {
6601 SET_ERROR_INSERT_VALUE(8028);
6602 return;
6603 }//if
6604 if (ERROR_INSERTED(8043)) {
6605 CLEAR_ERROR_INSERT_VALUE;
6606 sendSignalWithDelay(cownref, GSN_COMPLETED, signal, 2000, 3);
6607 return;
6608 }//if
6609 if (ERROR_INSERTED(8044)) {
6610 SET_ERROR_INSERT_VALUE(8047);
6611 sendSignalWithDelay(cownref, GSN_COMPLETED, signal, 2000, 3);
6612 return;
6613 }//if
6614 #endif
6615 localTcConnectptr.i = signal->theData[0];
6616 jamEntry();
6617 ptrCheckGuard(localTcConnectptr, TtcConnectFilesize, localTcConnectRecord);
6618 bool Tcond1 = (localTcConnectptr.p->tcConnectstate != OS_COMPLETING);
6619 localApiConnectptr.i = localTcConnectptr.p->apiConnect;
6620 if (Tcond1) {
6621 warningReport(signal, 6);
6622 return;
6623 }//if
6624 ptrCheckGuard(localApiConnectptr, TapiConnectFilesize,
6625 localApiConnectRecord);
6626 UintR Tdata1 = localApiConnectptr.p->transid[0] - signal->theData[1];
6627 UintR Tdata2 = localApiConnectptr.p->transid[1] - signal->theData[2];
6628 UintR Tcounter = localApiConnectptr.p->counter - 1;
6629 ConnectionState TapiConnectstate = localApiConnectptr.p->apiConnectstate;
6630 Tdata1 = Tdata1 | Tdata2;
6631 bool TcheckCondition =
6632 (TapiConnectstate != CS_COMPLETE_SENT) || (Tcounter != 0);
6633 if (Tdata1 != 0) {
6634 warningReport(signal, 7);
6635 return;
6636 }//if
6637 setApiConTimer(localApiConnectptr.i, ctcTimer, __LINE__);
6638 localApiConnectptr.p->counter = Tcounter;
6639 localTcConnectptr.p->tcConnectstate = OS_COMPLETED;
6640 localTcConnectptr.p->noOfNodes = 0; // == releaseNodes(signal)
6641 if (TcheckCondition) {
6642 jam();
6643 /*-------------------------------------------------------*/
6644 // We have not sent all COMPLETE requests yet. We could be
6645 // in the state that all sent are COMPLETED but we are
6646 // still waiting for a CONTINUEB to send the rest of the
6647 // COMPLETE requests.
6648 /*-------------------------------------------------------*/
6649 return;
6650 }//if
6651 if (ERROR_INSERTED(8021)) {
6652 jam();
6653 systemErrorLab(signal, __LINE__);
6654 }//if
6655 apiConnectptr = localApiConnectptr;
6656 releaseTransResources(signal);
6657 CRASH_INSERTION(8054);
6658 }//Dbtc::execCOMPLETED()
6659
6660 /*---------------------------------------------------------------------------*/
6661 /* RELEASE_TRANS_RESOURCES */
6662 /* RELEASE ALL RESOURCES THAT ARE CONNECTED TO THIS TRANSACTION. */
6663 /*---------------------------------------------------------------------------*/
releaseTransResources(Signal * signal)6664 void Dbtc::releaseTransResources(Signal* signal)
6665 {
6666 TcConnectRecordPtr localTcConnectptr;
6667 UintR TtcConnectFilesize = ctcConnectFilesize;
6668 TcConnectRecord *localTcConnectRecord = tcConnectRecord;
6669 apiConnectptr.p->m_transaction_nodes.clear();
6670 localTcConnectptr.i = apiConnectptr.p->firstTcConnect;
6671 do {
6672 jam();
6673 ptrCheckGuard(localTcConnectptr, TtcConnectFilesize, localTcConnectRecord);
6674 UintR rtrTcConnectptrIndex = localTcConnectptr.p->nextTcConnect;
6675 tcConnectptr.i = localTcConnectptr.i;
6676 tcConnectptr.p = localTcConnectptr.p;
6677 localTcConnectptr.i = rtrTcConnectptrIndex;
6678 releaseTcCon();
6679 } while (localTcConnectptr.i != RNIL);
6680 handleGcp(signal, apiConnectptr);
6681 releaseFiredTriggerData(&apiConnectptr.p->theFiredTriggers);
6682 releaseAllSeizedIndexOperations(apiConnectptr.p);
6683 releaseApiConCopy(signal);
6684 }//Dbtc::releaseTransResources()
6685
6686 /* *********************************************************************>> */
6687 /* MODULE: HANDLE_GCP */
6688 /* DESCRIPTION: HANDLES GLOBAL CHECKPOINT HANDLING AT THE COMPLETION */
6689 /* OF THE COMMIT PHASE AND THE ABORT PHASE. WE MUST ENSURE THAT TC */
6690 /* SENDS GCP_TCFINISHED WHEN ALL TRANSACTIONS BELONGING TO A CERTAIN */
6691 /* GLOBAL CHECKPOINT HAVE COMPLETED. */
6692 /* *********************************************************************>> */
handleGcp(Signal * signal,Ptr<ApiConnectRecord> regApiPtr)6693 void Dbtc::handleGcp(Signal* signal, Ptr<ApiConnectRecord> regApiPtr)
6694 {
6695 GcpRecord *localGcpRecord = gcpRecord;
6696 GcpRecordPtr localGcpPtr;
6697 UintR TgcpFilesize = cgcpFilesize;
6698 localGcpPtr.i = apiConnectptr.p->gcpPointer;
6699 ptrCheckGuard(localGcpPtr, TgcpFilesize, localGcpRecord);
6700 unlinkApiConnect(localGcpPtr, regApiPtr);
6701 if (localGcpPtr.p->firstApiConnect == RNIL) {
6702 if (localGcpPtr.p->gcpNomoretransRec == ZTRUE) {
6703 if (c_ongoing_take_over_cnt == 0)
6704 {
6705 jam();
6706 gcpTcfinished(signal, localGcpPtr.p->gcpId);
6707 unlinkGcp(localGcpPtr);
6708 }
6709 }//if
6710 }
6711 }//Dbtc::handleGcp()
6712
releaseApiConCopy(Signal * signal)6713 void Dbtc::releaseApiConCopy(Signal* signal)
6714 {
6715 ApiConnectRecord * const regApiPtr = apiConnectptr.p;
6716 ndbassert(regApiPtr->nextApiConnect == RNIL);
6717 UintR TfirstfreeApiConnectCopyOld = cfirstfreeApiConnectCopy;
6718 cfirstfreeApiConnectCopy = apiConnectptr.i;
6719 regApiPtr->nextApiConnect = TfirstfreeApiConnectCopyOld;
6720 setApiConTimer(apiConnectptr.i, 0, __LINE__);
6721 regApiPtr->apiConnectstate = CS_RESTART;
6722 ndbrequire(regApiPtr->commitAckMarker == RNIL);
6723 }//Dbtc::releaseApiConCopy()
6724
6725 /* ========================================================================= */
6726 /* ------- RELEASE ALL RECORDS CONNECTED TO A DIRTY WRITE OPERATION ------- */
6727 /* ========================================================================= */
releaseDirtyWrite(Signal * signal)6728 void Dbtc::releaseDirtyWrite(Signal* signal)
6729 {
6730 clearCommitAckMarker(apiConnectptr.p, tcConnectptr.p);
6731 unlinkReadyTcCon(signal);
6732 releaseTcCon();
6733 ApiConnectRecord * const regApiPtr = apiConnectptr.p;
6734 if (regApiPtr->apiConnectstate == CS_START_COMMITTING) {
6735 if (regApiPtr->firstTcConnect == RNIL) {
6736 jam();
6737 regApiPtr->apiConnectstate = CS_CONNECTED;
6738 setApiConTimer(apiConnectptr.i, 0, __LINE__);
6739 sendtckeyconf(signal, 1);
6740 }//if
6741 }//if
6742 }//Dbtc::releaseDirtyWrite()
6743
6744 /*****************************************************************************
6745 * L Q H K E Y R E F
6746 * WHEN LQHKEYREF IS RECEIVED DBTC WILL CHECK IF COMMIT FLAG WAS SENT FROM THE
6747 * APPLICATION. IF SO, THE WHOLE TRANSACTION WILL BE ROLLED BACK AND SIGNAL
6748 * TCROLLBACKREP WILL BE SENT TO THE API.
6749 *
6750 * OTHERWISE TC WILL CHECK THE ERRORCODE. IF THE ERRORCODE IS INDICATING THAT
6751 * THE "ROW IS NOT FOUND" FOR UPDATE/READ/DELETE OPERATIONS AND "ROW ALREADY
6752 * EXISTS" FOR INSERT OPERATIONS, DBTC WILL RELEASE THE OPERATION AND THEN
6753 * SEND RETURN SIGNAL TCKEYREF TO THE USER. THE USER THEN HAVE TO SEND
6754 * SIGNAL TC_COMMITREQ OR TC_ROLLBACKREQ TO CONCLUDE THE TRANSACTION.
6755 * IF ANY TCKEYREQ WITH COMMIT IS RECEIVED AND API_CONNECTSTATE EQUALS
6756 * "REC_LQHREFUSE",
6757 * THE OPERATION WILL BE TREATED AS AN OPERATION WITHOUT COMMIT. WHEN ANY
6758 * OTHER FAULTCODE IS RECEIVED THE WHOLE TRANSACTION MUST BE ROLLED BACK
6759 *****************************************************************************/
execLQHKEYREF(Signal * signal)6760 void Dbtc::execLQHKEYREF(Signal* signal)
6761 {
6762 const LqhKeyRef * const lqhKeyRef = (LqhKeyRef *)signal->getDataPtr();
6763 Uint32 indexId = 0;
6764 jamEntry();
6765
6766 UintR compare_transid1, compare_transid2;
6767 UintR TtcConnectFilesize = ctcConnectFilesize;
6768 /*-------------------------------------------------------------------------
6769 *
6770 * RELEASE NODE BUFFER(S) TO INDICATE THAT THIS OPERATION HAVE NO
6771 * TRANSACTION PARTS ACTIVE ANYMORE.
6772 * LQHKEYREF HAVE CLEARED ALL PARTS ON ITS PATH BACK TO TC.
6773 *-------------------------------------------------------------------------*/
6774 if (lqhKeyRef->connectPtr < TtcConnectFilesize) {
6775 /*-----------------------------------------------------------------------
6776 * WE HAVE TO CHECK THAT THE TRANSACTION IS STILL VALID. FIRST WE CHECK
6777 * THAT THE LQH IS STILL CONNECTED TO A TC, IF THIS HOLDS TRUE THEN THE
6778 * TC MUST BE CONNECTED TO AN API CONNECT RECORD.
6779 * WE MUST ENSURE THAT THE TRANSACTION ID OF THIS API CONNECT
6780 * RECORD IS STILL THE SAME AS THE ONE LQHKEYREF REFERS TO.
6781 * IF NOT SIMPLY EXIT AND FORGET THE SIGNAL SINCE THE TRANSACTION IS
6782 * ALREADY COMPLETED (ABORTED).
6783 *-----------------------------------------------------------------------*/
6784 tcConnectptr.i = lqhKeyRef->connectPtr;
6785 Uint32 errCode = terrorCode = lqhKeyRef->errorCode;
6786 ptrAss(tcConnectptr, tcConnectRecord);
6787 TcConnectRecord * const regTcPtr = tcConnectptr.p;
6788 if (regTcPtr->tcConnectstate == OS_OPERATING) {
6789 Uint32 save = apiConnectptr.i = regTcPtr->apiConnect;
6790 ptrCheckGuard(apiConnectptr, capiConnectFilesize, apiConnectRecord);
6791 ApiConnectRecord * const regApiPtr = apiConnectptr.p;
6792 compare_transid1 = regApiPtr->transid[0] ^ lqhKeyRef->transId1;
6793 compare_transid2 = regApiPtr->transid[1] ^ lqhKeyRef->transId2;
6794 compare_transid1 = compare_transid1 | compare_transid2;
6795 if (compare_transid1 != 0) {
6796 warningReport(signal, 25);
6797 return;
6798 }//if
6799
6800 const Uint32 triggeringOp = regTcPtr->triggeringOperation;
6801 ConnectionState TapiConnectstate = regApiPtr->apiConnectstate;
6802
6803 if (unlikely(TapiConnectstate == CS_ABORTING))
6804 {
6805 jam();
6806 goto do_abort;
6807 }
6808
6809 if (triggeringOp != RNIL) {
6810 jam();
6811 // This operation was created by a trigger execting operation
6812 TcConnectRecordPtr opPtr;
6813 TcConnectRecord *localTcConnectRecord = tcConnectRecord;
6814
6815 opPtr.i = triggeringOp;
6816 ptrCheckGuard(opPtr, ctcConnectFilesize, localTcConnectRecord);
6817
6818 const Uint32 opType = regTcPtr->operation;
6819 Ptr<TcDefinedTriggerData> trigPtr;
6820 c_theDefinedTriggers.getPtr(trigPtr, regTcPtr->currentTriggerId);
6821 switch(trigPtr.p->triggerType){
6822 case TriggerType::SECONDARY_INDEX:{
6823 jam();
6824
6825 // The operation executed an index trigger
6826 TcIndexData* indexData = c_theIndexes.getPtr(trigPtr.p->indexId);
6827 indexId = indexData->indexId;
6828 regApiPtr->errorData = indexId;
6829 if (errCode == ZALREADYEXIST)
6830 {
6831 jam();
6832 errCode = terrorCode = ZNOTUNIQUE;
6833 goto do_abort;
6834 }
6835 else if (!(opType == ZDELETE && errCode == ZNOT_FOUND)) {
6836 jam();
6837 /**
6838 * "Normal path"
6839 */
6840 goto do_abort;
6841 }
6842 else
6843 {
6844 jam();
6845 /** ZDELETE && NOT_FOUND */
6846 if (indexData->indexState != IS_BUILDING)
6847 {
6848 jam();
6849 goto do_abort;
6850 }
6851 }
6852 goto do_ignore;
6853 }
6854 case TriggerType::REORG_TRIGGER:
6855 jam();
6856 if (opType == ZINSERT && errCode == ZALREADYEXIST)
6857 {
6858 jam();
6859 ndbout_c("reorg, ignore ZALREADYEXIST");
6860 goto do_ignore;
6861 }
6862 else if (errCode == ZNOT_FOUND)
6863 {
6864 jam();
6865 ndbout_c("reorg, ignore ZNOT_FOUND");
6866 goto do_ignore;
6867 }
6868 else if (errCode == 839)
6869 {
6870 jam();
6871 ndbout_c("reorg, ignore 839");
6872 goto do_ignore;
6873 }
6874 else
6875 {
6876 ndbout_c("reorg: opType: %u errCode: %u", opType, errCode);
6877 }
6878 // fall-through
6879 goto do_abort;
6880 case TriggerType::FK_CHILD:
6881 jam();
6882 if (errCode == ZNOT_FOUND)
6883 {
6884 errCode = terrorCode = ZFK_NO_PARENT_ROW_EXISTS;
6885 }
6886 goto do_abort;
6887 case TriggerType::FK_PARENT:
6888 jam();
6889 /**
6890 * on delete/update of parent...
6891 * we found no child row...
6892 * that means FK not violated...
6893 */
6894 if (errCode == ZNOT_FOUND)
6895 {
6896 jam();
6897 if (regTcPtr->isIndexOp(regTcPtr->m_special_op_flags))
6898 {
6899 jam();
6900 /**
6901 * execTCINDXREQ adds an extra regApiPtr->lqhkeyreqrec++
6902 * undo this...
6903 */
6904 ndbassert(regApiPtr->lqhkeyreqrec > 0);
6905 regApiPtr->lqhkeyreqrec--;
6906 }
6907 goto do_ignore;
6908 }
6909 else
6910 {
6911 goto do_abort;
6912 }
6913 default:
6914 jam();
6915 ndbassert(false);
6916 goto do_abort;
6917 }
6918
6919 do_ignore:
6920 jam();
6921 /**
6922 * Ignore error
6923 */
6924 regApiPtr->lqhkeyreqrec--;
6925
6926 /**
6927 * An failing op in LQH, never leaves the commit ack marker around
6928 * TODO: This can be bug in ordinary code too!!!
6929 */
6930 clearCommitAckMarker(regApiPtr, regTcPtr);
6931
6932 unlinkReadyTcCon(signal);
6933 releaseTcCon();
6934
6935 trigger_op_finished(signal, apiConnectptr, RNIL, opPtr.p, 0);
6936
6937 if (ERROR_INSERTED(8105))
6938 {
6939 abortTransFromTrigger(signal, apiConnectptr, ZGET_DATAREC_ERROR);
6940 }
6941 return;
6942 }
6943
6944 do_abort:
6945 markOperationAborted(regApiPtr, regTcPtr);
6946
6947 if(regApiPtr->apiConnectstate == CS_ABORTING){
6948 /**
6949 * We're already aborting' so don't send an "extra" TCKEYREF
6950 */
6951 jam();
6952 return;
6953 }
6954
6955 const Uint32 abort = regTcPtr->m_execAbortOption;
6956 if (abort == TcKeyReq::AbortOnError || triggeringOp != RNIL) {
6957 /**
6958 * No error is allowed on this operation
6959 */
6960 TCKEY_abort(signal, 49);
6961 return;
6962 }//if
6963
6964 /* *************** */
6965 /* TCKEYREF < */
6966 /* *************** */
6967 TcKeyRef * const tcKeyRef = (TcKeyRef *) signal->getDataPtrSend();
6968 tcKeyRef->transId[0] = regApiPtr->transid[0];
6969 tcKeyRef->transId[1] = regApiPtr->transid[1];
6970 tcKeyRef->errorCode = terrorCode;
6971 bool isIndexOp = regTcPtr->isIndexOp(regTcPtr->m_special_op_flags);
6972 Uint32 indexOp = tcConnectptr.p->indexOp;
6973 Uint32 clientData = regTcPtr->clientData;
6974 unlinkReadyTcCon(signal); /* LINK TC CONNECT RECORD OUT OF */
6975 releaseTcCon(); /* RELEASE THE TC CONNECT RECORD */
6976 setApiConTimer(apiConnectptr.i, ctcTimer, __LINE__);
6977 if (isIndexOp) {
6978 jam();
6979 regApiPtr->lqhkeyreqrec--; // Compensate for extra during read
6980 tcKeyRef->connectPtr = indexOp;
6981 tcKeyRef->errorData = indexId;
6982 EXECUTE_DIRECT(DBTC, GSN_TCKEYREF, signal, TcKeyRef::SignalLength);
6983 apiConnectptr.i = save;
6984 apiConnectptr.p = regApiPtr;
6985 } else {
6986 jam();
6987 tcKeyRef->connectPtr = clientData;
6988 tcKeyRef->errorData = indexId;
6989 sendSignal(regApiPtr->ndbapiBlockref,
6990 GSN_TCKEYREF, signal, TcKeyRef::SignalLength, JBB);
6991 }//if
6992
6993 /*---------------------------------------------------------------------
6994 * SINCE WE ARE NOT ABORTING WE NEED TO UPDATE THE COUNT OF HOW MANY
6995 * LQHKEYREQ THAT HAVE RETURNED.
6996 * IF NO MORE OUTSTANDING LQHKEYREQ'S THEN WE NEED TO
6997 * TCKEYCONF (IF THERE IS ANYTHING TO SEND).
6998 *---------------------------------------------------------------------*/
6999 regApiPtr->lqhkeyreqrec--;
7000 if (regApiPtr->lqhkeyconfrec == regApiPtr->lqhkeyreqrec) {
7001 if (regApiPtr->apiConnectstate == CS_START_COMMITTING) {
7002 jam();
7003 diverify010Lab(signal);
7004 return;
7005 }
7006 else if (regApiPtr->tckeyrec > 0 ||
7007 tc_testbit(regApiPtr->m_flags, ApiConnectRecord::TF_EXEC_FLAG))
7008 {
7009 jam();
7010 sendtckeyconf(signal, 2);
7011 return;
7012 }
7013 }//if
7014 return;
7015
7016 } else {
7017 warningReport(signal, 26);
7018 }//if
7019 } else {
7020 errorReport(signal, 6);
7021 }//if
7022 return;
7023 }//Dbtc::execLQHKEYREF()
7024
clearCommitAckMarker(ApiConnectRecord * const regApiPtr,TcConnectRecord * const regTcPtr)7025 void Dbtc::clearCommitAckMarker(ApiConnectRecord * const regApiPtr,
7026 TcConnectRecord * const regTcPtr)
7027 {
7028 jam();
7029 const Uint32 commitAckMarker = regTcPtr->commitAckMarker;
7030 if (regApiPtr->commitAckMarker == RNIL)
7031 {
7032 jam();
7033 ndbassert(commitAckMarker == RNIL);
7034 }
7035
7036 if(commitAckMarker != RNIL)
7037 {
7038 jam();
7039 ndbrequire(regApiPtr->commitAckMarker == commitAckMarker);
7040 ndbrequire(regApiPtr->num_commit_ack_markers > 0);
7041 regApiPtr->num_commit_ack_markers--;
7042 regTcPtr->commitAckMarker = RNIL;
7043 if (regApiPtr->num_commit_ack_markers == 0)
7044 {
7045 jam();
7046 tc_clearbit(regApiPtr->m_flags,
7047 ApiConnectRecord::TF_COMMIT_ACK_MARKER_RECEIVED);
7048 releaseMarker(regApiPtr);
7049 }
7050 }
7051 }
7052
markOperationAborted(ApiConnectRecord * const regApiPtr,TcConnectRecord * const regTcPtr)7053 void Dbtc::markOperationAborted(ApiConnectRecord * const regApiPtr,
7054 TcConnectRecord * const regTcPtr)
7055 {
7056 /*------------------------------------------------------------------------
7057 * RELEASE NODES TO INDICATE THAT THE OPERATION IS ALREADY ABORTED IN THE
7058 * LQH'S ALSO SET STATE TO ABORTING TO INDICATE THE ABORT IS
7059 * ALREADY COMPLETED.
7060 *------------------------------------------------------------------------*/
7061 regTcPtr->noOfNodes = 0; // == releaseNodes(signal)
7062 regTcPtr->tcConnectstate = OS_ABORTING;
7063 clearCommitAckMarker(regApiPtr, regTcPtr);
7064 }
7065
7066 /*--------------------------------------*/
7067 /* EXIT AND WAIT FOR SIGNAL TCOMMITREQ */
7068 /* OR TCROLLBACKREQ FROM THE USER TO */
7069 /* CONTINUE THE TRANSACTION */
7070 /*--------------------------------------*/
execTC_COMMITREQ(Signal * signal)7071 void Dbtc::execTC_COMMITREQ(Signal* signal)
7072 {
7073 UintR compare_transid1, compare_transid2;
7074
7075 jamEntry();
7076 apiConnectptr.i = signal->theData[0];
7077 if (apiConnectptr.i < capiConnectFilesize) {
7078 ptrAss(apiConnectptr, apiConnectRecord);
7079 compare_transid1 = apiConnectptr.p->transid[0] ^ signal->theData[1];
7080 compare_transid2 = apiConnectptr.p->transid[1] ^ signal->theData[2];
7081 compare_transid1 = compare_transid1 | compare_transid2;
7082 if (compare_transid1 != 0) {
7083 jam();
7084 return;
7085 }//if
7086
7087 ApiConnectRecord * const regApiPtr = apiConnectptr.p;
7088
7089 const Uint32 apiConnectPtr = regApiPtr->ndbapiConnect;
7090 const Uint32 apiBlockRef = regApiPtr->ndbapiBlockref;
7091 const Uint32 transId1 = regApiPtr->transid[0];
7092 const Uint32 transId2 = regApiPtr->transid[1];
7093 Uint32 errorCode = 0;
7094
7095 regApiPtr->m_flags |= ApiConnectRecord::TF_EXEC_FLAG;
7096 switch (regApiPtr->apiConnectstate) {
7097 case CS_STARTED:
7098 tcConnectptr.i = regApiPtr->firstTcConnect;
7099 if (tcConnectptr.i != RNIL) {
7100 ptrCheckGuard(tcConnectptr, ctcConnectFilesize, tcConnectRecord);
7101 if (regApiPtr->lqhkeyconfrec == regApiPtr->lqhkeyreqrec) {
7102 jam();
7103 /*******************************************************************/
7104 // The proper case where the application is waiting for commit or
7105 // abort order.
7106 // Start the commit order.
7107 /*******************************************************************/
7108 regApiPtr->returnsignal = RS_TC_COMMITCONF;
7109 setApiConTimer(apiConnectptr.i, ctcTimer, __LINE__);
7110 diverify010Lab(signal);
7111 return;
7112 } else {
7113 jam();
7114 /*******************************************************************/
7115 // The transaction is started but not all operations are completed.
7116 // It is not possible to commit the transaction in this state.
7117 // We will abort it instead.
7118 /*******************************************************************/
7119 regApiPtr->returnsignal = RS_NO_RETURN;
7120 errorCode = ZTRANS_STATUS_ERROR;
7121 abort010Lab(signal);
7122 }//if
7123 } else {
7124 jam();
7125 /**
7126 * No operations, accept commit
7127 */
7128 TcCommitConf * const commitConf = (TcCommitConf *)&signal->theData[0];
7129 commitConf->apiConnectPtr = apiConnectPtr;
7130 commitConf->transId1 = transId1;
7131 commitConf->transId2 = transId2;
7132 commitConf->gci_hi = 0;
7133 commitConf->gci_lo = 0;
7134 sendSignal(apiBlockRef, GSN_TC_COMMITCONF, signal,
7135 TcCommitConf::SignalLength, JBB);
7136
7137 regApiPtr->returnsignal = RS_NO_RETURN;
7138 releaseAbortResources(signal);
7139 return;
7140 }//if
7141 break;
7142 case CS_RECEIVING:
7143 jam();
7144 /***********************************************************************/
7145 // A transaction is still receiving data. We cannot commit an unfinished
7146 // transaction. We will abort it instead.
7147 /***********************************************************************/
7148 regApiPtr->returnsignal = RS_NO_RETURN;
7149 errorCode = ZPREPAREINPROGRESS;
7150 abort010Lab(signal);
7151 break;
7152
7153 case CS_START_COMMITTING:
7154 case CS_COMMITTING:
7155 case CS_COMMIT_SENT:
7156 case CS_COMPLETING:
7157 case CS_COMPLETE_SENT:
7158 case CS_REC_COMMITTING:
7159 case CS_PREPARE_TO_COMMIT:
7160 jam();
7161 /***********************************************************************/
7162 // The transaction is already performing a commit but it is not concluded
7163 // yet.
7164 /***********************************************************************/
7165 errorCode = ZCOMMITINPROGRESS;
7166 break;
7167 case CS_ABORTING:
7168 jam();
7169 errorCode = regApiPtr->returncode ?
7170 regApiPtr->returncode : ZABORTINPROGRESS;
7171 break;
7172 case CS_START_SCAN:
7173 jam();
7174 /***********************************************************************/
7175 // The transaction is a scan. Scans cannot commit
7176 /***********************************************************************/
7177 errorCode = ZSCANINPROGRESS;
7178 break;
7179 default:
7180 warningHandlerLab(signal, __LINE__);
7181 return;
7182 }//switch
7183 TcCommitRef * const commitRef = (TcCommitRef*)&signal->theData[0];
7184 commitRef->apiConnectPtr = apiConnectPtr;
7185 commitRef->transId1 = transId1;
7186 commitRef->transId2 = transId2;
7187 commitRef->errorCode = errorCode;
7188 sendSignal(apiBlockRef, GSN_TC_COMMITREF, signal,
7189 TcCommitRef::SignalLength, JBB);
7190 return;
7191 } else /** apiConnectptr.i < capiConnectFilesize */ {
7192 jam();
7193 warningHandlerLab(signal, __LINE__);
7194 return;
7195 }
7196 }//Dbtc::execTC_COMMITREQ()
7197
7198 /**
7199 * TCROLLBACKREQ
7200 *
7201 * Format is:
7202 *
7203 * thedata[0] = apiconnectptr
7204 * thedata[1] = transid[0]
7205 * thedata[2] = transid[1]
7206 * OPTIONAL thedata[3] = flags
7207 *
7208 * Flags:
7209 * 0x1 = potentiallyBad data from API (try not to assert)
7210 */
execTCROLLBACKREQ(Signal * signal)7211 void Dbtc::execTCROLLBACKREQ(Signal* signal)
7212 {
7213 bool potentiallyBad= false;
7214 UintR compare_transid1, compare_transid2;
7215
7216 jamEntry();
7217
7218 if(unlikely((signal->getLength() >= 4) && (signal->theData[3] & 0x1)))
7219 {
7220 ndbout_c("Trying to roll back potentially bad txn\n");
7221 potentiallyBad= true;
7222 }
7223
7224 apiConnectptr.i = signal->theData[0];
7225 if (apiConnectptr.i >= capiConnectFilesize) {
7226 goto TC_ROLL_warning;
7227 }//if
7228 ptrAss(apiConnectptr, apiConnectRecord);
7229 compare_transid1 = apiConnectptr.p->transid[0] ^ signal->theData[1];
7230 compare_transid2 = apiConnectptr.p->transid[1] ^ signal->theData[2];
7231 compare_transid1 = compare_transid1 | compare_transid2;
7232 if (compare_transid1 != 0) {
7233 jam();
7234 return;
7235 }//if
7236
7237 apiConnectptr.p->m_flags |= ApiConnectRecord::TF_EXEC_FLAG;
7238 switch (apiConnectptr.p->apiConnectstate) {
7239 case CS_STARTED:
7240 case CS_RECEIVING:
7241 jam();
7242 apiConnectptr.p->returnsignal = RS_TCROLLBACKCONF;
7243 abort010Lab(signal);
7244 return;
7245 case CS_CONNECTED:
7246 jam();
7247 signal->theData[0] = apiConnectptr.p->ndbapiConnect;
7248 signal->theData[1] = apiConnectptr.p->transid[0];
7249 signal->theData[2] = apiConnectptr.p->transid[1];
7250 sendSignal(apiConnectptr.p->ndbapiBlockref, GSN_TCROLLBACKCONF,
7251 signal, 3, JBB);
7252 break;
7253 case CS_START_SCAN:
7254 case CS_PREPARE_TO_COMMIT:
7255 case CS_COMMITTING:
7256 case CS_COMMIT_SENT:
7257 case CS_COMPLETING:
7258 case CS_COMPLETE_SENT:
7259 case CS_WAIT_COMMIT_CONF:
7260 case CS_WAIT_COMPLETE_CONF:
7261 case CS_RESTART:
7262 case CS_DISCONNECTED:
7263 case CS_START_COMMITTING:
7264 case CS_REC_COMMITTING:
7265 jam();
7266 /* ***************< */
7267 /* TC_ROLLBACKREF < */
7268 /* ***************< */
7269 signal->theData[0] = apiConnectptr.p->ndbapiConnect;
7270 signal->theData[1] = apiConnectptr.p->transid[0];
7271 signal->theData[2] = apiConnectptr.p->transid[1];
7272 signal->theData[3] = ZROLLBACKNOTALLOWED;
7273 signal->theData[4] = apiConnectptr.p->apiConnectstate;
7274 sendSignal(apiConnectptr.p->ndbapiBlockref, GSN_TCROLLBACKREF,
7275 signal, 5, JBB);
7276 break;
7277 /* SEND A REFUSAL SIGNAL*/
7278 case CS_ABORTING:
7279 jam();
7280 if (apiConnectptr.p->abortState == AS_IDLE) {
7281 jam();
7282 signal->theData[0] = apiConnectptr.p->ndbapiConnect;
7283 signal->theData[1] = apiConnectptr.p->transid[0];
7284 signal->theData[2] = apiConnectptr.p->transid[1];
7285 sendSignal(apiConnectptr.p->ndbapiBlockref, GSN_TCROLLBACKCONF,
7286 signal, 3, JBB);
7287 } else {
7288 jam();
7289 apiConnectptr.p->returnsignal = RS_TCROLLBACKCONF;
7290 }//if
7291 break;
7292 case CS_WAIT_ABORT_CONF:
7293 jam();
7294 apiConnectptr.p->returnsignal = RS_TCROLLBACKCONF;
7295 break;
7296 default:
7297 goto TC_ROLL_system_error;
7298 break;
7299 }//switch
7300 return;
7301
7302 TC_ROLL_warning:
7303 jam();
7304 if(likely(potentiallyBad==false))
7305 warningHandlerLab(signal, __LINE__);
7306 return;
7307
7308 TC_ROLL_system_error:
7309 jam();
7310 if(likely(potentiallyBad==false))
7311 systemErrorLab(signal, __LINE__);
7312 return;
7313 }//Dbtc::execTCROLLBACKREQ()
7314
execTC_HBREP(Signal * signal)7315 void Dbtc::execTC_HBREP(Signal* signal)
7316 {
7317 const TcHbRep * const tcHbRep =
7318 (TcHbRep *)signal->getDataPtr();
7319
7320 jamEntry();
7321 apiConnectptr.i = tcHbRep->apiConnectPtr;
7322 ptrCheckGuard(apiConnectptr, capiConnectFilesize, apiConnectRecord);
7323
7324 if (apiConnectptr.p->transid[0] == tcHbRep->transId1 &&
7325 apiConnectptr.p->transid[1] == tcHbRep->transId2){
7326
7327 if (getApiConTimer(apiConnectptr.i) != 0){
7328 setApiConTimer(apiConnectptr.i, ctcTimer, __LINE__);
7329 } else {
7330 DEBUG("TCHBREP received when timer was off apiConnectptr.i="
7331 << apiConnectptr.i);
7332 }
7333 }
7334 }//Dbtc::execTCHBREP()
7335
7336 /*
7337 4.3.15 ABORT
7338 -----------
7339 */
7340 /*****************************************************************************/
7341 /* A B O R T */
7342 /* */
7343 /*****************************************************************************/
warningReport(Signal * signal,int place)7344 void Dbtc::warningReport(Signal* signal, int place)
7345 {
7346 switch (place) {
7347 case 0:
7348 jam();
7349 #ifdef ABORT_TRACE
7350 ndbout << "ABORTED to not active TC record" << endl;
7351 #endif
7352 break;
7353 case 1:
7354 jam();
7355 #ifdef ABORT_TRACE
7356 ndbout << "ABORTED to TC record active with new transaction" << endl;
7357 #endif
7358 break;
7359 case 2:
7360 jam();
7361 #ifdef ABORT_TRACE
7362 ndbout << "ABORTED to active TC record not expecting ABORTED" << endl;
7363 #endif
7364 break;
7365 case 3:
7366 jam();
7367 #ifdef ABORT_TRACE
7368 ndbout << "ABORTED to TC rec active with trans but wrong node" << endl;
7369 ndbout << "This is ok when aborting in node failure situations" << endl;
7370 #endif
7371 break;
7372 case 4:
7373 jam();
7374 #ifdef ABORT_TRACE
7375 ndbout << "Received COMMITTED in wrong state in Dbtc" << endl;
7376 #endif
7377 break;
7378 case 5:
7379 jam();
7380 #ifdef ABORT_TRACE
7381 ndbout << "Received COMMITTED with wrong transid in Dbtc" << endl;
7382 #endif
7383 break;
7384 case 6:
7385 jam();
7386 #ifdef ABORT_TRACE
7387 ndbout << "Received COMPLETED in wrong state in Dbtc" << endl;
7388 #endif
7389 break;
7390 case 7:
7391 jam();
7392 #ifdef ABORT_TRACE
7393 ndbout << "Received COMPLETED with wrong transid in Dbtc" << endl;
7394 #endif
7395 break;
7396 case 8:
7397 jam();
7398 #ifdef ABORT_TRACE
7399 ndbout << "Received COMMITCONF with tc-rec in wrong state in Dbtc" << endl;
7400 #endif
7401 break;
7402 case 9:
7403 jam();
7404 #ifdef ABORT_TRACE
7405 ndbout << "Received COMMITCONF with api-rec in wrong state in Dbtc" <<endl;
7406 #endif
7407 break;
7408 case 10:
7409 jam();
7410 #ifdef ABORT_TRACE
7411 ndbout << "Received COMMITCONF with wrong transid in Dbtc" << endl;
7412 #endif
7413 break;
7414 case 11:
7415 jam();
7416 #ifdef ABORT_TRACE
7417 ndbout << "Received COMMITCONF from wrong nodeid in Dbtc" << endl;
7418 #endif
7419 break;
7420 case 12:
7421 jam();
7422 #ifdef ABORT_TRACE
7423 ndbout << "Received COMPLETECONF, tc-rec in wrong state in Dbtc" << endl;
7424 #endif
7425 break;
7426 case 13:
7427 jam();
7428 #ifdef ABORT_TRACE
7429 ndbout << "Received COMPLETECONF, api-rec in wrong state in Dbtc" << endl;
7430 #endif
7431 break;
7432 case 14:
7433 jam();
7434 #ifdef ABORT_TRACE
7435 ndbout << "Received COMPLETECONF with wrong transid in Dbtc" << endl;
7436 #endif
7437 break;
7438 case 15:
7439 jam();
7440 #ifdef ABORT_TRACE
7441 ndbout << "Received COMPLETECONF from wrong nodeid in Dbtc" << endl;
7442 #endif
7443 break;
7444 case 16:
7445 jam();
7446 #ifdef ABORT_TRACE
7447 ndbout << "Received ABORTCONF, tc-rec in wrong state in Dbtc" << endl;
7448 #endif
7449 break;
7450 case 17:
7451 jam();
7452 #ifdef ABORT_TRACE
7453 ndbout << "Received ABORTCONF, api-rec in wrong state in Dbtc" << endl;
7454 #endif
7455 break;
7456 case 18:
7457 jam();
7458 #ifdef ABORT_TRACE
7459 ndbout << "Received ABORTCONF with wrong transid in Dbtc" << endl;
7460 #endif
7461 break;
7462 case 19:
7463 jam();
7464 #ifdef ABORT_TRACE
7465 ndbout << "Received ABORTCONF from wrong nodeid in Dbtc" << endl;
7466 #endif
7467 break;
7468 case 20:
7469 jam();
7470 #ifdef ABORT_TRACE
7471 ndbout << "Time-out waiting for ABORTCONF in Dbtc" << endl;
7472 #endif
7473 break;
7474 case 21:
7475 jam();
7476 #ifdef ABORT_TRACE
7477 ndbout << "Time-out waiting for COMMITCONF in Dbtc" << endl;
7478 #endif
7479 break;
7480 case 22:
7481 jam();
7482 #ifdef ABORT_TRACE
7483 ndbout << "Time-out waiting for COMPLETECONF in Dbtc" << endl;
7484 #endif
7485 break;
7486 case 23:
7487 jam();
7488 #ifdef ABORT_TRACE
7489 ndbout << "Received LQHKEYCONF in wrong tc-state in Dbtc" << endl;
7490 #endif
7491 break;
7492 case 24:
7493 jam();
7494 #ifdef ABORT_TRACE
7495 ndbout << "Received LQHKEYREF to wrong transid in Dbtc" << endl;
7496 #endif
7497 break;
7498 case 25:
7499 jam();
7500 #ifdef ABORT_TRACE
7501 ndbout << "Received LQHKEYREF in wrong state in Dbtc" << endl;
7502 #endif
7503 break;
7504 case 26:
7505 jam();
7506 #ifdef ABORT_TRACE
7507 ndbout << "Received LQHKEYCONF to wrong transid in Dbtc" << endl;
7508 #endif
7509 break;
7510 case 27:
7511 jam();
7512 // printState(signal, 27);
7513 #ifdef ABORT_TRACE
7514 ndbout << "Received LQHKEYCONF in wrong api-state in Dbtc" << endl;
7515 #endif
7516 break;
7517 case 28:
7518 jam();
7519 #ifdef ABORT_TRACE
7520 ndbout << "Discarding FIRE_TRIG_REF/CONF in Dbtc" << endl;
7521 #endif
7522 break;
7523 case 29:
7524 jam();
7525 #ifdef ABORT_TRACE
7526 ndbout << "Discarding TcContinueB::ZSEND_FIRE_TRIG_REQ in Dbtc" << endl;
7527 #endif
7528 break;
7529 default:
7530 jam();
7531 break;
7532 }//switch
7533 return;
7534 }//Dbtc::warningReport()
7535
errorReport(Signal * signal,int place)7536 void Dbtc::errorReport(Signal* signal, int place)
7537 {
7538 switch (place) {
7539 case 0:
7540 jam();
7541 break;
7542 case 1:
7543 jam();
7544 break;
7545 case 2:
7546 jam();
7547 break;
7548 case 3:
7549 jam();
7550 break;
7551 case 4:
7552 jam();
7553 break;
7554 case 5:
7555 jam();
7556 break;
7557 case 6:
7558 jam();
7559 break;
7560 default:
7561 jam();
7562 break;
7563 }//switch
7564 systemErrorLab(signal, __LINE__);
7565 return;
7566 }//Dbtc::errorReport()
7567
7568 /* ------------------------------------------------------------------------- */
7569 /* ------- ENTER ABORTED ------- */
7570 /* */
7571 /*-------------------------------------------------------------------------- */
execABORTED(Signal * signal)7572 void Dbtc::execABORTED(Signal* signal)
7573 {
7574 UintR compare_transid1, compare_transid2;
7575
7576 jamEntry();
7577 tcConnectptr.i = signal->theData[0];
7578 UintR Tnodeid = signal->theData[3];
7579 UintR TlastLqhInd = signal->theData[4];
7580
7581 if (ERROR_INSERTED(8040)) {
7582 CLEAR_ERROR_INSERT_VALUE;
7583 sendSignalWithDelay(cownref, GSN_ABORTED, signal, 2000, 5);
7584 return;
7585 }//if
7586 /*------------------------------------------------------------------------
7587 * ONE PARTICIPANT IN THE TRANSACTION HAS REPORTED THAT IT IS ABORTED.
7588 *------------------------------------------------------------------------*/
7589 if (tcConnectptr.i >= ctcConnectFilesize) {
7590 errorReport(signal, 0);
7591 return;
7592 }//if
7593 /*-------------------------------------------------------------------------
7594 * WE HAVE TO CHECK THAT THIS IS NOT AN OLD SIGNAL BELONGING TO A
7595 * TRANSACTION ALREADY ABORTED. THIS CAN HAPPEN WHEN TIME-OUT OCCURS
7596 * IN TC WAITING FOR ABORTED.
7597 *-------------------------------------------------------------------------*/
7598 ptrAss(tcConnectptr, tcConnectRecord);
7599 if (tcConnectptr.p->tcConnectstate != OS_ABORT_SENT) {
7600 warningReport(signal, 2);
7601 return;
7602 /*-----------------------------------------------------------------------*/
7603 // ABORTED reported on an operation not expecting ABORT.
7604 /*-----------------------------------------------------------------------*/
7605 }//if
7606 apiConnectptr.i = tcConnectptr.p->apiConnect;
7607 if (apiConnectptr.i >= capiConnectFilesize) {
7608 warningReport(signal, 0);
7609 return;
7610 }//if
7611 ptrAss(apiConnectptr, apiConnectRecord);
7612 compare_transid1 = apiConnectptr.p->transid[0] ^ signal->theData[1];
7613 compare_transid2 = apiConnectptr.p->transid[1] ^ signal->theData[2];
7614 compare_transid1 = compare_transid1 | compare_transid2;
7615 if (compare_transid1 != 0) {
7616 warningReport(signal, 1);
7617 return;
7618 }//if
7619 if (ERROR_INSERTED(8024)) {
7620 jam();
7621 systemErrorLab(signal, __LINE__);
7622 }//if
7623
7624 /**
7625 * Release marker
7626 */
7627 clearCommitAckMarker(apiConnectptr.p, tcConnectptr.p);
7628
7629 Uint32 i;
7630 Uint32 Tfound = 0;
7631 for (i = 0; i < tcConnectptr.p->noOfNodes; i++) {
7632 jam();
7633 if (tcConnectptr.p->tcNodedata[i] == Tnodeid) {
7634 /*---------------------------------------------------------------------
7635 * We have received ABORTED from one of the participants in this
7636 * operation in this aborted transaction.
7637 * Record all nodes that have completed abort.
7638 * If last indicator is set it means that no more replica has
7639 * heard of the operation and are thus also aborted.
7640 *---------------------------------------------------------------------*/
7641 jam();
7642 Tfound = 1;
7643 clearTcNodeData(signal, TlastLqhInd, i);
7644 }//if
7645 }//for
7646 if (Tfound == 0) {
7647 warningReport(signal, 3);
7648 return;
7649 }
7650 for (i = 0; i < tcConnectptr.p->noOfNodes; i++) {
7651 if (tcConnectptr.p->tcNodedata[i] != 0) {
7652 /*--------------------------------------------------------------------
7653 * There are still outstanding ABORTED's to wait for.
7654 *--------------------------------------------------------------------*/
7655 jam();
7656 return;
7657 }//if
7658 }//for
7659 tcConnectptr.p->noOfNodes = 0;
7660 tcConnectptr.p->tcConnectstate = OS_ABORTING;
7661 setApiConTimer(apiConnectptr.i, ctcTimer, __LINE__);
7662 apiConnectptr.p->counter--;
7663 if (apiConnectptr.p->counter > 0) {
7664 jam();
7665 /*----------------------------------------------------------------------
7666 * WE ARE STILL WAITING FOR MORE PARTICIPANTS TO SEND ABORTED.
7667 *----------------------------------------------------------------------*/
7668 return;
7669 }//if
7670 /*------------------------------------------------------------------------*/
7671 /* */
7672 /* WE HAVE NOW COMPLETED THE ABORT PROCESS. WE HAVE RECEIVED ABORTED */
7673 /* FROM ALL PARTICIPANTS IN THE TRANSACTION. WE CAN NOW RELEASE ALL */
7674 /* RESOURCES CONNECTED TO THE TRANSACTION AND SEND THE ABORT RESPONSE */
7675 /*------------------------------------------------------------------------*/
7676 releaseAbortResources(signal);
7677 }//Dbtc::execABORTED()
7678
clearTcNodeData(Signal * signal,UintR TLastLqhIndicator,UintR Tstart)7679 void Dbtc::clearTcNodeData(Signal* signal,
7680 UintR TLastLqhIndicator,
7681 UintR Tstart)
7682 {
7683 UintR Ti;
7684 if (TLastLqhIndicator == ZTRUE) {
7685 for (Ti = Tstart ; Ti < tcConnectptr.p->noOfNodes; Ti++) {
7686 jam();
7687 tcConnectptr.p->tcNodedata[Ti] = 0;
7688 }//for
7689 } else {
7690 jam();
7691 tcConnectptr.p->tcNodedata[Tstart] = 0;
7692 }//for
7693 }//clearTcNodeData()
7694
abortErrorLab(Signal * signal)7695 void Dbtc::abortErrorLab(Signal* signal)
7696 {
7697 ptrGuard(apiConnectptr);
7698 ApiConnectRecord * transP = apiConnectptr.p;
7699 if (transP->apiConnectstate == CS_ABORTING && transP->abortState != AS_IDLE){
7700 jam();
7701 return;
7702 }
7703 transP->returnsignal = RS_TCROLLBACKREP;
7704 if(transP->returncode == 0){
7705 jam();
7706 transP->returncode = terrorCode;
7707 }
7708 abort010Lab(signal);
7709 }//Dbtc::abortErrorLab()
7710
abort010Lab(Signal * signal)7711 void Dbtc::abort010Lab(Signal* signal)
7712 {
7713 ApiConnectRecord * transP = apiConnectptr.p;
7714 if (transP->apiConnectstate == CS_ABORTING && transP->abortState != AS_IDLE){
7715 jam();
7716 return;
7717 }
7718 transP->apiConnectstate = CS_ABORTING;
7719 /*------------------------------------------------------------------------*/
7720 /* AN ABORT DECISION HAS BEEN TAKEN FOR SOME REASON. WE NEED TO ABORT */
7721 /* ALL PARTICIPANTS IN THE TRANSACTION. */
7722 /*------------------------------------------------------------------------*/
7723 transP->abortState = AS_ACTIVE;
7724 transP->counter = 0;
7725
7726 if (transP->firstTcConnect == RNIL) {
7727 jam();
7728 /*--------------------------------------------------------------------*/
7729 /* WE HAVE NO PARTICIPANTS IN THE TRANSACTION. */
7730 /*--------------------------------------------------------------------*/
7731 releaseAbortResources(signal);
7732 return;
7733 }//if
7734 tcConnectptr.i = transP->firstTcConnect;
7735 abort015Lab(signal);
7736 }//Dbtc::abort010Lab()
7737
7738 /*--------------------------------------------------------------------------*/
7739 /* */
7740 /* WE WILL ABORT ONE NODE PER OPERATION AT A TIME. THIS IS TO KEEP */
7741 /* ERROR HANDLING OF THIS PROCESS FAIRLY SIMPLE AND TRACTABLE. */
7742 /* EVEN IF NO NODE OF THIS PARTICULAR NODE NUMBER NEEDS ABORTION WE */
7743 /* MUST ENSURE THAT ALL NODES ARE CHECKED. THUS A FAULTY NODE DOES */
7744 /* NOT MEAN THAT ALL NODES IN AN OPERATION IS ABORTED. FOR THIS REASON*/
7745 /* WE SET THE TCONTINUE_ABORT TO TRUE WHEN A FAULTY NODE IS DETECTED. */
7746 /*--------------------------------------------------------------------------*/
abort015Lab(Signal * signal)7747 void Dbtc::abort015Lab(Signal* signal)
7748 {
7749 Uint32 TloopCount = 0;
7750 ABORT020:
7751 jam();
7752 TloopCount++;
7753 ptrCheckGuard(tcConnectptr, ctcConnectFilesize, tcConnectRecord);
7754 switch (tcConnectptr.p->tcConnectstate) {
7755 case OS_WAIT_DIH:
7756 case OS_WAIT_KEYINFO:
7757 case OS_WAIT_ATTR:
7758 jam();
7759 /*----------------------------------------------------------------------*/
7760 /* WE ARE STILL WAITING FOR MORE KEYINFO/ATTRINFO. WE HAVE NOT CONTACTED*/
7761 /* ANY LQH YET AND SO WE CAN SIMPLY SET STATE TO ABORTING. */
7762 /*----------------------------------------------------------------------*/
7763 tcConnectptr.p->noOfNodes = 0; // == releaseAbort(signal)
7764 tcConnectptr.p->tcConnectstate = OS_ABORTING;
7765 break;
7766 case OS_CONNECTED:
7767 jam();
7768 /*-----------------------------------------------------------------------
7769 * WE ARE STILL IN THE INITIAL PHASE OF THIS OPERATION.
7770 * NEED NOT BOTHER ABOUT ANY LQH ABORTS.
7771 *-----------------------------------------------------------------------*/
7772 tcConnectptr.p->noOfNodes = 0; // == releaseAbort(signal)
7773 tcConnectptr.p->tcConnectstate = OS_ABORTING;
7774 break;
7775 case OS_PREPARED:
7776 jam();
7777 case OS_OPERATING:
7778 jam();
7779 case OS_FIRE_TRIG_REQ:
7780 jam();
7781 /*----------------------------------------------------------------------
7782 * WE HAVE SENT LQHKEYREQ AND ARE IN SOME STATE OF EITHER STILL
7783 * SENDING THE OPERATION, WAITING FOR REPLIES, WAITING FOR MORE
7784 * ATTRINFO OR OPERATION IS PREPARED. WE NEED TO ABORT ALL LQH'S.
7785 *----------------------------------------------------------------------*/
7786 releaseAndAbort(signal);
7787 tcConnectptr.p->tcConnectstate = OS_ABORT_SENT;
7788 TloopCount += 127;
7789 break;
7790 case OS_ABORTING:
7791 jam();
7792 break;
7793 case OS_ABORT_SENT:
7794 jam();
7795 DEBUG("ABORT_SENT state in abort015Lab(), not expected");
7796 systemErrorLab(signal, __LINE__);
7797 return;
7798 default:
7799 jam();
7800 DEBUG("tcConnectstate = " << tcConnectptr.p->tcConnectstate);
7801 systemErrorLab(signal, __LINE__);
7802 return;
7803 }//switch
7804
7805 if (tcConnectptr.p->nextTcConnect != RNIL) {
7806 jam();
7807 tcConnectptr.i = tcConnectptr.p->nextTcConnect;
7808 if (TloopCount < 1024 &&
7809 !ERROR_INSERTED(8089) &&
7810 !ERROR_INSERTED(8105))
7811 {
7812 goto ABORT020;
7813 }
7814 else
7815 {
7816 jam();
7817 /*---------------------------------------------------------------------
7818 * Reset timer to avoid time-out in real-time break.
7819 * Increase counter to ensure that we don't think that all ABORTED have
7820 * been received before all have been sent.
7821 *---------------------------------------------------------------------*/
7822 apiConnectptr.p->counter++;
7823 setApiConTimer(apiConnectptr.i, ctcTimer, __LINE__);
7824 signal->theData[0] = TcContinueB::ZABORT_BREAK;
7825 signal->theData[1] = tcConnectptr.i;
7826 signal->theData[2] = apiConnectptr.i;
7827 signal->theData[3] = apiConnectptr.p->transid[0];
7828 signal->theData[4] = apiConnectptr.p->transid[1];
7829 if (ERROR_INSERTED(8089))
7830 {
7831 sendSignalWithDelay(cownref, GSN_CONTINUEB, signal, 100, 3);
7832 return;
7833 }
7834 sendSignal(cownref, GSN_CONTINUEB, signal, 5, JBB);
7835 return;
7836 }//if
7837 }//if
7838
7839 if (ERROR_INSERTED(8089))
7840 {
7841 CLEAR_ERROR_INSERT_VALUE;
7842 }
7843
7844 if (apiConnectptr.p->counter > 0) {
7845 jam();
7846 setApiConTimer(apiConnectptr.i, ctcTimer, __LINE__);
7847 return;
7848 }//if
7849 /*-----------------------------------------------------------------------
7850 * WE HAVE NOW COMPLETED THE ABORT PROCESS. WE HAVE RECEIVED ABORTED
7851 * FROM ALL PARTICIPANTS IN THE TRANSACTION. WE CAN NOW RELEASE ALL
7852 * RESOURCES CONNECTED TO THE TRANSACTION AND SEND THE ABORT RESPONSE
7853 *------------------------------------------------------------------------*/
7854 releaseAbortResources(signal);
7855 }//Dbtc::abort015Lab()
7856
7857 /*--------------------------------------------------------------------------*/
7858 /* RELEASE KEY AND ATTRINFO OBJECTS AND SEND ABORT TO THE LQH BLOCK. */
7859 /*--------------------------------------------------------------------------*/
releaseAndAbort(Signal * signal)7860 int Dbtc::releaseAndAbort(Signal* signal)
7861 {
7862 HostRecordPtr localHostptr;
7863 UintR TnoLoops = tcConnectptr.p->noOfNodes;
7864
7865 apiConnectptr.p->counter++;
7866 bool prevAlive = false;
7867 for (Uint32 Ti = 0; Ti < TnoLoops ; Ti++) {
7868 localHostptr.i = tcConnectptr.p->tcNodedata[Ti];
7869 ptrCheckGuard(localHostptr, chostFilesize, hostRecord);
7870 if (localHostptr.p->hostStatus == HS_ALIVE) {
7871 jam();
7872 if (prevAlive) {
7873 // if previous is alive, its LQH forwards abort to this node
7874 jam();
7875 continue;
7876 }
7877 /* ************< */
7878 /* ABORT < */
7879 /* ************< */
7880 Uint32 instanceKey = tcConnectptr.p->lqhInstanceKey;
7881 tblockref = numberToRef(DBLQH, instanceKey, localHostptr.i);
7882 signal->theData[0] = tcConnectptr.i;
7883 signal->theData[1] = cownref;
7884 signal->theData[2] = apiConnectptr.p->transid[0];
7885 signal->theData[3] = apiConnectptr.p->transid[1];
7886 sendSignal(tblockref, GSN_ABORT, signal, 4, JBB);
7887 prevAlive = true;
7888 } else {
7889 jam();
7890 signal->theData[0] = tcConnectptr.i;
7891 signal->theData[1] = apiConnectptr.p->transid[0];
7892 signal->theData[2] = apiConnectptr.p->transid[1];
7893 signal->theData[3] = localHostptr.i;
7894 signal->theData[4] = ZFALSE;
7895 sendSignal(cownref, GSN_ABORTED, signal, 5, JBB);
7896 prevAlive = false;
7897 }//if
7898 }//for
7899 return 1;
7900 }//Dbtc::releaseAndAbort()
7901
7902 /* ------------------------------------------------------------------------- */
7903 /* ------- ENTER TIME_SIGNAL ------- */
7904 /* */
7905 /* ------------------------------------------------------------------------- */
execTIME_SIGNAL(Signal * signal)7906 void Dbtc::execTIME_SIGNAL(Signal* signal)
7907 {
7908 jamEntry();
7909
7910 const NDB_TICKS currentTime = NdbTick_getCurrentTicks();
7911 Uint64 num_ms_elapsed = elapsed_time(signal,
7912 currentTime,
7913 c_latestTIME_SIGNAL,
7914 Uint32(TC_TIME_SIGNAL_DELAY));
7915 sendTIME_SIGNAL(signal, currentTime, Uint32(TC_TIME_SIGNAL_DELAY));
7916
7917 /**
7918 * The code here will make calls to timer_handling that appears to happen
7919 * every 10ms but in reality they come in batches of up to 10 10ms
7920 * intervals. The timer_handling will check if a new scan of PK timeouts
7921 * is to start, this happens after an idle check period of 500ms. So
7922 * we actually need only check this a divisor of 500 ms and 400ms. 400ms
7923 * is how long we are idle between scans to check for scan timeouts.
7924 * The reason to separate those is to make sure that they don't run
7925 * at the same time as much.
7926 *
7927 * One reason to run the updates of the timer_handling as often as once
7928 * per 50ms is that it is also then that we update the timer that is used
7929 * to check for timeouts on transaction. So 50ms is the granularity of
7930 * when we see timeouts.
7931 *
7932 * The reason for keeping the 10ms appearance of timer_handling is to
7933 * decrease changes in this part of the code. This could be changed
7934 * in the future.
7935 */
7936 c_elapsed_time_millis += num_ms_elapsed;
7937 while (c_elapsed_time_millis > Uint64(10))
7938 {
7939 jam();
7940 c_elapsed_time_millis -= Uint64(10);
7941 timer_handling(signal);
7942 }
7943 }//execTIME_SIGNAL()
7944
timer_handling(Signal * signal)7945 void Dbtc::timer_handling(Signal *signal)
7946 {
7947 ctcTimer++;
7948 checkStartTimeout(signal);
7949 checkStartFragTimeout(signal);
7950 }
7951
7952 /*------------------------------------------------*/
7953 /* Start timeout handling if not already going on */
7954 /*------------------------------------------------*/
checkStartTimeout(Signal * signal)7955 void Dbtc::checkStartTimeout(Signal* signal)
7956 {
7957 ctimeOutCheckCounter++;
7958 if (ctimeOutCheckActive == TOCS_TRUE) {
7959 jam();
7960 // Check heartbeat of timeout loop
7961 if(ctimeOutCheckHeartbeat > ctimeOutCheckLastHeartbeat){
7962 jam();
7963 ctimeOutMissedHeartbeats = 0;
7964 }else{
7965 jam();
7966 /**
7967 * This code simply checks that the scan for PK timeouts haven't
7968 * lost itself, a sort of watchdog for that code. If that would
7969 * occur we would no longer have any timeout handling of
7970 * transactions which would render the system useless. This is
7971 * to protect ourselves for future bugs in the code that we
7972 * might introduce by mistake.
7973 *
7974 * 100 is simply an arbitrary number that needs to be bigger
7975 * than the maximum number of calls to timer_handling that
7976 * we can have in one call to execTIME_SIGNAL. This is
7977 * currently 10 but could change in the future.
7978 */
7979 ctimeOutMissedHeartbeats++;
7980 if (ctimeOutMissedHeartbeats > 100){
7981 jam();
7982 systemErrorLab(signal, __LINE__);
7983 }
7984 }
7985 ctimeOutCheckLastHeartbeat = ctimeOutCheckHeartbeat;
7986 return;
7987 }//if
7988 if (ctimeOutCheckCounter < ctimeOutCheckDelay) {
7989 jam();
7990 /*------------------------------------------------------------------*/
7991 /* */
7992 /* NO TIME-OUT CHECKED THIS TIME. WAIT MORE. */
7993 /*------------------------------------------------------------------*/
7994 return;
7995 }//if
7996 ctimeOutCheckActive = TOCS_TRUE;
7997 ctimeOutCheckCounter = 0;
7998 ctimeOutMissedHeartbeats = 0;
7999 timeOutLoopStartLab(signal, 0); // 0 is first api connect record
8000 return;
8001 }//checkStartTimeout()
8002
8003 /*----------------------------------------------------------------*/
8004 /* Start fragment (scan) timeout handling if not already going on */
8005 /*----------------------------------------------------------------*/
checkStartFragTimeout(Signal * signal)8006 void Dbtc::checkStartFragTimeout(Signal* signal)
8007 {
8008 ctimeOutCheckFragCounter++;
8009 if (ctimeOutCheckFragActive == TOCS_TRUE) {
8010 jam();
8011 // Check heartbeat of scan timeout loop
8012 if(ctimeOutCheckHeartbeatScan > ctimeOutCheckLastHeartbeatScan)
8013 {
8014 jam();
8015 ctimeOutMissedHeartbeatsScan = 0;
8016 }
8017 else
8018 {
8019 /**
8020 * Exactly the same code as for PK timeouts, but here to check the
8021 * scan for scan timeouts. Same comments apply as above.
8022 */
8023 jam();
8024 ctimeOutMissedHeartbeatsScan++;
8025 if (ctimeOutMissedHeartbeatsScan > 100){
8026 jam();
8027 systemErrorLab(signal, __LINE__);
8028 }
8029 }
8030 ctimeOutCheckLastHeartbeatScan = ctimeOutCheckHeartbeatScan;
8031 return;
8032 }//if
8033 if (ctimeOutCheckFragCounter < ctimeOutCheckDelayScan) {
8034 jam();
8035 /*------------------------------------------------------------------*/
8036 /* NO TIME-OUT CHECKED THIS TIME. WAIT MORE. */
8037 /*------------------------------------------------------------------*/
8038 return;
8039 }//if
8040
8041 // Go through the fragment records and look for timeout in a scan.
8042 ctimeOutCheckFragActive = TOCS_TRUE;
8043 ctimeOutCheckFragCounter = 0;
8044 ctimeOutMissedHeartbeatsScan = 0;
8045 timeOutLoopStartFragLab(signal, 0); // 0 means first scan record
8046 }//checkStartFragTimeout()
8047
8048 /*------------------------------------------------------------------*/
8049 /* IT IS NOW TIME TO CHECK WHETHER ANY TRANSACTIONS HAVE */
8050 /* BEEN DELAYED FOR SO LONG THAT WE ARE FORCED TO PERFORM */
8051 /* SOME ACTION, EITHER ABORT OR RESEND OR REMOVE A NODE FROM */
8052 /* THE WAITING PART OF A PROTOCOL. */
8053 /*
8054 The algorithm used here is to check 1024 transactions at a time before
8055 doing a real-time break.
8056 To avoid aborting both transactions in a deadlock detected by time-out
8057 we insert a random extra time-out of upto 630 ms by using the lowest
8058 six bits of the api connect reference.
8059 We spread it out from 0 to 630 ms if base time-out is larger than 3 sec,
8060 we spread it out from 0 to 70 ms if base time-out is smaller than 300 msec,
8061 and otherwise we spread it out 310 ms.
8062 */
8063 /*------------------------------------------------------------------*/
timeOutLoopStartLab(Signal * signal,Uint32 api_con_ptr)8064 void Dbtc::timeOutLoopStartLab(Signal* signal, Uint32 api_con_ptr)
8065 {
8066 Uint32 end_ptr, time_passed, time_out_value, mask_value;
8067 Uint32 old_mask_value= 0;
8068 const Uint32 api_con_sz= capiConnectFilesize;
8069 const Uint32 tc_timer= ctcTimer;
8070 const Uint32 time_out_param= ctimeOutValue;
8071 const Uint32 old_time_out_param= c_abortRec.oldTimeOutValue;
8072
8073 ctimeOutCheckHeartbeat = tc_timer;
8074
8075 if (api_con_ptr + 1024 < api_con_sz) {
8076 jam();
8077 end_ptr= api_con_ptr + 1024;
8078 } else {
8079 jam();
8080 end_ptr= api_con_sz;
8081 }
8082 if (time_out_param > 300) {
8083 jam();
8084 mask_value= 63;
8085 } else if (time_out_param < 30) {
8086 jam();
8087 mask_value= 7;
8088 } else {
8089 jam();
8090 mask_value= 31;
8091 }
8092 if (time_out_param != old_time_out_param &&
8093 getNodeState().getSingleUserMode())
8094 {
8095 // abort during single user mode, use old_mask_value as flag
8096 // and calculate value to be used for connections with allowed api
8097 if (old_time_out_param > 300) {
8098 jam();
8099 old_mask_value= 63;
8100 } else if (old_time_out_param < 30) {
8101 jam();
8102 old_mask_value= 7;
8103 } else {
8104 jam();
8105 old_mask_value= 31;
8106 }
8107 }
8108 for ( ; api_con_ptr < end_ptr; api_con_ptr++) {
8109 Uint32 api_timer= getApiConTimer(api_con_ptr);
8110 if (api_timer != 0) {
8111 jam();
8112 jamLine(api_con_ptr & 0xFFFF);
8113 Uint32 error= ZTIME_OUT_ERROR;
8114 time_out_value= time_out_param + (ndb_rand() & mask_value);
8115 if (unlikely(old_mask_value)) // abort during single user mode
8116 {
8117 apiConnectptr.i = api_con_ptr;
8118 ptrCheckGuard(apiConnectptr, capiConnectFilesize, apiConnectRecord);
8119 if ((getNodeState().getSingleUserApi() ==
8120 refToNode(apiConnectptr.p->ndbapiBlockref)) ||
8121 !(apiConnectptr.p->singleUserMode & (1 << NDB_SUM_LOCKED)))
8122 {
8123 // api allowed during single user, use original timeout
8124 time_out_value=
8125 old_time_out_param + (api_con_ptr & old_mask_value);
8126 }
8127 else
8128 {
8129 error= ZCLUSTER_IN_SINGLEUSER_MODE;
8130 }
8131 }
8132 time_passed= tc_timer - api_timer;
8133 if (time_passed > time_out_value)
8134 {
8135 jam();
8136 timeOutFoundLab(signal, api_con_ptr, error);
8137 api_con_ptr++;
8138 break;
8139 }
8140 }
8141 }
8142 if (api_con_ptr == api_con_sz) {
8143 jam();
8144 /*------------------------------------------------------------------*/
8145 /* */
8146 /* WE HAVE NOW CHECKED ALL TRANSACTIONS FOR TIME-OUT AND ALSO */
8147 /* STARTED TIME-OUT HANDLING OF THOSE WE FOUND. WE ARE NOW */
8148 /* READY AND CAN WAIT FOR THE NEXT TIME-OUT CHECK. */
8149 /*------------------------------------------------------------------*/
8150 ctimeOutCheckActive = TOCS_FALSE;
8151 } else {
8152 jam();
8153 sendContinueTimeOutControl(signal, api_con_ptr);
8154 }
8155 return;
8156 }//Dbtc::timeOutLoopStartLab()
8157
timeOutFoundLab(Signal * signal,Uint32 TapiConPtr,Uint32 errCode)8158 void Dbtc::timeOutFoundLab(Signal* signal, Uint32 TapiConPtr, Uint32 errCode)
8159 {
8160 apiConnectptr.i = TapiConPtr;
8161 ptrCheckGuard(apiConnectptr, capiConnectFilesize, apiConnectRecord);
8162 /*------------------------------------------------------------------*/
8163 /* */
8164 /* THIS TRANSACTION HAVE EXPERIENCED A TIME-OUT AND WE NEED TO*/
8165 /* FIND OUT WHAT WE NEED TO DO BASED ON THE STATE INFORMATION.*/
8166 /*------------------------------------------------------------------*/
8167 DEBUG("[ H'" << hex << apiConnectptr.p->transid[0]
8168 << " H'" << apiConnectptr.p->transid[1] << "] " << dec
8169 << "Time-out in state = " << apiConnectptr.p->apiConnectstate
8170 << " apiConnectptr.i = " << apiConnectptr.i
8171 << " - exec: "
8172 << tc_testbit(apiConnectptr.p->m_flags, ApiConnectRecord::TF_EXEC_FLAG)
8173 << " - place: " << c_apiConTimer_line[apiConnectptr.i]
8174 << " code: " << errCode
8175 << " lqhkeyreqrec: " << apiConnectptr.p->lqhkeyreqrec
8176 << " lqhkeyconfrec: " << apiConnectptr.p->lqhkeyconfrec
8177 << " pendingTriggers: " << apiConnectptr.p->pendingTriggers
8178 );
8179 switch (apiConnectptr.p->apiConnectstate) {
8180 case CS_STARTED:
8181 if(apiConnectptr.p->lqhkeyreqrec == apiConnectptr.p->lqhkeyconfrec &&
8182 errCode != ZCLUSTER_IN_SINGLEUSER_MODE){
8183 jam();
8184 /*
8185 We are waiting for application to continue the transaction. In this
8186 particular state we will use the application timeout parameter rather
8187 than the shorter Deadlock detection timeout.
8188 */
8189 if (c_appl_timeout_value == 0 ||
8190 (ctcTimer - getApiConTimer(apiConnectptr.i)) <= c_appl_timeout_value) {
8191 jam();
8192 return;
8193 }//if
8194 }
8195 apiConnectptr.p->returnsignal = RS_TCROLLBACKREP;
8196 apiConnectptr.p->returncode = errCode;
8197 abort010Lab(signal);
8198 return;
8199 case CS_RECEIVING:
8200 case CS_REC_COMMITTING:
8201 case CS_START_COMMITTING:
8202 case CS_WAIT_FIRE_TRIG_REQ:
8203 case CS_SEND_FIRE_TRIG_REQ:
8204 jam();
8205 /*------------------------------------------------------------------*/
8206 /* WE ARE STILL IN THE PREPARE PHASE AND THE TRANSACTION HAS */
8207 /* NOT YET REACHED ITS COMMIT POINT. THUS IT IS NOW OK TO */
8208 /* START ABORTING THE TRANSACTION. ALSO START CHECKING THE */
8209 /* REMAINING TRANSACTIONS. */
8210 /*------------------------------------------------------------------*/
8211 terrorCode = errCode;
8212 abortErrorLab(signal);
8213 return;
8214 case CS_COMMITTING:
8215 jam();
8216 /*------------------------------------------------------------------*/
8217 // We are simply waiting for a signal in the job buffer. Only extreme
8218 // conditions should get us here. We ignore it.
8219 /*------------------------------------------------------------------*/
8220 case CS_COMPLETING:
8221 jam();
8222 /*------------------------------------------------------------------*/
8223 // We are simply waiting for a signal in the job buffer. Only extreme
8224 // conditions should get us here. We ignore it.
8225 /*------------------------------------------------------------------*/
8226 case CS_PREPARE_TO_COMMIT:
8227 {
8228 jam();
8229 /*------------------------------------------------------------------*/
8230 /* WE ARE WAITING FOR DIH TO COMMIT THE TRANSACTION. WE SIMPLY*/
8231 /* KEEP WAITING SINCE THERE IS NO BETTER IDEA ON WHAT TO DO. */
8232 /* IF IT IS BLOCKED THEN NO TRANSACTION WILL PASS THIS GATE. */
8233 // To ensure against strange bugs we crash the system if we have passed
8234 // time-out period by a factor of 10 and it is also at least 5 seconds.
8235 /*------------------------------------------------------------------*/
8236 Uint32 time_passed = ctcTimer - getApiConTimer(apiConnectptr.i);
8237 if (time_passed > 500 &&
8238 time_passed > (5 * cDbHbInterval) &&
8239 time_passed > (10 * ctimeOutValue))
8240 {
8241 jam();
8242 ndbout_c("timeOutFoundLab trans: 0x%x 0x%x state: %u",
8243 apiConnectptr.p->transid[0],
8244 apiConnectptr.p->transid[1],
8245 (Uint32)apiConnectptr.p->apiConnectstate);
8246
8247 // Reset timeout to not flood log...
8248 setApiConTimer(apiConnectptr.i, 0, __LINE__);
8249 }//if
8250 break;
8251 }
8252 case CS_COMMIT_SENT:
8253 jam();
8254 /*------------------------------------------------------------------*/
8255 /* WE HAVE SENT COMMIT TO A NUMBER OF NODES. WE ARE CURRENTLY */
8256 /* WAITING FOR THEIR REPLY. WITH NODE RECOVERY SUPPORTED WE */
8257 /* WILL CHECK FOR CRASHED NODES AND RESEND THE COMMIT SIGNAL */
8258 /* TO THOSE NODES THAT HAVE MISSED THE COMMIT SIGNAL DUE TO */
8259 /* A NODE FAILURE. */
8260 /*------------------------------------------------------------------*/
8261 tabortInd = ZCOMMIT_SETUP;
8262 setupFailData(signal);
8263 toCommitHandlingLab(signal);
8264 return;
8265 case CS_COMPLETE_SENT:
8266 jam();
8267 /*--------------------------------------------------------------------*/
8268 /* WE HAVE SENT COMPLETE TO A NUMBER OF NODES. WE ARE CURRENTLY */
8269 /* WAITING FOR THEIR REPLY. WITH NODE RECOVERY SUPPORTED WE */
8270 /* WILL CHECK FOR CRASHED NODES AND RESEND THE COMPLETE SIGNAL */
8271 /* TO THOSE NODES THAT HAVE MISSED THE COMPLETE SIGNAL DUE TO */
8272 /* A NODE FAILURE. */
8273 /*--------------------------------------------------------------------*/
8274 tabortInd = ZCOMMIT_SETUP;
8275 setupFailData(signal);
8276 toCompleteHandlingLab(signal);
8277 return;
8278 case CS_ABORTING:
8279 jam();
8280 /*------------------------------------------------------------------*/
8281 /* TIME-OUT DURING ABORT. WE NEED TO SEND ABORTED FOR ALL */
8282 /* NODES THAT HAVE FAILED BEFORE SENDING ABORTED. */
8283 /*------------------------------------------------------------------*/
8284 tcConnectptr.i = apiConnectptr.p->firstTcConnect;
8285 sendAbortedAfterTimeout(signal, 0);
8286 break;
8287 case CS_START_SCAN:{
8288 jam();
8289
8290 /*
8291 We are waiting for application to continue the transaction. In this
8292 particular state we will use the application timeout parameter rather
8293 than the shorter Deadlock detection timeout.
8294 */
8295 if (c_appl_timeout_value == 0 ||
8296 (ctcTimer - getApiConTimer(apiConnectptr.i)) <= c_appl_timeout_value) {
8297 jam();
8298 return;
8299 }//if
8300
8301 ScanRecordPtr scanPtr;
8302 scanPtr.i = apiConnectptr.p->apiScanRec;
8303 ptrCheckGuard(scanPtr, cscanrecFileSize, scanRecord);
8304 scanError(signal, scanPtr, ZSCANTIME_OUT_ERROR);
8305 break;
8306 }
8307 case CS_WAIT_ABORT_CONF:
8308 jam();
8309 tcConnectptr.i = apiConnectptr.p->currentTcConnect;
8310 ptrCheckGuard(tcConnectptr, ctcConnectFilesize, tcConnectRecord);
8311 arrGuard(apiConnectptr.p->currentReplicaNo, MAX_REPLICAS);
8312 hostptr.i = tcConnectptr.p->tcNodedata[apiConnectptr.p->currentReplicaNo];
8313 ptrCheckGuard(hostptr, chostFilesize, hostRecord);
8314 if (hostptr.p->hostStatus == HS_ALIVE) {
8315 /*------------------------------------------------------------------*/
8316 // Time-out waiting for ABORTCONF. We will resend the ABORTREQ just in
8317 // case.
8318 /*------------------------------------------------------------------*/
8319 warningReport(signal, 20);
8320 apiConnectptr.p->timeOutCounter++;
8321 if (apiConnectptr.p->timeOutCounter > 3) {
8322 /*------------------------------------------------------------------*/
8323 // 100 time-outs are not acceptable. We will shoot down the node
8324 // not responding.
8325 /*------------------------------------------------------------------*/
8326 reportNodeFailed(signal, hostptr.i);
8327 }//if
8328 apiConnectptr.p->currentReplicaNo++;
8329 }//if
8330 tcurrentReplicaNo = (Uint8)Z8NIL;
8331 toAbortHandlingLab(signal);
8332 return;
8333 case CS_WAIT_COMMIT_CONF:
8334 jam();
8335 CRASH_INSERTION(8053);
8336 tcConnectptr.i = apiConnectptr.p->currentTcConnect;
8337 ptrCheckGuard(tcConnectptr, ctcConnectFilesize, tcConnectRecord);
8338 arrGuard(apiConnectptr.p->currentReplicaNo, MAX_REPLICAS);
8339 hostptr.i = tcConnectptr.p->tcNodedata[apiConnectptr.p->currentReplicaNo];
8340 ptrCheckGuard(hostptr, chostFilesize, hostRecord);
8341 if (hostptr.p->hostStatus == HS_ALIVE) {
8342 /*------------------------------------------------------------------*/
8343 // Time-out waiting for COMMITCONF. We will resend the COMMITREQ just in
8344 // case.
8345 /*------------------------------------------------------------------*/
8346 warningReport(signal, 21);
8347 apiConnectptr.p->timeOutCounter++;
8348 if (apiConnectptr.p->timeOutCounter > 3) {
8349 /*------------------------------------------------------------------*/
8350 // 100 time-outs are not acceptable. We will shoot down the node
8351 // not responding.
8352 /*------------------------------------------------------------------*/
8353 reportNodeFailed(signal, hostptr.i);
8354 }//if
8355 apiConnectptr.p->currentReplicaNo++;
8356 }//if
8357 tcurrentReplicaNo = (Uint8)Z8NIL;
8358 toCommitHandlingLab(signal);
8359 return;
8360 case CS_WAIT_COMPLETE_CONF:
8361 jam();
8362 tcConnectptr.i = apiConnectptr.p->currentTcConnect;
8363 ptrCheckGuard(tcConnectptr, ctcConnectFilesize, tcConnectRecord);
8364 arrGuard(apiConnectptr.p->currentReplicaNo, MAX_REPLICAS);
8365 hostptr.i = tcConnectptr.p->tcNodedata[apiConnectptr.p->currentReplicaNo];
8366 ptrCheckGuard(hostptr, chostFilesize, hostRecord);
8367 if (hostptr.p->hostStatus == HS_ALIVE) {
8368 /*------------------------------------------------------------------*/
8369 // Time-out waiting for COMPLETECONF. We will resend the COMPLETEREQ
8370 // just in case.
8371 /*------------------------------------------------------------------*/
8372 warningReport(signal, 22);
8373 apiConnectptr.p->timeOutCounter++;
8374 if (apiConnectptr.p->timeOutCounter > 100) {
8375 /*------------------------------------------------------------------*/
8376 // 100 time-outs are not acceptable. We will shoot down the node
8377 // not responding.
8378 /*------------------------------------------------------------------*/
8379 reportNodeFailed(signal, hostptr.i);
8380 }//if
8381 apiConnectptr.p->currentReplicaNo++;
8382 }//if
8383 tcurrentReplicaNo = (Uint8)Z8NIL;
8384 toCompleteHandlingLab(signal);
8385 return;
8386 case CS_FAIL_PREPARED:
8387 jam();
8388 case CS_FAIL_COMMITTING:
8389 jam();
8390 case CS_FAIL_COMMITTED:
8391 jam();
8392 case CS_RESTART:
8393 jam();
8394 case CS_FAIL_ABORTED:
8395 jam();
8396 case CS_DISCONNECTED:
8397 jam();
8398 default:
8399 jam();
8400 /*------------------------------------------------------------------*/
8401 /* AN IMPOSSIBLE STATE IS SET. CRASH THE SYSTEM. */
8402 /*------------------------------------------------------------------*/
8403 DEBUG("State = " << apiConnectptr.p->apiConnectstate);
8404 systemErrorLab(signal, __LINE__);
8405 return;
8406 }//switch
8407 return;
8408 }//Dbtc::timeOutFoundLab()
8409
sendAbortedAfterTimeout(Signal * signal,int Tcheck)8410 void Dbtc::sendAbortedAfterTimeout(Signal* signal, int Tcheck)
8411 {
8412 ApiConnectRecord * transP = apiConnectptr.p;
8413 if(transP->abortState == AS_IDLE){
8414 jam();
8415 warningEvent("TC: %d: %d state=%d abort==IDLE place: %d fop=%d t: %d",
8416 __LINE__,
8417 apiConnectptr.i,
8418 transP->apiConnectstate,
8419 c_apiConTimer_line[apiConnectptr.i],
8420 transP->firstTcConnect,
8421 c_apiConTimer[apiConnectptr.i]
8422 );
8423 ndbout_c("TC: %d: %d state=%d abort==IDLE place: %d fop=%d t: %d",
8424 __LINE__,
8425 apiConnectptr.i,
8426 transP->apiConnectstate,
8427 c_apiConTimer_line[apiConnectptr.i],
8428 transP->firstTcConnect,
8429 c_apiConTimer[apiConnectptr.i]
8430 );
8431 ndbrequire(false);
8432 setApiConTimer(apiConnectptr.i, 0, __LINE__);
8433 return;
8434 }
8435
8436 bool found = false;
8437 OperationState tmp[16];
8438
8439 Uint32 TloopCount = 0;
8440 do {
8441 jam();
8442 if (tcConnectptr.i == RNIL) {
8443 jam();
8444
8445 #ifdef VM_TRACE
8446 ndbout_c("found: %d Tcheck: %d apiConnectptr.p->counter: %d",
8447 found, Tcheck, apiConnectptr.p->counter);
8448 #endif
8449 if (found || apiConnectptr.p->counter)
8450 {
8451 jam();
8452 /**
8453 * We sent atleast one ABORT/ABORTED
8454 * or ZABORT_TIMEOUT_BREAK is in job buffer
8455 * wait for reception...
8456 */
8457 return;
8458 }
8459
8460 if (Tcheck == 1)
8461 {
8462 jam();
8463 releaseAbortResources(signal);
8464 return;
8465 }
8466
8467 if (Tcheck == 0)
8468 {
8469 jam();
8470 /*------------------------------------------------------------------
8471 * All nodes had already reported ABORTED for all tcConnect records.
8472 * Crash since it is an error situation that we then received a
8473 * time-out.
8474 *------------------------------------------------------------------*/
8475 char buf[96]; buf[0] = 0;
8476 char buf2[96];
8477 BaseString::snprintf(buf, sizeof(buf), "TC %d: %d counter: %d ops:",
8478 __LINE__, apiConnectptr.i,
8479 apiConnectptr.p->counter);
8480 for(Uint32 i = 0; i<TloopCount; i++)
8481 {
8482 BaseString::snprintf(buf2, sizeof(buf2), "%s %d", buf, tmp[i]);
8483 BaseString::snprintf(buf, sizeof(buf), "%s", buf2);
8484 }
8485 warningEvent("%s", buf);
8486 ndbout_c("%s", buf);
8487 ndbrequire(false);
8488 releaseAbortResources(signal);
8489 return;
8490 }
8491
8492 return;
8493 }//if
8494 TloopCount++;
8495 if (TloopCount >= 1024) {
8496 jam();
8497 /*------------------------------------------------------------------*/
8498 // Insert a real-time break for large transactions to avoid blowing
8499 // away the job buffer.
8500 /*------------------------------------------------------------------*/
8501 setApiConTimer(apiConnectptr.i, ctcTimer, __LINE__);
8502 apiConnectptr.p->counter++;
8503 signal->theData[0] = TcContinueB::ZABORT_TIMEOUT_BREAK;
8504 signal->theData[1] = tcConnectptr.i;
8505 signal->theData[2] = apiConnectptr.i;
8506 if (ERROR_INSERTED(8080))
8507 {
8508 ndbout_c("sending ZABORT_TIMEOUT_BREAK delayed (%d %d)",
8509 Tcheck, apiConnectptr.p->counter);
8510 sendSignalWithDelay(cownref, GSN_CONTINUEB, signal, 2000, 3);
8511 }
8512 else
8513 {
8514 sendSignal(cownref, GSN_CONTINUEB, signal, 3, JBB);
8515 }
8516 return;
8517 }//if
8518 ptrCheckGuard(tcConnectptr, ctcConnectFilesize, tcConnectRecord);
8519 if(TloopCount < 16){
8520 jam();
8521 tmp[TloopCount-1] = tcConnectptr.p->tcConnectstate;
8522 }
8523
8524 if (tcConnectptr.p->tcConnectstate == OS_ABORT_SENT) {
8525 jam();
8526 /*------------------------------------------------------------------*/
8527 // We have sent an ABORT signal to this node but not yet received any
8528 // reply. We have to send an ABORTED signal on our own in some cases.
8529 // If the node is declared as up and running and still do not respond
8530 // in time to the ABORT signal we will declare it as dead.
8531 /*------------------------------------------------------------------*/
8532 UintR Ti = 0;
8533 arrGuard(tcConnectptr.p->noOfNodes, MAX_REPLICAS+1);
8534 for (Ti = 0; Ti < tcConnectptr.p->noOfNodes; Ti++) {
8535 jam();
8536 if (tcConnectptr.p->tcNodedata[Ti] != 0) {
8537 TloopCount += 31;
8538 found = true;
8539 hostptr.i = tcConnectptr.p->tcNodedata[Ti];
8540 ptrCheckGuard(hostptr, chostFilesize, hostRecord);
8541 if (hostptr.p->hostStatus == HS_ALIVE) {
8542 jam();
8543 /*---------------------------------------------------------------
8544 * A backup replica has not sent ABORTED.
8545 * Could be that a node before him has crashed.
8546 * Send an ABORT signal specifically to this node.
8547 * We will not send to any more nodes after this
8548 * to avoid race problems.
8549 * To also ensure that we use this message also as a heartbeat
8550 * we will move this node to the primary replica seat.
8551 * The primary replica and any failed node after it will
8552 * be removed from the node list. Update also number of nodes.
8553 * Finally break the loop to ensure we don't mess
8554 * things up by executing another loop.
8555 * We also update the timer to ensure we don't get time-out
8556 * too early.
8557 *--------------------------------------------------------------*/
8558 Uint32 instanceKey = tcConnectptr.p->lqhInstanceKey;
8559 BlockReference TBRef = numberToRef(DBLQH, instanceKey, hostptr.i);
8560 signal->theData[0] = tcConnectptr.i;
8561 signal->theData[1] = cownref;
8562 signal->theData[2] = apiConnectptr.p->transid[0];
8563 signal->theData[3] = apiConnectptr.p->transid[1];
8564 sendSignal(TBRef, GSN_ABORT, signal, 4, JBB);
8565 setApiConTimer(apiConnectptr.i, ctcTimer, __LINE__);
8566 break;
8567 } else {
8568 jam();
8569 /*--------------------------------------------------------------
8570 * The node we are waiting for is dead. We will send ABORTED to
8571 * ourselves vicarious for the failed node.
8572 *--------------------------------------------------------------*/
8573 setApiConTimer(apiConnectptr.i, ctcTimer, __LINE__);
8574 signal->theData[0] = tcConnectptr.i;
8575 signal->theData[1] = apiConnectptr.p->transid[0];
8576 signal->theData[2] = apiConnectptr.p->transid[1];
8577 signal->theData[3] = hostptr.i;
8578 signal->theData[4] = ZFALSE;
8579 sendSignal(cownref, GSN_ABORTED, signal, 5, JBB);
8580 }//if
8581 }//if
8582 }//for
8583 }//if
8584 tcConnectptr.i = tcConnectptr.p->nextTcConnect;
8585 } while (1);
8586 }//Dbtc::sendAbortedAfterTimeout()
8587
reportNodeFailed(Signal * signal,NodeId nodeId)8588 void Dbtc::reportNodeFailed(Signal* signal, NodeId nodeId)
8589 {
8590 DisconnectRep * const rep = (DisconnectRep *)&signal->theData[0];
8591 rep->nodeId = nodeId;
8592 rep->err = DisconnectRep::TcReportNodeFailed;
8593 sendSignal(QMGR_REF, GSN_DISCONNECT_REP, signal,
8594 DisconnectRep::SignalLength, JBB);
8595 }//Dbtc::reportNodeFailed()
8596
8597 /*-------------------------------------------------*/
8598 /* Timeout-loop for scanned fragments. */
8599 /*-------------------------------------------------*/
timeOutLoopStartFragLab(Signal * signal,Uint32 TscanConPtr)8600 void Dbtc::timeOutLoopStartFragLab(Signal* signal, Uint32 TscanConPtr)
8601 {
8602 ScanFragRecPtr timeOutPtr[8];
8603 UintR tfragTimer[8];
8604 UintR texpiredTime[8];
8605 UintR TloopCount = 0;
8606 Uint32 TtcTimer = ctcTimer;
8607
8608 ctimeOutCheckHeartbeatScan = TtcTimer;
8609
8610 while ((TscanConPtr + 8) < cscanFragrecFileSize) {
8611 jam();
8612 timeOutPtr[0].i = TscanConPtr + 0;
8613 timeOutPtr[1].i = TscanConPtr + 1;
8614 timeOutPtr[2].i = TscanConPtr + 2;
8615 timeOutPtr[3].i = TscanConPtr + 3;
8616 timeOutPtr[4].i = TscanConPtr + 4;
8617 timeOutPtr[5].i = TscanConPtr + 5;
8618 timeOutPtr[6].i = TscanConPtr + 6;
8619 timeOutPtr[7].i = TscanConPtr + 7;
8620
8621 c_scan_frag_pool.getPtrForce(timeOutPtr[0]);
8622 c_scan_frag_pool.getPtrForce(timeOutPtr[1]);
8623 c_scan_frag_pool.getPtrForce(timeOutPtr[2]);
8624 c_scan_frag_pool.getPtrForce(timeOutPtr[3]);
8625 c_scan_frag_pool.getPtrForce(timeOutPtr[4]);
8626 c_scan_frag_pool.getPtrForce(timeOutPtr[5]);
8627 c_scan_frag_pool.getPtrForce(timeOutPtr[6]);
8628 c_scan_frag_pool.getPtrForce(timeOutPtr[7]);
8629
8630 tfragTimer[0] = timeOutPtr[0].p->scanFragTimer;
8631 tfragTimer[1] = timeOutPtr[1].p->scanFragTimer;
8632 tfragTimer[2] = timeOutPtr[2].p->scanFragTimer;
8633 tfragTimer[3] = timeOutPtr[3].p->scanFragTimer;
8634 tfragTimer[4] = timeOutPtr[4].p->scanFragTimer;
8635 tfragTimer[5] = timeOutPtr[5].p->scanFragTimer;
8636 tfragTimer[6] = timeOutPtr[6].p->scanFragTimer;
8637 tfragTimer[7] = timeOutPtr[7].p->scanFragTimer;
8638
8639 texpiredTime[0] = TtcTimer - tfragTimer[0];
8640 texpiredTime[1] = TtcTimer - tfragTimer[1];
8641 texpiredTime[2] = TtcTimer - tfragTimer[2];
8642 texpiredTime[3] = TtcTimer - tfragTimer[3];
8643 texpiredTime[4] = TtcTimer - tfragTimer[4];
8644 texpiredTime[5] = TtcTimer - tfragTimer[5];
8645 texpiredTime[6] = TtcTimer - tfragTimer[6];
8646 texpiredTime[7] = TtcTimer - tfragTimer[7];
8647
8648 for (Uint32 Ti = 0; Ti < 8; Ti++) {
8649 jam();
8650 if (tfragTimer[Ti] != 0) {
8651
8652 if (texpiredTime[Ti] > ctimeOutValue) {
8653 jam();
8654 DEBUG("Fragment timeout found:"<<
8655 " ctimeOutValue=" <<ctimeOutValue
8656 <<", texpiredTime="<<texpiredTime[Ti]<<endl
8657 <<" tfragTimer="<<tfragTimer[Ti]
8658 <<", ctcTimer="<<ctcTimer);
8659 timeOutFoundFragLab(signal, TscanConPtr + Ti);
8660 return;
8661 }//if
8662 }//if
8663 }//for
8664 TscanConPtr += 8;
8665 /*----------------------------------------------------------------*/
8666 /* We split the process up checking 1024 fragmentrecords at a time*/
8667 /* to maintain real time behaviour. */
8668 /*----------------------------------------------------------------*/
8669 if (TloopCount++ > 128 ) {
8670 jam();
8671 signal->theData[0] = TcContinueB::ZCONTINUE_TIME_OUT_FRAG_CONTROL;
8672 signal->theData[1] = TscanConPtr;
8673 sendSignal(cownref, GSN_CONTINUEB, signal, 2, JBB);
8674 return;
8675 }//if
8676 }//while
8677 for ( ; TscanConPtr < cscanFragrecFileSize; TscanConPtr++){
8678 jam();
8679 timeOutPtr[0].i = TscanConPtr;
8680 c_scan_frag_pool.getPtrForce(timeOutPtr[0]);
8681 if (timeOutPtr[0].p->scanFragTimer != 0) {
8682 texpiredTime[0] = ctcTimer - timeOutPtr[0].p->scanFragTimer;
8683 if (texpiredTime[0] > ctimeOutValue) {
8684 jam();
8685 DEBUG("Fragment timeout found:"<<
8686 " ctimeOutValue=" <<ctimeOutValue
8687 <<", texpiredTime="<<texpiredTime[0]<<endl
8688 <<" tfragTimer="<<tfragTimer[0]
8689 <<", ctcTimer="<<ctcTimer);
8690 timeOutFoundFragLab(signal, TscanConPtr);
8691 return;
8692 }//if
8693 }//if
8694 }//for
8695 ctimeOutCheckFragActive = TOCS_FALSE;
8696
8697 return;
8698 }//timeOutLoopStartFragLab()
8699
8700 /*--------------------------------------------------------------------------*/
8701 /*Handle the heartbeat signal from LQH in a scan process */
8702 // (Set timer on fragrec.)
8703 /*--------------------------------------------------------------------------*/
execSCAN_HBREP(Signal * signal)8704 void Dbtc::execSCAN_HBREP(Signal* signal)
8705 {
8706 jamEntry();
8707
8708 scanFragptr.i = signal->theData[0];
8709 c_scan_frag_pool.getPtr(scanFragptr);
8710 switch (scanFragptr.p->scanFragState){
8711 case ScanFragRec::LQH_ACTIVE:
8712 break;
8713 default:
8714 DEBUG("execSCAN_HBREP: scanFragState="<<scanFragptr.p->scanFragState);
8715 systemErrorLab(signal, __LINE__);
8716 break;
8717 }
8718
8719 ScanRecordPtr scanptr;
8720 scanptr.i = scanFragptr.p->scanRec;
8721 ptrCheckGuard(scanptr, cscanrecFileSize, scanRecord);
8722
8723 apiConnectptr.i = scanptr.p->scanApiRec;
8724 ptrCheckGuard(apiConnectptr, capiConnectFilesize, apiConnectRecord);
8725
8726 if (!(apiConnectptr.p->transid[0] == signal->theData[1] &&
8727 apiConnectptr.p->transid[1] == signal->theData[2])){
8728 jam();
8729 /**
8730 * Send signal back to sender so that the crash occurs there
8731 */
8732 // Save original transid
8733 signal->theData[3] = signal->theData[0];
8734 signal->theData[4] = signal->theData[1];
8735 // Set transid to illegal values
8736 signal->theData[1] = RNIL;
8737 signal->theData[2] = RNIL;
8738
8739 sendSignal(signal->senderBlockRef(), GSN_SCAN_HBREP, signal, 5, JBA);
8740 DEBUG("SCAN_HBREP with wrong transid("
8741 <<signal->theData[3]<<", "<<signal->theData[4]<<")");
8742 return;
8743 }//if
8744
8745 // Update timer on ScanFragRec
8746 if (scanFragptr.p->scanFragTimer != 0){
8747 updateBuddyTimer(apiConnectptr);
8748 scanFragptr.p->startFragTimer(ctcTimer);
8749 } else {
8750 ndbassert(false);
8751 DEBUG("SCAN_HBREP when scanFragTimer was turned off");
8752 }
8753 }//execSCAN_HBREP()
8754
8755 /*--------------------------------------------------------------------------*/
8756 /* Timeout has occured on a fragment which means a scan has timed out. */
8757 /* If this is true we have an error in LQH/ACC. */
8758 /*--------------------------------------------------------------------------*/
timeOutFoundFragLab(Signal * signal,UintR TscanConPtr)8759 void Dbtc::timeOutFoundFragLab(Signal* signal, UintR TscanConPtr)
8760 {
8761 ScanFragRecPtr ptr;
8762 c_scan_frag_pool.getPtr(ptr, TscanConPtr);
8763 #ifdef VM_TRACE
8764 {
8765 ScanRecordPtr scanptr;
8766 scanptr.i = ptr.p->scanRec;
8767 ptrCheckGuard(scanptr, cscanrecFileSize, scanRecord);
8768 ApiConnectRecordPtr TlocalApiConnectptr;
8769 TlocalApiConnectptr.i = scanptr.p->scanApiRec;
8770 ptrCheckGuard(TlocalApiConnectptr, capiConnectFilesize, apiConnectRecord);
8771
8772 DEBUG("[ H'" << hex << TlocalApiConnectptr.p->transid[0]
8773 << " H'" << TlocalApiConnectptr.p->transid[1] << "] "
8774 << TscanConPtr << " timeOutFoundFragLab: scanFragState = "
8775 << ptr.p->scanFragState);
8776 }
8777 #endif
8778
8779 const Uint32 time_out_param= ctimeOutValue;
8780 const Uint32 old_time_out_param= c_abortRec.oldTimeOutValue;
8781
8782 if (unlikely(time_out_param != old_time_out_param &&
8783 getNodeState().getSingleUserMode()))
8784 {
8785 jam();
8786 ScanRecordPtr scanptr;
8787 scanptr.i = ptr.p->scanRec;
8788 ptrCheckGuard(scanptr, cscanrecFileSize, scanRecord);
8789 ApiConnectRecordPtr TlocalApiConnectptr;
8790 TlocalApiConnectptr.i = scanptr.p->scanApiRec;
8791 ptrCheckGuard(TlocalApiConnectptr, capiConnectFilesize, apiConnectRecord);
8792
8793 if (refToNode(TlocalApiConnectptr.p->ndbapiBlockref) ==
8794 getNodeState().getSingleUserApi())
8795 {
8796 jam();
8797 Uint32 val = ctcTimer - ptr.p->scanFragTimer;
8798 if (val <= old_time_out_param)
8799 {
8800 jam();
8801 goto next;
8802 }
8803 }
8804 }
8805
8806 /*-------------------------------------------------------------------------*/
8807 // The scan fragment has expired its timeout. Check its state to decide
8808 // what to do.
8809 /*-------------------------------------------------------------------------*/
8810 switch (ptr.p->scanFragState) {
8811 case ScanFragRec::WAIT_GET_PRIMCONF:
8812 jam();
8813 /**
8814 * Time-out waiting for local DIH, we will continue waiting forever.
8815 * This should only occur when we run in an unstable environment where
8816 * the main thread goes slow.
8817 * We reset timer to avoid getting here again immediately.
8818 */
8819 ptr.p->startFragTimer(ctcTimer);
8820 #ifdef VM_TRACE
8821 g_eventLogger->warning("Time-out in WAIT_GET_PRIMCONF: scanRecord = %u",
8822 ptr.i);
8823 #endif
8824 break;
8825 case ScanFragRec::LQH_ACTIVE:{
8826 jam();
8827
8828 /**
8829 * The LQH expired it's timeout, try to close it
8830 */
8831 NodeId nodeId = refToNode(ptr.p->lqhBlockref);
8832 Uint32 connectCount = getNodeInfo(nodeId).m_connectCount;
8833 ScanRecordPtr scanptr;
8834 scanptr.i = ptr.p->scanRec;
8835 ptrCheckGuard(scanptr, cscanrecFileSize, scanRecord);
8836
8837 if(connectCount != ptr.p->m_connectCount){
8838 jam();
8839 /**
8840 * The node has died
8841 */
8842 ptr.p->scanFragState = ScanFragRec::COMPLETED;
8843 ptr.p->stopFragTimer();
8844 {
8845 ScanFragList run(c_scan_frag_pool, scanptr.p->m_running_scan_frags);
8846 run.release(ptr);
8847 }
8848 }
8849
8850 scanError(signal, scanptr, ZSCAN_FRAG_LQH_ERROR);
8851 break;
8852 }
8853 case ScanFragRec::DELIVERED:
8854 jam();
8855 case ScanFragRec::IDLE:
8856 jam();
8857 case ScanFragRec::QUEUED_FOR_DELIVERY:
8858 jam();
8859 /*-----------------------------------------------------------------------
8860 * Should never occur. We will simply report set the timer to zero and
8861 * continue. In a debug version we should crash here but not in a release
8862 * version. In a release version we will simply set the time-out to zero.
8863 *-----------------------------------------------------------------------*/
8864 #ifdef VM_TRACE
8865 systemErrorLab(signal, __LINE__);
8866 #endif
8867 scanFragptr.p->stopFragTimer();
8868 break;
8869 default:
8870 jam();
8871 /*-----------------------------------------------------------------------
8872 * Non-existent state. Crash.
8873 *-----------------------------------------------------------------------*/
8874 systemErrorLab(signal, __LINE__);
8875 break;
8876 }//switch
8877
8878 next:
8879 signal->theData[0] = TcContinueB::ZCONTINUE_TIME_OUT_FRAG_CONTROL;
8880 signal->theData[1] = TscanConPtr + 1;
8881 sendSignal(cownref, GSN_CONTINUEB, signal, 2, JBB);
8882 return;
8883 }//timeOutFoundFragLab()
8884
8885
8886 /*
8887 4.3.16 GCP_NOMORETRANS
8888 ----------------------
8889 */
8890 /*****************************************************************************
8891 * G C P _ N O M O R E T R A N S
8892 *
8893 * WHEN DBTC RECEIVES SIGNAL GCP_NOMORETRANS A CHECK IS DONE TO FIND OUT IF
8894 * THERE ARE ANY GLOBAL CHECKPOINTS GOING ON - CFIRSTGCP /= RNIL. DBTC THEN
8895 * SEARCHES THE GCP_RECORD FILE TO FIND OUT IF THERE ARE ANY TRANSACTIONS NOT
8896 * CONCLUDED WITH THIS SPECIFIC CHECKPOINT - GCP_PTR:GCP_ID = TCHECK_GCP_ID.
8897 * FOR EACH TRANSACTION WHERE API_CONNECTSTATE EQUALS PREPARED, COMMITTING,
8898 * COMMITTED OR COMPLETING SIGNAL CONTINUEB IS SENT WITH A DELAY OF 100 MS,
8899 * THE COUNTER GCP_PTR:OUTSTANDINGAPI IS INCREASED. WHEN CONTINUEB IS RECEIVED
8900 * THE COUNTER IS DECREASED AND A CHECK IS DONE TO FIND OUT IF ALL
8901 * TRANSACTIONS ARE CONCLUDED. IF SO, SIGNAL GCP_TCFINISHED IS SENT.
8902 *****************************************************************************/
execGCP_NOMORETRANS(Signal * signal)8903 void Dbtc::execGCP_NOMORETRANS(Signal* signal)
8904 {
8905 jamEntry();
8906 GCPNoMoreTrans* req = (GCPNoMoreTrans*)signal->getDataPtr();
8907 c_gcp_ref = req->senderRef;
8908 c_gcp_data = req->senderData;
8909 Uint32 gci_lo = req->gci_lo;
8910 Uint32 gci_hi = req->gci_hi;
8911 tcheckGcpId = gci_lo | (Uint64(gci_hi) << 32);
8912
8913 Ptr<GcpRecord> gcpPtr;
8914 if (cfirstgcp != RNIL) {
8915 jam();
8916 /* A GLOBAL CHECKPOINT IS GOING ON */
8917 gcpPtr.i = cfirstgcp; /* SET POINTER TO FIRST GCP IN QUEUE*/
8918 ptrCheckGuard(gcpPtr, cgcpFilesize, gcpRecord);
8919 if (gcpPtr.p->gcpId == tcheckGcpId)
8920 {
8921 jam();
8922 bool empty = gcpPtr.p->firstApiConnect == RNIL;
8923 bool nfhandling = c_ongoing_take_over_cnt;
8924
8925 if (empty && nfhandling)
8926 {
8927 jam();
8928 ndbout_c("NOT returning gcpTcfinished due to nfhandling %u/%u",
8929 gci_hi, gci_lo);
8930 }
8931
8932 if (!empty || c_ongoing_take_over_cnt)
8933 {
8934 jam();
8935 gcpPtr.p->gcpNomoretransRec = ZTRUE;
8936 } else {
8937 jam();
8938 gcpTcfinished(signal, tcheckGcpId);
8939 unlinkGcp(gcpPtr);
8940 }//if
8941 }
8942 else if (c_ongoing_take_over_cnt == 0)
8943 {
8944 jam();
8945 /*------------------------------------------------------------*/
8946 /* IF IT IS NOT THE FIRST THEN THERE SHOULD BE NO */
8947 /* RECORD FOR THIS GLOBAL CHECKPOINT. WE ALWAYS REMOVE */
8948 /* THE GLOBAL CHECKPOINTS IN ORDER. */
8949 /*------------------------------------------------------------*/
8950 gcpTcfinished(signal, tcheckGcpId);
8951 }
8952 else
8953 {
8954 jam();
8955 goto outoforder;
8956 }
8957 }
8958 else if (c_ongoing_take_over_cnt == 0)
8959 {
8960 jam();
8961 gcpTcfinished(signal, tcheckGcpId);
8962 }
8963 else
8964 {
8965 seize:
8966 jam();
8967 ndbout_c("execGCP_NOMORETRANS(%u/%u) c_ongoing_take_over_cnt -> seize",
8968 gci_hi, gci_lo);
8969 seizeGcp(gcpPtr, tcheckGcpId);
8970 gcpPtr.p->gcpNomoretransRec = ZTRUE;
8971 }
8972 return;
8973
8974 outoforder:
8975 printf("ooo: execGCP_NOMORETRANS tcheckGcpId: %u/%u cfirstgcp: %u/%u",
8976 gci_hi, gci_lo,
8977 Uint32(gcpPtr.p->gcpId >> 32), Uint32(gcpPtr.p->gcpId));
8978
8979 if (tcheckGcpId < gcpPtr.p->gcpId)
8980 {
8981 jam();
8982
8983 Ptr<GcpRecord> tmp;
8984 tmp.i = cfirstfreeGcp;
8985 ptrCheckGuard(tmp, cgcpFilesize, gcpRecord);
8986 cfirstfreeGcp = tmp.p->nextGcp;
8987
8988 tmp.p->gcpId = tcheckGcpId;
8989 tmp.p->nextGcp = cfirstgcp;
8990 tmp.p->firstApiConnect = RNIL;
8991 tmp.p->lastApiConnect = RNIL;
8992 tmp.p->gcpNomoretransRec = ZTRUE;
8993 cfirstgcp = tmp.i;
8994 ndbout_c("LINK FIRST");
8995 return;
8996 }
8997 else
8998 {
8999 Ptr<GcpRecord> prev = gcpPtr;
9000 while (tcheckGcpId > gcpPtr.p->gcpId)
9001 {
9002 jam();
9003 if (gcpPtr.p->nextGcp == RNIL)
9004 {
9005 printf("nextGcp == RNIL -> ");
9006 goto seize;
9007 }
9008
9009 prev = gcpPtr;
9010 gcpPtr.i = gcpPtr.p->nextGcp;
9011 ptrCheckGuard(gcpPtr, cgcpFilesize, gcpRecord);
9012 }
9013
9014 if (tcheckGcpId == gcpPtr.p->gcpId)
9015 {
9016 jam();
9017 gcpPtr.p->gcpNomoretransRec = ZTRUE;
9018 ndbout_c("found");
9019 return;
9020 }
9021 ndbrequire(prev.i != gcpPtr.i); // checked earlier with initial "<"
9022 ndbrequire(prev.p->gcpId < tcheckGcpId);
9023 ndbrequire(gcpPtr.p->gcpId > tcheckGcpId);
9024
9025 Ptr<GcpRecord> tmp;
9026 tmp.i = cfirstfreeGcp;
9027 ptrCheckGuard(tmp, cgcpFilesize, gcpRecord);
9028 cfirstfreeGcp = tmp.p->nextGcp;
9029
9030 tmp.p->gcpId = tcheckGcpId;
9031 tmp.p->nextGcp = gcpPtr.i;
9032 tmp.p->firstApiConnect = RNIL;
9033 tmp.p->lastApiConnect = RNIL;
9034 tmp.p->gcpNomoretransRec = ZTRUE;
9035 prev.p->nextGcp = tmp.i;
9036 ndbout_c("link middle %u/%u < %u/%u < %u/%u",
9037 Uint32(prev.p->gcpId >> 32), Uint32(prev.p->gcpId),
9038 gci_hi, gci_lo,
9039 Uint32(gcpPtr.p->gcpId >> 32), Uint32(gcpPtr.p->gcpId));
9040 return;
9041 }
9042 }//Dbtc::execGCP_NOMORETRANS()
9043
9044 /*****************************************************************************/
9045 /* */
9046 /* TAKE OVER MODULE */
9047 /* */
9048 /*****************************************************************************/
9049 /* */
9050 /* THIS PART OF TC TAKES OVER THE COMMIT/ABORT OF TRANSACTIONS WHERE THE */
9051 /* NODE ACTING AS TC HAVE FAILED. IT STARTS BY QUERYING ALL NODES ABOUT */
9052 /* ANY OPERATIONS PARTICIPATING IN A TRANSACTION WHERE THE TC NODE HAVE */
9053 /* FAILED. */
9054 /* */
9055 /* AFTER RECEIVING INFORMATION FROM ALL NODES ABOUT OPERATION STATUS THIS */
9056 /* CODE WILL ENSURE THAT ALL AFFECTED TRANSACTIONS ARE PROPERLY ABORTED OR*/
9057 /* COMMITTED. THE ORIGINATING APPLICATION NODE WILL ALSO BE CONTACTED. */
9058 /* IF THE ORIGINATING APPLICATION ALSO FAILED THEN THERE IS CURRENTLY NO */
9059 /* WAY TO FIND OUT WHETHER A TRANSACTION WAS PERFORMED OR NOT. */
9060 /*****************************************************************************/
execNODE_FAILREP(Signal * signal)9061 void Dbtc::execNODE_FAILREP(Signal* signal)
9062 {
9063 jamEntry();
9064
9065 NodeFailRep * const nodeFail = (NodeFailRep *)&signal->theData[0];
9066
9067 cfailure_nr = nodeFail->failNo;
9068 const Uint32 tnoOfNodes = nodeFail->noOfNodes;
9069 const Uint32 tnewMasterId = nodeFail->masterNodeId;
9070 Uint32 cdata[MAX_NDB_NODES];
9071
9072 arrGuard(tnoOfNodes, MAX_NDB_NODES);
9073 Uint32 i;
9074 int index = 0;
9075 for (i = 1; i< MAX_NDB_NODES; i++)
9076 {
9077 if(NdbNodeBitmask::get(nodeFail->theNodes, i))
9078 {
9079 cdata[index] = i;
9080 index++;
9081 }//if
9082 }//for
9083
9084 cmasterNodeId = tnewMasterId;
9085
9086 if (ERROR_INSERTED(8098))
9087 SET_ERROR_INSERT_VALUE(8099); /* Disable 8098 on node failure */
9088
9089 HostRecordPtr myHostPtr;
9090
9091 tcNodeFailptr.i = 0;
9092 ptrAss(tcNodeFailptr, tcFailRecord);
9093 for (i = 0; i < tnoOfNodes; i++)
9094 {
9095 jam();
9096 myHostPtr.i = cdata[i];
9097 ptrCheckGuard(myHostPtr, chostFilesize, hostRecord);
9098
9099 /*------------------------------------------------------------*/
9100 /* SET STATUS OF THE FAILED NODE TO DEAD SINCE IT HAS */
9101 /* FAILED. */
9102 /*------------------------------------------------------------*/
9103 myHostPtr.p->hostStatus = HS_DEAD;
9104 myHostPtr.p->m_nf_bits = HostRecord::NF_NODE_FAIL_BITS;
9105 c_ongoing_take_over_cnt++;
9106 c_alive_nodes.clear(myHostPtr.i);
9107
9108 if (tcNodeFailptr.p->failStatus == FS_LISTENING)
9109 {
9110 jam();
9111 /*------------------------------------------------------------*/
9112 /* THE CURRENT TAKE OVER CAN BE AFFECTED BY THIS NODE */
9113 /* FAILURE. */
9114 /*------------------------------------------------------------*/
9115 if (myHostPtr.p->lqhTransStatus == LTS_ACTIVE)
9116 {
9117 jam();
9118 /*------------------------------------------------------------*/
9119 /* WE WERE WAITING FOR THE FAILED NODE IN THE TAKE OVER */
9120 /* PROTOCOL FOR TC. */
9121 /*------------------------------------------------------------*/
9122 signal->theData[0] = TcContinueB::ZNODE_TAKE_OVER_COMPLETED;
9123 signal->theData[1] = myHostPtr.i;
9124 sendSignal(cownref, GSN_CONTINUEB, signal, 2, JBB);
9125 }//if
9126 }//if
9127
9128 jam();
9129 signal->theData[0] = myHostPtr.i;
9130 sendSignal(cownref, GSN_TAKE_OVERTCREQ, signal, 1, JBB);
9131
9132 checkScanActiveInFailedLqh(signal, 0, myHostPtr.i);
9133 nodeFailCheckTransactions(signal, 0, myHostPtr.i);
9134 Callback cb = {safe_cast(&Dbtc::ndbdFailBlockCleanupCallback),
9135 myHostPtr.i};
9136 simBlockNodeFailure(signal, myHostPtr.i, cb);
9137 }
9138
9139 if (m_deferred_enabled == 0)
9140 {
9141 jam();
9142 Uint32 ok = 1;
9143 for(Uint32 n = c_alive_nodes.find_first();
9144 n != c_alive_nodes.NotFound;
9145 n = c_alive_nodes.find_next(n+1))
9146 {
9147 if (!ndbd_deferred_unique_constraints(getNodeInfo(n).m_version))
9148 {
9149 jam();
9150 ok = 0;
9151 break;
9152 }
9153 }
9154 if (ok)
9155 {
9156 jam();
9157 m_deferred_enabled = ~Uint32(0);
9158 }
9159 }
9160 }//Dbtc::execNODE_FAILREP()
9161
9162 void
checkNodeFailComplete(Signal * signal,Uint32 failedNodeId,Uint32 bit)9163 Dbtc::checkNodeFailComplete(Signal* signal,
9164 Uint32 failedNodeId,
9165 Uint32 bit)
9166 {
9167 hostptr.i = failedNodeId;
9168 ptrCheckGuard(hostptr, chostFilesize, hostRecord);
9169 hostptr.p->m_nf_bits &= ~bit;
9170 if (hostptr.p->m_nf_bits == 0)
9171 {
9172 NFCompleteRep * const nfRep = (NFCompleteRep *)&signal->theData[0];
9173 nfRep->blockNo = DBTC;
9174 nfRep->nodeId = cownNodeid;
9175 nfRep->failedNodeId = hostptr.i;
9176
9177 if (instance() == 0)
9178 {
9179 jam();
9180 sendSignal(cdihblockref, GSN_NF_COMPLETEREP, signal,
9181 NFCompleteRep::SignalLength, JBB);
9182 sendSignal(QMGR_REF, GSN_NF_COMPLETEREP, signal,
9183 NFCompleteRep::SignalLength, JBB);
9184 }
9185 else
9186 {
9187 /**
9188 * Send to proxy
9189 */
9190 sendSignal(DBTC_REF, GSN_NF_COMPLETEREP, signal,
9191 NFCompleteRep::SignalLength, JBB);
9192 }
9193 }
9194
9195 CRASH_INSERTION(8058);
9196 if (ERROR_INSERTED(8059))
9197 {
9198 signal->theData[0] = 9999;
9199 sendSignalWithDelay(numberToRef(CMVMI, hostptr.i),
9200 GSN_NDB_TAMPER, signal, 100, 1);
9201 }
9202 }
9203
checkScanActiveInFailedLqh(Signal * signal,Uint32 scanPtrI,Uint32 failedNodeId)9204 void Dbtc::checkScanActiveInFailedLqh(Signal* signal,
9205 Uint32 scanPtrI,
9206 Uint32 failedNodeId){
9207
9208 ScanRecordPtr scanptr;
9209 for (scanptr.i = scanPtrI; scanptr.i < cscanrecFileSize; scanptr.i++) {
9210 jam();
9211 ptrAss(scanptr, scanRecord);
9212 bool found = false;
9213 if (scanptr.p->scanState != ScanRecord::IDLE){
9214 jam();
9215 ScanFragRecPtr ptr;
9216 ScanFragList run(c_scan_frag_pool, scanptr.p->m_running_scan_frags);
9217
9218 for(run.first(ptr); !ptr.isNull(); ){
9219 jam();
9220 ScanFragRecPtr curr = ptr;
9221 run.next(ptr);
9222 if (curr.p->scanFragState == ScanFragRec::LQH_ACTIVE &&
9223 refToNode(curr.p->lqhBlockref) == failedNodeId){
9224 jam();
9225
9226 run.release(curr);
9227 curr.p->scanFragState = ScanFragRec::COMPLETED;
9228 curr.p->stopFragTimer();
9229 found = true;
9230 }
9231 }
9232
9233 ScanFragList deliv(c_scan_frag_pool, scanptr.p->m_delivered_scan_frags);
9234 for(deliv.first(ptr); !ptr.isNull(); deliv.next(ptr))
9235 {
9236 jam();
9237 if (refToNode(ptr.p->lqhBlockref) == failedNodeId)
9238 {
9239 jam();
9240 found = true;
9241 break;
9242 }
9243 }
9244 }
9245 if(found){
9246 jam();
9247 scanError(signal, scanptr, ZSCAN_LQH_ERROR);
9248 }
9249
9250 // Send CONTINUEB to continue later
9251 signal->theData[0] = TcContinueB::ZCHECK_SCAN_ACTIVE_FAILED_LQH;
9252 signal->theData[1] = scanptr.i + 1; // Check next scanptr
9253 signal->theData[2] = failedNodeId;
9254 sendSignal(cownref, GSN_CONTINUEB, signal, 3, JBB);
9255 return;
9256 }//for
9257
9258 checkNodeFailComplete(signal, failedNodeId, HostRecord::NF_CHECK_SCAN);
9259 }
9260
9261 void
nodeFailCheckTransactions(Signal * signal,Uint32 transPtrI,Uint32 failedNodeId)9262 Dbtc::nodeFailCheckTransactions(Signal* signal,
9263 Uint32 transPtrI,
9264 Uint32 failedNodeId)
9265 {
9266 jam();
9267 Ptr<ApiConnectRecord> transPtr;
9268 Uint32 TtcTimer = ctcTimer;
9269 Uint32 TapplTimeout = c_appl_timeout_value;
9270 Uint32 RT_BREAK = 64;
9271 Uint32 endPtrI = transPtrI + RT_BREAK;
9272 if (endPtrI > capiConnectFilesize)
9273 {
9274 endPtrI = capiConnectFilesize;
9275 }
9276
9277 for (transPtr.i = transPtrI; transPtr.i < endPtrI; transPtr.i++)
9278 {
9279 ptrCheckGuard(transPtr, capiConnectFilesize, apiConnectRecord);
9280 if (transPtr.p->m_transaction_nodes.get(failedNodeId))
9281 {
9282 jam();
9283
9284 // Force timeout regardless of state
9285 c_appl_timeout_value = 1;
9286 setApiConTimer(transPtr.i, TtcTimer - 2, __LINE__);
9287 timeOutFoundLab(signal, transPtr.i, ZNODEFAIL_BEFORE_COMMIT);
9288 c_appl_timeout_value = TapplTimeout;
9289
9290 transPtr.i++;
9291 break;
9292 }
9293 }
9294
9295 if (transPtr.i == capiConnectFilesize)
9296 {
9297 jam();
9298 checkNodeFailComplete(signal, failedNodeId,
9299 HostRecord::NF_CHECK_TRANSACTION);
9300 }
9301 else
9302 {
9303 signal->theData[0] = TcContinueB::ZNF_CHECK_TRANSACTIONS;
9304 signal->theData[1] = transPtr.i;
9305 signal->theData[2] = failedNodeId;
9306 sendSignal(cownref, GSN_CONTINUEB, signal, 3, JBB);
9307 }
9308 }
9309
9310 void
ndbdFailBlockCleanupCallback(Signal * signal,Uint32 failedNodeId,Uint32 ignoredRc)9311 Dbtc::ndbdFailBlockCleanupCallback(Signal* signal,
9312 Uint32 failedNodeId,
9313 Uint32 ignoredRc)
9314 {
9315 jamEntry();
9316
9317 checkNodeFailComplete(signal, failedNodeId,
9318 HostRecord::NF_BLOCK_HANDLE);
9319 }
9320
9321 void
apiFailBlockCleanupCallback(Signal * signal,Uint32 failedNodeId,Uint32 ignoredRc)9322 Dbtc::apiFailBlockCleanupCallback(Signal* signal,
9323 Uint32 failedNodeId,
9324 Uint32 ignoredRc)
9325 {
9326 jamEntry();
9327
9328 signal->theData[0] = failedNodeId;
9329 signal->theData[1] = reference();
9330 sendSignal(capiFailRef, GSN_API_FAILCONF, signal, 2, JBB);
9331 }
9332
9333 void
checkScanFragList(Signal * signal,Uint32 failedNodeId,ScanRecord * scanP,ScanFragList::Head & head)9334 Dbtc::checkScanFragList(Signal* signal,
9335 Uint32 failedNodeId,
9336 ScanRecord * scanP,
9337 ScanFragList::Head & head){
9338
9339 DEBUG("checkScanActiveInFailedLqh: scanFragError");
9340 }
9341
execTAKE_OVERTCCONF(Signal * signal)9342 void Dbtc::execTAKE_OVERTCCONF(Signal* signal)
9343 {
9344 jamEntry();
9345
9346 if (!checkNodeFailSequence(signal))
9347 {
9348 jam();
9349 return;
9350 }
9351
9352 Uint32 failedNodeId = signal->theData[0];
9353 hostptr.i = failedNodeId;
9354 ptrCheckGuard(hostptr, chostFilesize, hostRecord);
9355
9356 Uint32 senderRef = signal->theData[1];
9357 if (signal->getLength() < 2)
9358 {
9359 jam();
9360 senderRef = 0; // currently only used to see if it's from self
9361 }
9362
9363 if (senderRef != reference())
9364 {
9365 jam();
9366
9367 tcNodeFailptr.i = 0;
9368 ptrAss(tcNodeFailptr, tcFailRecord);
9369
9370 /**
9371 * Node should be in queue
9372 */
9373 Uint32 i = 0;
9374 Uint32 end = tcNodeFailptr.p->queueIndex;
9375 for (; i<end; i++)
9376 {
9377 jam();
9378 if (tcNodeFailptr.p->queueList[i] == hostptr.i)
9379 {
9380 g_eventLogger->info("DBTC instance %u: Removed node %u"
9381 " from takeover queue, %u failed nodes remaining",
9382 instance(),
9383 hostptr.i,
9384 end - 1);
9385
9386 jam();
9387 break;
9388 }
9389 }
9390 ndbrequire(i != end);
9391 tcNodeFailptr.p->queueList[i] = tcNodeFailptr.p->queueList[end-1];
9392 tcNodeFailptr.p->queueIndex = end - 1;
9393 }
9394
9395 Uint32 cnt = c_ongoing_take_over_cnt;
9396 ndbrequire(cnt);
9397 c_ongoing_take_over_cnt = cnt - 1;
9398 checkNodeFailComplete(signal, hostptr.i, HostRecord::NF_TAKEOVER);
9399
9400 if (cnt == 1 && cfirstgcp != RNIL)
9401 {
9402 /**
9403 * Check if there are any hanging GCP_NOMORETRANS
9404 */
9405 GcpRecordPtr tmpGcpPointer;
9406 tmpGcpPointer.i = cfirstgcp;
9407 ptrCheckGuard(tmpGcpPointer, cgcpFilesize, gcpRecord);
9408 if (tmpGcpPointer.p->gcpNomoretransRec &&
9409 tmpGcpPointer.p->firstApiConnect == RNIL)
9410 {
9411 jam();
9412 ndbout_c("completing gcp %u/%u in execTAKE_OVERTCCONF",
9413 Uint32(tmpGcpPointer.p->gcpId >> 32),
9414 Uint32(tmpGcpPointer.p->gcpId));
9415 gcpTcfinished(signal, tmpGcpPointer.p->gcpId);
9416 unlinkGcp(tmpGcpPointer);
9417 }
9418 }
9419 }//Dbtc::execTAKE_OVERTCCONF()
9420
execTAKE_OVERTCREQ(Signal * signal)9421 void Dbtc::execTAKE_OVERTCREQ(Signal* signal)
9422 {
9423 jamEntry();
9424 Uint32 failedNodeId = signal->theData[0];
9425 tcNodeFailptr.i = 0;
9426 ptrAss(tcNodeFailptr, tcFailRecord);
9427 if (tcNodeFailptr.p->failStatus != FS_IDLE ||
9428 cmasterNodeId != getOwnNodeId() ||
9429 (! (instance() == 0 /* single TC */ ||
9430 instance() == TAKE_OVER_INSTANCE))) /* in mt-TC case let 1 instance
9431 do take-over */
9432 {
9433 jam();
9434 /*------------------------------------------------------------*/
9435 /* WE CAN CURRENTLY ONLY HANDLE ONE TAKE OVER AT A TIME */
9436 /*------------------------------------------------------------*/
9437 /* IF MORE THAN ONE TAKE OVER IS REQUESTED WE WILL */
9438 /* QUEUE THE TAKE OVER AND START IT AS SOON AS THE */
9439 /* PREVIOUS ARE COMPLETED. */
9440 /*------------------------------------------------------------*/
9441 g_eventLogger->info("DBTC instance %u: Inserting failed node %u into"
9442 " takeover queue, length now=%u",
9443 instance(),
9444 failedNodeId,
9445 tcNodeFailptr.p->queueIndex + 1);
9446 arrGuard(tcNodeFailptr.p->queueIndex, MAX_NDB_NODES);
9447 tcNodeFailptr.p->queueList[tcNodeFailptr.p->queueIndex] = failedNodeId;
9448 tcNodeFailptr.p->queueIndex++;
9449 return;
9450 }//if
9451 ndbrequire(instance() == 0 || instance() == TAKE_OVER_INSTANCE);
9452 g_eventLogger->info("DBTC instance %u: Starting take over of node %u",
9453 instance(),
9454 failedNodeId);
9455 startTakeOverLab(signal, 0, failedNodeId);
9456 }//Dbtc::execTAKE_OVERTCREQ()
9457
9458 /**
9459 TC Takeover protocol
9460 --------------------
9461 When a node fails it has a set of transactions ongoing in many cases. In
9462 order to complete those transactions we have implemented a take over
9463 protocol.
9464
9465 The failed node was transaction controller for a set of transactions.
9466 The transaction controller has failed, so we cannot ask it for the
9467 state of the transactions. This means that we need to rebuild the
9468 transaction state of all transactions that was controlled by the failed
9469 node. If there are several node failures at the same time, then we'll
9470 take over one node at a time. The TC take over is only handled by the
9471 first TC instance, most of the work of the take over is handled by the
9472 LQH instances that need to scan all ongoing operations to send the
9473 operations to the TC instance that takes over. For the ndbd it is handled
9474 by the TC instance simply.
9475
9476 With the introduction of multiple TC instances we have also seen it fit
9477 to handle also the take over of one TC instance in multiple steps. We use
9478 one step per TC instance we take over. If the TC take over fails due to
9479 not having sufficient amount of transaction records or operations records,
9480 we will also run several steps for each TC instance we take over.
9481
9482 The TC take over process will eventually complete as long as there isn't
9483 any transaction that is bigger than the number of operation records
9484 available for TC take over.
9485
9486 The protocol works as follows:
9487
9488 Master TC (take over TC instance, starting at instance 0):
9489 Sends:
9490 LQH_TRANSREQ (Take over data reference,
9491 Master TC block reference,
9492 TC Take over node id,
9493 TC Take over instance id)
9494
9495 This signal is sent to the LQH proxy block in each of the alive nodes.
9496 From the proxy block it is sent to each LQH instance. For ndbd's we
9497 send it directly to the LQH block.
9498
9499 Each LQH instance scans the operations for any operations that has a
9500 TC reference that comes from the TC node and TC instance that has failed.
9501 For each such operation it sends a LQH_TRANSCONF signal that contains a
9502 lot of data about the transaction operation.
9503
9504 When the LQH instance have completed the scan of its operations then it
9505 will send a special LQH_TRANSCONF with a last operation flag set. All
9506 LQH_TRANSCONF is sent through the LQH proxy such that we can check when
9507 all LQH instances have completed their scans. We will only send one
9508 LQH_TRANSCONF signal from each node.
9509
9510 The Master TC that performs the take over builds the state of each
9511 transaction such that it can decide whether the transaction was
9512 committed or not, if it wasn't committed we will abort it.
9513
9514 The design is certain that each step will at least handle one transaction
9515 for each take over step. Normally it will complete all transactions in
9516 one instance in each step, we can though handle also other uncommon cases.
9517 */
9518
9519 /*------------------------------------------------------------*/
9520 /* INITIALISE THE HASH TABLES FOR STORING TRANSACTIONS */
9521 /* AND OPERATIONS DURING TC TAKE OVER. */
9522 /*------------------------------------------------------------*/
startTakeOverLab(Signal * signal,Uint32 instanceId,Uint32 failedNodeId)9523 void Dbtc::startTakeOverLab(Signal* signal,
9524 Uint32 instanceId,
9525 Uint32 failedNodeId)
9526 {
9527 for (Uint32 i = 0; i < TRANSID_FAIL_HASH_SIZE; i++) {
9528 ctransidFailHash[i] = RNIL;
9529 }//for
9530 for (Uint32 i = 0; i < TC_FAIL_HASH_SIZE; i++) {
9531 ctcConnectFailHash[i] = RNIL;
9532 }//for
9533 tcNodeFailptr.p->failStatus = FS_LISTENING;
9534 tcNodeFailptr.p->takeOverNode = failedNodeId;
9535 tcNodeFailptr.p->takeOverInstanceId = instanceId;
9536 tcNodeFailptr.p->takeOverFailed = false;
9537 tcNodeFailptr.p->maxInstanceId = 0;
9538 tcNodeFailptr.p->handledOneTransaction = false;
9539 for (hostptr.i = 1; hostptr.i < MAX_NDB_NODES; hostptr.i++) {
9540 jam();
9541 ptrAss(hostptr, hostRecord);
9542 if (hostptr.p->hostStatus == HS_ALIVE)
9543 {
9544 LqhTransReq * const lqhTransReq = (LqhTransReq *)&signal->theData[0];
9545 Uint32 sig_len;
9546 jam();
9547 tblockref = calcLqhBlockRef(hostptr.i);
9548 hostptr.p->lqhTransStatus = LTS_ACTIVE;
9549 lqhTransReq->senderData = tcNodeFailptr.i;
9550 lqhTransReq->senderRef = cownref;
9551 lqhTransReq->failedNodeId = failedNodeId;
9552 lqhTransReq->instanceId = instanceId;
9553 if (ndbd_multi_tc_instance_takeover(getNodeInfo(hostptr.i).m_version))
9554 {
9555 /* The node does support the new LQH_TRANSREQ protocol */
9556 sig_len = LqhTransReq::SignalLength;
9557 }
9558 else
9559 {
9560 sig_len = LqhTransReq::OldSignalLength;
9561 }
9562 if (ERROR_INSERTED(8064) && hostptr.i == getOwnNodeId())
9563 {
9564 ndbout_c("sending delayed GSN_LQH_TRANSREQ to self");
9565 sendSignalWithDelay(tblockref, GSN_LQH_TRANSREQ, signal, 100, sig_len);
9566 CLEAR_ERROR_INSERT_VALUE;
9567 }
9568 else
9569 {
9570 sendSignal(tblockref, GSN_LQH_TRANSREQ, signal, sig_len, JBB);
9571 }
9572 }//if
9573 }//for
9574 }//Dbtc::startTakeOverLab()
9575
9576 Uint32
get_transid_fail_bucket(Uint32 transid1)9577 Dbtc::get_transid_fail_bucket(Uint32 transid1)
9578 {
9579 return transid1 & (TRANSID_FAIL_HASH_SIZE - 1);
9580 }
9581
9582 void
insert_transid_fail_hash(Uint32 transid1)9583 Dbtc::insert_transid_fail_hash(Uint32 transid1)
9584 {
9585 Uint32 bucket = get_transid_fail_bucket(transid1);
9586 apiConnectptr.p->nextApiConnect = ctransidFailHash[bucket];
9587 ctransidFailHash[bucket] = apiConnectptr.i;
9588 return;
9589 }
9590
9591 bool
findApiConnectFail(Signal * signal,Uint32 transid1,Uint32 transid2)9592 Dbtc::findApiConnectFail(Signal *signal, Uint32 transid1, Uint32 transid2)
9593 {
9594 Uint32 bucket = get_transid_fail_bucket(transid1);
9595 apiConnectptr.i = ctransidFailHash[bucket];
9596
9597 while (apiConnectptr.i != RNIL)
9598 {
9599 jam();
9600 ptrCheckGuard(apiConnectptr, capiConnectFilesize, apiConnectRecord);
9601 if (apiConnectptr.p->transid[0] == transid1 &&
9602 apiConnectptr.p->transid[1] == transid2)
9603 {
9604 jam();
9605 return true;
9606 }
9607 apiConnectptr.i = apiConnectptr.p->nextApiConnect;
9608 }
9609 jam();
9610 return false;
9611 }
9612
releaseMarker(ApiConnectRecord * const regApiPtr)9613 void Dbtc::releaseMarker(ApiConnectRecord * const regApiPtr)
9614 {
9615 Uint32 marker = regApiPtr->commitAckMarker;
9616 if (marker != RNIL)
9617 {
9618 regApiPtr->commitAckMarker = RNIL;
9619 CommitAckMarkerBuffer::DataBufferPool & pool =
9620 c_theCommitAckMarkerBufferPool;
9621 CommitAckMarker * tmp = m_commitAckMarkerHash.getPtr(marker);
9622 LocalDataBuffer<5> commitAckMarkers(pool, tmp->theDataBuffer);
9623 commitAckMarkers.release();
9624 m_commitAckMarkerHash.release(marker);
9625 }
9626 }
9627
remove_from_transid_fail_hash(Signal * signal,Uint32 transid1)9628 void Dbtc::remove_from_transid_fail_hash(Signal *signal, Uint32 transid1)
9629 {
9630 ApiConnectRecordPtr locApiConnectptr;
9631 ApiConnectRecordPtr prevApiConptr;
9632
9633 prevApiConptr.i = RNIL;
9634 Uint32 bucket = get_transid_fail_bucket(transid1);
9635 locApiConnectptr.i = ctransidFailHash[bucket];
9636 ndbrequire(locApiConnectptr.i != RNIL);
9637 do
9638 {
9639 ptrCheckGuard(locApiConnectptr, capiConnectFilesize, apiConnectRecord);
9640 if (locApiConnectptr.i == apiConnectptr.i)
9641 {
9642 if (prevApiConptr.i == RNIL)
9643 {
9644 jam();
9645 /* We were first in the hash linked list */
9646 ndbassert(ctransidFailHash[bucket] == apiConnectptr.i);
9647 ctransidFailHash[bucket] = apiConnectptr.p->nextApiConnect;
9648 }
9649 else
9650 {
9651 /* Link past our record in the hash list */
9652 jam();
9653 ptrCheckGuard(prevApiConptr, capiConnectFilesize, apiConnectRecord);
9654 prevApiConptr.p->nextApiConnect = apiConnectptr.p->nextApiConnect;
9655 }
9656 apiConnectptr.p->nextApiConnect = RNIL;
9657 return;
9658 }
9659 else
9660 {
9661 jam();
9662 prevApiConptr.i = locApiConnectptr.i;
9663 locApiConnectptr.i = locApiConnectptr.p->nextApiConnect;
9664 }
9665 } while (locApiConnectptr.i != RNIL);
9666 ndbrequire(false);
9667 }
9668
9669 Uint32
get_tc_fail_bucket(Uint32 transid1,Uint32 opRec)9670 Dbtc::get_tc_fail_bucket(Uint32 transid1, Uint32 opRec)
9671 {
9672 return (transid1 ^ opRec) & (TC_FAIL_HASH_SIZE - 1);
9673 }
9674
9675 void
insert_tc_fail_hash(Uint32 transid1,Uint32 tcOprec)9676 Dbtc::insert_tc_fail_hash(Uint32 transid1, Uint32 tcOprec)
9677 {
9678 Uint32 bucket = get_tc_fail_bucket(transid1, tcOprec);
9679 tcConnectptr.p->nextTcFailHash = ctcConnectFailHash[bucket];
9680 ctcConnectFailHash[bucket] = tcConnectptr.i;
9681 }
9682
9683 bool
findTcConnectFail(Signal * signal,Uint32 transid1,Uint32 transid2,Uint32 tcOprec)9684 Dbtc::findTcConnectFail(Signal* signal,
9685 Uint32 transid1,
9686 Uint32 transid2,
9687 Uint32 tcOprec)
9688 {
9689 Uint32 bucket = get_tc_fail_bucket(transid1, tcOprec);
9690
9691 tcConnectptr.i = ctcConnectFailHash[bucket];
9692 while (tcConnectptr.i != RNIL)
9693 {
9694 ptrCheckGuard(tcConnectptr, ctcConnectFilesize, tcConnectRecord);
9695 if (tcConnectptr.p->tcOprec == tcOprec &&
9696 tcConnectptr.p->apiConnect == apiConnectptr.i &&
9697 apiConnectptr.p->transid[0] == transid1 &&
9698 apiConnectptr.p->transid[1] == transid2)
9699 {
9700 jam();
9701 return true;
9702 }
9703 else
9704 {
9705 jam();
9706 tcConnectptr.i = tcConnectptr.p->nextTcFailHash;
9707 }
9708 }
9709 jam();
9710 return false;
9711 }
9712
remove_transaction_from_tc_fail_hash(Signal * signal)9713 void Dbtc::remove_transaction_from_tc_fail_hash(Signal *signal)
9714 {
9715 TcConnectRecordPtr remTcConnectptr;
9716
9717 remTcConnectptr.i = apiConnectptr.p->firstTcConnect;
9718 while (remTcConnectptr.i != RNIL)
9719 {
9720 jam();
9721 TcConnectRecordPtr loopTcConnectptr;
9722 TcConnectRecordPtr prevTcConnectptr;
9723 ptrCheckGuard(remTcConnectptr, ctcConnectFilesize, tcConnectRecord);
9724 bool found = false;
9725 Uint32 bucket = get_tc_fail_bucket(apiConnectptr.p->transid[0],
9726 remTcConnectptr.p->tcOprec);
9727 prevTcConnectptr.i = RNIL;
9728 loopTcConnectptr.i = ctcConnectFailHash[bucket];
9729 while (loopTcConnectptr.i != RNIL)
9730 {
9731 if (loopTcConnectptr.i == remTcConnectptr.i)
9732 {
9733 found = true;
9734 if (prevTcConnectptr.i == RNIL)
9735 {
9736 jam();
9737 /* We were first in the hash linked list */
9738 ndbassert(ctcConnectFailHash[bucket] == remTcConnectptr.i);
9739 ctcConnectFailHash[bucket] = remTcConnectptr.p->nextTcFailHash;
9740 }
9741 else
9742 {
9743 /* Link past our record in the hash list */
9744 jam();
9745 ptrCheckGuard(prevTcConnectptr, ctcConnectFilesize, tcConnectRecord);
9746 prevTcConnectptr.p->nextTcFailHash =
9747 remTcConnectptr.p->nextTcFailHash;
9748 }
9749 remTcConnectptr.p->nextTcFailHash = RNIL;
9750 break;
9751 }
9752 else
9753 {
9754 jam();
9755 ptrCheckGuard(loopTcConnectptr, ctcConnectFilesize, tcConnectRecord);
9756 prevTcConnectptr.i = loopTcConnectptr.i;
9757 loopTcConnectptr.i = loopTcConnectptr.p->nextTcFailHash;
9758 }
9759 }
9760 ndbrequire(found);
9761 remTcConnectptr.i = remTcConnectptr.p->nextTcConnect;
9762 }
9763 }
9764
9765 /*------------------------------------------------------------*/
9766 /* A REPORT OF AN OPERATION WHERE TC FAILED HAS ARRIVED.*/
9767 /*------------------------------------------------------------*/
execLQH_TRANSCONF(Signal * signal)9768 void Dbtc::execLQH_TRANSCONF(Signal* signal)
9769 {
9770 jamEntry();
9771 LqhTransConf * const lqhTransConf = (LqhTransConf *)&signal->theData[0];
9772
9773 if (ERROR_INSERTED(8102))
9774 {
9775 jam();
9776 if ((((LqhTransConf::OperationStatus)lqhTransConf->operationStatus) ==
9777 LqhTransConf::LastTransConf) &&
9778 signal->getSendersBlockRef() != reference())
9779 {
9780 jam();
9781 ndbout_c("Delaying final LQH_TRANSCONF from Lqh @ node %u",
9782 refToNode(signal->getSendersBlockRef()));
9783 // Force multi-tc takeover
9784 ((LqhTransConf*)lqhTransConf)->maxInstanceId = 4;
9785 sendSignalWithDelay(reference(),
9786 GSN_LQH_TRANSCONF,
9787 signal,
9788 5000,
9789 signal->getLength());
9790 return;
9791 }
9792 }
9793
9794 CRASH_INSERTION(8060);
9795
9796 tcNodeFailptr.i = lqhTransConf->tcRef;
9797 ptrCheckGuard(tcNodeFailptr, 1, tcFailRecord);
9798 NodeId nodeId = lqhTransConf->lqhNodeId;
9799 LqhTransConf::OperationStatus transStatus =
9800 (LqhTransConf::OperationStatus)lqhTransConf->operationStatus;
9801 Uint32 transid1 = lqhTransConf->transId1;
9802 Uint32 transid2 = lqhTransConf->transId2;
9803 Uint32 tcOprec = lqhTransConf->oldTcOpRec;
9804 Uint32 reqinfo = lqhTransConf->requestInfo;
9805 Uint64 gci = Uint64(lqhTransConf->gci_hi) << 32;
9806 cnodes[0] = lqhTransConf->nextNodeId1;
9807 cnodes[1] = lqhTransConf->nextNodeId2;
9808 cnodes[2] = lqhTransConf->nextNodeId3;
9809 const BlockReference ref = lqhTransConf->apiRef;
9810 BlockReference applRef = lqhTransConf->apiRef;
9811 Uint32 applOprec = lqhTransConf->apiOpRec;
9812 const Uint32 tableId = lqhTransConf->tableId;
9813 Uint32 gci_lo = lqhTransConf->gci_lo;
9814 Uint32 fragId = lqhTransConf->fragId;
9815
9816 if (transStatus == LqhTransConf::Committed &&
9817 unlikely(signal->getLength() < LqhTransConf::SignalLength_GCI_LO))
9818 {
9819 jam();
9820 gci_lo = 0;
9821 ndbassert(!ndb_check_micro_gcp(getNodeInfo(nodeId).m_version));
9822 }
9823 gci |= gci_lo;
9824
9825 if (transStatus == LqhTransConf::LastTransConf){
9826 jam();
9827 Uint32 maxInstanceId = lqhTransConf->maxInstanceId;
9828 if (unlikely(signal->getLength() < LqhTransConf::SignalLength_INST_ID))
9829 {
9830 maxInstanceId = 0;
9831 }
9832 ndbassert(maxInstanceId < NDBMT_MAX_BLOCK_INSTANCES);
9833 /* A node has reported one phase of take over handling as completed. */
9834 nodeTakeOverCompletedLab(signal, nodeId, maxInstanceId);
9835 return;
9836 }//if
9837 if (transStatus == LqhTransConf::Marker){
9838 jam();
9839 reqinfo = 0;
9840 LqhTransConf::setMarkerFlag(reqinfo, 1);
9841 } else {
9842 TableRecordPtr tabPtr;
9843 tabPtr.i = tableId;
9844 ptrCheckGuard(tabPtr, ctabrecFilesize, tableRecord);
9845 switch((DictTabInfo::TableType)tabPtr.p->tableType){
9846 case DictTabInfo::SystemTable:
9847 case DictTabInfo::UserTable:
9848 break;
9849 default:
9850 applRef = 0;
9851 applOprec = 0;
9852 }
9853 }
9854
9855 if (findApiConnectFail(signal, transid1, transid2))
9856 {
9857 /**
9858 * Found a transaction record, record the added info about this
9859 * transaction as received in this message
9860 */
9861 updateApiStateFail(signal,
9862 transid1,
9863 transid2,
9864 transStatus,
9865 reqinfo,
9866 applRef,
9867 gci,
9868 nodeId);
9869 }
9870 else
9871 {
9872 if (cfirstfreeApiConnectFail == RNIL)
9873 {
9874 jam();
9875 /**
9876 * We failed to allocate a transaction record, we will record that
9877 * we failed to handle all transactions and we will not allocate
9878 * any more transaction records as part of taking over this instance
9879 * of the failed TC. The failed transactions will be taken over in
9880 * a second step of the TC take over of this instance and possibly
9881 * even more than two steps will be performed.
9882 *
9883 * This could happen if the master node has less transaction records
9884 * than the failed node which is possible but not recommended.
9885 */
9886 Uint32 apiConnect = capiConnectFilesize / 3;
9887 g_eventLogger->info("Need to do another round of TC takeover handling."
9888 " The failed node had a higher setting of "
9889 "MaxNoOfConcurrentTransactions than this node has, "
9890 "this node has MaxNoOfConcurrentTransactions = %u",
9891 apiConnect);
9892 tcNodeFailptr.p->takeOverFailed = true;
9893 return;
9894 }
9895 else if (tcNodeFailptr.p->takeOverFailed)
9896 {
9897 jam();
9898 /**
9899 * After we failed to allocate a transaction record we won't
9900 * try to allocate any new ones since it might mean that we
9901 * miss operations of a transaction.
9902 */
9903 return;
9904 }
9905 /**
9906 * A new transaction was found, allocate a record for it and fill
9907 * it with info as received in LQH_TRANSCONF message. Also insert
9908 * it in hash table for transaction records in TC take over.
9909 */
9910 seizeApiConnectFail(signal);
9911 insert_transid_fail_hash(transid1);
9912 initApiConnectFail(signal,
9913 transid1,
9914 transid2,
9915 transStatus,
9916 reqinfo,
9917 applRef,
9918 gci,
9919 nodeId);
9920 }
9921
9922 if(apiConnectptr.p->ndbapiBlockref == 0 && applRef != 0)
9923 {
9924 jam();
9925 apiConnectptr.p->ndbapiBlockref = ref;
9926 apiConnectptr.p->ndbapiConnect = applOprec;
9927 }
9928
9929 if (transStatus != LqhTransConf::Marker)
9930 {
9931 Uint32 instanceKey;
9932
9933 if (unlikely(signal->getLength() < LqhTransConf::SignalLength_FRAG_ID))
9934 {
9935 jam();
9936 instanceKey = 0;
9937 }
9938 else
9939 {
9940 jam();
9941 instanceKey = getInstanceKey(tableId, fragId);
9942 }
9943 if (findTcConnectFail(signal, transid1, transid2, tcOprec))
9944 {
9945 jam();
9946 updateTcStateFail(signal,
9947 instanceKey,
9948 tcOprec,
9949 reqinfo,
9950 transStatus,
9951 nodeId);
9952 }
9953 else
9954 {
9955 if (cfirstfreeTcConnectFail == RNIL)
9956 {
9957 /**
9958 * We failed to allocate a TC record, given that we can no longer
9959 * complete take over of this transaction we must handle the failed
9960 * transaction take over. We also set takeOverFailed to true to
9961 * ensure that we cannot start any new transaction take over after
9962 * this one. This is imperative to do since otherwise a new operation
9963 * on the failed transaction can come along and find free resources.
9964 * This would not be a correct behavior so we need to protect against
9965 * it by not starting any transactions after any seize failure.
9966 *
9967 * As long as we don't have transactions that are bigger than the
9968 * available number of TC records we should make progress at each
9969 * step and the algorithm should eventually complete.
9970 *
9971 * This could happen if the master node have fewer operation records
9972 * than the failed node had. This could happen but isn't
9973 * recommended.
9974 */
9975 Uint32 tcConnect = ctcConnectFilesize;
9976 jam();
9977 g_eventLogger->info("Need to do another round of TC takeover handling."
9978 " The failed node had a higher setting of "
9979 "MaxNoOfConcurrentOperations than this node has, "
9980 "this node has MaxNoOfConcurrentOperations = %u",
9981 tcConnect);
9982 tcNodeFailptr.p->takeOverFailed = true;
9983 remove_transaction_from_tc_fail_hash(signal);
9984 releaseMarker(apiConnectptr.p);
9985 remove_from_transid_fail_hash(signal, transid1);
9986 releaseTakeOver(signal);
9987 }
9988 else
9989 {
9990 jam();
9991 seizeTcConnectFail(signal);
9992 linkTcInConnectionlist(signal);
9993 insert_tc_fail_hash(transid1, tcOprec);
9994 initTcConnectFail(signal,
9995 instanceKey,
9996 tcOprec,
9997 reqinfo,
9998 transStatus,
9999 nodeId);
10000 }
10001 }
10002 }
10003 }//Dbtc::execLQH_TRANSCONF()
10004
10005 /*------------------------------------------------------------*/
10006 /* A NODE HAS REPORTED COMPLETION OF TAKE OVER REPORTING*/
10007 /*------------------------------------------------------------*/
nodeTakeOverCompletedLab(Signal * signal,NodeId nodeId,Uint32 maxInstanceId)10008 void Dbtc::nodeTakeOverCompletedLab(Signal* signal,
10009 NodeId nodeId,
10010 Uint32 maxInstanceId)
10011 {
10012 Uint32 guard0;
10013
10014 CRASH_INSERTION(8061);
10015
10016 if (unlikely(maxInstanceId >= NDBMT_MAX_BLOCK_INSTANCES))
10017 {
10018 /**
10019 * bug# 19193927 : LQH sends junk max instance id
10020 * Bug is fixed, but handle upgrade
10021 */
10022 maxInstanceId = NDBMT_MAX_BLOCK_INSTANCES - 1;
10023 }
10024 if (tcNodeFailptr.p->maxInstanceId < maxInstanceId)
10025 {
10026 jam();
10027 tcNodeFailptr.p->maxInstanceId = maxInstanceId;
10028 }
10029 hostptr.i = nodeId;
10030 ptrCheckGuard(hostptr, chostFilesize, hostRecord);
10031 hostptr.p->lqhTransStatus = LTS_IDLE;
10032 for (hostptr.i = 1; hostptr.i < MAX_NDB_NODES; hostptr.i++) {
10033 jam();
10034 ptrAss(hostptr, hostRecord);
10035 if (hostptr.p->hostStatus == HS_ALIVE) {
10036 if (hostptr.p->lqhTransStatus == LTS_ACTIVE) {
10037 jam();
10038 /*------------------------------------------------------------*/
10039 /* NOT ALL NODES ARE COMPLETED WITH REPORTING IN THE */
10040 /* TAKE OVER. */
10041 /*------------------------------------------------------------*/
10042 return;
10043 }//if
10044 }//if
10045 }//for
10046 /*------------------------------------------------------------*/
10047 /* ALL NODES HAVE REPORTED ON THE STATUS OF THE VARIOUS */
10048 /* OPERATIONS THAT WAS CONTROLLED BY THE FAILED TC. WE */
10049 /* ARE NOW IN A POSITION TO COMPLETE ALL OF THOSE */
10050 /* TRANSACTIONS EITHER IN A SUCCESSFUL WAY OR IN AN */
10051 /* UNSUCCESSFUL WAY. WE WILL ALSO REPORT THIS CONCLUSION*/
10052 /* TO THE APPLICATION IF THAT IS STILL ALIVE. */
10053 /*------------------------------------------------------------*/
10054 tcNodeFailptr.p->currentHashIndexTakeOver = 0;
10055 tcNodeFailptr.p->completedTakeOver = 0;
10056 tcNodeFailptr.p->failStatus = FS_COMPLETING;
10057 guard0 = cnoParallelTakeOver - 1;
10058 /*------------------------------------------------------------*/
10059 /* WE WILL COMPLETE THE TRANSACTIONS BY STARTING A */
10060 /* NUMBER OF PARALLEL ACTIVITIES. EACH ACTIVITY WILL */
10061 /* COMPLETE ONE TRANSACTION AT A TIME AND IN THAT */
10062 /* TRANSACTION IT WILL COMPLETE ONE OPERATION AT A TIME.*/
10063 /* WHEN ALL ACTIVITIES ARE COMPLETED THEN THE TAKE OVER */
10064 /* IS COMPLETED. */
10065 /*------------------------------------------------------------*/
10066 arrGuard(guard0, MAX_NDB_NODES);
10067 for (tindex = 0; tindex <= guard0; tindex++) {
10068 jam();
10069 tcNodeFailptr.p->takeOverProcState[tindex] = ZTAKE_OVER_ACTIVE;
10070 signal->theData[0] = TcContinueB::ZCOMPLETE_TRANS_AT_TAKE_OVER;
10071 signal->theData[1] = tcNodeFailptr.i;
10072 signal->theData[2] = tindex;
10073 sendSignal(cownref, GSN_CONTINUEB, signal, 3, JBB);
10074 }//for
10075 }//Dbtc::nodeTakeOverCompletedLab()
10076
10077 /*------------------------------------------------------------*/
10078 /* COMPLETE A NEW TRANSACTION FROM THE HASH TABLE OF */
10079 /* TRANSACTIONS TO COMPLETE. */
10080 /*------------------------------------------------------------*/
completeTransAtTakeOverLab(Signal * signal,UintR TtakeOverInd)10081 void Dbtc::completeTransAtTakeOverLab(Signal* signal, UintR TtakeOverInd)
10082 {
10083 jam();
10084 while (tcNodeFailptr.p->currentHashIndexTakeOver < TRANSID_FAIL_HASH_SIZE)
10085 {
10086 jam();
10087 apiConnectptr.i =
10088 ctransidFailHash[tcNodeFailptr.p->currentHashIndexTakeOver];
10089 if (apiConnectptr.i != RNIL) {
10090 jam();
10091 /*------------------------------------------------------------*/
10092 /* WE HAVE FOUND A TRANSACTION THAT NEEDS TO BE */
10093 /* COMPLETED. REMOVE IT FROM THE HASH TABLE SUCH THAT */
10094 /* NOT ANOTHER ACTIVITY ALSO TRIES TO COMPLETE THIS */
10095 /* TRANSACTION. */
10096 /*------------------------------------------------------------*/
10097 ptrCheckGuard(apiConnectptr, capiConnectFilesize, apiConnectRecord);
10098 ctransidFailHash[tcNodeFailptr.p->currentHashIndexTakeOver] =
10099 apiConnectptr.p->nextApiConnect;
10100 tcNodeFailptr.p->handledOneTransaction = true;
10101 completeTransAtTakeOverDoOne(signal, TtakeOverInd);
10102 // One transaction taken care of, return from this function
10103 // and wait for the next CONTINUEB to continue processing
10104 break;
10105
10106 } else {
10107 if (tcNodeFailptr.p->currentHashIndexTakeOver <
10108 (TRANSID_FAIL_HASH_SIZE -1)){
10109 jam();
10110 tcNodeFailptr.p->currentHashIndexTakeOver++;
10111 } else {
10112 jam();
10113 completeTransAtTakeOverDoLast(signal, TtakeOverInd);
10114 tcNodeFailptr.p->currentHashIndexTakeOver++;
10115 }//if
10116 }//if
10117 }//while
10118 }//Dbtc::completeTransAtTakeOverLab()
10119
10120
completeTransAtTakeOverDoLast(Signal * signal,UintR TtakeOverInd)10121 void Dbtc::completeTransAtTakeOverDoLast(Signal* signal, UintR TtakeOverInd)
10122 {
10123 Uint32 guard0;
10124 /*------------------------------------------------------------*/
10125 /* THERE ARE NO MORE TRANSACTIONS TO COMPLETE. THIS */
10126 /* ACTIVITY IS COMPLETED. */
10127 /*------------------------------------------------------------*/
10128 arrGuard(TtakeOverInd, MAX_NDB_NODES);
10129 if (tcNodeFailptr.p->takeOverProcState[TtakeOverInd] != ZTAKE_OVER_ACTIVE) {
10130 jam();
10131 systemErrorLab(signal, __LINE__);
10132 return;
10133 }//if
10134 /**
10135 * If we need to continue with take over processing it will still be with
10136 * the same node.
10137 */
10138 if (tcNodeFailptr.p->takeOverFailed == ZTRUE)
10139 {
10140 /**
10141 * We performed a take over and it didn't complete, we will try
10142 * again. The reason it failed was due to this TC instance
10143 * not having sufficient resources to handle all transactions,
10144 * we should however make progress and thus eventually we should
10145 * be able to complete it. The only reason that it could completely
10146 * fail is if there is one transaction which is so big that we
10147 * cannot calculate its outcome.
10148 *
10149 * Given that we haven't completed this round, we continue with
10150 * one more attempt on the same TC instance.
10151 */
10152 jam();
10153 g_eventLogger->info("DBTC instance %u: Continuing take over of "
10154 "DBTC instance %u in node %u",
10155 instance(),
10156 tcNodeFailptr.p->takeOverInstanceId,
10157 tcNodeFailptr.p->takeOverNode);
10158 ndbrequire(tcNodeFailptr.p->handledOneTransaction);
10159 startTakeOverLab(signal,
10160 tcNodeFailptr.p->takeOverInstanceId,
10161 tcNodeFailptr.p->takeOverNode);
10162 return;
10163 }
10164 if (tcNodeFailptr.p->takeOverInstanceId < tcNodeFailptr.p->maxInstanceId)
10165 {
10166 /**
10167 * We deal with one TC instance at a time, we have completed one
10168 * instance and there are more instances to handle. Let's continue
10169 * with the next instance.
10170 */
10171 jam();
10172 g_eventLogger->info("DBTC instance %u: Completed take over of "
10173 "DBTC instance %u in failed node %u,"
10174 " continuing with the next instance",
10175 instance(),
10176 tcNodeFailptr.p->takeOverInstanceId,
10177 tcNodeFailptr.p->takeOverNode);
10178 startTakeOverLab(signal,
10179 tcNodeFailptr.p->takeOverInstanceId + 1,
10180 tcNodeFailptr.p->takeOverNode);
10181 return;
10182 }
10183 /**
10184 * We have completed take over of this node for all its TC instances.
10185 * We will continue taking over other nodes if there are any more
10186 * nodes to take over.
10187 */
10188 tcNodeFailptr.p->takeOverProcState[TtakeOverInd] = ZTAKE_OVER_IDLE;
10189 tcNodeFailptr.p->completedTakeOver++;
10190
10191 g_eventLogger->info("DBTC instance %u: Completed take over"
10192 " of failed node %u",
10193 instance(),
10194 tcNodeFailptr.p->takeOverNode);
10195 CRASH_INSERTION(8062);
10196
10197 if (tcNodeFailptr.p->completedTakeOver == cnoParallelTakeOver) {
10198 jam();
10199 /*------------------------------------------------------------*/
10200 /* WE WERE THE LAST ACTIVITY THAT WAS COMPLETED. WE NEED*/
10201 /* TO REPORT THE COMPLETION OF THE TAKE OVER TO ALL */
10202 /* NODES THAT ARE ALIVE. */
10203 /*------------------------------------------------------------*/
10204 NodeReceiverGroup rg(DBTC, c_alive_nodes);
10205 signal->theData[0] = tcNodeFailptr.p->takeOverNode;
10206 signal->theData[1] = reference();
10207 sendSignal(rg, GSN_TAKE_OVERTCCONF, signal, 2, JBB);
10208
10209 if (tcNodeFailptr.p->queueIndex > 0) {
10210 jam();
10211 /*------------------------------------------------------------*/
10212 /* THERE ARE MORE NODES TO TAKE OVER. WE NEED TO START */
10213 /* THE TAKE OVER. */
10214 /*------------------------------------------------------------*/
10215 Uint32 failedNodeId = tcNodeFailptr.p->queueList[0];
10216 guard0 = tcNodeFailptr.p->queueIndex - 1;
10217 arrGuard(guard0 + 1, MAX_NDB_NODES);
10218 for (Uint32 i = 0; i <= guard0; i++) {
10219 jam();
10220 tcNodeFailptr.p->queueList[i] = tcNodeFailptr.p->queueList[i+1];
10221 }//for
10222 tcNodeFailptr.p->queueIndex--;
10223 g_eventLogger->info("DBTC instance %u: Starting next DBTC node"
10224 " take over for failed node %u,"
10225 " %u failed nodes remaining in takeover queue",
10226 instance(),
10227 failedNodeId,
10228 tcNodeFailptr.p->queueIndex);
10229 startTakeOverLab(signal, 0, failedNodeId);
10230 return;
10231 } else {
10232 jam();
10233 tcNodeFailptr.p->failStatus = FS_IDLE;
10234 }//if
10235 }//if
10236 return;
10237 }//Dbtc::completeTransAtTakeOverDoLast()
10238
completeTransAtTakeOverDoOne(Signal * signal,UintR TtakeOverInd)10239 void Dbtc::completeTransAtTakeOverDoOne(Signal* signal, UintR TtakeOverInd)
10240 {
10241 apiConnectptr.p->takeOverRec = (Uint8)tcNodeFailptr.i;
10242 apiConnectptr.p->takeOverInd = TtakeOverInd;
10243
10244 switch (apiConnectptr.p->apiConnectstate) {
10245 case CS_FAIL_COMMITTED:
10246 jam();
10247 /*------------------------------------------------------------*/
10248 /* ALL PARTS OF THE TRANSACTIONS REPORTED COMMITTED. WE */
10249 /* HAVE THUS COMPLETED THE COMMIT PHASE. WE CAN REPORT */
10250 /* COMMITTED TO THE APPLICATION AND CONTINUE WITH THE */
10251 /* COMPLETE PHASE. */
10252 /*------------------------------------------------------------*/
10253 sendTCKEY_FAILCONF(signal, apiConnectptr.p);
10254 tcConnectptr.i = apiConnectptr.p->firstTcConnect;
10255 ptrCheckGuard(tcConnectptr, ctcConnectFilesize, tcConnectRecord);
10256 apiConnectptr.p->currentTcConnect = tcConnectptr.i;
10257 apiConnectptr.p->currentReplicaNo = tcConnectptr.p->lastReplicaNo;
10258 tcurrentReplicaNo = tcConnectptr.p->lastReplicaNo;
10259 commitGciHandling(signal, apiConnectptr.p->globalcheckpointid);
10260 toCompleteHandlingLab(signal);
10261 return;
10262 case CS_FAIL_COMMITTING:
10263 jam();
10264 /*------------------------------------------------------------*/
10265 /* AT LEAST ONE PART WAS ONLY PREPARED AND AT LEAST ONE */
10266 /* PART WAS COMMITTED. COMPLETE THE COMMIT PHASE FIRST. */
10267 /* THEN CONTINUE AS AFTER COMMITTED. */
10268 /*------------------------------------------------------------*/
10269 tcConnectptr.i = apiConnectptr.p->firstTcConnect;
10270 ptrCheckGuard(tcConnectptr, ctcConnectFilesize, tcConnectRecord);
10271 apiConnectptr.p->currentTcConnect = tcConnectptr.i;
10272 apiConnectptr.p->currentReplicaNo = tcConnectptr.p->lastReplicaNo;
10273 tcurrentReplicaNo = tcConnectptr.p->lastReplicaNo;
10274 commitGciHandling(signal, apiConnectptr.p->globalcheckpointid);
10275 toCommitHandlingLab(signal);
10276 return;
10277 case CS_FAIL_ABORTING:
10278 case CS_FAIL_PREPARED:
10279 jam();
10280 /*------------------------------------------------------------*/
10281 /* WE WILL ABORT THE TRANSACTION IF IT IS IN A PREPARED */
10282 /* STATE IN THIS VERSION. IN LATER VERSIONS WE WILL */
10283 /* HAVE TO ADD CODE FOR HANDLING OF PREPARED-TO-COMMIT */
10284 /* TRANSACTIONS. THESE ARE NOT ALLOWED TO ABORT UNTIL WE*/
10285 /* HAVE HEARD FROM THE TRANSACTION COORDINATOR. */
10286 /* */
10287 /* IT IS POSSIBLE TO COMMIT TRANSACTIONS THAT ARE */
10288 /* PREPARED ACTUALLY. WE WILL LEAVE THIS PROBLEM UNTIL */
10289 /* LATER VERSIONS. */
10290 /*------------------------------------------------------------*/
10291 tcConnectptr.i = apiConnectptr.p->firstTcConnect;
10292 ptrCheckGuard(tcConnectptr, ctcConnectFilesize, tcConnectRecord);
10293 apiConnectptr.p->currentTcConnect = tcConnectptr.i;
10294 apiConnectptr.p->currentReplicaNo = tcConnectptr.p->lastReplicaNo;
10295 tcurrentReplicaNo = tcConnectptr.p->lastReplicaNo;
10296 toAbortHandlingLab(signal);
10297 return;
10298 case CS_FAIL_ABORTED:
10299 jam();
10300 sendTCKEY_FAILREF(signal, apiConnectptr.p);
10301
10302 signal->theData[0] = TcContinueB::ZCOMPLETE_TRANS_AT_TAKE_OVER;
10303 signal->theData[1] = (UintR)apiConnectptr.p->takeOverRec;
10304 signal->theData[2] = apiConnectptr.p->takeOverInd;
10305 sendSignal(cownref, GSN_CONTINUEB, signal, 3, JBB);
10306 releaseTakeOver(signal);
10307 break;
10308 case CS_FAIL_COMPLETED:
10309 jam();
10310 sendTCKEY_FAILCONF(signal, apiConnectptr.p);
10311
10312 signal->theData[0] = TcContinueB::ZCOMPLETE_TRANS_AT_TAKE_OVER;
10313 signal->theData[1] = (UintR)apiConnectptr.p->takeOverRec;
10314 signal->theData[2] = apiConnectptr.p->takeOverInd;
10315 sendSignal(cownref, GSN_CONTINUEB, signal, 3, JBB);
10316 releaseApiConnectFail(signal);
10317 break;
10318 default:
10319 jam();
10320 systemErrorLab(signal, __LINE__);
10321 return;
10322 }//switch
10323 }//Dbtc::completeTransAtTakeOverDoOne()
10324
10325 void
sendTCKEY_FAILREF(Signal * signal,ApiConnectRecord * regApiPtr)10326 Dbtc::sendTCKEY_FAILREF(Signal* signal, ApiConnectRecord * regApiPtr){
10327 jam();
10328
10329 const Uint32 ref = regApiPtr->ndbapiBlockref;
10330 const NodeId nodeId = refToNode(ref);
10331 if(ref != 0)
10332 {
10333 jam();
10334 bool connectedToNode = getNodeInfo(nodeId).m_connected;
10335 signal->theData[0] = regApiPtr->ndbapiConnect;
10336 signal->theData[1] = regApiPtr->transid[0];
10337 signal->theData[2] = regApiPtr->transid[1];
10338
10339 if (likely(connectedToNode))
10340 {
10341 jam();
10342 sendSignal(ref, GSN_TCKEY_FAILREF, signal, 3, JBB);
10343 }
10344 else
10345 {
10346 routeTCKEY_FAILREFCONF(signal, regApiPtr, GSN_TCKEY_FAILREF, 3);
10347 }
10348 }
10349 releaseMarker(regApiPtr);
10350 }
10351
10352 void
sendTCKEY_FAILCONF(Signal * signal,ApiConnectRecord * regApiPtr)10353 Dbtc::sendTCKEY_FAILCONF(Signal* signal, ApiConnectRecord * regApiPtr){
10354 jam();
10355 TcKeyFailConf * const failConf = (TcKeyFailConf *)&signal->theData[0];
10356
10357 const Uint32 ref = regApiPtr->ndbapiBlockref;
10358 const Uint32 marker = regApiPtr->commitAckMarker;
10359 const NodeId nodeId = refToNode(ref);
10360 if(ref != 0)
10361 {
10362 jam();
10363 failConf->apiConnectPtr = regApiPtr->ndbapiConnect | (marker != RNIL);
10364 failConf->transId1 = regApiPtr->transid[0];
10365 failConf->transId2 = regApiPtr->transid[1];
10366
10367 bool connectedToNode = getNodeInfo(nodeId).m_connected;
10368 if (likely(connectedToNode))
10369 {
10370 jam();
10371 sendSignal(ref, GSN_TCKEY_FAILCONF, signal,
10372 TcKeyFailConf::SignalLength, JBB);
10373 }
10374 else
10375 {
10376 routeTCKEY_FAILREFCONF(signal, regApiPtr,
10377 GSN_TCKEY_FAILCONF, TcKeyFailConf::SignalLength);
10378 }
10379 }
10380 regApiPtr->commitAckMarker = RNIL;
10381 }
10382
10383 void
routeTCKEY_FAILREFCONF(Signal * signal,const ApiConnectRecord * regApiPtr,Uint32 gsn,Uint32 len)10384 Dbtc::routeTCKEY_FAILREFCONF(Signal* signal, const ApiConnectRecord* regApiPtr,
10385 Uint32 gsn, Uint32 len)
10386 {
10387 jam();
10388
10389 Uint32 ref = regApiPtr->ndbapiBlockref;
10390
10391 /**
10392 * We're not connected
10393 * so we find another node in same node group as died node
10394 * and send to it, so that it can forward
10395 */
10396 tcNodeFailptr.i = regApiPtr->takeOverRec;
10397 ptrCheckGuard(tcNodeFailptr, 1, tcFailRecord);
10398
10399 /**
10400 * Save signal
10401 */
10402 Uint32 save[25];
10403 ndbrequire(len <= 25);
10404 memcpy(save, signal->theData, 4*len);
10405
10406 Uint32 node = tcNodeFailptr.p->takeOverNode;
10407
10408 CheckNodeGroups * sd = (CheckNodeGroups*)signal->getDataPtrSend();
10409 sd->blockRef = reference();
10410 sd->requestType =
10411 CheckNodeGroups::Direct |
10412 CheckNodeGroups::GetNodeGroupMembers;
10413 sd->nodeId = node;
10414 EXECUTE_DIRECT(DBDIH, GSN_CHECKNODEGROUPSREQ, signal,
10415 CheckNodeGroups::SignalLength, 0);
10416 jamEntry();
10417
10418 NdbNodeBitmask mask;
10419 mask.assign(sd->mask);
10420 mask.clear(getOwnNodeId());
10421 memcpy(signal->theData, save, 4*len);
10422
10423 Uint32 i = 0;
10424 while((i = mask.find(i + 1)) != NdbNodeBitmask::NotFound)
10425 {
10426 jam();
10427 HostRecordPtr localHostptr;
10428 localHostptr.i = i;
10429 ptrCheckGuard(localHostptr, chostFilesize, hostRecord);
10430 if (localHostptr.p->hostStatus == HS_ALIVE)
10431 {
10432 jam();
10433 signal->theData[len] = gsn;
10434 signal->theData[len+1] = ref;
10435 sendSignal(calcTcBlockRef(i), GSN_TCKEY_FAILREFCONF_R,
10436 signal, len+2, JBB);
10437 return;
10438 }
10439 }
10440
10441
10442 /**
10443 * This code was 'unfinished' code for partially connected API's
10444 * it does however not really work...
10445 * and we seriously need to think about semantics for API connect
10446 */
10447 #if 0
10448 ndbrequire(getNodeInfo(refToNode(ref)).m_type == NodeInfo::DB);
10449 #endif
10450 }
10451
10452 void
execTCKEY_FAILREFCONF_R(Signal * signal)10453 Dbtc::execTCKEY_FAILREFCONF_R(Signal* signal)
10454 {
10455 jamEntry();
10456 Uint32 len = signal->getLength();
10457 Uint32 gsn = signal->theData[len-2];
10458 Uint32 ref = signal->theData[len-1];
10459 sendSignal(ref, gsn, signal, len-2, JBB);
10460 }
10461
10462 /*------------------------------------------------------------*/
10463 /* THIS PART HANDLES THE ABORT PHASE IN THE CASE OF A */
10464 /* NODE FAILURE BEFORE THE COMMIT DECISION. */
10465 /*------------------------------------------------------------*/
10466 /* ABORT REQUEST SUCCESSFULLY COMPLETED ON TNODEID */
10467 /*------------------------------------------------------------*/
execABORTCONF(Signal * signal)10468 void Dbtc::execABORTCONF(Signal* signal)
10469 {
10470 UintR compare_transid1, compare_transid2;
10471
10472 jamEntry();
10473 tcConnectptr.i = signal->theData[0];
10474 NodeId nodeId = signal->theData[2];
10475 if (ERROR_INSERTED(8045)) {
10476 CLEAR_ERROR_INSERT_VALUE;
10477 sendSignalWithDelay(cownref, GSN_ABORTCONF, signal, 2000, 5);
10478 return;
10479 }//if
10480 if (tcConnectptr.i >= ctcConnectFilesize) {
10481 errorReport(signal, 5);
10482 return;
10483 }//if
10484 ptrAss(tcConnectptr, tcConnectRecord);
10485 if (tcConnectptr.p->tcConnectstate != OS_WAIT_ABORT_CONF) {
10486 warningReport(signal, 16);
10487 return;
10488 }//if
10489 apiConnectptr.i = tcConnectptr.p->apiConnect;
10490 ptrCheckGuard(apiConnectptr, capiConnectFilesize, apiConnectRecord);
10491 if (apiConnectptr.p->apiConnectstate != CS_WAIT_ABORT_CONF) {
10492 warningReport(signal, 17);
10493 return;
10494 }//if
10495 compare_transid1 = apiConnectptr.p->transid[0] ^ signal->theData[3];
10496 compare_transid2 = apiConnectptr.p->transid[1] ^ signal->theData[4];
10497 compare_transid1 = compare_transid1 | compare_transid2;
10498 if (compare_transid1 != 0) {
10499 warningReport(signal, 18);
10500 return;
10501 }//if
10502 arrGuard(apiConnectptr.p->currentReplicaNo, MAX_REPLICAS);
10503 if (tcConnectptr.p->tcNodedata[apiConnectptr.p->currentReplicaNo] !=
10504 nodeId) {
10505 warningReport(signal, 19);
10506 return;
10507 }//if
10508 tcurrentReplicaNo = (Uint8)Z8NIL;
10509 tcConnectptr.p->tcConnectstate = OS_ABORTING;
10510 toAbortHandlingLab(signal);
10511 }//Dbtc::execABORTCONF()
10512
toAbortHandlingLab(Signal * signal)10513 void Dbtc::toAbortHandlingLab(Signal* signal)
10514 {
10515 do {
10516 if (tcurrentReplicaNo != (Uint8)Z8NIL) {
10517 jam();
10518 arrGuard(tcurrentReplicaNo, MAX_REPLICAS);
10519 const LqhTransConf::OperationStatus stat =
10520 (LqhTransConf::OperationStatus)
10521 tcConnectptr.p->failData[tcurrentReplicaNo];
10522 switch(stat){
10523 case LqhTransConf::InvalidStatus:
10524 case LqhTransConf::Aborted:
10525 jam();
10526 /*empty*/;
10527 break;
10528 case LqhTransConf::Prepared:
10529 jam();
10530 hostptr.i = tcConnectptr.p->tcNodedata[tcurrentReplicaNo];
10531 ptrCheckGuard(hostptr, chostFilesize, hostRecord);
10532 if (hostptr.p->hostStatus == HS_ALIVE) {
10533 jam();
10534 Uint32 instanceKey = tcConnectptr.p->lqhInstanceKey;
10535 tblockref = numberToRef(DBLQH, instanceKey, hostptr.i);
10536 setApiConTimer(apiConnectptr.i, ctcTimer, __LINE__);
10537 tcConnectptr.p->tcConnectstate = OS_WAIT_ABORT_CONF;
10538 apiConnectptr.p->apiConnectstate = CS_WAIT_ABORT_CONF;
10539 apiConnectptr.p->timeOutCounter = 0;
10540 signal->theData[0] = tcConnectptr.i;
10541 signal->theData[1] = cownref;
10542 signal->theData[2] = apiConnectptr.p->transid[0];
10543 signal->theData[3] = apiConnectptr.p->transid[1];
10544 signal->theData[4] = apiConnectptr.p->tcBlockref;
10545 signal->theData[5] = tcConnectptr.p->tcOprec;
10546 sendSignal(tblockref, GSN_ABORTREQ, signal, 6, JBB);
10547 return;
10548 }//if
10549 break;
10550 default:
10551 jam();
10552 systemErrorLab(signal, __LINE__);
10553 return;
10554 }//switch
10555 }//if
10556 if (apiConnectptr.p->currentReplicaNo > 0) {
10557 jam();
10558 /*------------------------------------------------------------*/
10559 /* THERE IS STILL ANOTHER REPLICA THAT NEEDS TO BE */
10560 /* ABORTED. */
10561 /*------------------------------------------------------------*/
10562 apiConnectptr.p->currentReplicaNo--;
10563 tcurrentReplicaNo = apiConnectptr.p->currentReplicaNo;
10564 } else {
10565 /*------------------------------------------------------------*/
10566 /* THE LAST REPLICA IN THIS OPERATION HAVE COMMITTED. */
10567 /*------------------------------------------------------------*/
10568 tcConnectptr.i = tcConnectptr.p->nextTcConnect;
10569 if (tcConnectptr.i == RNIL) {
10570 /*------------------------------------------------------------*/
10571 /* WE HAVE COMPLETED THE ABORT PHASE. WE CAN NOW REPORT */
10572 /* THE ABORT STATUS TO THE APPLICATION AND CONTINUE */
10573 /* WITH THE NEXT TRANSACTION. */
10574 /*------------------------------------------------------------*/
10575 if (apiConnectptr.p->takeOverRec != (Uint8)Z8NIL) {
10576 jam();
10577 sendTCKEY_FAILREF(signal, apiConnectptr.p);
10578
10579 /*------------------------------------------------------------*/
10580 /* WE HAVE COMPLETED THIS TRANSACTION NOW AND CAN */
10581 /* CONTINUE THE PROCESS WITH THE NEXT TRANSACTION. */
10582 /*------------------------------------------------------------*/
10583 signal->theData[0] = TcContinueB::ZCOMPLETE_TRANS_AT_TAKE_OVER;
10584 signal->theData[1] = (UintR)apiConnectptr.p->takeOverRec;
10585 signal->theData[2] = apiConnectptr.p->takeOverInd;
10586 sendSignal(cownref, GSN_CONTINUEB, signal, 3, JBB);
10587 releaseTakeOver(signal);
10588 } else {
10589 jam();
10590 releaseAbortResources(signal);
10591 }//if
10592 return;
10593 }//if
10594 apiConnectptr.p->currentTcConnect = tcConnectptr.i;
10595 ptrCheckGuard(tcConnectptr, ctcConnectFilesize, tcConnectRecord);
10596 apiConnectptr.p->currentReplicaNo = tcConnectptr.p->lastReplicaNo;
10597 tcurrentReplicaNo = tcConnectptr.p->lastReplicaNo;
10598 }//if
10599 } while (1);
10600 }//Dbtc::toAbortHandlingLab()
10601
10602 /*------------------------------------------------------------*/
10603 /* THIS PART HANDLES THE COMMIT PHASE IN THE CASE OF A */
10604 /* NODE FAILURE IN THE MIDDLE OF THE COMMIT PHASE. */
10605 /*------------------------------------------------------------*/
10606 /* COMMIT REQUEST SUCCESSFULLY COMPLETED ON TNODEID */
10607 /*------------------------------------------------------------*/
execCOMMITCONF(Signal * signal)10608 void Dbtc::execCOMMITCONF(Signal* signal)
10609 {
10610 UintR compare_transid1, compare_transid2;
10611
10612 jamEntry();
10613 tcConnectptr.i = signal->theData[0];
10614 NodeId nodeId = signal->theData[1];
10615 if (ERROR_INSERTED(8046)) {
10616 CLEAR_ERROR_INSERT_VALUE;
10617 sendSignalWithDelay(cownref, GSN_COMMITCONF, signal, 2000, 4);
10618 return;
10619 }//if
10620 if (tcConnectptr.i >= ctcConnectFilesize) {
10621 errorReport(signal, 4);
10622 return;
10623 }//if
10624 ptrAss(tcConnectptr, tcConnectRecord);
10625 if (tcConnectptr.p->tcConnectstate != OS_WAIT_COMMIT_CONF) {
10626 warningReport(signal, 8);
10627 return;
10628 }//if
10629 apiConnectptr.i = tcConnectptr.p->apiConnect;
10630 ptrCheckGuard(apiConnectptr, capiConnectFilesize, apiConnectRecord);
10631 if (apiConnectptr.p->apiConnectstate != CS_WAIT_COMMIT_CONF) {
10632 warningReport(signal, 9);
10633 return;
10634 }//if
10635 compare_transid1 = apiConnectptr.p->transid[0] ^ signal->theData[2];
10636 compare_transid2 = apiConnectptr.p->transid[1] ^ signal->theData[3];
10637 compare_transid1 = compare_transid1 | compare_transid2;
10638 if (compare_transid1 != 0) {
10639 warningReport(signal, 10);
10640 return;
10641 }//if
10642 arrGuard(apiConnectptr.p->currentReplicaNo, MAX_REPLICAS);
10643 if (tcConnectptr.p->tcNodedata[apiConnectptr.p->currentReplicaNo] !=
10644 nodeId) {
10645 warningReport(signal, 11);
10646 return;
10647 }//if
10648 if (ERROR_INSERTED(8026)) {
10649 jam();
10650 systemErrorLab(signal, __LINE__);
10651 }//if
10652 tcurrentReplicaNo = (Uint8)Z8NIL;
10653 tcConnectptr.p->tcConnectstate = OS_COMMITTED;
10654 toCommitHandlingLab(signal);
10655 }//Dbtc::execCOMMITCONF()
10656
toCommitHandlingLab(Signal * signal)10657 void Dbtc::toCommitHandlingLab(Signal* signal)
10658 {
10659 do {
10660 if (tcurrentReplicaNo != (Uint8)Z8NIL) {
10661 jam();
10662 arrGuard(tcurrentReplicaNo, MAX_REPLICAS);
10663 switch (tcConnectptr.p->failData[tcurrentReplicaNo]) {
10664 case LqhTransConf::InvalidStatus:
10665 jam();
10666 /*empty*/;
10667 break;
10668 case LqhTransConf::Committed:
10669 jam();
10670 /*empty*/;
10671 break;
10672 case LqhTransConf::Prepared:
10673 jam();
10674 /*------------------------------------------------------------*/
10675 /* THE NODE WAS PREPARED AND IS WAITING FOR ABORT OR */
10676 /* COMMIT REQUEST FROM TC. */
10677 /*------------------------------------------------------------*/
10678 hostptr.i = tcConnectptr.p->tcNodedata[tcurrentReplicaNo];
10679 ptrCheckGuard(hostptr, chostFilesize, hostRecord);
10680 if (hostptr.p->hostStatus == HS_ALIVE) {
10681 jam();
10682 Uint32 instanceKey = tcConnectptr.p->lqhInstanceKey;
10683 tblockref = numberToRef(DBLQH, instanceKey, hostptr.i);
10684 setApiConTimer(apiConnectptr.i, ctcTimer, __LINE__);
10685 apiConnectptr.p->apiConnectstate = CS_WAIT_COMMIT_CONF;
10686 apiConnectptr.p->timeOutCounter = 0;
10687 tcConnectptr.p->tcConnectstate = OS_WAIT_COMMIT_CONF;
10688 Uint64 gci = apiConnectptr.p->globalcheckpointid;
10689 signal->theData[0] = tcConnectptr.i;
10690 signal->theData[1] = cownref;
10691 signal->theData[2] = Uint32(gci >> 32); // XXX JON
10692 signal->theData[3] = apiConnectptr.p->transid[0];
10693 signal->theData[4] = apiConnectptr.p->transid[1];
10694 signal->theData[5] = apiConnectptr.p->tcBlockref;
10695 signal->theData[6] = tcConnectptr.p->tcOprec;
10696 signal->theData[7] = Uint32(gci);
10697 sendSignal(tblockref, GSN_COMMITREQ, signal, 8, JBB);
10698 return;
10699 }//if
10700 break;
10701 default:
10702 jam();
10703 systemErrorLab(signal, __LINE__);
10704 return;
10705 break;
10706 }//switch
10707 }//if
10708 if (apiConnectptr.p->currentReplicaNo > 0) {
10709 jam();
10710 /*------------------------------------------------------------*/
10711 /* THERE IS STILL ANOTHER REPLICA THAT NEEDS TO BE */
10712 /* COMMITTED. */
10713 /*------------------------------------------------------------*/
10714 apiConnectptr.p->currentReplicaNo--;
10715 tcurrentReplicaNo = apiConnectptr.p->currentReplicaNo;
10716 } else {
10717 /*------------------------------------------------------------*/
10718 /* THE LAST REPLICA IN THIS OPERATION HAVE COMMITTED. */
10719 /*------------------------------------------------------------*/
10720 tcConnectptr.i = tcConnectptr.p->nextTcConnect;
10721 if (tcConnectptr.i == RNIL) {
10722 /*------------------------------------------------------------*/
10723 /* WE HAVE COMPLETED THE COMMIT PHASE. WE CAN NOW REPORT*/
10724 /* THE COMMIT STATUS TO THE APPLICATION AND CONTINUE */
10725 /* WITH THE COMPLETE PHASE. */
10726 /*------------------------------------------------------------*/
10727 if (apiConnectptr.p->takeOverRec != (Uint8)Z8NIL) {
10728 jam();
10729 sendTCKEY_FAILCONF(signal, apiConnectptr.p);
10730 } else {
10731 jam();
10732 apiConnectptr = sendApiCommit(signal);
10733 }//if
10734 apiConnectptr.p->currentTcConnect = apiConnectptr.p->firstTcConnect;
10735 tcConnectptr.i = apiConnectptr.p->firstTcConnect;
10736 ptrCheckGuard(tcConnectptr, ctcConnectFilesize, tcConnectRecord);
10737 tcurrentReplicaNo = tcConnectptr.p->lastReplicaNo;
10738 apiConnectptr.p->currentReplicaNo = tcurrentReplicaNo;
10739 toCompleteHandlingLab(signal);
10740 return;
10741 }//if
10742 apiConnectptr.p->currentTcConnect = tcConnectptr.i;
10743 ptrCheckGuard(tcConnectptr, ctcConnectFilesize, tcConnectRecord);
10744 apiConnectptr.p->currentReplicaNo = tcConnectptr.p->lastReplicaNo;
10745 tcurrentReplicaNo = tcConnectptr.p->lastReplicaNo;
10746 }//if
10747 } while (1);
10748 }//Dbtc::toCommitHandlingLab()
10749
10750 /*------------------------------------------------------------*/
10751 /* COMMON PART TO HANDLE COMPLETE PHASE WHEN ANY NODE */
10752 /* HAVE FAILED. */
10753 /*------------------------------------------------------------*/
10754 /* THE NODE WITH TNODEID HAVE COMPLETED THE OPERATION */
10755 /*------------------------------------------------------------*/
execCOMPLETECONF(Signal * signal)10756 void Dbtc::execCOMPLETECONF(Signal* signal)
10757 {
10758 UintR compare_transid1, compare_transid2;
10759
10760 jamEntry();
10761 tcConnectptr.i = signal->theData[0];
10762 NodeId nodeId = signal->theData[1];
10763 if (ERROR_INSERTED(8047)) {
10764 CLEAR_ERROR_INSERT_VALUE;
10765 sendSignalWithDelay(cownref, GSN_COMPLETECONF, signal, 2000, 4);
10766 return;
10767 }//if
10768 if (tcConnectptr.i >= ctcConnectFilesize) {
10769 errorReport(signal, 3);
10770 return;
10771 }//if
10772 ptrAss(tcConnectptr, tcConnectRecord);
10773 if (tcConnectptr.p->tcConnectstate != OS_WAIT_COMPLETE_CONF) {
10774 warningReport(signal, 12);
10775 return;
10776 }//if
10777 apiConnectptr.i = tcConnectptr.p->apiConnect;
10778 ptrCheckGuard(apiConnectptr, capiConnectFilesize, apiConnectRecord);
10779 if (apiConnectptr.p->apiConnectstate != CS_WAIT_COMPLETE_CONF) {
10780 warningReport(signal, 13);
10781 return;
10782 }//if
10783 compare_transid1 = apiConnectptr.p->transid[0] ^ signal->theData[2];
10784 compare_transid2 = apiConnectptr.p->transid[1] ^ signal->theData[3];
10785 compare_transid1 = compare_transid1 | compare_transid2;
10786 if (compare_transid1 != 0) {
10787 warningReport(signal, 14);
10788 return;
10789 }//if
10790 arrGuard(apiConnectptr.p->currentReplicaNo, MAX_REPLICAS);
10791 if (tcConnectptr.p->tcNodedata[apiConnectptr.p->currentReplicaNo] !=
10792 nodeId) {
10793 warningReport(signal, 15);
10794 return;
10795 }//if
10796 if (ERROR_INSERTED(8028)) {
10797 jam();
10798 systemErrorLab(signal, __LINE__);
10799 }//if
10800 tcConnectptr.p->tcConnectstate = OS_COMPLETED;
10801 tcurrentReplicaNo = (Uint8)Z8NIL;
10802 toCompleteHandlingLab(signal);
10803 }//Dbtc::execCOMPLETECONF()
10804
toCompleteHandlingLab(Signal * signal)10805 void Dbtc::toCompleteHandlingLab(Signal* signal)
10806 {
10807 do {
10808 if (tcurrentReplicaNo != (Uint8)Z8NIL) {
10809 jam();
10810 arrGuard(tcurrentReplicaNo, MAX_REPLICAS);
10811 switch (tcConnectptr.p->failData[tcurrentReplicaNo]) {
10812 case LqhTransConf::InvalidStatus:
10813 jam();
10814 /*empty*/;
10815 break;
10816 default:
10817 jam();
10818 /*------------------------------------------------------------*/
10819 /* THIS NODE DID NOT REPORT ANYTHING FOR THIS OPERATION */
10820 /* IT MUST HAVE FAILED. */
10821 /*------------------------------------------------------------*/
10822 /*------------------------------------------------------------*/
10823 /* SEND COMPLETEREQ TO THE NEXT REPLICA. */
10824 /*------------------------------------------------------------*/
10825 hostptr.i = tcConnectptr.p->tcNodedata[tcurrentReplicaNo];
10826 ptrCheckGuard(hostptr, chostFilesize, hostRecord);
10827 if (hostptr.p->hostStatus == HS_ALIVE) {
10828 jam();
10829 Uint32 instanceKey = tcConnectptr.p->lqhInstanceKey;
10830 tblockref = numberToRef(DBLQH, instanceKey, hostptr.i);
10831 setApiConTimer(apiConnectptr.i, ctcTimer, __LINE__);
10832 tcConnectptr.p->tcConnectstate = OS_WAIT_COMPLETE_CONF;
10833 apiConnectptr.p->apiConnectstate = CS_WAIT_COMPLETE_CONF;
10834 apiConnectptr.p->timeOutCounter = 0;
10835 tcConnectptr.p->apiConnect = apiConnectptr.i;
10836 signal->theData[0] = tcConnectptr.i;
10837 signal->theData[1] = cownref;
10838 signal->theData[2] = apiConnectptr.p->transid[0];
10839 signal->theData[3] = apiConnectptr.p->transid[1];
10840 signal->theData[4] = apiConnectptr.p->tcBlockref;
10841 signal->theData[5] = tcConnectptr.p->tcOprec;
10842 sendSignal(tblockref, GSN_COMPLETEREQ, signal, 6, JBB);
10843 return;
10844 }//if
10845 break;
10846 }//switch
10847 }//if
10848 if (apiConnectptr.p->currentReplicaNo != 0) {
10849 jam();
10850 /*------------------------------------------------------------*/
10851 /* THERE ARE STILL MORE REPLICAS IN THIS OPERATION. WE */
10852 /* NEED TO CONTINUE WITH THOSE REPLICAS. */
10853 /*------------------------------------------------------------*/
10854 apiConnectptr.p->currentReplicaNo--;
10855 tcurrentReplicaNo = apiConnectptr.p->currentReplicaNo;
10856 } else {
10857 tcConnectptr.i = tcConnectptr.p->nextTcConnect;
10858 if (tcConnectptr.i == RNIL) {
10859 /*------------------------------------------------------------*/
10860 /* WE HAVE COMPLETED THIS TRANSACTION NOW AND CAN */
10861 /* CONTINUE THE PROCESS WITH THE NEXT TRANSACTION. */
10862 /*------------------------------------------------------------*/
10863 if (apiConnectptr.p->takeOverRec != (Uint8)Z8NIL) {
10864 jam();
10865 signal->theData[0] = TcContinueB::ZCOMPLETE_TRANS_AT_TAKE_OVER;
10866 signal->theData[1] = (UintR)apiConnectptr.p->takeOverRec;
10867 signal->theData[2] = apiConnectptr.p->takeOverInd;
10868 sendSignal(cownref, GSN_CONTINUEB, signal, 3, JBB);
10869 handleGcp(signal, apiConnectptr);
10870 releaseTakeOver(signal);
10871 } else {
10872 jam();
10873 releaseTransResources(signal);
10874 }//if
10875 return;
10876 }//if
10877 /*------------------------------------------------------------*/
10878 /* WE HAVE COMPLETED AN OPERATION AND THERE ARE MORE TO */
10879 /* COMPLETE. TAKE THE NEXT OPERATION AND START WITH THE */
10880 /* FIRST REPLICA SINCE IT IS THE COMPLETE PHASE. */
10881 /*------------------------------------------------------------*/
10882 apiConnectptr.p->currentTcConnect = tcConnectptr.i;
10883 ptrCheckGuard(tcConnectptr, ctcConnectFilesize, tcConnectRecord);
10884 tcurrentReplicaNo = tcConnectptr.p->lastReplicaNo;
10885 apiConnectptr.p->currentReplicaNo = tcurrentReplicaNo;
10886 }//if
10887 } while (1);
10888 }//Dbtc::toCompleteHandlingLab()
10889
10890 /*----------------------------------------------------------*/
10891 /* INITIALISE AN API CONNECT FAIL RECORD */
10892 /*----------------------------------------------------------*/
initApiConnectFail(Signal * signal,Uint32 transid1,Uint32 transid2,LqhTransConf::OperationStatus transStatus,Uint32 reqinfo,BlockReference applRef,Uint64 gci,NodeId nodeId)10893 void Dbtc::initApiConnectFail(Signal* signal,
10894 Uint32 transid1,
10895 Uint32 transid2,
10896 LqhTransConf::OperationStatus transStatus,
10897 Uint32 reqinfo,
10898 BlockReference applRef,
10899 Uint64 gci,
10900 NodeId nodeId)
10901 {
10902 apiConnectptr.p->transid[0] = transid1;
10903 apiConnectptr.p->transid[1] = transid2;
10904 apiConnectptr.p->firstTcConnect = RNIL;
10905 apiConnectptr.p->currSavePointId = 0;
10906 apiConnectptr.p->lastTcConnect = RNIL;
10907 BlockReference blockRef = calcTcBlockRef(tcNodeFailptr.p->takeOverNode);
10908
10909 apiConnectptr.p->tcBlockref = blockRef;
10910 apiConnectptr.p->ndbapiBlockref = 0;
10911 apiConnectptr.p->ndbapiConnect = 0;
10912 apiConnectptr.p->buddyPtr = RNIL;
10913 apiConnectptr.p->m_transaction_nodes.clear();
10914 apiConnectptr.p->singleUserMode = 0;
10915 setApiConTimer(apiConnectptr.i, 0, __LINE__);
10916 switch(transStatus){
10917 case LqhTransConf::Committed:
10918 jam();
10919 apiConnectptr.p->globalcheckpointid = gci;
10920 apiConnectptr.p->apiConnectstate = CS_FAIL_COMMITTED;
10921 break;
10922 case LqhTransConf::Prepared:
10923 jam();
10924 apiConnectptr.p->apiConnectstate = CS_FAIL_PREPARED;
10925 break;
10926 case LqhTransConf::Aborted:
10927 jam();
10928 apiConnectptr.p->apiConnectstate = CS_FAIL_ABORTED;
10929 break;
10930 case LqhTransConf::Marker:
10931 jam();
10932 apiConnectptr.p->apiConnectstate = CS_FAIL_COMPLETED;
10933 break;
10934 default:
10935 jam();
10936 systemErrorLab(signal, __LINE__);
10937 }//if
10938 apiConnectptr.p->commitAckMarker = RNIL;
10939 if(LqhTransConf::getMarkerFlag(reqinfo)){
10940 jam();
10941 CommitAckMarkerPtr tmp;
10942
10943 {
10944 CommitAckMarker key;
10945 key.transid1 = transid1;
10946 key.transid2 = transid2;
10947 if (m_commitAckMarkerHash.find(tmp, key))
10948 {
10949 /**
10950 * We found a "lingering" marker...
10951 * most probably from earlier node failure
10952 * check consistency using lots of it-statements
10953 */
10954 jam();
10955 if (tmp.p->apiConnectPtr == RNIL)
10956 {
10957 jam();
10958 // ok - marker had no transaction, use it...
10959 }
10960 else
10961 {
10962 ApiConnectRecordPtr transPtr;
10963 transPtr.i = tmp.p->apiConnectPtr;
10964 ptrCheckGuard(transPtr, capiConnectFilesize, apiConnectRecord);
10965 if (transPtr.p->commitAckMarker == RNIL)
10966 {
10967 jam();
10968 // ok - marker had a transaction that had moved on, use it...
10969 }
10970 else if (transPtr.p->commitAckMarker != tmp.i)
10971 {
10972 jam();
10973 // ok - marker had a transaction that had moved on, use it...
10974 }
10975 else
10976 {
10977 jam();
10978 /**
10979 * marker pointed to a transaction that was pointing to marker...
10980 * i.e both transaction + marker lingering...
10981 * treat this as an updateApiStateFail and release already seize trans
10982 */
10983 releaseApiConnectFail(signal);
10984 apiConnectptr = transPtr;
10985 updateApiStateFail(signal,
10986 transid1,
10987 transid2,
10988 transStatus,
10989 reqinfo,
10990 applRef,
10991 gci,
10992 nodeId);
10993 return;
10994 }
10995 }
10996 }
10997 else
10998 {
10999 jam();
11000 m_commitAckMarkerHash.seize(tmp);
11001 ndbrequire(tmp.i != RNIL);
11002 new (tmp.p) CommitAckMarker();
11003 tmp.p->transid1 = transid1;
11004 tmp.p->transid2 = transid2;
11005 m_commitAckMarkerHash.add(tmp);
11006 }
11007 }
11008
11009 apiConnectptr.p->commitAckMarker = tmp.i;
11010 tmp.p->apiNodeId = refToNode(applRef);
11011 tmp.p->apiConnectPtr = apiConnectptr.i;
11012 ndbrequire(tmp.p->insert_in_commit_ack_marker_all(this, nodeId));
11013 }
11014 }//Dbtc::initApiConnectFail()
11015
11016 /*------------------------------------------------------------*/
11017 /* INITIALISE AT TC CONNECT AT TAKE OVER WHEN ALLOCATING*/
11018 /* THE TC CONNECT RECORD. */
11019 /*------------------------------------------------------------*/
initTcConnectFail(Signal * signal,Uint32 instanceKey,Uint32 tcOprec,Uint32 reqinfo,LqhTransConf::OperationStatus transStatus,NodeId nodeId)11020 void Dbtc::initTcConnectFail(Signal* signal,
11021 Uint32 instanceKey,
11022 Uint32 tcOprec,
11023 Uint32 reqinfo,
11024 LqhTransConf::OperationStatus transStatus,
11025 NodeId nodeId)
11026 {
11027 TcConnectRecord * regTcPtr = tcConnectptr.p;
11028 regTcPtr->apiConnect = apiConnectptr.i;
11029 regTcPtr->tcOprec = tcOprec;
11030 Uint32 replicaNo = LqhTransConf::getReplicaNo(reqinfo);
11031 for (Uint32 i = 0; i < MAX_REPLICAS; i++) {
11032 regTcPtr->failData[i] = LqhTransConf::InvalidStatus;
11033 }//for
11034 regTcPtr->tcNodedata[replicaNo] = nodeId;
11035 regTcPtr->failData[replicaNo] = transStatus;
11036 regTcPtr->lastReplicaNo = LqhTransConf::getLastReplicaNo(reqinfo);
11037 regTcPtr->dirtyOp = LqhTransConf::getDirtyFlag(reqinfo);
11038 regTcPtr->lqhInstanceKey = instanceKey;
11039 }//Dbtc::initTcConnectFail()
11040
11041 /*----------------------------------------------------------*/
11042 /* INITIALISE TC NODE FAIL RECORD. */
11043 /*----------------------------------------------------------*/
initTcFail(Signal * signal)11044 void Dbtc::initTcFail(Signal* signal)
11045 {
11046 tcNodeFailptr.i = 0;
11047 ptrAss(tcNodeFailptr, tcFailRecord);
11048 tcNodeFailptr.p->queueIndex = 0;
11049 tcNodeFailptr.p->failStatus = FS_IDLE;
11050 }//Dbtc::initTcFail()
11051
11052 /*----------------------------------------------------------*/
11053 /* RELEASE_TAKE_OVER */
11054 /*----------------------------------------------------------*/
releaseTakeOver(Signal * signal)11055 void Dbtc::releaseTakeOver(Signal* signal)
11056 {
11057 TcConnectRecordPtr rtoNextTcConnectptr;
11058
11059 rtoNextTcConnectptr.i = apiConnectptr.p->firstTcConnect;
11060 do {
11061 jam();
11062 tcConnectptr.i = rtoNextTcConnectptr.i;
11063 ptrCheckGuard(tcConnectptr, ctcConnectFilesize, tcConnectRecord);
11064 rtoNextTcConnectptr.i = tcConnectptr.p->nextTcConnect;
11065 releaseTcConnectFail(signal);
11066 } while (rtoNextTcConnectptr.i != RNIL);
11067 releaseApiConnectFail(signal);
11068 }//Dbtc::releaseTakeOver()
11069
11070 /*---------------------------------------------------------------------------*/
11071 /* SETUP_FAIL_DATA */
11072 /* SETUP DATA TO REUSE TAKE OVER CODE FOR HANDLING ABORT/COMMIT IN NODE */
11073 /* FAILURE SITUATIONS. */
11074 /*---------------------------------------------------------------------------*/
setupFailData(Signal * signal)11075 void Dbtc::setupFailData(Signal* signal)
11076 {
11077 tcConnectptr.i = apiConnectptr.p->firstTcConnect;
11078 do {
11079 ptrCheckGuard(tcConnectptr, ctcConnectFilesize, tcConnectRecord);
11080 switch (tcConnectptr.p->tcConnectstate) {
11081 case OS_PREPARED:
11082 case OS_COMMITTING:
11083 jam();
11084 arrGuard(tcConnectptr.p->lastReplicaNo, MAX_REPLICAS);
11085 for (tindex = 0; tindex <= tcConnectptr.p->lastReplicaNo; tindex++) {
11086 jam();
11087 /*-------------------------------------------------------------------
11088 * KEYDATA IS USED TO KEEP AN INDICATION OF STATE IN LQH.
11089 * IN THIS CASE ALL LQH'S ARE PREPARED AND WAITING FOR
11090 * COMMIT/ABORT DECISION.
11091 *------------------------------------------------------------------*/
11092 tcConnectptr.p->failData[tindex] = LqhTransConf::Prepared;
11093 }//for
11094 break;
11095 case OS_COMMITTED:
11096 case OS_COMPLETING:
11097 jam();
11098 arrGuard(tcConnectptr.p->lastReplicaNo, MAX_REPLICAS);
11099 for (tindex = 0; tindex <= tcConnectptr.p->lastReplicaNo; tindex++) {
11100 jam();
11101 /*-------------------------------------------------------------------
11102 * KEYDATA IS USED TO KEEP AN INDICATION OF STATE IN LQH.
11103 * IN THIS CASE ALL LQH'S ARE COMMITTED AND WAITING FOR
11104 * COMPLETE MESSAGE.
11105 *------------------------------------------------------------------*/
11106 tcConnectptr.p->failData[tindex] = LqhTransConf::Committed;
11107 }//for
11108 break;
11109 case OS_COMPLETED:
11110 jam();
11111 arrGuard(tcConnectptr.p->lastReplicaNo, MAX_REPLICAS);
11112 for (tindex = 0; tindex <= tcConnectptr.p->lastReplicaNo; tindex++) {
11113 jam();
11114 /*-------------------------------------------------------------------
11115 * KEYDATA IS USED TO KEEP AN INDICATION OF STATE IN LQH.
11116 * IN THIS CASE ALL LQH'S ARE COMPLETED.
11117 *-------------------------------------------------------------------*/
11118 tcConnectptr.p->failData[tindex] = LqhTransConf::InvalidStatus;
11119 }//for
11120 break;
11121 default:
11122 jam();
11123 sendSystemError(signal, __LINE__);
11124 break;
11125 }//switch
11126 if (tabortInd != ZCOMMIT_SETUP) {
11127 jam();
11128 for (UintR Ti = 0; Ti <= tcConnectptr.p->lastReplicaNo; Ti++) {
11129 hostptr.i = tcConnectptr.p->tcNodedata[Ti];
11130 ptrCheckGuard(hostptr, chostFilesize, hostRecord);
11131 if (hostptr.p->hostStatus != HS_ALIVE) {
11132 jam();
11133 /*-----------------------------------------------------------------
11134 * FAILURE OF ANY INVOLVED NODE ALWAYS INVOKES AN ABORT DECISION.
11135 *-----------------------------------------------------------------*/
11136 tabortInd = ZTRUE;
11137 }//if
11138 }//for
11139 }//if
11140 tcConnectptr.p->tcConnectstate = OS_TAKE_OVER;
11141 tcConnectptr.p->tcOprec = tcConnectptr.i;
11142 tcConnectptr.i = tcConnectptr.p->nextTcConnect;
11143 } while (tcConnectptr.i != RNIL);
11144 apiConnectptr.p->tcBlockref = cownref;
11145 apiConnectptr.p->currentTcConnect = apiConnectptr.p->firstTcConnect;
11146 tcConnectptr.i = apiConnectptr.p->firstTcConnect;
11147 ptrCheckGuard(tcConnectptr, ctcConnectFilesize, tcConnectRecord);
11148 apiConnectptr.p->currentReplicaNo = tcConnectptr.p->lastReplicaNo;
11149 tcurrentReplicaNo = tcConnectptr.p->lastReplicaNo;
11150 }//Dbtc::setupFailData()
11151
11152 /*----------------------------------------------------------*/
11153 /* UPDATE THE STATE OF THE API CONNECT FOR THIS PART. */
11154 /*----------------------------------------------------------*/
updateApiStateFail(Signal * signal,Uint32 transid1,Uint32 transid2,LqhTransConf::OperationStatus transStatus,Uint32 reqinfo,BlockReference applRef,Uint64 gci,NodeId nodeId)11155 void Dbtc::updateApiStateFail(Signal* signal,
11156 Uint32 transid1,
11157 Uint32 transid2,
11158 LqhTransConf::OperationStatus transStatus,
11159 Uint32 reqinfo,
11160 BlockReference applRef,
11161 Uint64 gci,
11162 NodeId nodeId)
11163 {
11164 if(LqhTransConf::getMarkerFlag(reqinfo))
11165 {
11166 CommitAckMarkerPtr tmp;
11167 const Uint32 marker = apiConnectptr.p->commitAckMarker;
11168 if (marker == RNIL)
11169 {
11170 jam();
11171
11172 m_commitAckMarkerHash.seize(tmp);
11173 ndbrequire(tmp.i != RNIL);
11174
11175 new (tmp.p) CommitAckMarker();
11176 apiConnectptr.p->commitAckMarker = tmp.i;
11177 tmp.p->transid1 = transid1;
11178 tmp.p->transid2 = transid2;
11179 tmp.p->apiNodeId = refToNode(applRef);
11180 tmp.p->apiConnectPtr = apiConnectptr.i;
11181 #if defined VM_TRACE || defined ERROR_INSERT
11182 {
11183 CommitAckMarkerPtr check;
11184 ndbrequire(!m_commitAckMarkerHash.find(check, *tmp.p));
11185 }
11186 #endif
11187 m_commitAckMarkerHash.add(tmp);
11188 } else {
11189 jam();
11190 tmp.i = marker;
11191 tmp.p = m_commitAckMarkerHash.getPtr(marker);
11192
11193 ndbrequire(tmp.p->transid1 == transid1);
11194 ndbrequire(tmp.p->transid2 == transid2);
11195 }
11196 ndbrequire(tmp.p->insert_in_commit_ack_marker_all(this, nodeId));
11197 }
11198
11199 switch (transStatus) {
11200 case LqhTransConf::Committed:
11201 jam();
11202 switch (apiConnectptr.p->apiConnectstate) {
11203 case CS_FAIL_COMMITTING:
11204 case CS_FAIL_COMMITTED:
11205 jam();
11206 ndbrequire(gci == apiConnectptr.p->globalcheckpointid);
11207 break;
11208 case CS_FAIL_PREPARED:
11209 jam();
11210 apiConnectptr.p->apiConnectstate = CS_FAIL_COMMITTING;
11211 apiConnectptr.p->globalcheckpointid = gci;
11212 break;
11213 case CS_FAIL_COMPLETED:
11214 jam();
11215 apiConnectptr.p->globalcheckpointid = gci;
11216 apiConnectptr.p->apiConnectstate = CS_FAIL_COMMITTED;
11217 break;
11218 default:
11219 jam();
11220 systemErrorLab(signal, __LINE__);
11221 break;
11222 }//switch
11223 break;
11224 case LqhTransConf::Prepared:
11225 jam();
11226 switch (apiConnectptr.p->apiConnectstate) {
11227 case CS_FAIL_COMMITTED:
11228 jam();
11229 apiConnectptr.p->apiConnectstate = CS_FAIL_COMMITTING;
11230 break;
11231 case CS_FAIL_ABORTED:
11232 jam();
11233 apiConnectptr.p->apiConnectstate = CS_FAIL_ABORTING;
11234 break;
11235 case CS_FAIL_COMMITTING:
11236 case CS_FAIL_PREPARED:
11237 case CS_FAIL_ABORTING:
11238 jam();
11239 /*empty*/;
11240 break;
11241 default:
11242 jam();
11243 systemErrorLab(signal, __LINE__);
11244 break;
11245 }//switch
11246 break;
11247 case LqhTransConf::Aborted:
11248 jam();
11249 switch (apiConnectptr.p->apiConnectstate) {
11250 case CS_FAIL_COMMITTING:
11251 case CS_FAIL_COMMITTED:
11252 jam();
11253 systemErrorLab(signal, __LINE__);
11254 break;
11255 case CS_FAIL_PREPARED:
11256 jam();
11257 apiConnectptr.p->apiConnectstate = CS_FAIL_ABORTING;
11258 break;
11259 case CS_FAIL_ABORTING:
11260 case CS_FAIL_ABORTED:
11261 jam();
11262 /*empty*/;
11263 break;
11264 default:
11265 jam();
11266 systemErrorLab(signal, __LINE__);
11267 break;
11268 }//switch
11269 break;
11270 case LqhTransConf::Marker:
11271 jam();
11272 break;
11273 default:
11274 jam();
11275 systemErrorLab(signal, __LINE__);
11276 break;
11277 }//switch
11278 }//Dbtc::updateApiStateFail()
11279
11280 /*------------------------------------------------------------*/
11281 /* UPDATE_TC_STATE_FAIL */
11282 /* */
11283 /* WE NEED TO UPDATE THE STATUS OF TC_CONNECT RECORD AND*/
11284 /* WE ALSO NEED TO CHECK THAT THERE IS CONSISTENCY */
11285 /* BETWEEN THE DIFFERENT REPLICAS. */
11286 /*------------------------------------------------------------*/
updateTcStateFail(Signal * signal,Uint32 instanceKey,Uint32 tcOprec,Uint32 reqinfo,LqhTransConf::OperationStatus transStatus,NodeId nodeId)11287 void Dbtc::updateTcStateFail(Signal* signal,
11288 Uint32 instanceKey,
11289 Uint32 tcOprec,
11290 Uint32 reqinfo,
11291 LqhTransConf::OperationStatus transStatus,
11292 NodeId nodeId)
11293 {
11294 const Uint8 replicaNo = LqhTransConf::getReplicaNo(reqinfo);
11295 const Uint8 lastReplicaNo = LqhTransConf::getLastReplicaNo(reqinfo);
11296 const Uint8 dirtyOp = LqhTransConf::getDirtyFlag(reqinfo);
11297
11298 TcConnectRecord * regTcPtr = tcConnectptr.p;
11299
11300 ndbrequire(regTcPtr->apiConnect == apiConnectptr.i);
11301 ndbrequire(regTcPtr->failData[replicaNo] == LqhTransConf::InvalidStatus);
11302 ndbrequire(regTcPtr->lastReplicaNo == lastReplicaNo);
11303 ndbrequire(regTcPtr->dirtyOp == dirtyOp);
11304
11305 regTcPtr->tcNodedata[replicaNo] = nodeId;
11306 regTcPtr->failData[replicaNo] = transStatus;
11307 ndbrequire(regTcPtr->tcOprec == tcOprec);
11308 ndbrequire(regTcPtr->lqhInstanceKey == instanceKey)
11309 }//Dbtc::updateTcStateFail()
11310
execTCGETOPSIZEREQ(Signal * signal)11311 void Dbtc::execTCGETOPSIZEREQ(Signal* signal)
11312 {
11313 jamEntry();
11314 CRASH_INSERTION(8000);
11315
11316 UintR Tuserpointer = signal->theData[0]; /* DBDIH POINTER */
11317 BlockReference Tusersblkref = signal->theData[1];/* DBDIH BLOCK REFERENCE */
11318 signal->theData[0] = Tuserpointer;
11319 signal->theData[1] = coperationsize;
11320 sendSignal(Tusersblkref, GSN_TCGETOPSIZECONF, signal, 2, JBB);
11321 }//Dbtc::execTCGETOPSIZEREQ()
11322
execTC_CLOPSIZEREQ(Signal * signal)11323 void Dbtc::execTC_CLOPSIZEREQ(Signal* signal)
11324 {
11325 jamEntry();
11326 CRASH_INSERTION(8001);
11327
11328 tuserpointer = signal->theData[0];
11329 tusersblkref = signal->theData[1];
11330 /* DBDIH BLOCK REFERENCE */
11331 coperationsize = 0;
11332 signal->theData[0] = tuserpointer;
11333 sendSignal(tusersblkref, GSN_TC_CLOPSIZECONF, signal, 1, JBB);
11334 }//Dbtc::execTC_CLOPSIZEREQ()
11335
11336 /* ######################################################################### */
11337 /* ####### ERROR MODULE ####### */
11338 /* ######################################################################### */
tabStateErrorLab(Signal * signal)11339 void Dbtc::tabStateErrorLab(Signal* signal)
11340 {
11341 terrorCode = ZSTATE_ERROR;
11342 releaseAtErrorLab(signal);
11343 }//Dbtc::tabStateErrorLab()
11344
wrongSchemaVersionErrorLab(Signal * signal)11345 void Dbtc::wrongSchemaVersionErrorLab(Signal* signal)
11346 {
11347 const TcKeyReq * const tcKeyReq = (TcKeyReq *)&signal->theData[0];
11348
11349 TableRecordPtr tabPtr;
11350 tabPtr.i = tcKeyReq->tableId;
11351 const Uint32 schemVer = tcKeyReq->tableSchemaVersion;
11352 ptrCheckGuard(tabPtr, ctabrecFilesize, tableRecord);
11353
11354 terrorCode = tabPtr.p->getErrorCode(schemVer);
11355
11356 abortErrorLab(signal);
11357 }//Dbtc::wrongSchemaVersionErrorLab()
11358
noFreeConnectionErrorLab(Signal * signal)11359 void Dbtc::noFreeConnectionErrorLab(Signal* signal)
11360 {
11361 terrorCode = ZNO_FREE_TC_CONNECTION;
11362 abortErrorLab(signal); /* RECORD. OTHERWISE GOTO ERRORHANDLING */
11363 }//Dbtc::noFreeConnectionErrorLab()
11364
aiErrorLab(Signal * signal)11365 void Dbtc::aiErrorLab(Signal* signal)
11366 {
11367 terrorCode = ZLENGTH_ERROR;
11368 abortErrorLab(signal);
11369 }//Dbtc::aiErrorLab()
11370
seizeDatabuferrorLab(Signal * signal)11371 void Dbtc::seizeDatabuferrorLab(Signal* signal)
11372 {
11373 terrorCode = ZGET_DATAREC_ERROR;
11374 releaseAtErrorLab(signal);
11375 }//Dbtc::seizeDatabuferrorLab()
11376
appendToSectionErrorLab(Signal * signal)11377 void Dbtc::appendToSectionErrorLab(Signal* signal)
11378 {
11379 terrorCode = ZGET_DATAREC_ERROR;
11380 releaseAtErrorLab(signal);
11381 }//Dbtc::appendToSectionErrorLab
11382
releaseAtErrorLab(Signal * signal)11383 void Dbtc::releaseAtErrorLab(Signal* signal)
11384 {
11385 ptrGuard(tcConnectptr);
11386 tcConnectptr.p->tcConnectstate = OS_ABORTING;
11387 /*-------------------------------------------------------------------------*
11388 * A FAILURE OF THIS OPERATION HAS OCCURRED. THIS FAILURE WAS EITHER A
11389 * FAULTY PARAMETER OR A RESOURCE THAT WAS NOT AVAILABLE.
11390 * WE WILL ABORT THE ENTIRE TRANSACTION SINCE THIS IS THE SAFEST PATH
11391 * TO HANDLE THIS PROBLEM.
11392 * SINCE WE HAVE NOT YET CONTACTED ANY LQH WE SET NUMBER OF NODES TO ZERO
11393 * WE ALSO SET THE STATE TO ABORTING TO INDICATE THAT WE ARE NOT EXPECTING
11394 * ANY SIGNALS.
11395 *-------------------------------------------------------------------------*/
11396 tcConnectptr.p->noOfNodes = 0;
11397 abortErrorLab(signal);
11398 }//Dbtc::releaseAtErrorLab()
11399
warningHandlerLab(Signal * signal,int line)11400 void Dbtc::warningHandlerLab(Signal* signal, int line)
11401 {
11402 ndbassert(false);
11403 }//Dbtc::warningHandlerLab()
11404
systemErrorLab(Signal * signal,int line)11405 void Dbtc::systemErrorLab(Signal* signal, int line)
11406 {
11407 progError(line, NDBD_EXIT_NDBREQUIRE);
11408 }//Dbtc::systemErrorLab()
11409
11410
11411 #ifdef ERROR_INSERT
testFragmentDrop(Signal * signal)11412 bool Dbtc::testFragmentDrop(Signal* signal)
11413 {
11414 Uint32 fragIdToDrop= ~0;
11415 /* Drop some fragments to test the dropped fragment handling code */
11416 if (ERROR_INSERTED(8074))
11417 fragIdToDrop= 1;
11418 else if (ERROR_INSERTED(8075))
11419 fragIdToDrop= 2;
11420 else if (ERROR_INSERTED(8076))
11421 fragIdToDrop= 3;
11422
11423 if ((signal->header.m_fragmentInfo == fragIdToDrop) ||
11424 ERROR_INSERTED(8077)) // Drop all fragments
11425 {
11426 /* This signal fragment should be dropped
11427 * Let's throw away the sections, and call the
11428 * signal dropped report handler
11429 * This code is replicating the effect of the code in
11430 * TransporterCallback::deliver_signal()
11431 */
11432 SectionHandle handle(this, signal);
11433 Uint32 secCount= handle.m_cnt;
11434 releaseSections(handle);
11435 SignalDroppedRep* rep = (SignalDroppedRep*)signal->theData;
11436 Uint32 gsn = signal->header.theVerId_signalNumber;
11437 Uint32 len = signal->header.theLength;
11438 Uint32 newLen= (len > 22 ? 22 : len);
11439 memmove(rep->originalData, signal->theData, (4 * newLen));
11440 rep->originalGsn = gsn;
11441 rep->originalLength = len;
11442 rep->originalSectionCount = secCount;
11443 signal->header.theVerId_signalNumber = GSN_SIGNAL_DROPPED_REP;
11444 signal->header.theLength = newLen + 3;
11445 signal->header.m_noOfSections = 0;
11446
11447 executeFunction(GSN_SIGNAL_DROPPED_REP, signal);
11448 return true;
11449 }
11450 return false;
11451 }
11452 #endif
11453
11454 /* ######################################################################### *
11455 * ####### SCAN MODULE ####### *
11456 * ######################################################################### *
11457
11458 The application orders a scan of a table. We divide the scan into a scan on
11459 each fragment. The scan uses the primary replicas since the scan might be
11460 used for an update in a separate transaction.
11461
11462 Scans are always done as a separate transaction. Locks from the scan
11463 can be overtaken by another transaction. Scans can never lock the entire
11464 table. Locks are released immediately after the read has been verified
11465 by the application. There is not even an option to leave the locks.
11466 The reason is that this would hurt real-time behaviour too much.
11467
11468 -# The first step in handling a scan of a table is to receive all signals
11469 defining the scan. If failures occur during this step we release all
11470 resource and reply with SCAN_TABREF providing the error code.
11471 If system load is too high, the request will not be allowed.
11472
11473 -# The second step retrieves the number of fragments that exist in the
11474 table. It also ensures that the table actually exist. After this,
11475 the scan is ready to be parallelised. The idea is that the receiving
11476 process (hereafter called delivery process) will start up a number
11477 of scan processes. Each of these scan processes will
11478 independently scan one fragment at a time. The delivery
11479 process object is the scan record and the scan process object is
11480 the scan fragment record plus the scan operation record.
11481
11482 -# The third step is thus performed in parallel. In the third step each
11483 scan process retrieves the primary replica of the fragment it will
11484 scan. Then it starts the scan as soon as the load on that node permits.
11485
11486 The LQH returns either when it retrieved the maximum number of tuples or
11487 when it has retrived at least one tuple and is hindered by a lock to
11488 retrieve the next tuple. This is to ensure that a scan process never
11489 can be involved in a deadlock situation.
11490
11491 Tuples from each fragment scan are sent directly to API from TUP, and tuples
11492 from different fragments are delivered in parallel (so will be interleaved
11493 when received).
11494
11495 When a batch of tuples from one fragment has been fully fetched, the scan of
11496 that fragment will not continue until the previous batch has been
11497 acknowledged by API with a SCAN_NEXTREQ signal.
11498
11499
11500 ERROR HANDLING
11501
11502 As already mentioned it is rather easy to handle errors before the scan
11503 processes have started. In this case it is enough to release the resources
11504 and send SCAN_TAB_REF.
11505
11506 If an error occurs in any of the scan processes then we have to stop all
11507 scan processes. We do however only stop the delivery process and ask
11508 the api to order us to close the scan. The reason is that we can easily
11509 enter into difficult timing problems since the application and this
11510 block is out of synch we will thus always start by report the error to
11511 the application and wait for a close request. This error report uses the
11512 SCAN_TABREF signal with a special error code that the api must check for.
11513
11514
11515 CLOSING AN ACTIVE SCAN
11516
11517 The application can close a scan for several reasons before it is completed.
11518 One reason was mentioned above where an error in a scan process led to a
11519 request to close the scan. Another reason could simply be that the
11520 application found what it looked for and is thus not interested in the
11521 rest of the scan.
11522
11523 IT COULD ALSO BE DEPENDENT ON INTERNAL ERRORS IN THE API.
11524
11525 When a close scan request is received, all scan processes are stopped and all
11526 resources belonging to those scan processes are released. Stopping the scan
11527 processes most often includes communication with an LQH where the local scan
11528 is controlled. Finally all resources belonging to the scan is released and
11529 the SCAN_TABCONF is sent with an indication of that the scan is closed.
11530
11531
11532 CLOSING A COMPLETED SCAN
11533
11534 When all scan processes are completed then a report is sent to the
11535 application which indicates that no more tuples can be fetched.
11536 The application will send a close scan and the same action as when
11537 closing an active scan is performed.
11538 In this case it will of course not find any active scan processes.
11539 It will even find all scan processes already released.
11540
11541 The reason for requiring the api to close the scan is the same as above.
11542 It is to avoid any timing problems due to that the api and this block
11543 is out of synch.
11544
11545 * ######################################################################## */
execSCAN_TABREQ(Signal * signal)11546 void Dbtc::execSCAN_TABREQ(Signal* signal)
11547 {
11548 jamEntry();
11549
11550 #ifdef ERROR_INSERT
11551 /* Test fragmented + dropped signal handling */
11552 if (ERROR_INSERTED(8074) ||
11553 ERROR_INSERTED(8075) ||
11554 ERROR_INSERTED(8076) ||
11555 ERROR_INSERTED(8077))
11556 {
11557 jam();
11558 if (testFragmentDrop(signal)) {
11559 jam();
11560 return;
11561 }
11562 } /* End of test fragmented + dropped signal handling */
11563 #endif
11564
11565 /* Reassemble if the request was fragmented */
11566 if (!assembleFragments(signal)){
11567 jam();
11568 return;
11569 }
11570
11571 const ScanTabReq * const scanTabReq = (ScanTabReq *)&signal->theData[0];
11572 const Uint32 ri = scanTabReq->requestInfo;
11573 const Uint32 schemaVersion = scanTabReq->tableSchemaVersion;
11574 const Uint32 transid1 = scanTabReq->transId1;
11575 const Uint32 transid2 = scanTabReq->transId2;
11576 const Uint32 tmpXX = scanTabReq->buddyConPtr;
11577 const Uint32 buddyPtr = (tmpXX == 0xFFFFFFFF ? RNIL : tmpXX);
11578 Uint32 currSavePointId = 0;
11579
11580 Uint32 noOprecPerFrag = ScanTabReq::getScanBatch(ri);
11581 Uint32 errCode;
11582 ScanRecordPtr scanptr;
11583
11584 /* Short SCANTABREQ has 1 section, Long has 2 or 3.
11585 * Section 0 : NDBAPI receiver ids (Mandatory)
11586 * Section 1 : ATTRINFO section (Mandatory for long SCAN_TABREQ
11587 * Section 2 : KEYINFO section (Optional for long SCAN_TABREQ
11588 */
11589 Uint32 numSections= signal->getNoOfSections();
11590 ndbassert( numSections >= 1 );
11591 bool isLongReq= numSections >= 2;
11592
11593 SectionHandle handle(this, signal);
11594 SegmentedSectionPtr api_op_ptr;
11595 handle.getSection(api_op_ptr, 0);
11596 // Scan parallelism is determined by the number of receiver ids sent
11597 Uint32 scanParallel = api_op_ptr.sz;
11598 Uint32 scanConcurrency = scanParallel;
11599 Uint32 * apiPtr = signal->theData+25; // temp storage
11600 copy(apiPtr, api_op_ptr);
11601
11602 Uint32 aiLength= 0;
11603 Uint32 keyLen= 0;
11604
11605 if (likely(isLongReq))
11606 {
11607 SegmentedSectionPtr attrInfoPtr, keyInfoPtr;
11608 /* Long SCANTABREQ, determine Ai and Key length from sections */
11609 handle.getSection(attrInfoPtr, ScanTabReq::AttrInfoSectionNum);
11610 aiLength= attrInfoPtr.sz;
11611 if (numSections == 3)
11612 {
11613 handle.getSection(keyInfoPtr, ScanTabReq::KeyInfoSectionNum);
11614 keyLen= keyInfoPtr.sz;
11615 }
11616 }
11617 else
11618 {
11619 /* Short SCANTABREQ, get Ai and Key length from signal */
11620 aiLength = (scanTabReq->attrLenKeyLen & 0xFFFF);
11621 keyLen = scanTabReq->attrLenKeyLen >> 16;
11622 }
11623
11624 apiConnectptr.i = scanTabReq->apiConnectPtr;
11625 tabptr.i = scanTabReq->tableId;
11626
11627 if (apiConnectptr.i >= capiConnectFilesize)
11628 {
11629 jam();
11630 releaseSections(handle);
11631 warningHandlerLab(signal, __LINE__);
11632 return;
11633 }//if
11634
11635 ptrAss(apiConnectptr, apiConnectRecord);
11636 ApiConnectRecord * transP = apiConnectptr.p;
11637
11638 if (transP->apiConnectstate != CS_CONNECTED) {
11639 jam();
11640 // could be left over from TCKEYREQ rollback
11641 if (transP->apiConnectstate == CS_ABORTING &&
11642 transP->abortState == AS_IDLE) {
11643 jam();
11644 } else if(transP->apiConnectstate == CS_STARTED &&
11645 transP->firstTcConnect == RNIL){
11646 jam();
11647 // left over from simple/dirty read
11648 } else {
11649 jam();
11650 jamLine(transP->apiConnectstate);
11651 errCode = ZSTATE_ERROR;
11652 goto SCAN_TAB_error_no_state_change;
11653 }
11654 }
11655
11656 if(tabptr.i >= ctabrecFilesize)
11657 {
11658 errCode = ZUNKNOWN_TABLE_ERROR;
11659 goto SCAN_TAB_error;
11660 }
11661
11662 if (unlikely (ScanTabReq::getViaSPJFlag(ri) &&
11663 /* Check that all nodes can handle SPJ requests. */
11664 !ndb_join_pushdown(getNodeVersionInfo().m_type[NodeInfo::DB]
11665 .m_min_version)))
11666 {
11667 jam();
11668 errCode = 4003; // Function not implemented
11669 goto SCAN_TAB_error;
11670 }
11671
11672 ptrAss(tabptr, tableRecord);
11673 if ((aiLength == 0) ||
11674 (!tabptr.p->checkTable(schemaVersion)) ||
11675 (scanConcurrency == 0) ||
11676 (cfirstfreeScanrec == RNIL)) {
11677 goto SCAN_error_check;
11678 }
11679 if (buddyPtr != RNIL) {
11680 jam();
11681 ApiConnectRecordPtr buddyApiPtr;
11682 buddyApiPtr.i = buddyPtr;
11683 ptrCheckGuard(buddyApiPtr, capiConnectFilesize, apiConnectRecord);
11684 if ((transid1 == buddyApiPtr.p->transid[0]) &&
11685 (transid2 == buddyApiPtr.p->transid[1])) {
11686 jam();
11687
11688 if (buddyApiPtr.p->apiConnectstate == CS_ABORTING) {
11689 // transaction has been aborted
11690 jam();
11691 errCode = buddyApiPtr.p->returncode;
11692 goto SCAN_TAB_error;
11693 }//if
11694 currSavePointId = buddyApiPtr.p->currSavePointId;
11695 buddyApiPtr.p->currSavePointId++;
11696 }
11697 }
11698
11699 if (getNodeState().startLevel == NodeState::SL_SINGLEUSER &&
11700 getNodeState().getSingleUserApi() !=
11701 refToNode(apiConnectptr.p->ndbapiBlockref))
11702 {
11703 errCode = ZCLUSTER_IN_SINGLEUSER_MODE;
11704 goto SCAN_TAB_error;
11705 }
11706
11707 scanptr = seizeScanrec(signal);
11708 ndbrequire(transP->apiScanRec == RNIL);
11709 ndbrequire(scanptr.p->scanApiRec == RNIL);
11710
11711 errCode = initScanrec(scanptr, scanTabReq, scanParallel, noOprecPerFrag,
11712 apiPtr);
11713 if (unlikely(errCode))
11714 {
11715 jam();
11716 transP->apiScanRec = scanptr.i;
11717 releaseScanResources(signal, scanptr, true /* NotStarted */);
11718 goto SCAN_TAB_error;
11719 }
11720
11721 releaseSection(handle.m_ptr[ScanTabReq::ReceiverIdSectionNum].i);
11722 if (likely(isLongReq))
11723 {
11724 jam();
11725 /* We keep the AttrInfo and KeyInfo sections */
11726 scanptr.p->scanAttrInfoPtr = handle.m_ptr[ScanTabReq::AttrInfoSectionNum].i;
11727 if (keyLen)
11728 {
11729 jam();
11730 scanptr.p->scanKeyInfoPtr = handle.m_ptr[ScanTabReq::KeyInfoSectionNum].i;
11731 }
11732 }
11733 else
11734 {
11735 jam();
11736 seizeCacheRecord(signal);
11737 cachePtr.p->attrlength = aiLength;
11738 cachePtr.p->keylen = keyLen;
11739 cachePtr.p->save1 = 0;
11740 }
11741 handle.clear();
11742
11743 scanptr.p->m_scan_dist_key = scanTabReq->distributionKey;
11744 scanptr.p->m_scan_dist_key_flag = ScanTabReq::getDistributionKeyFlag(ri);
11745
11746 transP->apiScanRec = scanptr.i;
11747 transP->returncode = 0;
11748 transP->transid[0] = transid1;
11749 transP->transid[1] = transid2;
11750 transP->buddyPtr = buddyPtr;
11751
11752 // The scan is started
11753 transP->apiConnectstate = CS_START_SCAN;
11754 transP->currSavePointId = currSavePointId;
11755
11756 /**********************************************************
11757 * We start the timer on scanRec to be able to discover a
11758 * timeout in the API the API now is in charge!
11759 ***********************************************************/
11760 setApiConTimer(apiConnectptr.i, ctcTimer, __LINE__);
11761 updateBuddyTimer(apiConnectptr);
11762
11763 /***********************************************************
11764 * WE HAVE NOW RECEIVED ALL REFERENCES TO SCAN OBJECTS IN
11765 * THE API. WE ARE NOW READY TO RECEIVE THE ATTRIBUTE INFO
11766 * IF ANY TO RECEIVE.
11767 **********************************************************/
11768 scanptr.p->scanState = ScanRecord::WAIT_AI;
11769
11770 if (ERROR_INSERTED(8038))
11771 {
11772 /**
11773 * Force API_FAILREQ
11774 */
11775 signal->theData[0] = refToNode(apiConnectptr.p->ndbapiBlockref);
11776 sendSignal(QMGR_REF, GSN_API_FAILREQ, signal, 1, JBA);
11777 CLEAR_ERROR_INSERT_VALUE;
11778 }
11779
11780 if (isLongReq)
11781 {
11782 /* All AttrInfo (and KeyInfo) has been received, continue
11783 * processing
11784 */
11785 diFcountReqLab(signal, scanptr);
11786 }
11787
11788 return;
11789
11790 SCAN_error_check:
11791 if (aiLength == 0) {
11792 jam();
11793 errCode = ZSCAN_AI_LEN_ERROR;
11794 goto SCAN_TAB_error;
11795 }//if
11796 if (!tabptr.p->checkTable(schemaVersion)){
11797 jam();
11798 errCode = tabptr.p->getErrorCode(schemaVersion);
11799 goto SCAN_TAB_error;
11800 }//if
11801 if (scanConcurrency == 0) {
11802 jam();
11803 errCode = ZNO_CONCURRENCY_ERROR;
11804 goto SCAN_TAB_error;
11805 }//if
11806 ndbrequire(cfirstfreeScanrec == RNIL);
11807 ndbrequire(cConcScanCount == cscanrecFileSize);
11808 jam();
11809 errCode = ZNO_SCANREC_ERROR;
11810 goto SCAN_TAB_error;
11811
11812 SCAN_TAB_error:
11813 jam();
11814 /**
11815 * Prepare for up coming ATTRINFO/KEYINFO
11816 */
11817 transP->apiConnectstate = CS_ABORTING;
11818 transP->abortState = AS_IDLE;
11819 transP->transid[0] = transid1;
11820 transP->transid[1] = transid2;
11821
11822 SCAN_TAB_error_no_state_change:
11823
11824 releaseSections(handle);
11825
11826 ScanTabRef * ref = (ScanTabRef*)&signal->theData[0];
11827 ref->apiConnectPtr = transP->ndbapiConnect;
11828 ref->transId1 = transid1;
11829 ref->transId2 = transid2;
11830 ref->errorCode = errCode;
11831 ref->closeNeeded = 0;
11832 sendSignal(transP->ndbapiBlockref, GSN_SCAN_TABREF,
11833 signal, ScanTabRef::SignalLength, JBB);
11834 return;
11835 }//Dbtc::execSCAN_TABREQ()
11836
11837 Uint32
initScanrec(ScanRecordPtr scanptr,const ScanTabReq * scanTabReq,UintR scanParallel,UintR noOprecPerFrag,const Uint32 apiPtr[])11838 Dbtc::initScanrec(ScanRecordPtr scanptr,
11839 const ScanTabReq * scanTabReq,
11840 UintR scanParallel,
11841 UintR noOprecPerFrag,
11842 const Uint32 apiPtr[])
11843 {
11844 const UintR ri = scanTabReq->requestInfo;
11845 scanptr.p->scanApiRec = apiConnectptr.i;
11846 scanptr.p->scanTableref = tabptr.i;
11847 scanptr.p->scanSchemaVersion = scanTabReq->tableSchemaVersion;
11848 scanptr.p->scanParallel = scanParallel;
11849 scanptr.p->first_batch_size_rows = scanTabReq->first_batch_size;
11850 scanptr.p->batch_byte_size = scanTabReq->batch_byte_size;
11851 scanptr.p->batch_size_rows = noOprecPerFrag;
11852 scanptr.p->m_scan_block_no = DBLQH;
11853 scanptr.p->m_scan_dist_key_flag = 0;
11854
11855 Uint32 tmp = 0;
11856 ScanFragReq::setLockMode(tmp, ScanTabReq::getLockMode(ri));
11857 ScanFragReq::setHoldLockFlag(tmp, ScanTabReq::getHoldLockFlag(ri));
11858 ScanFragReq::setKeyinfoFlag(tmp, ScanTabReq::getKeyinfoFlag(ri));
11859 ScanFragReq::setReadCommittedFlag(tmp,ScanTabReq::getReadCommittedFlag(ri));
11860 ScanFragReq::setRangeScanFlag(tmp, ScanTabReq::getRangeScanFlag(ri));
11861 ScanFragReq::setDescendingFlag(tmp, ScanTabReq::getDescendingFlag(ri));
11862 ScanFragReq::setTupScanFlag(tmp, ScanTabReq::getTupScanFlag(ri));
11863 ScanFragReq::setNoDiskFlag(tmp, ScanTabReq::getNoDiskFlag(ri));
11864 if (ScanTabReq::getViaSPJFlag(ri))
11865 {
11866 jam();
11867 scanptr.p->m_scan_block_no = DBSPJ;
11868 }
11869
11870 scanptr.p->scanRequestInfo = tmp;
11871 scanptr.p->scanStoredProcId = scanTabReq->storedProcId;
11872 scanptr.p->scanState = ScanRecord::RUNNING;
11873 scanptr.p->m_queued_count = 0;
11874 scanptr.p->m_booked_fragments_count = 0;
11875 scanptr.p->m_scan_cookie = DihScanTabConf::InvalidCookie;
11876 scanptr.p->m_close_scan_req = false;
11877 scanptr.p->m_pass_all_confs = ScanTabReq::getPassAllConfsFlag(ri);
11878 scanptr.p->m_4word_conf = ScanTabReq::get4WordConf(ri);
11879 scanptr.p->scanKeyInfoPtr = RNIL;
11880 scanptr.p->scanAttrInfoPtr = RNIL;
11881
11882 ScanFragList list(c_scan_frag_pool,
11883 scanptr.p->m_running_scan_frags);
11884 for (Uint32 i = 0; i < scanParallel; i++) {
11885 jam();
11886 ScanFragRecPtr ptr;
11887 if (unlikely((list.seizeFirst(ptr) == false) ||
11888 ERROR_INSERTED(8093)))
11889 {
11890 jam();
11891 goto errout;
11892 }
11893 ptr.p->scanFragState = ScanFragRec::IDLE;
11894 ptr.p->scanRec = scanptr.i;
11895 ptr.p->scanFragId = 0;
11896 ptr.p->m_apiPtr = apiPtr[i];
11897 }//for
11898
11899 (* (ScanTabReq::getRangeScanFlag(ri) ?
11900 &c_counters.c_range_scan_count :
11901 &c_counters.c_scan_count))++;
11902 return 0;
11903 errout:
11904 {
11905 ScanFragRecPtr ptr;
11906 bool found = list.first(ptr);
11907 while (found)
11908 {
11909 ScanFragRecPtr old_ptr = ptr;
11910 ptr.p->scanFragState = ScanFragRec::COMPLETED;
11911 found = list.next(ptr);
11912 list.release(old_ptr);
11913 }
11914 }
11915 return ZSCAN_FRAGREC_ERROR;
11916 }//Dbtc::initScanrec()
11917
scanTabRefLab(Signal * signal,Uint32 errCode)11918 void Dbtc::scanTabRefLab(Signal* signal, Uint32 errCode)
11919 {
11920 ScanTabRef * ref = (ScanTabRef*)&signal->theData[0];
11921 ref->apiConnectPtr = apiConnectptr.p->ndbapiConnect;
11922 ref->transId1 = apiConnectptr.p->transid[0];
11923 ref->transId2 = apiConnectptr.p->transid[1];
11924 ref->errorCode = errCode;
11925 ref->closeNeeded = 0;
11926 sendSignal(apiConnectptr.p->ndbapiBlockref, GSN_SCAN_TABREF,
11927 signal, ScanTabRef::SignalLength, JBB);
11928 }//Dbtc::scanTabRefLab()
11929
11930 /**
11931 * scanKeyinfoLab
11932 * Handle reception of KeyInfo for a Scan
11933 */
scanKeyinfoLab(Signal * signal)11934 void Dbtc::scanKeyinfoLab(Signal* signal)
11935 {
11936 /* Receive KEYINFO for a SCAN operation
11937 * Note that old NDBAPI nodes sometimes send header-only KEYINFO signals
11938 */
11939 CacheRecord * const regCachePtr = cachePtr.p;
11940 UintR TkeyLen = regCachePtr->keylen;
11941 UintR Tlen = regCachePtr->save1;
11942
11943 Uint32 wordsInSignal= MIN(KeyInfo::DataLength,
11944 (TkeyLen - Tlen));
11945
11946 ndbassert( signal->getLength() ==
11947 (KeyInfo::HeaderLength + wordsInSignal) );
11948
11949 if (unlikely ((! appendToSection(regCachePtr->keyInfoSectionI,
11950 &signal->theData[KeyInfo::HeaderLength],
11951 wordsInSignal)) ||
11952 ERROR_INSERTED(8094)))
11953 {
11954 jam();
11955 Uint32 transid0 = apiConnectptr.p->transid[0];
11956 Uint32 transid1 = apiConnectptr.p->transid[1];
11957 ndbrequire(apiConnectptr.p->apiScanRec != RNIL);
11958 ScanRecordPtr scanPtr;
11959 scanPtr.i = apiConnectptr.p->apiScanRec;
11960 ptrCheckGuard(scanPtr, cscanrecFileSize, scanRecord);
11961 abortScanLab(signal,
11962 scanPtr,
11963 ZGET_DATAREC_ERROR,
11964 true /* Not started */);
11965
11966 /* Prepare for up coming ATTRINFO/KEYINFO */
11967 apiConnectptr.p->apiConnectstate = CS_ABORTING;
11968 apiConnectptr.p->abortState = AS_IDLE;
11969 apiConnectptr.p->transid[0] = transid0;
11970 apiConnectptr.p->transid[1] = transid1;
11971
11972 return;
11973 }
11974
11975 Tlen+= wordsInSignal;
11976 regCachePtr->save1 = Tlen;
11977
11978 if (Tlen < TkeyLen)
11979 {
11980 jam();
11981 /* More KeyInfo still to come - continue waiting */
11982 setApiConTimer(apiConnectptr.i, ctcTimer, __LINE__);
11983 return;
11984 }
11985
11986 /* All KeyInfo has been received, we will now start receiving
11987 * ATTRINFO
11988 */
11989 jam();
11990 ndbassert(Tlen == TkeyLen);
11991 return;
11992 } // scanKeyinfoLab
11993
11994 /*---------------------------------------------------------------------------*/
11995 /* */
11996 /* RECEPTION OF ATTRINFO FOR SCAN TABLE REQUEST. */
11997 /*---------------------------------------------------------------------------*/
scanAttrinfoLab(Signal * signal,UintR Tlen)11998 void Dbtc::scanAttrinfoLab(Signal* signal, UintR Tlen)
11999 {
12000 ScanRecordPtr scanptr;
12001 scanptr.i = apiConnectptr.p->apiScanRec;
12002 ptrCheckGuard(scanptr, cscanrecFileSize, scanRecord);
12003 cachePtr.i = apiConnectptr.p->cachePtr;
12004 ptrCheckGuard(cachePtr, ccacheFilesize, cacheRecord);
12005 CacheRecord * const regCachePtr = cachePtr.p;
12006 ndbrequire(scanptr.p->scanState == ScanRecord::WAIT_AI);
12007
12008 regCachePtr->currReclenAi = regCachePtr->currReclenAi + Tlen;
12009
12010 if (unlikely(! appendToSection(regCachePtr->attrInfoSectionI,
12011 &signal->theData[AttrInfo::HeaderLength],
12012 Tlen)))
12013 {
12014 jam();
12015 abortScanLab(signal, scanptr, ZGET_ATTRBUF_ERROR, true);
12016 return;
12017 }
12018
12019 if (regCachePtr->currReclenAi == regCachePtr->attrlength)
12020 {
12021 jam();
12022 /* We have now received all the signals defining this
12023 * scan. We are ready to start executing the scan
12024 */
12025 scanptr.p->scanAttrInfoPtr = regCachePtr->attrInfoSectionI;
12026 scanptr.p->scanKeyInfoPtr = regCachePtr->keyInfoSectionI;
12027 releaseCacheRecord(apiConnectptr, regCachePtr);
12028 diFcountReqLab(signal, scanptr);
12029 return;
12030 }
12031 else if (unlikely (regCachePtr->currReclenAi > regCachePtr->attrlength))
12032 {
12033 jam();
12034 abortScanLab(signal, scanptr, ZLENGTH_ERROR, true);
12035 return;
12036 }
12037
12038 /* Still some ATTRINFO to arrive...*/
12039 return;
12040 }//Dbtc::scanAttrinfoLab()
12041
diFcountReqLab(Signal * signal,ScanRecordPtr scanptr)12042 void Dbtc::diFcountReqLab(Signal* signal, ScanRecordPtr scanptr)
12043 {
12044 /**
12045 * Check so that the table is not being dropped
12046 */
12047 TableRecordPtr tabPtr;
12048 tabPtr.i = scanptr.p->scanTableref;
12049 tabPtr.p = &tableRecord[tabPtr.i];
12050 if (tabPtr.p->checkTable(scanptr.p->scanSchemaVersion)){
12051 ;
12052 } else {
12053 abortScanLab(signal, scanptr,
12054 tabPtr.p->getErrorCode(scanptr.p->scanSchemaVersion),
12055 true);
12056 return;
12057 }
12058
12059 scanptr.p->scanNextFragId = 0;
12060 scanptr.p->m_booked_fragments_count= 0;
12061 scanptr.p->scanState = ScanRecord::WAIT_FRAGMENT_COUNT;
12062
12063 /*************************************************
12064 * THE FIRST STEP TO RECEIVE IS SUCCESSFULLY COMPLETED.
12065 ***************************************************/
12066 ndbassert(scanptr.p->m_scan_cookie == DihScanTabConf::InvalidCookie);
12067 DihScanTabReq * req = (DihScanTabReq*)signal->getDataPtrSend();
12068 req->senderRef = reference();
12069 req->senderData = scanptr.p->scanApiRec;
12070 req->tableId = scanptr.p->scanTableref;
12071 req->schemaTransId = 0;
12072 sendSignal(cdihblockref, GSN_DIH_SCAN_TAB_REQ, signal,
12073 DihScanTabReq::SignalLength, JBB);
12074 return;
12075 }//Dbtc::diFcountReqLab()
12076
12077 /********************************************************************
12078 * execDIH_SCAN_TAB_CONF
12079 *
12080 * WE HAVE ASKED DIH ABOUT THE NUMBER OF FRAGMENTS IN THIS TABLE.
12081 * WE WILL NOW START A NUMBER OF PARALLEL SCAN PROCESSES. EACH OF
12082 * THESE WILL SCAN ONE FRAGMENT AT A TIME. THEY WILL CONTINUE THIS
12083 * UNTIL THERE ARE NO MORE FRAGMENTS TO SCAN OR UNTIL THE APPLICATION
12084 * CLOSES THE SCAN.
12085 ********************************************************************/
execDIH_SCAN_TAB_CONF(Signal * signal)12086 void Dbtc::execDIH_SCAN_TAB_CONF(Signal* signal)
12087 {
12088 jamEntry();
12089 DihScanTabConf * conf = (DihScanTabConf*)signal->getDataPtr();
12090 Uint32 tfragCount = conf->fragmentCount;
12091 apiConnectptr.i = conf->senderData;
12092 ptrCheckGuard(apiConnectptr, capiConnectFilesize, apiConnectRecord);
12093 ApiConnectRecord * const regApiPtr = apiConnectptr.p;
12094 ScanRecordPtr scanptr;
12095 scanptr.i = regApiPtr->apiScanRec;
12096 ptrCheckGuard(scanptr, cscanrecFileSize, scanRecord);
12097 ndbrequire(scanptr.p->scanState == ScanRecord::WAIT_FRAGMENT_COUNT);
12098 scanptr.p->m_scan_cookie = conf->scanCookie;
12099 ndbrequire(scanptr.p->m_scan_cookie != DihScanTabConf::InvalidCookie);
12100
12101 if (conf->reorgFlag)
12102 {
12103 jam();
12104 ScanFragReq::setReorgFlag(scanptr.p->scanRequestInfo, ScanFragReq::REORG_NOT_MOVED);
12105 }
12106 if (regApiPtr->apiFailState == ZTRUE) {
12107 jam();
12108 releaseScanResources(signal, scanptr, true);
12109 handleApiFailState(signal, apiConnectptr.i);
12110 return;
12111 }//if
12112 if (tfragCount == 0) {
12113 jam();
12114 abortScanLab(signal, scanptr, ZNO_FRAGMENT_ERROR, true);
12115 return;
12116 }//if
12117
12118 /**
12119 * Check so that the table is not being dropped
12120 */
12121 TableRecordPtr tabPtr;
12122 tabPtr.i = scanptr.p->scanTableref;
12123 tabPtr.p = &tableRecord[tabPtr.i];
12124 if (tabPtr.p->checkTable(scanptr.p->scanSchemaVersion)){
12125 ;
12126 } else {
12127 abortScanLab(signal, scanptr,
12128 tabPtr.p->getErrorCode(scanptr.p->scanSchemaVersion),
12129 true);
12130 return;
12131 }
12132
12133 if (scanptr.p->m_scan_dist_key_flag)
12134 {
12135 jam();
12136 ndbrequire(DictTabInfo::isOrderedIndex(tabPtr.p->tableType) ||
12137 tabPtr.p->get_user_defined_partitioning());
12138
12139 DiGetNodesReq * req = (DiGetNodesReq *)&signal->theData[0];
12140 const DiGetNodesConf * get_conf = (DiGetNodesConf *)&signal->theData[0];
12141 req->tableId = tabPtr.i;
12142 req->hashValue = scanptr.p->m_scan_dist_key;
12143 req->distr_key_indicator = tabPtr.p->get_user_defined_partitioning();
12144 req->jamBufferPtr = jamBuffer();
12145 EXECUTE_DIRECT(DBDIH, GSN_DIGETNODESREQ, signal,
12146 DiGetNodesReq::SignalLength, 0);
12147 UintR TerrorIndicator = signal->theData[0];
12148 jamEntry();
12149 if (TerrorIndicator != 0)
12150 {
12151 jam();
12152 abortScanLab(signal, scanptr,
12153 signal->theData[1],
12154 true);
12155 return;
12156 }
12157
12158 scanptr.p->scanNextFragId = get_conf->fragId;
12159 tfragCount = 1;
12160 }
12161
12162 scanptr.p->scanParallel = tfragCount;
12163 scanptr.p->scanNoFrag = tfragCount;
12164 scanptr.p->scanState = ScanRecord::RUNNING;
12165
12166 setApiConTimer(apiConnectptr.i, 0, __LINE__);
12167 updateBuddyTimer(apiConnectptr);
12168
12169 /** Need own local scope of list(...,m_running_scan_frags) */
12170 {
12171 ScanFragRecPtr ptr;
12172 ScanFragList list(c_scan_frag_pool, scanptr.p->m_running_scan_frags);
12173
12174 /**
12175 * Initially list(...,m_running_scan_frags) contains an 'IDLE' entry
12176 * for all fragments. Now assign fragId to those 'tfragCount' fragments
12177 * to execute in parallel.
12178 */
12179 for (list.first(ptr); !ptr.isNull() && tfragCount;
12180 list.next(ptr), tfragCount--){
12181 jam();
12182
12183 ndbassert(ptr.p->scanFragState == ScanFragRec::IDLE);
12184 ptr.p->lqhBlockref = 0;
12185 ptr.p->scanFragId = scanptr.p->scanNextFragId++;
12186 }//for
12187
12188 /**
12189 * Any remaining fragments, not allowed to execute in parallel, are
12190 * put into the 'queued-list' until they can be executed.
12191 */
12192 ScanFragList queued(c_scan_frag_pool, scanptr.p->m_queued_scan_frags);
12193 for (; !ptr.isNull();)
12194 {
12195 jam();
12196 ptr.p->m_ops = 0;
12197 ptr.p->m_totalLen = 0;
12198 ptr.p->m_scan_frag_conf_status = 1;
12199 ptr.p->scanFragState = ScanFragRec::QUEUED_FOR_DELIVERY;
12200 ptr.p->stopFragTimer();
12201
12202 ScanFragRecPtr tmp;
12203 tmp.i = ptr.i;
12204 tmp.p = ptr.p;
12205 list.next(ptr);
12206 list.remove(tmp);
12207 queued.addFirst(tmp);
12208 scanptr.p->m_queued_count++;
12209 }
12210 }
12211
12212 /**
12213 * Start by requesting fragment info from DIH.
12214 * Max MAX_DIH_FRAG_REQS fragments can be requested at once.
12215 * If needed we will send more requests after CONF is received.
12216 */
12217 jam();
12218 sendDihGetNodesReq(signal, scanptr);
12219
12220 }//Dbtc::execDIH_SCAN_TAB_CONF()
12221
12222 /********************************************************************
12223 * sendDihGetNodesReq
12224 *
12225 * Will check the 'm_running_scan_frags' list for fragments which
12226 * are still 'IDLE'. These should be started by requesting
12227 * node info in a DIH_SCAN_GET_NODES_REQ.
12228 *
12229 * In order to avoid CPU starvation, or unmanagable huge FragItem[],
12230 * max MAX_DIH_FRAG_REQS are requested in a single signal.
12231 * If there are more fragments, we have to repeatable call this
12232 * function when CONF for the first fragment set is received.
12233 ********************************************************************/
sendDihGetNodesReq(Signal * signal,ScanRecordPtr scanptr)12234 void Dbtc::sendDihGetNodesReq(Signal* signal, ScanRecordPtr scanptr)
12235 {
12236 jam();
12237 ScanFragRecPtr ptr;
12238 DihScanGetNodesReq* req = (DihScanGetNodesReq*)signal->getDataPtrSend();
12239 Uint32 fragCnt = 0;
12240
12241 { // running-list scope
12242 ScanFragList list(c_scan_frag_pool, scanptr.p->m_running_scan_frags);
12243
12244 for (list.first(ptr);
12245 !ptr.isNull() && fragCnt < DihScanGetNodesReq::MAX_DIH_FRAG_REQS;
12246 list.next(ptr))
12247 {
12248 jam();
12249
12250 /**
12251 * Check correct CONTINUEB(ZSTART_FRAG_SCAN) handling in
12252 * combination with multiple DIH_SCAN_GET_NODES_REQ /_CONF.
12253 * Setup such that we will have a one fragment REQ
12254 * pending after this REQ.
12255 * ::startFragScans executed when first _CONF arrives
12256 * will be delayed with CONTINUEB in order to possibly
12257 * bring it out of sequence with last (remaining) _CONF.
12258 */
12259 if (ERROR_INSERTED(8097) &&
12260 fragCnt > 0 &&
12261 ptr.p->scanFragId == scanptr.p->scanNoFrag-1) //Last FragId
12262 {
12263 jam();
12264 break;
12265 }
12266
12267 if (ptr.p->scanFragState == ScanFragRec::IDLE) // Start it NOW!.
12268 {
12269 jam();
12270 ptr.p->scanFragState = ScanFragRec::WAIT_GET_PRIMCONF;
12271 ptr.p->startFragTimer(ctcTimer);
12272 req->fragItem[fragCnt].senderData = ptr.i;
12273 req->fragItem[fragCnt].fragId = ptr.p->scanFragId;
12274
12275 fragCnt++;
12276 } // if IDLE
12277 }
12278 } // running-list scope
12279
12280 if (fragCnt > 0)
12281 {
12282 jam();
12283 req->senderRef = reference();
12284 req->tableId = scanptr.p->scanTableref;
12285 req->scanCookie = scanptr.p->m_scan_cookie;
12286 req->fragCnt = fragCnt;
12287
12288 /** Always send as a long signal, even if a short would
12289 * have been sufficient in the (rare) case of 'fragCnt==1'
12290 */
12291 Ptr<SectionSegment> fragReq;
12292 const Uint32 len = fragCnt*DihScanGetNodesReq::FragItem::Length;
12293
12294 if (ERROR_INSERTED_CLEAR(8095) || // Fail once
12295 unlikely(!import(fragReq, (Uint32*)req->fragItem, len)))
12296 {
12297 jam();
12298
12299 /** Handling of failed REQ is similar to :execDIH_SCAN_GET_NODES_REF */
12300 for (Uint32 i = 0; i < fragCnt; i++)
12301 {
12302 jam();
12303 ptr.i = req->fragItem[i].senderData;
12304 c_scan_frag_pool.getPtr(ptr);
12305
12306 ndbrequire(ptr.p->scanFragState == ScanFragRec::WAIT_GET_PRIMCONF);
12307 ptr.p->scanFragState = ScanFragRec::COMPLETED;
12308 ptr.p->stopFragTimer();
12309 {
12310 ScanFragList run(c_scan_frag_pool, scanptr.p->m_running_scan_frags);
12311 run.release(ptr);
12312 }
12313 }
12314 scanError(signal, scanptr, ZGET_DATAREC_ERROR);
12315 return;
12316 }
12317 SectionHandle handle(this, fragReq.i);
12318 sendSignal(cdihblockref, GSN_DIH_SCAN_GET_NODES_REQ, signal,
12319 DihScanGetNodesReq::FixedSignalLength,
12320 JBB, &handle);
12321 }
12322 }//Dbtc::sendDihGetNodesReq
12323
12324 /******************************************************
12325 * execDIH_SCAN_TAB_REF
12326 ******************************************************/
execDIH_SCAN_TAB_REF(Signal * signal)12327 void Dbtc::execDIH_SCAN_TAB_REF(Signal* signal)
12328 {
12329 jamEntry();
12330 DihScanTabRef * ref = (DihScanTabRef*)signal->getDataPtr();
12331 const Uint32 errCode = ref->error;
12332 apiConnectptr.i = ref->senderData;
12333 ptrCheckGuard(apiConnectptr, capiConnectFilesize, apiConnectRecord);
12334 ScanRecordPtr scanptr;
12335 scanptr.i = apiConnectptr.p->apiScanRec;
12336 ptrCheckGuard(scanptr, cscanrecFileSize, scanRecord);
12337 ndbrequire(scanptr.p->scanState == ScanRecord::WAIT_FRAGMENT_COUNT);
12338 if (apiConnectptr.p->apiFailState == ZTRUE) {
12339 jam();
12340 releaseScanResources(signal, scanptr, true);
12341 handleApiFailState(signal, apiConnectptr.i);
12342 return;
12343 }//if
12344 abortScanLab(signal, scanptr, errCode, true);
12345 }//Dbtc::execDIH_SCAN_TAB_REF()
12346
abortScanLab(Signal * signal,ScanRecordPtr scanptr,Uint32 errCode,bool not_started)12347 void Dbtc::abortScanLab(Signal* signal, ScanRecordPtr scanptr, Uint32 errCode,
12348 bool not_started)
12349 {
12350 scanTabRefLab(signal, errCode);
12351 releaseScanResources(signal, scanptr, not_started);
12352 }//Dbtc::abortScanLab()
12353
releaseScanResources(Signal * signal,ScanRecordPtr scanPtr,bool not_started)12354 void Dbtc::releaseScanResources(Signal* signal,
12355 ScanRecordPtr scanPtr,
12356 bool not_started)
12357 {
12358 if (apiConnectptr.p->cachePtr != RNIL) {
12359 cachePtr.i = apiConnectptr.p->cachePtr;
12360 ptrCheckGuard(cachePtr, ccacheFilesize, cacheRecord);
12361 releaseKeys();
12362 releaseAttrinfo();
12363 }//if
12364
12365 if (not_started)
12366 {
12367 jam();
12368 ScanFragList run(c_scan_frag_pool, scanPtr.p->m_running_scan_frags);
12369 ScanFragList queue(c_scan_frag_pool, scanPtr.p->m_queued_scan_frags);
12370 ScanFragRecPtr ptr;
12371 bool found = run.first(ptr);
12372 while (found)
12373 {
12374 ScanFragRecPtr old_ptr = ptr;
12375 ptr.p->scanFragState = ScanFragRec::COMPLETED;
12376 found = run.next(ptr);
12377 run.release(old_ptr);
12378 }
12379 found = queue.first(ptr);
12380 while (found)
12381 {
12382 ScanFragRecPtr old_ptr = ptr;
12383 ptr.p->scanFragState = ScanFragRec::COMPLETED;
12384 found = queue.next(ptr);
12385 queue.release(old_ptr);
12386 }
12387 }
12388
12389 if (scanPtr.p->scanKeyInfoPtr != RNIL)
12390 {
12391 releaseSection(scanPtr.p->scanKeyInfoPtr);
12392 scanPtr.p->scanKeyInfoPtr = RNIL;
12393 }
12394
12395 if (scanPtr.p->scanAttrInfoPtr != RNIL)
12396 {
12397 releaseSection(scanPtr.p->scanAttrInfoPtr);
12398 scanPtr.p->scanAttrInfoPtr = RNIL;
12399 }
12400
12401 ndbrequire(scanPtr.p->m_running_scan_frags.isEmpty());
12402 ndbrequire(scanPtr.p->m_queued_scan_frags.isEmpty());
12403 ndbrequire(scanPtr.p->m_delivered_scan_frags.isEmpty());
12404
12405 ndbassert(scanPtr.p->scanApiRec == apiConnectptr.i);
12406 ndbassert(apiConnectptr.p->apiScanRec == scanPtr.i);
12407
12408 if (scanPtr.p->m_scan_cookie != DihScanTabConf::InvalidCookie)
12409 {
12410 /* Cookie was requested, 'return' it */
12411 DihScanTabCompleteRep* rep = (DihScanTabCompleteRep*)signal->getDataPtrSend();
12412 rep->tableId = scanPtr.p->scanTableref;
12413 rep->scanCookie = scanPtr.p->m_scan_cookie;
12414 sendSignal(cdihblockref, GSN_DIH_SCAN_TAB_COMPLETE_REP,
12415 signal, DihScanTabCompleteRep::SignalLength, JBB);
12416 scanPtr.p->m_scan_cookie = DihScanTabConf::InvalidCookie;
12417 }
12418
12419 // link into free list
12420 scanPtr.p->nextScan = cfirstfreeScanrec;
12421 scanPtr.p->scanState = ScanRecord::IDLE;
12422 scanPtr.p->scanApiRec = RNIL;
12423 cfirstfreeScanrec = scanPtr.i;
12424 ndbassert(cConcScanCount > 0);
12425 cConcScanCount--;
12426
12427 apiConnectptr.p->apiScanRec = RNIL;
12428 apiConnectptr.p->apiConnectstate = CS_CONNECTED;
12429 setApiConTimer(apiConnectptr.i, 0, __LINE__);
12430 }//Dbtc::releaseScanResources()
12431
12432
12433 /****************************************************************
12434 * execDIH_SCAN_GET_NODES_CONF
12435 *
12436 * WE HAVE RECEIVED THE PRIMARY NODES OF ALL FRAGMENTS.
12437 * WE ARE NOW READY TO ASK FOR PERMISSION TO LOAD THESE
12438 * NODES WITH A SCAN OPERATIONS.
12439 ****************************************************************/
execDIH_SCAN_GET_NODES_CONF(Signal * signal)12440 void Dbtc::execDIH_SCAN_GET_NODES_CONF(Signal* signal)
12441 {
12442 jamEntry();
12443 DihScanGetNodesConf * conf = (DihScanGetNodesConf*)signal->getDataPtr();
12444 const Uint32 tableId = conf->tableId;
12445
12446 if (signal->getNoOfSections() > 0)
12447 {
12448 // Long signal: FragItems listed in first section
12449 jam();
12450 SectionHandle handle(this, signal);
12451 ndbassert(handle.m_cnt==1);
12452 startFragScansLab(signal, tableId, handle, 0);
12453
12454 /**
12455 * NOTE: No sendDihGetNodesReq() as part of this branch!
12456 * startFragScansLab() will, when required, sendDihGetNodesReq()
12457 * after it has completed without a CONTINUEB, or after
12458 * CONTINUEB(ZSTART_FRAG_SCAN) completed last fragment.
12459 */
12460 }
12461 else // Short signal, with single FragItem
12462 {
12463 jam();
12464 ndbassert(conf->fragCnt == 1);
12465 ndbassert(signal->getLength()
12466 == DihScanGetNodesConf::FixedSignalLength + DihScanGetNodesConf::FragItem::Length);
12467
12468 DihScanGetNodesConf::FragItem fragConf[1];
12469 memcpy(fragConf, conf->fragItem, 4 * DihScanGetNodesConf::FragItem::Length);
12470 startFragScanLab(signal, tableId, fragConf[0]);
12471
12472 /**
12473 * As MAX_DIH_FRAG_REQS fragments can be requested at once,
12474 * we may have to send more DIH_SCAN_GET_NODES_REQ now
12475 */
12476 ScanRecordPtr scanptr;
12477 scanptr.i = scanFragptr.p->scanRec;
12478 ptrCheckGuard(scanptr, cscanrecFileSize, scanRecord);
12479 sendDihGetNodesReq(signal, scanptr);
12480 }
12481 }//Dbtc::execDIH_SCAN_GET_NODES_CONF
12482
12483 /****************************************************************
12484 * startFragScansLab
12485 *
12486 * PROCESS THE LIST OF DihScanGetNodesConf::FragItem RECEIVED
12487 * FROM ::execDIH_SCAN_GET_NODES_CONF. SEND A 'SCAN_FRAGREQ'
12488 * FOR EACH OF THESE.
12489 * AVOID PRODUCING TOO MANY LOCAL SIGNALS WHICH MAY RESULT IN
12490 * A 'Out of SendBuffers' ERROR. IN THESE CASES WE TAKE A BREAK
12491 * AND CONTINUEB LATER.
12492 ****************************************************************/
startFragScansLab(Signal * signal,Uint32 tableId,SectionHandle & handle,Uint32 secOffs)12493 void Dbtc::startFragScansLab(Signal* signal, Uint32 tableId,
12494 SectionHandle& handle, Uint32 secOffs)
12495 {
12496 Uint32 cntLocalSignals = 0;
12497 const NodeId ownNodeId = getOwnNodeId();
12498 SectionReader fragReader(handle.m_ptr[0], getSectionSegmentPool());
12499 ndbassert((fragReader.getSize() % DihScanGetNodesConf::FragItem::Length) == 0);
12500 ndbrequire(fragReader.step(secOffs));
12501
12502 DihScanGetNodesConf::FragItem fragConf;
12503 while (fragReader.getWords((Uint32*)&fragConf,DihScanGetNodesConf::FragItem::Length))
12504 {
12505 jam();
12506
12507 /**
12508 * ::startFragScans() should be allowed to take a CONTINUEB break
12509 * at any point. Execution of that CONTINUEB may be delayed
12510 * due to job buffer scheduling policy.
12511 * Check that such delay will not be harmfull.
12512 */
12513 if (ERROR_INSERTED_CLEAR(8097))
12514 {
12515 jam();
12516 signal->theData[0] = TcContinueB::ZSTART_FRAG_SCANS;
12517 signal->theData[1] = tableId;
12518 signal->theData[2] = secOffs;
12519 sendSignalWithDelay(reference(), GSN_CONTINUEB, signal, 3, 10, &handle);
12520 return;
12521 }
12522
12523 if (fragConf.nodes[0] == ownNodeId)
12524 {
12525 cntLocalSignals++;
12526
12527 /**
12528 * A max fanout of 1::4 of consumed::produced signals are allowed.
12529 * If we are about to produce more, we have to contine later.
12530 */
12531 if (cntLocalSignals >= 4)
12532 {
12533 jam();
12534 signal->theData[0] = TcContinueB::ZSTART_FRAG_SCANS;
12535 signal->theData[1] = tableId;
12536 signal->theData[2] = secOffs;
12537 sendSignal(reference(), GSN_CONTINUEB, signal, 3, JBB, &handle);
12538 return;
12539 }
12540 }
12541
12542 startFragScanLab(signal, tableId, fragConf);
12543 secOffs += DihScanGetNodesConf::FragItem::Length;
12544 } //while
12545
12546 jam();
12547 releaseSections(handle);
12548
12549 /**
12550 * Scan for all fragments in current DIH_SCAN_GET_NODES_CONF
12551 * completed. Send more DIH_SCAN_GET_NODES_REQ if required:
12552 * (As MAX_DIH_FRAG_REQS fragments can be requested at once)
12553 */
12554 ScanRecordPtr scanptr;
12555 scanptr.i = scanFragptr.p->scanRec;
12556 ptrCheckGuard(scanptr, cscanrecFileSize, scanRecord);
12557 sendDihGetNodesReq(signal, scanptr);
12558 }//Dbtc::startFragScansLab
12559
startFragScanLab(Signal * signal,Uint32 tableId,const DihScanGetNodesConf::FragItem & fragConf)12560 void Dbtc::startFragScanLab(Signal* signal, Uint32 tableId,
12561 const DihScanGetNodesConf::FragItem& fragConf)
12562 {
12563 jam();
12564 const NodeId ownNodeId = getOwnNodeId();
12565
12566 scanFragptr.i = fragConf.senderData;
12567 c_scan_frag_pool.getPtr(scanFragptr);
12568
12569 NodeId nodeId = fragConf.nodes[0];
12570 arrGuard(nodeId, MAX_NDB_NODES);
12571
12572 if (ERROR_INSERTED(8050) && nodeId != ownNodeId)
12573 {
12574 /* Asked to scan a fragment which is not on the same node as the
12575 * TC - transaction hinting / scan partition pruning has failed
12576 * Used by testPartitioning.cpp
12577 */
12578 CRASH_INSERTION(8050);
12579 }
12580
12581 ndbrequire(scanFragptr.p->scanFragState == ScanFragRec::WAIT_GET_PRIMCONF);
12582 scanFragptr.p->stopFragTimer();
12583
12584 ScanRecordPtr scanptr;
12585 scanptr.i = scanFragptr.p->scanRec;
12586 ptrCheckGuard(scanptr, cscanrecFileSize, scanRecord);
12587
12588 /**
12589 * This must be false as select count(*) otherwise
12590 * can "pass" committing on backup fragments and
12591 * get incorrect row count
12592 */
12593 if (false && ScanFragReq::getReadCommittedFlag(scanptr.p->scanRequestInfo))
12594 {
12595 jam();
12596 for (Uint32 i = 1; i<fragConf.count; i++)
12597 {
12598 if (fragConf.nodes[i] == ownNodeId)
12599 {
12600 jam();
12601 nodeId = ownNodeId;
12602 break;
12603 }
12604 }
12605 }
12606
12607 {
12608 /**
12609 * Check table
12610 */
12611 TableRecordPtr tabPtr;
12612 tabPtr.i = scanptr.p->scanTableref;
12613 ptrAss(tabPtr, tableRecord);
12614 Uint32 schemaVersion = scanptr.p->scanSchemaVersion;
12615 if (ERROR_INSERTED(8081) || tabPtr.p->checkTable(schemaVersion) == false)
12616 {
12617 jam();
12618 Uint32 err;
12619 if (ERROR_INSERTED(8081))
12620 {
12621 err = ZTIME_OUT_ERROR;
12622 CLEAR_ERROR_INSERT_VALUE;
12623 }
12624 else
12625 {
12626 err = tabPtr.p->getErrorCode(schemaVersion);
12627 }
12628 {
12629 scanFragptr.p->scanFragState = ScanFragRec::COMPLETED;
12630 ScanFragList run(c_scan_frag_pool, scanptr.p->m_running_scan_frags);
12631 run.release(scanFragptr);
12632 }
12633 scanError(signal, scanptr, err);
12634 return;
12635 }
12636 }
12637
12638 apiConnectptr.i = scanptr.p->scanApiRec;
12639 ptrCheckGuard(apiConnectptr, capiConnectFilesize, apiConnectRecord);
12640 switch (scanptr.p->scanState) {
12641 case ScanRecord::CLOSING_SCAN:
12642 jam();
12643 updateBuddyTimer(apiConnectptr);
12644 {
12645 scanFragptr.p->scanFragState = ScanFragRec::COMPLETED;
12646 ScanFragList run(c_scan_frag_pool, scanptr.p->m_running_scan_frags);
12647 run.release(scanFragptr);
12648 }
12649 close_scan_req_send_conf(signal, scanptr);
12650 return;
12651 default:
12652 jam();
12653 /*empty*/;
12654 break;
12655 }//switch
12656
12657 /* Send SCANFRAGREQ to LQH block
12658 * SCANFRAGREQ with optional KEYINFO and mandatory ATTRINFO are
12659 * now sent to LQH
12660 * This starts the scan on the given fragment.
12661 * If this is the last SCANFRAGREQ, sendScanFragReq will release
12662 * the KeyInfo and AttrInfo sections when sending.
12663 */
12664 Uint32 instanceKey = fragConf.instanceKey;
12665 scanFragptr.p->lqhBlockref = numberToRef(scanptr.p->m_scan_block_no,
12666 instanceKey, nodeId);
12667
12668 scanFragptr.p->m_connectCount = getNodeInfo(nodeId).m_connectCount;
12669
12670 /* Determine whether this is the last scanFragReq
12671 * Handle normal scan-all-fragments and partition pruned
12672 * scan-one-fragment cases.
12673 *
12674 * (Note that this assumes that fragments are processed in order,
12675 * and that DIH_SCAN_GET_NODES_CONF signals are received in the
12676 * order that the DIH_SCAN_GET_NODES_REQs were sent)
12677 */
12678 bool isLastScanFragReq= ((scanptr.p->scanNextFragId >=
12679 scanptr.p->scanNoFrag) &&
12680 (scanFragptr.p->scanFragId ==
12681 (scanptr.p->scanNextFragId - 1)));
12682
12683 sendScanFragReq(signal, scanptr.p, scanFragptr.p, isLastScanFragReq);
12684
12685 scanFragptr.p->scanFragState = ScanFragRec::LQH_ACTIVE;
12686 scanFragptr.p->startFragTimer(ctcTimer);
12687 updateBuddyTimer(apiConnectptr);
12688 /*********************************************
12689 * WE HAVE NOW STARTED A FRAGMENT SCAN. NOW
12690 * WAIT FOR THE FIRST SCANNED RECORDS
12691 *********************************************/
12692 }//Dbtc::startFragScanLab
12693
12694
12695 /***************************************************
12696 * execDIH_SCAN_GET_NODES_REF
12697 *
12698 * WE ARE NOW FORCED TO STOP THE SCAN. THIS ERROR
12699 * IS NOT RECOVERABLE SINCE THERE IS A PROBLEM WITH
12700 * FINDING A PRIMARY REPLICA OF SOME FRAGMENT(s).
12701 ***************************************************/
execDIH_SCAN_GET_NODES_REF(Signal * signal)12702 void Dbtc::execDIH_SCAN_GET_NODES_REF(Signal* signal)
12703 {
12704 jamEntry();
12705 const DihScanGetNodesRef* ref = (DihScanGetNodesRef*)signal->getDataPtr();
12706 //const Uint32 tableId = ref->tableId;
12707 const Uint32 fragCnt = ref->fragCnt;
12708 const Uint32 errCode = ref->errCode;
12709
12710 if (signal->getNoOfSections() > 0)
12711 {
12712 // Long signal: FragItems listed in first section
12713 jam();
12714 SectionHandle handle(this, signal);
12715 ndbassert(handle.m_cnt==1);
12716
12717 SegmentedSectionPtr fragRefSection;
12718 ndbrequire(handle.getSection(fragRefSection,0));
12719 ndbassert(fragRefSection.p->m_sz == (fragCnt*DihScanGetNodesRef::FragItem::Length));
12720 ndbassert(fragCnt <= DihScanGetNodesReq::MAX_DIH_FRAG_REQS);
12721 copy((Uint32*)ref->fragItem, fragRefSection);
12722 releaseSections(handle);
12723 }
12724 else // Short signal, single frag in ref->fragItem[0]
12725 {
12726 ndbassert(fragCnt == 1);
12727 ndbassert(signal->getLength()
12728 == DihScanGetNodesRef::FixedSignalLength + DihScanGetNodesRef::FragItem::Length);
12729 }
12730
12731 ScanRecordPtr scanptr;
12732 scanptr.setNull();
12733
12734 for (Uint32 i = 0; i < fragCnt; i++)
12735 {
12736 jam();
12737 scanFragptr.i = ref->fragItem[i].senderData;
12738 c_scan_frag_pool.getPtr(scanFragptr);
12739
12740 ndbrequire(scanFragptr.p->scanFragState == ScanFragRec::WAIT_GET_PRIMCONF);
12741 scanFragptr.p->scanFragState = ScanFragRec::COMPLETED;
12742 scanFragptr.p->stopFragTimer();
12743
12744 // All scanFrags should belong to the same table scan
12745 ndbassert(scanptr.isNull() || scanptr.i==scanFragptr.p->scanRec);
12746 if (scanptr.isNull())
12747 {
12748 jam();
12749 scanptr.i = scanFragptr.p->scanRec;
12750 ptrCheckGuard(scanptr, cscanrecFileSize, scanRecord);
12751 }
12752 {
12753 ScanFragList run(c_scan_frag_pool, scanptr.p->m_running_scan_frags);
12754 run.release(scanFragptr);
12755 }
12756 }
12757
12758 scanError(signal, scanptr, errCode);
12759 }//Dbtc::execDIH_SCAN_GET_NODES_REF()
12760
12761 /**
12762 * Dbtc::execSCAN_FRAGREF
12763 * Our attempt to scan a fragment was refused
12764 * set error code and close all other fragment
12765 * scan's belonging to this scan
12766 */
execSCAN_FRAGREF(Signal * signal)12767 void Dbtc::execSCAN_FRAGREF(Signal* signal)
12768 {
12769 const ScanFragRef * const ref = (ScanFragRef *)&signal->theData[0];
12770
12771 jamEntry();
12772 const Uint32 errCode = ref->errorCode;
12773
12774 scanFragptr.i = ref->senderData;
12775 c_scan_frag_pool.getPtr(scanFragptr);
12776
12777 ScanRecordPtr scanptr;
12778 scanptr.i = scanFragptr.p->scanRec;
12779 ptrCheckGuard(scanptr, cscanrecFileSize, scanRecord);
12780
12781 apiConnectptr.i = scanptr.p->scanApiRec;
12782 ptrCheckGuard(apiConnectptr, capiConnectFilesize, apiConnectRecord);
12783
12784 Uint32 transid1 = apiConnectptr.p->transid[0] ^ ref->transId1;
12785 Uint32 transid2 = apiConnectptr.p->transid[1] ^ ref->transId2;
12786 transid1 = transid1 | transid2;
12787 if (transid1 != 0) {
12788 jam();
12789 systemErrorLab(signal, __LINE__);
12790 }//if
12791
12792 /**
12793 * Set errorcode, close connection to this lqh fragment,
12794 * stop fragment timer and call scanFragError to start
12795 * close of the other fragment scans
12796 */
12797 ndbrequire(scanFragptr.p->scanFragState == ScanFragRec::LQH_ACTIVE);
12798 scanFragptr.p->scanFragState = ScanFragRec::COMPLETED;
12799 scanFragptr.p->stopFragTimer();
12800 {
12801 ScanFragList run(c_scan_frag_pool, scanptr.p->m_running_scan_frags);
12802 run.release(scanFragptr);
12803 }
12804 scanError(signal, scanptr, errCode);
12805 }//Dbtc::execSCAN_FRAGREF()
12806
12807 /**
12808 * Dbtc::scanError
12809 *
12810 * Called when an error occurs during
12811 */
scanError(Signal * signal,ScanRecordPtr scanptr,Uint32 errorCode)12812 void Dbtc::scanError(Signal* signal, ScanRecordPtr scanptr, Uint32 errorCode)
12813 {
12814 jam();
12815 ScanRecord* scanP = scanptr.p;
12816
12817 DEBUG("scanError, errorCode = "<< errorCode <<
12818 ", scanState = " << scanptr.p->scanState);
12819
12820 apiConnectptr.i = scanP->scanApiRec;
12821 ptrCheckGuard(apiConnectptr, capiConnectFilesize, apiConnectRecord);
12822 ndbrequire(apiConnectptr.p->apiScanRec == scanptr.i);
12823
12824 if(scanP->scanState == ScanRecord::CLOSING_SCAN){
12825 jam();
12826 close_scan_req_send_conf(signal, scanptr);
12827 return;
12828 }
12829
12830 ndbrequire(scanP->scanState == ScanRecord::RUNNING);
12831
12832 /**
12833 * Close scan wo/ having received an order to do so
12834 */
12835 close_scan_req(signal, scanptr, false);
12836
12837 const bool apiFail = (apiConnectptr.p->apiFailState == ZTRUE);
12838 if(apiFail){
12839 jam();
12840 return;
12841 }
12842
12843 ScanTabRef * ref = (ScanTabRef*)&signal->theData[0];
12844 ref->apiConnectPtr = apiConnectptr.p->ndbapiConnect;
12845 ref->transId1 = apiConnectptr.p->transid[0];
12846 ref->transId2 = apiConnectptr.p->transid[1];
12847 ref->errorCode = errorCode;
12848 ref->closeNeeded = 1;
12849 sendSignal(apiConnectptr.p->ndbapiBlockref, GSN_SCAN_TABREF,
12850 signal, ScanTabRef::SignalLength, JBB);
12851 }//Dbtc::scanError()
12852
12853 /************************************************************
12854 * execSCAN_FRAGCONF
12855 *
12856 * A NUMBER OF OPERATIONS HAVE BEEN COMPLETED IN THIS
12857 * FRAGMENT. TAKE CARE OF AND ISSUE FURTHER ACTIONS.
12858 ************************************************************/
execSCAN_FRAGCONF(Signal * signal)12859 void Dbtc::execSCAN_FRAGCONF(Signal* signal)
12860 {
12861 Uint32 transid1, transid2, total_len;
12862 jamEntry();
12863
12864 const ScanFragConf * const conf = (ScanFragConf*)&signal->theData[0];
12865 const Uint32 noCompletedOps = conf->completedOps;
12866 const Uint32 status = conf->fragmentCompleted;
12867
12868 scanFragptr.i = conf->senderData;
12869 c_scan_frag_pool.getPtr(scanFragptr);
12870
12871 ScanRecordPtr scanptr;
12872 scanptr.i = scanFragptr.p->scanRec;
12873 ptrCheckGuard(scanptr, cscanrecFileSize, scanRecord);
12874
12875 apiConnectptr.i = scanptr.p->scanApiRec;
12876 ptrCheckGuard(apiConnectptr, capiConnectFilesize, apiConnectRecord);
12877
12878 transid1 = apiConnectptr.p->transid[0] ^ conf->transId1;
12879 transid2 = apiConnectptr.p->transid[1] ^ conf->transId2;
12880 total_len= conf->total_len;
12881 transid1 = transid1 | transid2;
12882 if (transid1 != 0) {
12883 jam();
12884 systemErrorLab(signal, __LINE__);
12885 }//if
12886
12887 ndbrequire(scanFragptr.p->scanFragState == ScanFragRec::LQH_ACTIVE);
12888
12889 if(scanptr.p->scanState == ScanRecord::CLOSING_SCAN){
12890 jam();
12891 if(status == 0){
12892 /**
12893 * We have started closing = we sent a close -> ignore this
12894 */
12895 return;
12896 } else {
12897 jam();
12898 scanFragptr.p->stopFragTimer();
12899 scanFragptr.p->scanFragState = ScanFragRec::COMPLETED;
12900 {
12901 ScanFragList run(c_scan_frag_pool, scanptr.p->m_running_scan_frags);
12902 run.release(scanFragptr);
12903 }
12904 }
12905 close_scan_req_send_conf(signal, scanptr);
12906 return;
12907 }
12908
12909 if(noCompletedOps == 0 && status != 0 &&
12910 !scanptr.p->m_pass_all_confs &&
12911 scanptr.p->scanNextFragId+scanptr.p->m_booked_fragments_count < scanptr.p->scanNoFrag){
12912 /**
12913 * Start on next fragment. Don't do this if we scan via the SPJ block. In
12914 * that case, dropping the last SCAN_TABCONF message for a fragment would
12915 * mean dropping the 'nodeMask' (which is sent in ScanFragConf::total_len).
12916 * This would confuse the API with respect to which pushed operations that
12917 * would get new tuples in the next batch. If we use SPJ, we must thus
12918 * send SCAN_TABCONF and let the API ask for the next batch.
12919 */
12920 scanFragptr.p->scanFragState = ScanFragRec::WAIT_GET_PRIMCONF;
12921 scanFragptr.p->startFragTimer(ctcTimer);
12922
12923 scanFragptr.p->scanFragId = scanptr.p->scanNextFragId++;
12924 DihScanGetNodesReq* req = (DihScanGetNodesReq*)signal->getDataPtrSend();
12925 req->senderRef = reference();
12926 req->tableId = scanptr.p->scanTableref;
12927 req->scanCookie = scanptr.p->m_scan_cookie;
12928 req->fragCnt = 1;
12929 req->fragItem[0].senderData = scanFragptr.i;
12930 req->fragItem[0].fragId = scanFragptr.p->scanFragId;
12931 sendSignal(cdihblockref, GSN_DIH_SCAN_GET_NODES_REQ, signal,
12932 DihScanGetNodesReq::FixedSignalLength
12933 + DihScanGetNodesReq::FragItem::Length,
12934 JBB);
12935 return;
12936 }
12937 /*
12938 Uint32 totalLen = 0;
12939 for(Uint32 i = 0; i<noCompletedOps; i++){
12940 Uint32 tmp = conf->opReturnDataLen[i];
12941 totalLen += tmp;
12942 }
12943 */
12944 {
12945 ScanFragList run(c_scan_frag_pool, scanptr.p->m_running_scan_frags);
12946 ScanFragList queued(c_scan_frag_pool, scanptr.p->m_queued_scan_frags);
12947
12948 run.remove(scanFragptr);
12949 queued.addFirst(scanFragptr);
12950 scanptr.p->m_queued_count++;
12951 }
12952
12953 if (status != 0 &&
12954 scanptr.p->m_pass_all_confs &&
12955 scanptr.p->scanNextFragId+scanptr.p->m_booked_fragments_count
12956 < scanptr.p->scanNoFrag){
12957 /**
12958 * nodeMask(=total_len) should be zero since there will be no more
12959 * rows from this fragment.
12960 */
12961 ndbrequire(total_len==0);
12962 /**
12963 * Now set it to one to tell the API that there may be more rows from
12964 * the next fragment.
12965 */
12966 total_len = 1;
12967 }
12968
12969 scanFragptr.p->m_scan_frag_conf_status = status;
12970 scanFragptr.p->m_ops = noCompletedOps;
12971 scanFragptr.p->m_totalLen = total_len;
12972 scanFragptr.p->scanFragState = ScanFragRec::QUEUED_FOR_DELIVERY;
12973 scanFragptr.p->stopFragTimer();
12974
12975 if(scanptr.p->m_queued_count > /** Min */ 0){
12976 jam();
12977 sendScanTabConf(signal, scanptr);
12978 }
12979 }//Dbtc::execSCAN_FRAGCONF()
12980
12981 /****************************************************************************
12982 * execSCAN_NEXTREQ
12983 *
12984 * THE APPLICATION HAS PROCESSED THE TUPLES TRANSFERRED AND IS NOW READY FOR
12985 * MORE. THIS SIGNAL IS ALSO USED TO CLOSE THE SCAN.
12986 ****************************************************************************/
execSCAN_NEXTREQ(Signal * signal)12987 void Dbtc::execSCAN_NEXTREQ(Signal* signal)
12988 {
12989 const ScanNextReq * const req = (ScanNextReq *)&signal->theData[0];
12990 const UintR transid1 = req->transId1;
12991 const UintR transid2 = req->transId2;
12992 const UintR stopScan = req->stopScan;
12993
12994 jamEntry();
12995
12996 SectionHandle handle(this, signal);
12997 apiConnectptr.i = req->apiConnectPtr;
12998 if (apiConnectptr.i >= capiConnectFilesize) {
12999 jam();
13000 releaseSections(handle);
13001 warningHandlerLab(signal, __LINE__);
13002 return;
13003 }//if
13004 ptrAss(apiConnectptr, apiConnectRecord);
13005
13006 /**
13007 * Check transid
13008 */
13009 const UintR ctransid1 = apiConnectptr.p->transid[0] ^ transid1;
13010 const UintR ctransid2 = apiConnectptr.p->transid[1] ^ transid2;
13011 if ((ctransid1 | ctransid2) != 0){
13012 releaseSections(handle);
13013 ScanTabRef * ref = (ScanTabRef*)&signal->theData[0];
13014 ref->apiConnectPtr = apiConnectptr.p->ndbapiConnect;
13015 ref->transId1 = transid1;
13016 ref->transId2 = transid2;
13017 ref->errorCode = ZSTATE_ERROR;
13018 ref->closeNeeded = 0;
13019 sendSignal(signal->senderBlockRef(), GSN_SCAN_TABREF,
13020 signal, ScanTabRef::SignalLength, JBB);
13021 DEBUG("Wrong transid");
13022 return;
13023 }
13024
13025 /**
13026 * Check state of API connection
13027 */
13028 if (apiConnectptr.p->apiConnectstate != CS_START_SCAN) {
13029 jam();
13030 releaseSections(handle);
13031 if (apiConnectptr.p->apiConnectstate == CS_CONNECTED) {
13032 jam();
13033 /*********************************************************************
13034 * The application sends a SCAN_NEXTREQ after experiencing a time-out.
13035 * We will send a SCAN_TABREF to indicate a time-out occurred.
13036 *********************************************************************/
13037 DEBUG("scanTabRefLab: ZSCANTIME_OUT_ERROR2");
13038 ndbout_c("apiConnectptr(%d) -> abort", apiConnectptr.i);
13039 ndbrequire(false); //B2 indication of strange things going on
13040 scanTabRefLab(signal, ZSCANTIME_OUT_ERROR2);
13041 return;
13042 }
13043 DEBUG("scanTabRefLab: ZSTATE_ERROR");
13044 DEBUG(" apiConnectstate="<<apiConnectptr.p->apiConnectstate);
13045 ndbrequire(false); //B2 indication of strange things going on
13046 scanTabRefLab(signal, ZSTATE_ERROR);
13047 return;
13048 }//if
13049
13050 /*******************************************************
13051 * START THE ACTUAL LOGIC OF SCAN_NEXTREQ.
13052 ********************************************************/
13053 // Stop the timer that is used to check for timeout in the API
13054 setApiConTimer(apiConnectptr.i, 0, __LINE__);
13055 ScanRecordPtr scanptr;
13056 scanptr.i = apiConnectptr.p->apiScanRec;
13057 ptrCheckGuard(scanptr, cscanrecFileSize, scanRecord);
13058 ScanRecord* scanP = scanptr.p;
13059
13060 /* Copy ReceiverIds to working space past end of signal
13061 * so that we don't overwrite them when sending signals
13062 */
13063 Uint32 len = 0;
13064 if (handle.m_cnt > 0)
13065 {
13066 jam();
13067 /* TODO : Add Dropped signal handling for SCAN_NEXTREQ */
13068 /* Receiver ids are in a long section */
13069 ndbrequire(signal->getLength() == ScanNextReq::SignalLength);
13070 ndbrequire(handle.m_cnt == 1);
13071 SegmentedSectionPtr receiverIdsSection;
13072 ndbrequire(handle.getSection(receiverIdsSection,
13073 ScanNextReq::ReceiverIdsSectionNum));
13074 len= receiverIdsSection.p->m_sz;
13075 ndbassert(len < (8192 - 25));
13076
13077 copy(signal->getDataPtrSend()+25, receiverIdsSection);
13078 releaseSections(handle);
13079 }
13080 else
13081 {
13082 jam();
13083 len= signal->getLength() - ScanNextReq::SignalLength;
13084 memcpy(signal->getDataPtrSend()+25,
13085 signal->getDataPtr()+ ScanNextReq::SignalLength,
13086 4 * len);
13087 }
13088
13089 if (stopScan == ZTRUE) {
13090 jam();
13091 /*********************************************************************
13092 * APPLICATION IS CLOSING THE SCAN.
13093 **********************************************************************/
13094 close_scan_req(signal, scanptr, true);
13095 return;
13096 }//if
13097
13098 if (scanptr.p->scanState == ScanRecord::CLOSING_SCAN){
13099 jam();
13100 /**
13101 * The scan is closing (typically due to error)
13102 * but the API hasn't understood it yet
13103 *
13104 * Wait for API close request
13105 */
13106 return;
13107 }
13108
13109 ScanFragNextReq tmp;
13110 tmp.requestInfo = 0;
13111 tmp.transId1 = apiConnectptr.p->transid[0];
13112 tmp.transId2 = apiConnectptr.p->transid[1];
13113 tmp.batch_size_rows = scanP->batch_size_rows;
13114 tmp.batch_size_bytes = scanP->batch_byte_size;
13115
13116 ScanFragList running(c_scan_frag_pool, scanP->m_running_scan_frags);
13117 ScanFragList delivered(c_scan_frag_pool, scanP->m_delivered_scan_frags);
13118 for(Uint32 i = 0 ; i<len; i++){
13119 jam();
13120 scanFragptr.i = signal->theData[i+25];
13121 c_scan_frag_pool.getPtr(scanFragptr);
13122 ndbrequire(scanFragptr.p->scanFragState == ScanFragRec::DELIVERED);
13123
13124 scanFragptr.p->startFragTimer(ctcTimer);
13125 scanFragptr.p->m_ops = 0;
13126
13127 if(scanFragptr.p->m_scan_frag_conf_status)
13128 {
13129 /**
13130 * last scan was complete
13131 */
13132 jam();
13133 ndbrequire(scanptr.p->scanNextFragId < scanptr.p->scanNoFrag);
13134 ndbassert(scanptr.p->m_booked_fragments_count);
13135 scanptr.p->m_booked_fragments_count--;
13136 scanFragptr.p->scanFragState = ScanFragRec::WAIT_GET_PRIMCONF;
13137
13138 scanFragptr.p->scanFragId = scanptr.p->scanNextFragId++;
13139
13140 DihScanGetNodesReq* req = (DihScanGetNodesReq*)signal->getDataPtrSend();
13141 req->senderRef = reference();
13142 req->tableId = scanptr.p->scanTableref;
13143 req->scanCookie = scanptr.p->m_scan_cookie;
13144 req->fragCnt = 1;
13145 req->fragItem[0].senderData = scanFragptr.i;
13146 req->fragItem[0].fragId = scanFragptr.p->scanFragId;
13147 sendSignal(cdihblockref, GSN_DIH_SCAN_GET_NODES_REQ, signal,
13148 DihScanGetNodesReq::FixedSignalLength
13149 + DihScanGetNodesReq::FragItem::Length,
13150 JBB);
13151 }
13152 else
13153 {
13154 jam();
13155 scanFragptr.p->scanFragState = ScanFragRec::LQH_ACTIVE;
13156 ScanFragNextReq * req = (ScanFragNextReq*)signal->getDataPtrSend();
13157 * req = tmp;
13158 req->senderData = scanFragptr.i;
13159 sendSignal(scanFragptr.p->lqhBlockref, GSN_SCAN_NEXTREQ, signal,
13160 ScanFragNextReq::SignalLength, JBB);
13161 }
13162 delivered.remove(scanFragptr);
13163 running.addFirst(scanFragptr);
13164 }//for
13165
13166 }//Dbtc::execSCAN_NEXTREQ()
13167
13168 void
close_scan_req(Signal * signal,ScanRecordPtr scanPtr,bool req_received)13169 Dbtc::close_scan_req(Signal* signal, ScanRecordPtr scanPtr, bool req_received){
13170
13171 ScanRecord* scanP = scanPtr.p;
13172 ndbrequire(scanPtr.p->scanState != ScanRecord::IDLE);
13173 ScanRecord::ScanState old = scanPtr.p->scanState;
13174 scanPtr.p->scanState = ScanRecord::CLOSING_SCAN;
13175 scanPtr.p->m_close_scan_req = req_received;
13176
13177 if (old == ScanRecord::WAIT_FRAGMENT_COUNT)
13178 {
13179 jam();
13180 scanPtr.p->scanState = old;
13181 return; // Will continue on execDI_FCOUNTCONF
13182 }
13183
13184 /**
13185 * Queue : Action
13186 * ============= : =================
13187 * completed : -
13188 * running : close -> LQH
13189 * delivered w/ : close -> LQH
13190 * delivered wo/ : move to completed
13191 * queued w/ : close -> LQH
13192 * queued wo/ : move to completed
13193 */
13194
13195 ScanFragNextReq * nextReq = (ScanFragNextReq*)&signal->theData[0];
13196 nextReq->requestInfo = 0;
13197 ScanFragNextReq::setCloseFlag(nextReq->requestInfo, 1);
13198 nextReq->transId1 = apiConnectptr.p->transid[0];
13199 nextReq->transId2 = apiConnectptr.p->transid[1];
13200
13201 {
13202 ScanFragRecPtr ptr;
13203 ScanFragList running(c_scan_frag_pool, scanP->m_running_scan_frags);
13204 ScanFragList delivered(c_scan_frag_pool, scanP->m_delivered_scan_frags);
13205 ScanFragList queued(c_scan_frag_pool, scanP->m_queued_scan_frags);
13206
13207 // Close running
13208 for(running.first(ptr); !ptr.isNull(); ){
13209 ScanFragRecPtr curr = ptr; // Remove while iterating...
13210 running.next(ptr);
13211
13212 switch(curr.p->scanFragState){
13213 case ScanFragRec::IDLE:
13214 jam(); // real early abort
13215 ndbrequire(old == ScanRecord::WAIT_AI || old == ScanRecord::RUNNING);
13216 curr.p->scanFragState = ScanFragRec::COMPLETED;
13217 running.release(curr);
13218 continue;
13219 case ScanFragRec::WAIT_GET_PRIMCONF:
13220 jam();
13221 continue;
13222 case ScanFragRec::LQH_ACTIVE:
13223 jam();
13224 break;
13225 default:
13226 jamLine(curr.p->scanFragState);
13227 ndbrequire(false);
13228 }
13229
13230 curr.p->startFragTimer(ctcTimer);
13231 curr.p->scanFragState = ScanFragRec::LQH_ACTIVE;
13232 nextReq->senderData = curr.i;
13233 sendSignal(curr.p->lqhBlockref, GSN_SCAN_NEXTREQ, signal,
13234 ScanFragNextReq::SignalLength, JBB);
13235 }
13236
13237 // Close delivered
13238 for(delivered.first(ptr); !ptr.isNull(); ){
13239 jam();
13240 ScanFragRecPtr curr = ptr; // Remove while iterating...
13241 delivered.next(ptr);
13242
13243 ndbrequire(curr.p->scanFragState == ScanFragRec::DELIVERED);
13244 delivered.remove(curr);
13245
13246 if (curr.p->m_scan_frag_conf_status == 0)
13247 {
13248 jam();
13249 running.addFirst(curr);
13250 curr.p->scanFragState = ScanFragRec::LQH_ACTIVE;
13251 curr.p->startFragTimer(ctcTimer);
13252 nextReq->senderData = curr.i;
13253 sendSignal(curr.p->lqhBlockref, GSN_SCAN_NEXTREQ, signal,
13254 ScanFragNextReq::SignalLength, JBB);
13255
13256 }
13257 else
13258 {
13259 jam();
13260 c_scan_frag_pool.release(curr);
13261 curr.p->scanFragState = ScanFragRec::COMPLETED;
13262 curr.p->stopFragTimer();
13263 }
13264 }//for
13265
13266 /**
13267 * All queued with data should be closed
13268 */
13269 for(queued.first(ptr); !ptr.isNull(); ){
13270 jam();
13271 ndbrequire(ptr.p->scanFragState == ScanFragRec::QUEUED_FOR_DELIVERY);
13272 ScanFragRecPtr curr = ptr; // Remove while iterating...
13273 queued.next(ptr);
13274
13275 queued.remove(curr);
13276 scanP->m_queued_count--;
13277
13278 if (curr.p->m_scan_frag_conf_status == 0)
13279 {
13280 jam();
13281 running.addFirst(curr);
13282 curr.p->scanFragState = ScanFragRec::LQH_ACTIVE;
13283 curr.p->startFragTimer(ctcTimer);
13284 nextReq->senderData = curr.i;
13285 sendSignal(curr.p->lqhBlockref, GSN_SCAN_NEXTREQ, signal,
13286 ScanFragNextReq::SignalLength, JBB);
13287 }
13288 else
13289 {
13290 jam();
13291 c_scan_frag_pool.release(curr);
13292 curr.p->scanFragState = ScanFragRec::COMPLETED;
13293 curr.p->stopFragTimer();
13294 }
13295 }
13296 }
13297 close_scan_req_send_conf(signal, scanPtr);
13298 }
13299
13300 void
close_scan_req_send_conf(Signal * signal,ScanRecordPtr scanPtr)13301 Dbtc::close_scan_req_send_conf(Signal* signal, ScanRecordPtr scanPtr){
13302
13303 jam();
13304
13305 ndbrequire(scanPtr.p->m_queued_scan_frags.isEmpty());
13306 ndbrequire(scanPtr.p->m_delivered_scan_frags.isEmpty());
13307 //ndbrequire(scanPtr.p->m_running_scan_frags.isEmpty());
13308
13309 if(!scanPtr.p->m_running_scan_frags.isEmpty()){
13310 jam();
13311 return;
13312 }
13313
13314 const bool apiFail = (apiConnectptr.p->apiFailState == ZTRUE);
13315
13316 if(!scanPtr.p->m_close_scan_req){
13317 jam();
13318 /**
13319 * The API hasn't order closing yet
13320 */
13321 return;
13322 }
13323
13324 Uint32 ref = apiConnectptr.p->ndbapiBlockref;
13325 if(!apiFail && ref){
13326 jam();
13327 ScanTabConf * conf = (ScanTabConf*)&signal->theData[0];
13328 conf->apiConnectPtr = apiConnectptr.p->ndbapiConnect;
13329 conf->requestInfo = ScanTabConf::EndOfData;
13330 conf->transId1 = apiConnectptr.p->transid[0];
13331 conf->transId2 = apiConnectptr.p->transid[1];
13332 sendSignal(ref, GSN_SCAN_TABCONF, signal, ScanTabConf::SignalLength, JBB);
13333 }
13334
13335 releaseScanResources(signal, scanPtr);
13336
13337 if(apiFail){
13338 jam();
13339 /**
13340 * API has failed
13341 */
13342 handleApiFailState(signal, apiConnectptr.i);
13343 }
13344 }
13345
13346 Dbtc::ScanRecordPtr
seizeScanrec(Signal * signal)13347 Dbtc::seizeScanrec(Signal* signal) {
13348 ScanRecordPtr scanptr;
13349 scanptr.i = cfirstfreeScanrec;
13350 ptrCheckGuard(scanptr, cscanrecFileSize, scanRecord);
13351 cfirstfreeScanrec = scanptr.p->nextScan;
13352 scanptr.p->nextScan = RNIL;
13353 cConcScanCount++;
13354 ndbrequire(scanptr.p->scanState == ScanRecord::IDLE);
13355 return scanptr;
13356 }//Dbtc::seizeScanrec()
13357
sendScanFragReq(Signal * signal,ScanRecord * scanP,ScanFragRec * scanFragP,bool isLastReq)13358 void Dbtc::sendScanFragReq(Signal* signal,
13359 ScanRecord* scanP,
13360 ScanFragRec* scanFragP,
13361 bool isLastReq)
13362 {
13363 Uint32 version= getNodeInfo(refToNode(scanFragP->lqhBlockref)).m_version;
13364 bool longFragReq= ((version >= NDBD_LONG_SCANFRAGREQ) &&
13365 (! ERROR_INSERTED(8070) &&
13366 ! ERROR_INSERTED(8088)));
13367
13368 SectionHandle sections(this);
13369 sections.m_ptr[0].i = scanP->scanAttrInfoPtr;
13370 sections.m_ptr[1].i = scanP->scanKeyInfoPtr;
13371
13372 sections.m_cnt = 1; // there is always attrInfo
13373
13374 if (scanP->scanKeyInfoPtr != RNIL)
13375 {
13376 jam();
13377 sections.m_cnt = 2; // and sometimes keyinfo
13378 }
13379
13380 if (isLastReq)
13381 {
13382 /* This send will release these sections, remove our
13383 * references to them
13384 */
13385 scanP->scanKeyInfoPtr = RNIL;
13386 scanP->scanAttrInfoPtr = RNIL;
13387 }
13388
13389 getSections(sections.m_cnt, sections.m_ptr);
13390
13391 ScanFragReq * const req = (ScanFragReq *)&signal->theData[0];
13392 Uint32 requestInfo = scanP->scanRequestInfo;
13393 ScanFragReq::setScanPrio(requestInfo, 1);
13394 apiConnectptr.i = scanP->scanApiRec;
13395 req->tableId = scanP->scanTableref;
13396 req->schemaVersion = scanP->scanSchemaVersion;
13397 ptrCheckGuard(apiConnectptr, capiConnectFilesize, apiConnectRecord);
13398 req->senderData = scanFragptr.i;
13399 req->requestInfo = requestInfo;
13400 req->fragmentNoKeyLen = scanFragP->scanFragId;
13401 req->resultRef = apiConnectptr.p->ndbapiBlockref;
13402 req->savePointId = apiConnectptr.p->currSavePointId;
13403 req->transId1 = apiConnectptr.p->transid[0];
13404 req->transId2 = apiConnectptr.p->transid[1];
13405 req->clientOpPtr = scanFragP->m_apiPtr;
13406 req->batch_size_rows= scanP->batch_size_rows;
13407 req->batch_size_bytes= scanP->batch_byte_size;
13408
13409 if (likely(longFragReq))
13410 {
13411 jam();
13412 /* Send long, possibly fragmented SCAN_FRAGREQ */
13413
13414 // TODO :
13415 // 1) Consider whether to adjust fragmentation threshold
13416 // a) When to fragment signal vs fragment size
13417 // b) Fragment size
13418 /* To reduce the copy burden we want to keep hold of the
13419 * AttrInfo and KeyInfo sections after sending them to
13420 * LQH. To do this we perform the fragmented send inline,
13421 * so that all fragments are sent *now*. This avoids any
13422 * problems with the fragmented send CONTINUE 'thread' using
13423 * the section while we hold or even release it. The
13424 * signal receiver can still take realtime breaks when
13425 * receiving.
13426 *
13427 * Indicate to sendFirstFragment that we want to keep the
13428 * fragments, so it must not free them, unless this is the
13429 * last request in which case they can be freed. If the
13430 * last request is a local send then a copy is avoided.
13431 */
13432 FragmentSendInfo fragSendInfo;
13433
13434 sendFirstFragment(fragSendInfo,
13435 NodeReceiverGroup(scanFragP->lqhBlockref),
13436 GSN_SCAN_FRAGREQ,
13437 signal,
13438 ScanFragReq::SignalLength,
13439 JBB,
13440 §ions,
13441 !isLastReq); // Keep sent sections unless
13442 // last send
13443
13444 while (fragSendInfo.m_status != FragmentSendInfo::SendComplete)
13445 {
13446 jam();
13447 /* Send remaining fragments */
13448 sendNextSegmentedFragment(signal, fragSendInfo);
13449 }
13450
13451 /* Clear handle, section deallocation handled elsewhere. */
13452 sections.clear();
13453 }
13454 else
13455 {
13456 jam();
13457 /* Short SCANFRAGREQ with separate KeyInfo and AttrInfo trains
13458 * Sent to older NDBD nodes during upgrade
13459 */
13460 Uint32 reqAttrLen = sections.m_ptr[0].sz;
13461 ScanFragReq::setAttrLen(req->requestInfo, reqAttrLen);
13462 if (sections.m_cnt > 1)
13463 {
13464 jam();
13465 /*
13466 * bug#13834481 missing shift, causing fragment not found
13467 * (error 1231) on 6.3 node.
13468 */
13469 req->fragmentNoKeyLen |= (sections.m_ptr[1].sz << 16);
13470 }
13471 sendSignal(scanFragP->lqhBlockref, GSN_SCAN_FRAGREQ, signal,
13472 ScanFragReq::SignalLength, JBB);
13473 if (sections.m_cnt > 1)
13474 {
13475 jam();
13476 /* Build KeyInfo train from KeyInfo long signal section */
13477 sendKeyInfoTrain(signal,
13478 scanFragP->lqhBlockref,
13479 scanFragptr.i,
13480 0, // Offset 0
13481 sections.m_ptr[1].i);
13482 }
13483
13484 if(ERROR_INSERTED(8035))
13485 globalTransporterRegistry.performSend();
13486
13487 if (!ERROR_INSERTED(8088))
13488 {
13489 ndbrequire(sendAttrInfoTrain(signal,
13490 scanFragP->lqhBlockref,
13491 scanFragptr.i,
13492 0, // Offset 0
13493 sections.m_ptr[0].i));
13494 }
13495
13496 if(ERROR_INSERTED(8035))
13497 globalTransporterRegistry.performSend();
13498
13499 if (isLastReq)
13500 {
13501 /* Free the sections here */
13502 releaseSections(sections);
13503 }
13504 else
13505 {
13506 sections.clear();
13507 }
13508 }
13509
13510 if (ERROR_INSERTED(8088))
13511 {
13512 signal->theData[0] = 9999;
13513 sendSignalWithDelay(CMVMI_REF, GSN_NDB_TAMPER, signal, 100, 1);
13514 }
13515 }//Dbtc::sendScanFragReq()
13516
13517
sendScanTabConf(Signal * signal,ScanRecordPtr scanPtr)13518 void Dbtc::sendScanTabConf(Signal* signal, ScanRecordPtr scanPtr) {
13519 jam();
13520 Uint32* ops = signal->getDataPtrSend()+4;
13521 Uint32 op_count = scanPtr.p->m_queued_count;
13522
13523 Uint32 words_per_op = 4;
13524 const Uint32 ref = apiConnectptr.p->ndbapiBlockref;
13525 if (!scanPtr.p->m_4word_conf)
13526 {
13527 jam();
13528 words_per_op = 3;
13529 }
13530
13531 if (4 + words_per_op * op_count > 25)
13532 {
13533 jam();
13534 ops += 21;
13535 }
13536
13537 int left = scanPtr.p->scanNoFrag - scanPtr.p->scanNextFragId;
13538 Uint32 booked = scanPtr.p->m_booked_fragments_count;
13539
13540 ScanTabConf * conf = (ScanTabConf*)&signal->theData[0];
13541 conf->apiConnectPtr = apiConnectptr.p->ndbapiConnect;
13542 conf->requestInfo = op_count;
13543 conf->transId1 = apiConnectptr.p->transid[0];
13544 conf->transId2 = apiConnectptr.p->transid[1];
13545 ScanFragRecPtr ptr;
13546 {
13547 ScanFragList queued(c_scan_frag_pool, scanPtr.p->m_queued_scan_frags);
13548 ScanFragList delivered(c_scan_frag_pool,scanPtr.p->m_delivered_scan_frags);
13549 for(queued.first(ptr); !ptr.isNull(); ){
13550 ndbrequire(ptr.p->scanFragState == ScanFragRec::QUEUED_FOR_DELIVERY);
13551 ScanFragRecPtr curr = ptr; // Remove while iterating...
13552 queued.next(ptr);
13553
13554 bool done = curr.p->m_scan_frag_conf_status && (left <= (int)booked);
13555 if(curr.p->m_scan_frag_conf_status)
13556 booked++;
13557
13558 * ops++ = curr.p->m_apiPtr;
13559 * ops++ = done ? RNIL : curr.i;
13560 if (words_per_op == 4)
13561 {
13562 * ops++ = curr.p->m_ops;
13563 * ops++ = curr.p->m_totalLen;
13564 }
13565 else
13566 {
13567 * ops++ = (curr.p->m_totalLen << 10) + curr.p->m_ops;
13568 }
13569
13570 queued.remove(curr);
13571 if(!done){
13572 delivered.addFirst(curr);
13573 curr.p->scanFragState = ScanFragRec::DELIVERED;
13574 curr.p->stopFragTimer();
13575 } else {
13576 c_scan_frag_pool.release(curr);
13577 curr.p->scanFragState = ScanFragRec::COMPLETED;
13578 curr.p->stopFragTimer();
13579 }
13580 }
13581 }
13582
13583 bool release = false;
13584 scanPtr.p->m_booked_fragments_count = booked;
13585 if(scanPtr.p->m_delivered_scan_frags.isEmpty() &&
13586 scanPtr.p->m_running_scan_frags.isEmpty())
13587 {
13588 jam();
13589 release = true;
13590 conf->requestInfo = op_count | ScanTabConf::EndOfData;
13591 }
13592 else
13593 {
13594 if (scanPtr.p->m_running_scan_frags.isEmpty())
13595 {
13596 jam();
13597 /**
13598 * All scan frags delivered...waiting for API
13599 */
13600 setApiConTimer(apiConnectptr.i, ctcTimer, __LINE__);
13601 }
13602 }
13603
13604 if (4 + words_per_op * op_count > 25)
13605 {
13606 jam();
13607 LinearSectionPtr ptr[3];
13608 ptr[0].p = signal->getDataPtrSend()+25;
13609 ptr[0].sz = words_per_op * op_count;
13610 sendSignal(ref, GSN_SCAN_TABCONF, signal,
13611 ScanTabConf::SignalLength, JBB, ptr, 1);
13612 }
13613 else
13614 {
13615 jam();
13616 sendSignal(ref, GSN_SCAN_TABCONF, signal,
13617 ScanTabConf::SignalLength + words_per_op * op_count, JBB);
13618 }
13619 scanPtr.p->m_queued_count = 0;
13620
13621 if (release)
13622 {
13623 jam();
13624 releaseScanResources(signal, scanPtr);
13625 }
13626
13627 }//Dbtc::sendScanTabConf()
13628
13629
gcpTcfinished(Signal * signal,Uint64 gci)13630 void Dbtc::gcpTcfinished(Signal* signal, Uint64 gci)
13631 {
13632 GCPTCFinished* conf = (GCPTCFinished*)signal->getDataPtrSend();
13633 conf->senderData = c_gcp_data;
13634 conf->gci_hi = Uint32(gci >> 32);
13635 conf->gci_lo = Uint32(gci);
13636 conf->tcFailNo = cfailure_nr; /* Indicate highest handled failno in GCP */
13637
13638 #ifdef ERROR_INSERT
13639 if (ERROR_INSERTED(8098))
13640 {
13641 if (cmasterNodeId == getOwnNodeId())
13642 {
13643 bool multi = ((gci&1) == 1);
13644 bool kill_me = ((gci&3) == 1);
13645 /* Kill multi 'assumes' NoOfReplicas=2, and skipping one
13646 * live node at a time avoids taking out a nodegroup
13647 */
13648 ndbout_c("TC killing multi : %u me : %u", multi, kill_me);
13649 Uint32 start = getOwnNodeId();
13650 bool skip = !kill_me;
13651 Uint32 pos = start;
13652 do
13653 {
13654 NodeInfo ni = getNodeInfo(pos);
13655 if ((ni.getType() == NODE_TYPE_DB) &&
13656 ni.m_connected)
13657 {
13658 /* Found a db node... */
13659 if (!skip)
13660 {
13661 ndbout_c("TC : Killing node %u", pos);
13662 signal->theData[0] = 9999;
13663 sendSignal(numberToRef(CMVMI, pos), GSN_DUMP_STATE_ORD, signal,
13664 1, JBA);
13665 if (!multi)
13666 break;
13667 skip = true;
13668 }
13669 else
13670 {
13671 ndbout_c("TC : Skipping node %u", pos);
13672 skip = false;
13673 }
13674 }
13675
13676 pos++;
13677 if (pos == MAX_NDB_NODES)
13678 pos = 1;
13679 } while (pos != start);
13680 }
13681
13682 /* Keep delaying GCP_TCFINISHED, but don't kill anymore */
13683 SET_ERROR_INSERT_VALUE(8099);
13684 }
13685
13686 if (ERROR_INSERTED(8099))
13687 {
13688 /* Slow it down */
13689 ndbout_c("TC : Sending delayed GCP_TCFINISHED (%u/%u), failNo %u to local DIH(%x)",
13690 conf->gci_hi, conf->gci_lo, cfailure_nr, cdihblockref);
13691 sendSignalWithDelay(cdihblockref, GSN_GCP_TCFINISHED, signal,
13692 2000, GCPTCFinished::SignalLength);
13693 return;
13694 }
13695 #endif
13696 sendSignal(c_gcp_ref, GSN_GCP_TCFINISHED, signal,
13697 GCPTCFinished::SignalLength, JBB);
13698 }//Dbtc::gcpTcfinished()
13699
initApiConnect(Signal * signal)13700 void Dbtc::initApiConnect(Signal* signal)
13701 {
13702 Uint32 tiacTmp;
13703 Uint32 guard4;
13704
13705 tiacTmp = capiConnectFilesize / 3;
13706 ndbrequire(tiacTmp > 0);
13707 guard4 = tiacTmp + 1;
13708 for (cachePtr.i = 0; cachePtr.i < guard4; cachePtr.i++) {
13709 refresh_watch_dog();
13710 ptrAss(cachePtr, cacheRecord);
13711 cachePtr.p->nextCacheRec = cachePtr.i + 1;
13712 }//for
13713 cachePtr.i = tiacTmp;
13714 ptrCheckGuard(cachePtr, ccacheFilesize, cacheRecord);
13715 cachePtr.p->nextCacheRec = RNIL;
13716 cfirstfreeCacheRec = 0;
13717
13718 guard4 = tiacTmp - 1;
13719 for (apiConnectptr.i = 0; apiConnectptr.i <= guard4; apiConnectptr.i++) {
13720 refresh_watch_dog();
13721 jam();
13722 ptrAss(apiConnectptr, apiConnectRecord);
13723 apiConnectptr.p->apiConnectstate = CS_DISCONNECTED;
13724 apiConnectptr.p->apiFailState = ZFALSE;
13725 setApiConTimer(apiConnectptr.i, 0, __LINE__);
13726 apiConnectptr.p->takeOverRec = (Uint8)Z8NIL;
13727 apiConnectptr.p->cachePtr = RNIL;
13728 apiConnectptr.p->nextApiConnect = apiConnectptr.i + 1;
13729 apiConnectptr.p->ndbapiBlockref = 0xFFFFFFFF; // Invalid ref
13730 apiConnectptr.p->commitAckMarker = RNIL;
13731 apiConnectptr.p->num_commit_ack_markers = 0;
13732 apiConnectptr.p->firstTcConnect = RNIL;
13733 apiConnectptr.p->lastTcConnect = RNIL;
13734 apiConnectptr.p->m_flags = 0;
13735 apiConnectptr.p->m_special_op_flags = 0;
13736 apiConnectptr.p->accumulatingIndexOp = RNIL;
13737 apiConnectptr.p->executingIndexOp = RNIL;
13738 apiConnectptr.p->buddyPtr = RNIL;
13739 apiConnectptr.p->currSavePointId = 0;
13740 apiConnectptr.p->m_transaction_nodes.clear();
13741 apiConnectptr.p->singleUserMode = 0;
13742 apiConnectptr.p->apiCopyRecord = RNIL;
13743 }//for
13744 apiConnectptr.i = tiacTmp - 1;
13745 ptrCheckGuard(apiConnectptr, capiConnectFilesize, apiConnectRecord);
13746 apiConnectptr.p->nextApiConnect = RNIL;
13747 cfirstfreeApiConnect = 0;
13748 guard4 = (2 * tiacTmp) - 1;
13749 for (apiConnectptr.i = tiacTmp; apiConnectptr.i <= guard4; apiConnectptr.i++)
13750 {
13751 refresh_watch_dog();
13752 jam();
13753 ptrCheckGuard(apiConnectptr, capiConnectFilesize, apiConnectRecord);
13754 apiConnectptr.p->apiConnectstate = CS_RESTART;
13755 apiConnectptr.p->apiFailState = ZFALSE;
13756 setApiConTimer(apiConnectptr.i, 0, __LINE__);
13757 apiConnectptr.p->takeOverRec = (Uint8)Z8NIL;
13758 apiConnectptr.p->cachePtr = RNIL;
13759 apiConnectptr.p->nextApiConnect = apiConnectptr.i + 1;
13760 apiConnectptr.p->ndbapiBlockref = 0xFFFFFFFF; // Invalid ref
13761 apiConnectptr.p->commitAckMarker = RNIL;
13762 apiConnectptr.p->num_commit_ack_markers = 0;
13763 apiConnectptr.p->firstTcConnect = RNIL;
13764 apiConnectptr.p->lastTcConnect = RNIL;
13765 apiConnectptr.p->m_flags = 0;
13766 apiConnectptr.p->m_special_op_flags = 0;
13767 apiConnectptr.p->accumulatingIndexOp = RNIL;
13768 apiConnectptr.p->executingIndexOp = RNIL;
13769 apiConnectptr.p->buddyPtr = RNIL;
13770 apiConnectptr.p->currSavePointId = 0;
13771 apiConnectptr.p->m_transaction_nodes.clear();
13772 apiConnectptr.p->singleUserMode = 0;
13773 apiConnectptr.p->apiCopyRecord = RNIL;
13774 }//for
13775 apiConnectptr.i = (2 * tiacTmp) - 1;
13776 ptrCheckGuard(apiConnectptr, capiConnectFilesize, apiConnectRecord);
13777 apiConnectptr.p->nextApiConnect = RNIL;
13778 cfirstfreeApiConnectCopy = tiacTmp;
13779 guard4 = (3 * tiacTmp) - 1;
13780 for (apiConnectptr.i = 2 * tiacTmp; apiConnectptr.i <= guard4;
13781 apiConnectptr.i++) {
13782 refresh_watch_dog();
13783 jam();
13784 ptrCheckGuard(apiConnectptr, capiConnectFilesize, apiConnectRecord);
13785 setApiConTimer(apiConnectptr.i, 0, __LINE__);
13786 apiConnectptr.p->apiFailState = ZFALSE;
13787 apiConnectptr.p->apiConnectstate = CS_RESTART;
13788 apiConnectptr.p->takeOverRec = (Uint8)Z8NIL;
13789 apiConnectptr.p->cachePtr = RNIL;
13790 apiConnectptr.p->nextApiConnect = apiConnectptr.i + 1;
13791 apiConnectptr.p->ndbapiBlockref = 0xFFFFFFFF; // Invalid ref
13792 apiConnectptr.p->commitAckMarker = RNIL;
13793 apiConnectptr.p->num_commit_ack_markers = 0;
13794 apiConnectptr.p->firstTcConnect = RNIL;
13795 apiConnectptr.p->lastTcConnect = RNIL;
13796 apiConnectptr.p->m_flags = 0;
13797 apiConnectptr.p->m_special_op_flags = 0;
13798 apiConnectptr.p->accumulatingIndexOp = RNIL;
13799 apiConnectptr.p->executingIndexOp = RNIL;
13800 apiConnectptr.p->buddyPtr = RNIL;
13801 apiConnectptr.p->currSavePointId = 0;
13802 apiConnectptr.p->m_transaction_nodes.clear();
13803 apiConnectptr.p->singleUserMode = 0;
13804 apiConnectptr.p->apiCopyRecord = RNIL;
13805 }//for
13806 apiConnectptr.i = (3 * tiacTmp) - 1;
13807 ptrCheckGuard(apiConnectptr, capiConnectFilesize, apiConnectRecord);
13808 apiConnectptr.p->nextApiConnect = RNIL;
13809 cfirstfreeApiConnectFail = 2 * tiacTmp;
13810 }//Dbtc::initApiConnect()
13811
initgcp(Signal * signal)13812 void Dbtc::initgcp(Signal* signal)
13813 {
13814 Ptr<GcpRecord> gcpPtr;
13815 ndbrequire(cgcpFilesize > 0);
13816 for (gcpPtr.i = 0; gcpPtr.i < cgcpFilesize; gcpPtr.i++) {
13817 ptrAss(gcpPtr, gcpRecord);
13818 gcpPtr.p->nextGcp = gcpPtr.i + 1;
13819 }//for
13820 gcpPtr.i = cgcpFilesize - 1;
13821 ptrCheckGuard(gcpPtr, cgcpFilesize, gcpRecord);
13822 gcpPtr.p->nextGcp = RNIL;
13823 cfirstfreeGcp = 0;
13824 cfirstgcp = RNIL;
13825 clastgcp = RNIL;
13826 }//Dbtc::initgcp()
13827
inithost(Signal * signal)13828 void Dbtc::inithost(Signal* signal)
13829 {
13830 cpackedListIndex = 0;
13831 ndbrequire(chostFilesize > 0);
13832 for (hostptr.i = 0; hostptr.i < chostFilesize; hostptr.i++) {
13833 jam();
13834 ptrAss(hostptr, hostRecord);
13835 hostptr.p->hostStatus = HS_DEAD;
13836 hostptr.p->inPackedList = false;
13837 hostptr.p->lqhTransStatus = LTS_IDLE;
13838 struct PackedWordsContainer * containerTCKEYCONF =
13839 &hostptr.p->packTCKEYCONF;
13840 containerTCKEYCONF->noOfPackedWords = 0;
13841 for (Uint32 i = 0; i < NDB_ARRAY_SIZE(hostptr.p->lqh_pack); i++)
13842 {
13843 struct PackedWordsContainer * container = &hostptr.p->lqh_pack[i];
13844 container->noOfPackedWords = 0;
13845 container->hostBlockRef = numberToRef(DBLQH, i, hostptr.i);
13846 }
13847 hostptr.p->m_nf_bits = 0;
13848 }//for
13849 c_alive_nodes.clear();
13850 }//Dbtc::inithost()
13851
initialiseRecordsLab(Signal * signal,UintR Tdata0,Uint32 retRef,Uint32 retData)13852 void Dbtc::initialiseRecordsLab(Signal* signal, UintR Tdata0,
13853 Uint32 retRef, Uint32 retData)
13854 {
13855 switch (Tdata0) {
13856 case 0:
13857 jam();
13858 initApiConnect(signal);
13859 break;
13860 case 1:
13861 jam();
13862 // UNUSED Free to initialise something
13863 break;
13864 case 2:
13865 jam();
13866 // UNUSED Free to initialise something
13867 break;
13868 case 3:
13869 jam();
13870 initgcp(signal);
13871 break;
13872 case 4:
13873 jam();
13874 inithost(signal);
13875 break;
13876 case 5:
13877 jam();
13878 // UNUSED Free to initialise something
13879 break;
13880 case 6:
13881 jam();
13882 initTable(signal);
13883 break;
13884 case 7:
13885 jam();
13886 initialiseScanrec(signal);
13887 break;
13888 case 8:
13889 jam();
13890 initialiseScanOprec(signal);
13891 break;
13892 case 9:
13893 jam();
13894 initialiseScanFragrec(signal);
13895 break;
13896 case 10:
13897 jam();
13898 initialiseTcConnect(signal);
13899 break;
13900 case 11:
13901 jam();
13902 initTcFail(signal);
13903
13904 {
13905 ReadConfigConf * conf = (ReadConfigConf*)signal->getDataPtrSend();
13906 conf->senderRef = reference();
13907 conf->senderData = retData;
13908 sendSignal(retRef, GSN_READ_CONFIG_CONF, signal,
13909 ReadConfigConf::SignalLength, JBB);
13910 }
13911 return;
13912 break;
13913 default:
13914 jam();
13915 systemErrorLab(signal, __LINE__);
13916 return;
13917 break;
13918 }//switch
13919
13920 signal->theData[0] = TcContinueB::ZINITIALISE_RECORDS;
13921 signal->theData[1] = Tdata0 + 1;
13922 signal->theData[2] = 0;
13923 signal->theData[3] = retRef;
13924 signal->theData[4] = retData;
13925 sendSignal(reference(), GSN_CONTINUEB, signal, 5, JBB);
13926 }
13927
13928 /* ========================================================================= */
13929 /* ======= INITIALISE_SCANREC ======= */
13930 /* */
13931 /* ========================================================================= */
initialiseScanrec(Signal * signal)13932 void Dbtc::initialiseScanrec(Signal* signal)
13933 {
13934 ScanRecordPtr scanptr;
13935 ndbrequire(cscanrecFileSize > 0);
13936 for (scanptr.i = 0; scanptr.i < cscanrecFileSize; scanptr.i++) {
13937 refresh_watch_dog();
13938 jam();
13939 ptrAss(scanptr, scanRecord);
13940 new (scanptr.p) ScanRecord();
13941 scanptr.p->scanState = ScanRecord::IDLE;
13942 scanptr.p->scanApiRec = RNIL;
13943 scanptr.p->nextScan = scanptr.i + 1;
13944 }//for
13945 scanptr.i = cscanrecFileSize - 1;
13946 ptrAss(scanptr, scanRecord);
13947 scanptr.p->nextScan = RNIL;
13948 cfirstfreeScanrec = 0;
13949 cConcScanCount = 0;
13950 }//Dbtc::initialiseScanrec()
13951
initialiseScanFragrec(Signal * signal)13952 void Dbtc::initialiseScanFragrec(Signal* signal)
13953 {
13954 }//Dbtc::initialiseScanFragrec()
13955
initialiseScanOprec(Signal * signal)13956 void Dbtc::initialiseScanOprec(Signal* signal)
13957 {
13958 }//Dbtc::initialiseScanOprec()
13959
initTable(Signal * signal)13960 void Dbtc::initTable(Signal* signal)
13961 {
13962
13963 ndbrequire(ctabrecFilesize > 0);
13964 for (tabptr.i = 0; tabptr.i < ctabrecFilesize; tabptr.i++) {
13965 refresh_watch_dog();
13966 ptrAss(tabptr, tableRecord);
13967 tabptr.p->currentSchemaVersion = 0;
13968 tabptr.p->m_flags = 0;
13969 tabptr.p->set_storedTable(true);
13970 tabptr.p->tableType = 0;
13971 tabptr.p->set_enabled(false);
13972 tabptr.p->set_dropping(false);
13973 tabptr.p->noOfKeyAttr = 0;
13974 tabptr.p->hasCharAttr = 0;
13975 tabptr.p->noOfDistrKeys = 0;
13976 tabptr.p->hasVarKeys = 0;
13977 }//for
13978 }//Dbtc::initTable()
13979
initialiseTcConnect(Signal * signal)13980 void Dbtc::initialiseTcConnect(Signal* signal)
13981 {
13982 ndbrequire(ctcConnectFilesize >= 2);
13983
13984 // Place half of tcConnectptr's in cfirstfreeTcConnectFail list
13985 Uint32 titcTmp = ctcConnectFilesize / 2;
13986 for (tcConnectptr.i = 0; tcConnectptr.i < titcTmp; tcConnectptr.i++) {
13987 refresh_watch_dog();
13988 jam();
13989 ptrAss(tcConnectptr, tcConnectRecord);
13990 new (tcConnectptr.p) TcConnectRecord();
13991 tcConnectptr.p->tcConnectstate = OS_CONNECTED;
13992 tcConnectptr.p->apiConnect = RNIL;
13993 tcConnectptr.p->noOfNodes = 0;
13994 tcConnectptr.p->nextTcConnect = tcConnectptr.i + 1;
13995 tcConnectptr.p->commitAckMarker = RNIL;
13996 }//for
13997 tcConnectptr.i = titcTmp - 1;
13998 ptrAss(tcConnectptr, tcConnectRecord);
13999 tcConnectptr.p->nextTcConnect = RNIL;
14000 cfirstfreeTcConnectFail = 0;
14001
14002 // Place other half in cfirstfreeTcConnect list
14003 for (tcConnectptr.i = titcTmp; tcConnectptr.i < ctcConnectFilesize;
14004 tcConnectptr.i++) {
14005 refresh_watch_dog();
14006 jam();
14007 ptrAss(tcConnectptr, tcConnectRecord);
14008 new (tcConnectptr.p) TcConnectRecord();
14009 tcConnectptr.p->tcConnectstate = OS_CONNECTED;
14010 tcConnectptr.p->apiConnect = RNIL;
14011 tcConnectptr.p->noOfNodes = 0;
14012 tcConnectptr.p->nextTcConnect = tcConnectptr.i + 1;
14013 tcConnectptr.p->commitAckMarker = RNIL;
14014 }//for
14015 tcConnectptr.i = ctcConnectFilesize - 1;
14016 ptrAss(tcConnectptr, tcConnectRecord);
14017 tcConnectptr.p->nextTcConnect = RNIL;
14018 cfirstfreeTcConnect = titcTmp;
14019 c_counters.cconcurrentOp = 0;
14020 }//Dbtc::initialiseTcConnect()
14021
14022 /* ------------------------------------------------------------------------- */
14023 /* ---- LINK A GLOBAL CHECKPOINT RECORD INTO THE LIST WITH TRANSACTIONS */
14024 /* WAITING FOR COMPLETION. */
14025 /* ------------------------------------------------------------------------- */
linkGciInGcilist(Ptr<GcpRecord> gcpPtr)14026 void Dbtc::linkGciInGcilist(Ptr<GcpRecord> gcpPtr)
14027 {
14028 GcpRecordPtr tmpGcpPointer;
14029 if (cfirstgcp == RNIL) {
14030 jam();
14031 cfirstgcp = gcpPtr.i;
14032 } else {
14033 jam();
14034 tmpGcpPointer.i = clastgcp;
14035 ptrCheckGuard(tmpGcpPointer, cgcpFilesize, gcpRecord);
14036 tmpGcpPointer.p->nextGcp = gcpPtr.i;
14037 }//if
14038 clastgcp = gcpPtr.i;
14039 }//Dbtc::linkGciInGcilist()
14040
14041 /* ------------------------------------------------------------------------- */
14042 /* ------- LINK A TC CONNECT RECORD INTO THE API LIST OF TC CONNECTIONS --- */
14043 /* ------------------------------------------------------------------------- */
linkTcInConnectionlist(Signal * signal)14044 void Dbtc::linkTcInConnectionlist(Signal* signal)
14045 {
14046 /* POINTER FOR THE CONNECT_RECORD */
14047 TcConnectRecordPtr ltcTcConnectptr;
14048
14049 tcConnectptr.p->nextTcConnect = RNIL;
14050 ltcTcConnectptr.i = apiConnectptr.p->lastTcConnect;
14051 apiConnectptr.p->lastTcConnect = tcConnectptr.i;
14052 if (ltcTcConnectptr.i == RNIL) {
14053 jam();
14054 apiConnectptr.p->firstTcConnect = tcConnectptr.i;
14055 } else {
14056 jam();
14057 ptrCheckGuard(ltcTcConnectptr, ctcConnectFilesize, tcConnectRecord);
14058 ltcTcConnectptr.p->nextTcConnect = tcConnectptr.i;
14059 }//if
14060 }//Dbtc::linkTcInConnectionlist()
14061
14062 /*---------------------------------------------------------------------------*/
14063 /* RELEASE_ABORT_RESOURCES */
14064 /* THIS CODE RELEASES ALL RESOURCES AFTER AN ABORT OF A TRANSACTION AND ALSO */
14065 /* SENDS THE ABORT DECISION TO THE APPLICATION. */
14066 /*---------------------------------------------------------------------------*/
releaseAbortResources(Signal * signal)14067 void Dbtc::releaseAbortResources(Signal* signal)
14068 {
14069 TcConnectRecordPtr rarTcConnectptr;
14070
14071 c_counters.cabortCount++;
14072 if (apiConnectptr.p->apiCopyRecord != RNIL)
14073 {
14074 // Put apiCopyRecord back in free list.
14075 jam();
14076 ApiConnectRecordPtr copyPtr;
14077 copyPtr.i = apiConnectptr.p->apiCopyRecord;
14078 ptrCheckGuard(copyPtr, capiConnectFilesize, apiConnectRecord);
14079 ndbassert(copyPtr.p->apiCopyRecord == RNIL);
14080 ndbassert(copyPtr.p->nextApiConnect == RNIL);
14081 copyPtr.p->nextApiConnect = cfirstfreeApiConnectCopy;
14082 cfirstfreeApiConnectCopy = copyPtr.i;
14083 apiConnectptr.p->apiCopyRecord = RNIL;
14084 }
14085 if (apiConnectptr.p->cachePtr != RNIL) {
14086 cachePtr.i = apiConnectptr.p->cachePtr;
14087 ptrCheckGuard(cachePtr, ccacheFilesize, cacheRecord);
14088 releaseAttrinfo();
14089 releaseKeys();
14090 }//if
14091 tcConnectptr.i = apiConnectptr.p->firstTcConnect;
14092 while (tcConnectptr.i != RNIL) {
14093 jam();
14094 ptrCheckGuard(tcConnectptr, ctcConnectFilesize, tcConnectRecord);
14095 // Clear any markers that have not already been cleared
14096 clearCommitAckMarker(apiConnectptr.p, tcConnectptr.p);
14097 rarTcConnectptr.i = tcConnectptr.p->nextTcConnect;
14098 releaseTcCon();
14099 tcConnectptr.i = rarTcConnectptr.i;
14100 }//while
14101
14102 ndbrequire(apiConnectptr.p->num_commit_ack_markers == 0);
14103 releaseMarker(apiConnectptr.p);
14104
14105 apiConnectptr.p->firstTcConnect = RNIL;
14106 apiConnectptr.p->lastTcConnect = RNIL;
14107 apiConnectptr.p->m_transaction_nodes.clear();
14108 apiConnectptr.p->singleUserMode = 0;
14109
14110 // MASV let state be CS_ABORTING until all
14111 // signals in the "air" have been received. Reset to CS_CONNECTED
14112 // will be done when a TCKEYREQ with start flag is received
14113 // or releaseApiCon is called
14114 // apiConnectptr.p->apiConnectstate = CS_CONNECTED;
14115 apiConnectptr.p->apiConnectstate = CS_ABORTING;
14116 apiConnectptr.p->abortState = AS_IDLE;
14117 releaseAllSeizedIndexOperations(apiConnectptr.p);
14118 releaseFiredTriggerData(&apiConnectptr.p->theFiredTriggers);
14119
14120 if (tc_testbit(apiConnectptr.p->m_flags, ApiConnectRecord::TF_EXEC_FLAG) ||
14121 apiConnectptr.p->apiFailState == ZTRUE)
14122 {
14123 jam();
14124 bool ok = false;
14125 Uint32 blockRef = apiConnectptr.p->ndbapiBlockref;
14126 ReturnSignal ret = apiConnectptr.p->returnsignal;
14127 apiConnectptr.p->returnsignal = RS_NO_RETURN;
14128 tc_clearbit(apiConnectptr.p->m_flags, ApiConnectRecord::TF_EXEC_FLAG);
14129 switch(ret){
14130 case RS_TCROLLBACKCONF:
14131 jam();
14132 ok = true;
14133 signal->theData[0] = apiConnectptr.p->ndbapiConnect;
14134 signal->theData[1] = apiConnectptr.p->transid[0];
14135 signal->theData[2] = apiConnectptr.p->transid[1];
14136 sendSignal(blockRef, GSN_TCROLLBACKCONF, signal, 3, JBB);
14137 break;
14138 case RS_TCROLLBACKREP:{
14139 jam();
14140 ok = true;
14141 #ifdef ERROR_INSERT
14142 if (ERROR_INSERTED(8101))
14143 {
14144 char buf[128];
14145 BaseString::snprintf(buf, sizeof(buf), "Sending CONTINUEB:ZDEBUG_DELAY_TCROLLBACKREP");
14146 warningEvent("%s", buf);
14147
14148 jam();
14149 signal->theData[0] = TcContinueB::ZDEBUG_DELAY_TCROLLBACKREP;
14150 signal->theData[1] = apiConnectptr.p->ndbapiConnect;
14151 signal->theData[2] = apiConnectptr.p->transid[0];
14152 signal->theData[3] = apiConnectptr.p->transid[1];
14153 signal->theData[4] = apiConnectptr.p->returncode;
14154 signal->theData[5] = apiConnectptr.p->errorData;
14155 signal->theData[6] = blockRef;
14156
14157 sendSignalWithDelay(reference(), GSN_CONTINUEB, signal, 100, 7);
14158 break;
14159 }
14160 #endif
14161 TcRollbackRep * const tcRollbackRep =
14162 (TcRollbackRep *) signal->getDataPtr();
14163
14164 tcRollbackRep->connectPtr = apiConnectptr.p->ndbapiConnect;
14165 tcRollbackRep->transId[0] = apiConnectptr.p->transid[0];
14166 tcRollbackRep->transId[1] = apiConnectptr.p->transid[1];
14167 tcRollbackRep->returnCode = apiConnectptr.p->returncode;
14168 tcRollbackRep->errorData = apiConnectptr.p->errorData;
14169 sendSignal(blockRef, GSN_TCROLLBACKREP, signal,
14170 TcRollbackRep::SignalLength, JBB);
14171 }
14172 break;
14173 case RS_NO_RETURN:
14174 jam();
14175 ok = true;
14176 break;
14177 case RS_TCKEYCONF:
14178 case RS_TC_COMMITCONF:
14179 break;
14180 }
14181 if(!ok){
14182 jam();
14183 ndbout_c("returnsignal = %d", apiConnectptr.p->returnsignal);
14184 sendSystemError(signal, __LINE__);
14185 }//if
14186
14187 }
14188 setApiConTimer(apiConnectptr.i, 0,
14189 100000+c_apiConTimer_line[apiConnectptr.i]);
14190 if (apiConnectptr.p->apiFailState == ZTRUE) {
14191 jam();
14192 handleApiFailState(signal, apiConnectptr.i);
14193 return;
14194 }//if
14195 }//Dbtc::releaseAbortResources()
14196
releaseApiCon(Signal * signal,UintR TapiConnectPtr)14197 void Dbtc::releaseApiCon(Signal* signal, UintR TapiConnectPtr)
14198 {
14199 ApiConnectRecordPtr TlocalApiConnectptr;
14200
14201 TlocalApiConnectptr.i = TapiConnectPtr;
14202 ptrCheckGuard(TlocalApiConnectptr, capiConnectFilesize, apiConnectRecord);
14203 ndbassert(TlocalApiConnectptr.p->apiCopyRecord == RNIL);
14204 ndbassert(TlocalApiConnectptr.p->nextApiConnect == RNIL);
14205 TlocalApiConnectptr.p->nextApiConnect = cfirstfreeApiConnect;
14206 cfirstfreeApiConnect = TlocalApiConnectptr.i;
14207 setApiConTimer(TlocalApiConnectptr.i, 0, __LINE__);
14208 TlocalApiConnectptr.p->apiConnectstate = CS_DISCONNECTED;
14209 ndbassert(TlocalApiConnectptr.p->m_transaction_nodes.isclear());
14210 ndbassert(TlocalApiConnectptr.p->apiScanRec == RNIL);
14211 ndbassert(TlocalApiConnectptr.p->cascading_scans_count == 0);
14212 TlocalApiConnectptr.p->ndbapiBlockref = 0;
14213 TlocalApiConnectptr.p->transid[0] = 0;
14214 TlocalApiConnectptr.p->transid[1] = 0;
14215 }//Dbtc::releaseApiCon()
14216
releaseApiConnectFail(Signal * signal)14217 void Dbtc::releaseApiConnectFail(Signal* signal)
14218 {
14219 apiConnectptr.p->apiConnectstate = CS_RESTART;
14220 apiConnectptr.p->takeOverRec = (Uint8)Z8NIL;
14221 setApiConTimer(apiConnectptr.i, 0, __LINE__);
14222 apiConnectptr.p->nextApiConnect = cfirstfreeApiConnectFail;
14223 cfirstfreeApiConnectFail = apiConnectptr.i;
14224 ndbrequire(apiConnectptr.p->commitAckMarker == RNIL);
14225 }//Dbtc::releaseApiConnectFail()
14226
releaseKeys()14227 void Dbtc::releaseKeys()
14228 {
14229 Uint32 keyInfoSectionI= cachePtr.p->keyInfoSectionI;
14230
14231 /* Release KeyInfo section if there is one */
14232 releaseSection(keyInfoSectionI);
14233 cachePtr.p->keyInfoSectionI= RNIL;
14234
14235 }//Dbtc::releaseKeys()
14236
releaseTcConnectFail(Signal * signal)14237 void Dbtc::releaseTcConnectFail(Signal* signal)
14238 {
14239 ptrGuard(tcConnectptr);
14240 tcConnectptr.p->nextTcConnect = cfirstfreeTcConnectFail;
14241 tcConnectptr.p->tcConnectstate = OS_CONNECTED;
14242 cfirstfreeTcConnectFail = tcConnectptr.i;
14243 }//Dbtc::releaseTcConnectFail()
14244
seizeApiConnect(Signal * signal)14245 void Dbtc::seizeApiConnect(Signal* signal)
14246 {
14247 if (cfirstfreeApiConnect != RNIL) {
14248 jam();
14249 terrorCode = ZOK;
14250 apiConnectptr.i = cfirstfreeApiConnect; /* ASSIGN A FREE RECORD FROM */
14251 ptrCheckGuard(apiConnectptr, capiConnectFilesize, apiConnectRecord);
14252 cfirstfreeApiConnect = apiConnectptr.p->nextApiConnect;
14253 apiConnectptr.p->nextApiConnect = RNIL;
14254 setApiConTimer(apiConnectptr.i, 0, __LINE__);
14255 apiConnectptr.p->apiConnectstate = CS_CONNECTED; /* STATE OF CONNECTION */
14256 tc_clearbit(apiConnectptr.p->m_flags,
14257 ApiConnectRecord::TF_TRIGGER_PENDING);
14258 apiConnectptr.p->m_special_op_flags = 0;
14259 } else {
14260 jam();
14261 terrorCode = ZNO_FREE_API_CONNECTION;
14262 }//if
14263 }//Dbtc::seizeApiConnect()
14264
seizeApiConnectFail(Signal * signal)14265 void Dbtc::seizeApiConnectFail(Signal* signal)
14266 {
14267 apiConnectptr.i = cfirstfreeApiConnectFail;
14268 ptrCheckGuard(apiConnectptr, capiConnectFilesize, apiConnectRecord);
14269 cfirstfreeApiConnectFail = apiConnectptr.p->nextApiConnect;
14270 apiConnectptr.p->nextApiConnect = RNIL;
14271 }//Dbtc::seizeApiConnectFail()
14272
seizeTcConnect(Signal * signal)14273 void Dbtc::seizeTcConnect(Signal* signal)
14274 {
14275 tcConnectptr.i = cfirstfreeTcConnect;
14276 ptrCheckGuard(tcConnectptr, ctcConnectFilesize, tcConnectRecord);
14277 cfirstfreeTcConnect = tcConnectptr.p->nextTcConnect;
14278 c_counters.cconcurrentOp++;
14279 tcConnectptr.p->m_special_op_flags = 0;
14280 tcConnectptr.p->tcConnectstate = OS_ABORTING;
14281 tcConnectptr.p->noOfNodes = 0;
14282 }//Dbtc::seizeTcConnect()
14283
seizeTcConnectFail(Signal * signal)14284 void Dbtc::seizeTcConnectFail(Signal* signal)
14285 {
14286 tcConnectptr.i = cfirstfreeTcConnectFail;
14287 ptrCheckGuard(tcConnectptr, ctcConnectFilesize, tcConnectRecord);
14288 cfirstfreeTcConnectFail = tcConnectptr.p->nextTcConnect;
14289 }//Dbtc::seizeTcConnectFail()
14290
14291 /**
14292 * sendAttrInfoTrain
14293 * This method sends an ATTRINFO signal train using AttrInfo
14294 * from the section passed, starting at the supplied offset
14295 */
sendAttrInfoTrain(Signal * signal,UintR TBRef,Uint32 connectPtr,Uint32 offset,Uint32 attrInfoIVal)14296 bool Dbtc::sendAttrInfoTrain(Signal* signal,
14297 UintR TBRef,
14298 Uint32 connectPtr,
14299 Uint32 offset,
14300 Uint32 attrInfoIVal)
14301 {
14302 ApiConnectRecord * const regApiPtr = apiConnectptr.p;
14303
14304 ndbassert( attrInfoIVal != RNIL );
14305 SectionReader attrInfoReader(attrInfoIVal, getSectionSegmentPool());
14306 Uint32 attrInfoLength= attrInfoReader.getSize();
14307
14308 ndbassert( offset < attrInfoLength );
14309 if (unlikely(! attrInfoReader.step( offset )))
14310 return false;
14311 attrInfoLength-= offset;
14312
14313 signal->theData[0] = connectPtr;
14314 signal->theData[1] = regApiPtr->transid[0];
14315 signal->theData[2] = regApiPtr->transid[1];
14316
14317 while (attrInfoLength != 0)
14318 {
14319 Uint32 dataInSignal= MIN(AttrInfo::DataLength, attrInfoLength);
14320
14321 if (unlikely(! attrInfoReader.getWords(&signal->theData[3],
14322 dataInSignal)))
14323 return false;
14324
14325 sendSignal(TBRef, GSN_ATTRINFO, signal,
14326 AttrInfo::HeaderLength + dataInSignal, JBB);
14327
14328 attrInfoLength-= dataInSignal;
14329 }
14330 return true;
14331 } //Dbtc::sendAttrInfoTrain()
14332
sendContinueTimeOutControl(Signal * signal,Uint32 TapiConPtr)14333 void Dbtc::sendContinueTimeOutControl(Signal* signal, Uint32 TapiConPtr)
14334 {
14335 signal->theData[0] = TcContinueB::ZCONTINUE_TIME_OUT_CONTROL;
14336 signal->theData[1] = TapiConPtr;
14337 sendSignal(cownref, GSN_CONTINUEB, signal, 2, JBB);
14338 }//Dbtc::sendContinueTimeOutControl()
14339
sendSystemError(Signal * signal,int line)14340 void Dbtc::sendSystemError(Signal* signal, int line)
14341 {
14342 progError(line, NDBD_EXIT_NDBREQUIRE);
14343 }//Dbtc::sendSystemError()
14344
14345 /* ========================================================================= */
14346 /* ------- LINK ACTUAL GCP OUT OF LIST ------- */
14347 /* ------------------------------------------------------------------------- */
unlinkGcp(Ptr<GcpRecord> tmpGcpPtr)14348 void Dbtc::unlinkGcp(Ptr<GcpRecord> tmpGcpPtr)
14349 {
14350 ndbrequire(cfirstgcp == tmpGcpPtr.i);
14351
14352 cfirstgcp = tmpGcpPtr.p->nextGcp;
14353 if (tmpGcpPtr.i == clastgcp) {
14354 jam();
14355 clastgcp = RNIL;
14356 }//if
14357
14358 tmpGcpPtr.p->nextGcp = cfirstfreeGcp;
14359 cfirstfreeGcp = tmpGcpPtr.i;
14360 }//Dbtc::unlinkGcp()
14361
14362 void
execDUMP_STATE_ORD(Signal * signal)14363 Dbtc::execDUMP_STATE_ORD(Signal* signal)
14364 {
14365 const Uint32 MAX_RECORDS_AT_A_TIME = 16;
14366
14367 jamEntry();
14368 DumpStateOrd * const dumpState = (DumpStateOrd *)&signal->theData[0];
14369 Uint32 arg = signal->theData[0];
14370
14371 // Dump set of ScanFragRecs
14372 if (dumpState->args[0] == DumpStateOrd::TcDumpSetOfScanFragRec){
14373 /**
14374 * DUMP 2500 12 10 1 1
14375 * Prints ScanFrag records 12 through 21 in instance 1.
14376 * The last parameter indicates whether to only print active instances.
14377 * If the parameter is missing it is set to 1 indicating printing only
14378 * active instances.
14379 *
14380 * Output to cluster log.
14381 */
14382 jam();
14383 Uint32 recordNo = 0;
14384 Uint32 numRecords = 0;
14385 Uint32 instanceId = 0;
14386 Uint32 includeOnlyActive = 1;
14387
14388 if (signal->getLength() >= 4)
14389 {
14390 recordNo = dumpState->args[1];
14391 numRecords = dumpState->args[2];
14392 instanceId = dumpState->args[3];
14393 if (signal->getLength() >= 5)
14394 {
14395 includeOnlyActive = dumpState->args[4];
14396 }
14397 }
14398 else
14399 {
14400 return;
14401 }
14402 if (instance() != instanceId)
14403 {
14404 return;
14405 }
14406 if (numRecords > MAX_RECORDS_AT_A_TIME)
14407 {
14408 numRecords = MAX_RECORDS_AT_A_TIME;
14409 }
14410 if (recordNo >= cscanFragrecFileSize)
14411 {
14412 return;
14413 }
14414
14415 ScanFragRecPtr sfp;
14416 sfp.i = recordNo;
14417 c_scan_frag_pool.getPtr(sfp);
14418 if (sfp.p->scanFragState != ScanFragRec::COMPLETED ||
14419 !includeOnlyActive)
14420 {
14421 dumpState->args[0] = DumpStateOrd::TcDumpOneScanFragRec;
14422 dumpState->args[1] = recordNo;
14423 dumpState->args[2] = instance();
14424 signal->setLength(3);
14425 execDUMP_STATE_ORD(signal);
14426 }
14427 numRecords--;
14428 recordNo++;
14429
14430 if (recordNo < cscanFragrecFileSize && numRecords > 0)
14431 {
14432 dumpState->args[0] = DumpStateOrd::TcDumpSetOfScanFragRec;
14433 dumpState->args[1] = recordNo;
14434 dumpState->args[2] = numRecords;
14435 dumpState->args[3] = instance();
14436 dumpState->args[4] = includeOnlyActive;
14437 sendSignal(reference(), GSN_DUMP_STATE_ORD, signal, 5, JBB);
14438 }
14439 return;
14440 }
14441
14442 // Dump one ScanFragRec
14443 if (dumpState->args[0] == DumpStateOrd::TcDumpOneScanFragRec){
14444 /**
14445 * DUMP 2501 12 1
14446 * Print ScanFrag record 12 in instance 1
14447 *
14448 * Output to cluster log.
14449 */
14450 jam();
14451 Uint32 recordNo = RNIL;
14452 Uint32 instanceId = RNIL;
14453 if (signal->getLength() == 3)
14454 {
14455 recordNo = dumpState->args[1];
14456 instanceId = dumpState->args[2];
14457 }
14458 else
14459 {
14460 return;
14461 }
14462 if (instanceId != instance())
14463 {
14464 return;
14465 }
14466 if (recordNo >= cscanFragrecFileSize)
14467 {
14468 return;
14469 }
14470
14471 ScanFragRecPtr sfp;
14472 sfp.i = recordNo;
14473 c_scan_frag_pool.getPtr(sfp);
14474 infoEvent("Dbtc::ScanFragRec[%d]: state=%d fragid=%d",
14475 sfp.i,
14476 sfp.p->scanFragState,
14477 sfp.p->scanFragId);
14478 infoEvent(" nodeid=%d, timer=%d",
14479 refToNode(sfp.p->lqhBlockref),
14480 sfp.p->scanFragTimer);
14481 return;
14482 }
14483
14484 // Dump set of ScanRecords
14485 if (dumpState->args[0] == DumpStateOrd::TcDumpSetOfScanRec){
14486 /**
14487 * DUMP 2502 12 10 1 1
14488 * Print Scan records 12 through 21 in instance 1
14489 * Last parameter == 0 indicates that we will print all
14490 * records, otherwise we will only print active scan records.
14491 * Last parameter is defaulting to 1 if not provided
14492 *
14493 * Output to the cluster log
14494 */
14495 jam();
14496 Uint32 recordNo = 0;
14497 Uint32 numRecords = 0;
14498 Uint32 instanceId = 0;
14499 Uint32 includeOnlyActive = 1;
14500
14501 if (signal->getLength() >= 4)
14502 {
14503 recordNo = dumpState->args[1];
14504 numRecords = dumpState->args[2];
14505 instanceId = dumpState->args[3];
14506 if (signal->getLength() >= 5)
14507 {
14508 includeOnlyActive = dumpState->args[4];
14509 }
14510 }
14511 else
14512 {
14513 return;
14514 }
14515 if (instance() != instanceId)
14516 {
14517 return;
14518 }
14519 if (numRecords > MAX_RECORDS_AT_A_TIME)
14520 {
14521 numRecords = MAX_RECORDS_AT_A_TIME;
14522 }
14523 if (recordNo >= cscanrecFileSize)
14524 {
14525 return;
14526 }
14527
14528 ScanRecordPtr sp;
14529 sp.i = recordNo;
14530 ptrAss(sp, scanRecord);
14531 if (sp.p->scanState != ScanRecord::IDLE ||
14532 !includeOnlyActive)
14533 {
14534 dumpState->args[0] = DumpStateOrd::TcDumpOneScanRec;
14535 dumpState->args[1] = recordNo;
14536 dumpState->args[2] = instance();
14537 signal->setLength(3);
14538 execDUMP_STATE_ORD(signal);
14539 }
14540
14541 numRecords--;
14542 recordNo++;
14543 if (recordNo < cscanrecFileSize && numRecords > 0)
14544 {
14545 dumpState->args[0] = DumpStateOrd::TcDumpSetOfScanRec;
14546 dumpState->args[1] = recordNo;
14547 dumpState->args[2] = numRecords;
14548 dumpState->args[3] = instance();
14549 dumpState->args[4] = includeOnlyActive;
14550 sendSignal(reference(), GSN_DUMP_STATE_ORD, signal, 5, JBB);
14551 }
14552 return;
14553 }
14554
14555 // Dump one ScanRecord
14556 // and associated ScanFragRec and ApiConnectRecord
14557 if (dumpState->args[0] == DumpStateOrd::TcDumpOneScanRec){
14558 /**
14559 * DUMP 2504 12 1
14560 * This will print ScanRecord 12 in instance 1 and all associated
14561 * ScanFrag records and ApiConnect records.
14562 *
14563 * It is necessary to provide both record number and instance id
14564 * to get anything printed using this dump command.
14565 */
14566 jam();
14567 Uint32 recordNo = RNIL;
14568 Uint32 instanceId = 0;
14569 if (signal->getLength() == 3)
14570 {
14571 recordNo = dumpState->args[1];
14572 instanceId = dumpState->args[2];
14573 }
14574 else
14575 {
14576 return;
14577 }
14578 if (instanceId != instance())
14579 {
14580 return;
14581 }
14582 if (recordNo >= cscanrecFileSize)
14583 {
14584 return;
14585 }
14586
14587 ScanRecordPtr sp;
14588 sp.i = recordNo;
14589 ptrAss(sp, scanRecord);
14590 infoEvent("Dbtc::ScanRecord[%d]: state=%d, "
14591 "nextfrag=%d, nofrag=%d",
14592 sp.i,
14593 sp.p->scanState,
14594 sp.p->scanNextFragId,
14595 sp.p->scanNoFrag);
14596 infoEvent(" para=%d, receivedop=%d, noOprecPerFrag=%d",
14597 sp.p->scanParallel,
14598 sp.p->scanReceivedOperations,
14599 sp.p->batch_size_rows);
14600 infoEvent(" schv=%d, tab=%d, sproc=%d",
14601 sp.p->scanSchemaVersion,
14602 sp.p->scanTableref,
14603 sp.p->scanStoredProcId);
14604 infoEvent(" apiRec=%d, next=%d",
14605 sp.p->scanApiRec, sp.p->nextScan);
14606
14607 if (sp.p->scanState != ScanRecord::IDLE){
14608 // Request dump of ScanFragRec
14609 ScanFragRecPtr sfptr;
14610 #define DUMP_SFR(x){\
14611 ScanFragList list(c_scan_frag_pool, x);\
14612 for(list.first(sfptr); !sfptr.isNull(); list.next(sfptr)){\
14613 dumpState->args[0] = DumpStateOrd::TcDumpOneScanFragRec; \
14614 dumpState->args[1] = sfptr.i;\
14615 dumpState->args[2] = instance(); \
14616 signal->setLength(3); \
14617 execDUMP_STATE_ORD(signal);\
14618 }}
14619
14620 DUMP_SFR(sp.p->m_running_scan_frags);
14621 DUMP_SFR(sp.p->m_queued_scan_frags);
14622 DUMP_SFR(sp.p->m_delivered_scan_frags);
14623
14624 // Request dump of ApiConnectRecord
14625 dumpState->args[0] = DumpStateOrd::TcDumpOneApiConnectRec;
14626 dumpState->args[1] = sp.p->scanApiRec;
14627 dumpState->args[2] = instance();
14628 signal->setLength(3);
14629 execDUMP_STATE_ORD(signal);
14630 }
14631 return;
14632 }
14633
14634 // Dump Set of TcConnectRecord(s)
14635 if (dumpState->args[0] == DumpStateOrd::TcDumpSetOfTcConnectRec)
14636 {
14637 /**
14638 * DUMP 2517 12 10 1 1
14639 * This will print recordNo from 12 to 21 in instance 1 (first
14640 * instance is number since instance 0 is the DBTC Proxy instance).
14641 * We will not print records that doesn't exist. The last parameter
14642 * indicates whether to include only active records or if we should
14643 * include all records. This last parameter defaults to 1 which means
14644 * we are only printing information about active records.
14645 *
14646 * It is necessary to specify record number, number of records
14647 * and instance id to get anything printed.
14648 *
14649 * Use this DUMP command with care and avoid printing more than
14650 * 10 records per dump command in production systems to avoid
14651 * overloading any parts of the system. Also print from instance
14652 * at a time since otherwise it will be almost impossible to know
14653 * which instance have generated what printout.
14654 *
14655 * The printouts will end up in the cluster log.
14656 */
14657 jam();
14658 Uint32 recordNo = RNIL;
14659 Uint32 instanceId = RNIL;
14660 Uint32 numRecords = 1;
14661 Uint32 includeOnlyActive = 1;
14662
14663 if (signal->getLength() >= 4)
14664 {
14665 recordNo = dumpState->args[1];
14666 numRecords = dumpState->args[2];
14667 instanceId = dumpState->args[3];
14668 if (signal->getLength() >= 5)
14669 {
14670 includeOnlyActive = dumpState->args[4];
14671 }
14672 }
14673 else
14674 {
14675 return;
14676 }
14677 if (instanceId != instance())
14678 {
14679 return;
14680 }
14681 if (numRecords > MAX_RECORDS_AT_A_TIME)
14682 {
14683 numRecords = MAX_RECORDS_AT_A_TIME;
14684 }
14685 if (recordNo >= ctcConnectFilesize)
14686 {
14687 return;
14688 }
14689
14690 TcConnectRecordPtr tc;
14691 tc.i = recordNo;
14692 ptrAss(tc, tcConnectRecord);
14693 if (tc.p->tcConnectstate == OS_CONNECTED ||
14694 !includeOnlyActive)
14695 {
14696 dumpState->args[0] = DumpStateOrd::TcDumpOneTcConnectRec;
14697 dumpState->args[1] = recordNo;
14698 dumpState->args[2] = instanceId;
14699 signal->setLength(3);
14700 execDUMP_STATE_ORD(signal);
14701 }
14702
14703 numRecords--;
14704 recordNo++;
14705 if (recordNo < ctcConnectFilesize && numRecords > 0)
14706 {
14707 dumpState->args[0] = DumpStateOrd::TcDumpSetOfTcConnectRec;
14708 dumpState->args[1] = recordNo;
14709 dumpState->args[2] = numRecords;
14710 dumpState->args[3] = instanceId;
14711 dumpState->args[4] = includeOnlyActive;
14712 sendSignal(reference(), GSN_DUMP_STATE_ORD, signal, 5, JBB);
14713 }
14714 return;
14715 }
14716
14717 // Dump one TcConnectRecord
14718 if (dumpState->args[0] == DumpStateOrd::TcDumpOneTcConnectRec)
14719 {
14720 /**
14721 * This part is mostly used as an assistant function to dump a range
14722 * of TcConnect records. It can also be invoked directly in
14723 * the following manner.
14724 *
14725 * DUMP 2516 12 1
14726 * Record 12 will be printed in instance 1
14727 */
14728 jam();
14729 Uint32 recordNo = RNIL;
14730 Uint32 instanceId = RNIL;
14731 if (signal->getLength() == 3)
14732 {
14733 recordNo = dumpState->args[1];
14734 instanceId = dumpState->args[2];
14735 }
14736 else
14737 {
14738 return;
14739 }
14740 if (recordNo >= ctcConnectFilesize)
14741 {
14742 return;
14743 }
14744 if (instanceId != instance())
14745 {
14746 return;
14747 }
14748
14749 TcConnectRecordPtr tc;
14750 tc.i = recordNo;
14751 ptrAss(tc, tcConnectRecord);
14752 infoEvent("Dbtc::TcConnectRecord[%d]: state=%d, apiCon=%d, "
14753 "commitAckMarker=%d",
14754 tc.i,
14755 tc.p->tcConnectstate,
14756 tc.p->apiConnect,
14757 tc.p->commitAckMarker);
14758 infoEvent(" special flags=%x, noOfNodes=%d, operation=%d",
14759 tc.p->m_special_op_flags,
14760 tc.p->noOfNodes,
14761 tc.p->operation);
14762 infoEvent(" clientData=%d, savePointId=%d, nodes(%d,%d,%d,%d), ",
14763 tc.p->clientData,
14764 tc.p->savePointId,
14765 tc.p->tcNodedata[0],
14766 tc.p->tcNodedata[1],
14767 tc.p->tcNodedata[2],
14768 tc.p->tcNodedata[3]);
14769 infoEvent(" next=%d, instance=%u ",
14770 tc.p->nextTcConnect,
14771 instance());
14772 return;
14773 }
14774
14775 // Dump Set of ApiConnectRecord(s)
14776 if (dumpState->args[0] == DumpStateOrd::TcDumpSetOfApiConnectRec)
14777 {
14778 /**
14779 * Print a range of ApiConnect records
14780 * This command is invoked by the following DUMP command:
14781 * DUMP 2515 12 2 1
14782 * Print ApiConnect record 12 through 13 in instance 1
14783 *
14784 * The output will end up in the cluster log.
14785 *
14786 * WARNING: Don't print more than at most 10 records at a time
14787 * in a production system.
14788 * Use the full set of parameters such that we also specify the
14789 * instance id. This is necessary to know what is actually printed
14790 * since the printout from instance 1 and instance 2 doesn't
14791 * differ.
14792 */
14793 jam();
14794 Uint32 recordNo = RNIL;
14795 Uint32 instanceId = RNIL;
14796 Uint32 numRecords = 1;
14797 Uint32 includeOnlyActive = 1;
14798
14799 if (signal->getLength() >= 4)
14800 {
14801 recordNo = dumpState->args[1];
14802 numRecords = dumpState->args[2];
14803 instanceId = dumpState->args[3];
14804 if (signal->getLength() >= 5)
14805 {
14806 includeOnlyActive = dumpState->args[4];
14807 }
14808 }
14809 else
14810 {
14811 return;
14812 }
14813 if (instanceId != instance())
14814 {
14815 return;
14816 }
14817 if (recordNo >= capiConnectFilesize)
14818 {
14819 return;
14820 }
14821
14822 ApiConnectRecordPtr ap;
14823 ap.i = recordNo;
14824 ptrAss(ap, apiConnectRecord);
14825
14826 if (!includeOnlyActive ||
14827 ((ap.p->apiConnectstate != CS_CONNECTED) &&
14828 (ap.p->apiConnectstate != CS_ABORTING ||
14829 ap.p->abortState != AS_IDLE)))
14830 {
14831 dumpState->args[0] = DumpStateOrd::TcDumpOneApiConnectRec;
14832 dumpState->args[1] = recordNo;
14833 dumpState->args[2] = instanceId;
14834 signal->setLength(3);
14835 execDUMP_STATE_ORD(signal);
14836 }
14837
14838 numRecords--;
14839 recordNo++;
14840 if (recordNo < capiConnectFilesize && numRecords > 0)
14841 {
14842 dumpState->args[0] = DumpStateOrd::TcDumpSetOfApiConnectRec;
14843 dumpState->args[1] = recordNo;
14844 dumpState->args[2] = numRecords;
14845 dumpState->args[3] = instanceId;
14846 dumpState->args[4] = includeOnlyActive;
14847 sendSignal(reference(), GSN_DUMP_STATE_ORD, signal, 5, JBB);
14848 }
14849 return;
14850 }
14851
14852 // Dump one ApiConnectRecord
14853 if (dumpState->args[0] == DumpStateOrd::TcDumpOneApiConnectRec){
14854 /**
14855 * Print one ApiConnect record.
14856 * This is a support function to DUMP 2515. It can also
14857 * be used directly using the following command.
14858 *
14859 * DUMP 2505 12 1
14860 * Print ApiConnect record 12 in instance 1
14861 *
14862 * The output will be printed to the cluster log.
14863 */
14864 jam();
14865 Uint32 recordNo = RNIL;
14866 Uint32 instanceId = RNIL;
14867 if (signal->getLength() == 3)
14868 {
14869 recordNo = dumpState->args[1];
14870 instanceId = dumpState->args[2];
14871 }
14872 else
14873 {
14874 return;
14875 }
14876
14877 if (recordNo >= capiConnectFilesize)
14878 {
14879 return;
14880 }
14881 if (instanceId != instance())
14882 {
14883 return;
14884 }
14885
14886 ApiConnectRecordPtr ap;
14887 ap.i = recordNo;
14888 ptrAss(ap, apiConnectRecord);
14889 infoEvent("Dbtc::ApiConnectRecord[%d]: state=%d, abortState=%d, "
14890 "apiFailState=%d",
14891 ap.i,
14892 ap.p->apiConnectstate,
14893 ap.p->abortState,
14894 ap.p->apiFailState);
14895 infoEvent(" transid(0x%x, 0x%x), apiBref=0x%x, scanRec=%d",
14896 ap.p->transid[0],
14897 ap.p->transid[1],
14898 ap.p->ndbapiBlockref,
14899 ap.p->apiScanRec);
14900 infoEvent(" ctcTimer=%d, apiTimer=%d, counter=%d, retcode=%d, "
14901 "retsig=%d",
14902 ctcTimer, getApiConTimer(ap.i),
14903 ap.p->counter,
14904 ap.p->returncode,
14905 ap.p->returnsignal);
14906 infoEvent(" lqhkeyconfrec=%d, lqhkeyreqrec=%d, "
14907 "tckeyrec=%d",
14908 ap.p->lqhkeyconfrec,
14909 ap.p->lqhkeyreqrec,
14910 ap.p->tckeyrec);
14911 infoEvent(" next=%d, instance=%u, firstTc=%d ",
14912 ap.p->nextApiConnect,
14913 instance(),
14914 ap.p->firstTcConnect);
14915 return;
14916 }
14917
14918 if (dumpState->args[0] == DumpStateOrd::TcDumpApiConnectRecSummary)
14919 {
14920 /**
14921 * This DUMP command is used to print a summary of ApiConnect record
14922 * connected to API nodes.
14923 * The following use of it is allowed:
14924 * DUMP 2514 1
14925 * This will print a summary of all ApiConnect records in instance 1
14926 *
14927 * Output is to the node log.
14928 */
14929 jam();
14930 Uint32 apiNode = 1;
14931 Uint32 pos = 0;
14932
14933 Uint32 seized_count = 0; /* Number seized by an Api */
14934 Uint32 stateless_count = 0; /* Number 'started' with no ops */
14935 Uint32 stateful_count = 0; /* Number running */
14936 Uint32 scan_count = 0; /* Number used for scans */
14937 const Uint32 userVisibleConnectFilesize = capiConnectFilesize / 3;
14938
14939 if (signal->getLength() == 2)
14940 {
14941 if (instance() != dumpState->args[1])
14942 {
14943 return;
14944 }
14945 ndbout_c("Start of ApiConnectRec summary (%u total allocated)",
14946 userVisibleConnectFilesize);
14947 /*
14948 * total allocated = MaxNoOfConcurrentTransactions
14949 * total allocated = unseized + SUM_over_Api_nodes(seized)
14950 * unseized can be seized by any Api node
14951 * seized are 'owned' by a particular api node, can't be used
14952 * by others until they are manually released.
14953 * seized = seized_unused + stateless + stateful + scan
14954 * seized_unused are 'idle' connection objects owned by an
14955 * api node.
14956 * stateless are potentially idle connection objects, last
14957 * used in a TC-stateless operation (e.g. read committed)
14958 * stateful are in use, handling some transaction
14959 * scan are in use, handling a table or index scan
14960 */
14961 }
14962 else if (signal->getLength() == 7)
14963 {
14964 apiNode = dumpState->args[1];
14965 pos = dumpState->args[2];
14966 seized_count = dumpState->args[3];
14967 stateless_count = dumpState->args[4];
14968 stateful_count = dumpState->args[5];
14969 scan_count = dumpState->args[6];
14970 }
14971 else
14972 {
14973 return;
14974 }
14975
14976 if (apiNode == 0)
14977 return;
14978
14979 while (apiNode < MAX_NODES)
14980 {
14981 if (getNodeInfo(apiNode).getType() == NODE_TYPE_API &&
14982 getNodeInfo(apiNode).m_version != 0)
14983 {
14984 break;
14985 }
14986 apiNode ++;
14987 }
14988
14989 if (apiNode >= MAX_NODES)
14990 {
14991 ndbout_c("End of ApiConnectRec summary");
14992 return;
14993 }
14994
14995 Uint32 limit = MIN(pos + 16, userVisibleConnectFilesize);
14996
14997 while(pos < limit)
14998 {
14999 apiConnectptr.i = pos;
15000 ptrCheckGuard(apiConnectptr, capiConnectFilesize, apiConnectRecord);
15001 /* Following code mostly similar to that for NdbInfo transactions table */
15002 Uint32 conState = apiConnectptr.p->apiConnectstate;
15003
15004 if (conState == CS_ABORTING && apiConnectptr.p->abortState == AS_IDLE)
15005 {
15006 /**
15007 * These is for all practical purposes equal
15008 */
15009 conState = CS_CONNECTED;
15010 }
15011
15012 if ((refToNode(apiConnectptr.p->ndbapiBlockref) == apiNode) &&
15013 (conState != CS_DISCONNECTED))
15014 {
15015 seized_count++;
15016
15017 if (conState == CS_STARTED &&
15018 apiConnectptr.p->lqhkeyreqrec == 0)
15019 {
15020 stateless_count++;
15021 }
15022 else if (conState == CS_START_SCAN)
15023 {
15024 scan_count++;
15025 }
15026 else if (conState != CS_CONNECTED)
15027 {
15028 stateful_count++;
15029 }
15030 }
15031
15032 pos++;
15033 }
15034
15035 if (pos >= userVisibleConnectFilesize)
15036 {
15037 /* Finished with this apiNode, output info, if any */
15038 // if (seized_count > 0)
15039 {
15040 ndbout_c(" Api node %u connect records seized : %u stateless : %u stateful : %u scan : %u",
15041 apiNode, seized_count, stateless_count, stateful_count, scan_count);
15042 seized_count = 0;
15043 stateless_count = 0;
15044 stateful_count = 0;
15045 scan_count = 0;
15046 }
15047
15048 apiNode++;
15049 pos = 0;
15050 }
15051
15052 signal->theData[0] = DumpStateOrd::TcDumpApiConnectRecSummary;
15053 signal->theData[1] = apiNode;
15054 signal->theData[2] = pos;
15055 signal->theData[3] = seized_count;
15056 signal->theData[4] = stateless_count;
15057 signal->theData[5] = stateful_count;
15058 signal->theData[6] = scan_count;
15059
15060 sendSignal(reference(), GSN_DUMP_STATE_ORD, signal, 7, JBB);
15061 return;
15062 }
15063
15064 if (dumpState->args[0] == DumpStateOrd::TcSetTransactionTimeout){
15065 jam();
15066 if(signal->getLength() > 1){
15067 set_timeout_value(signal->theData[1]);
15068 }
15069 }
15070
15071 if (dumpState->args[0] == DumpStateOrd::TcSetApplTransactionTimeout){
15072 jam();
15073 if(signal->getLength() > 1){
15074 set_appl_timeout_value(signal->theData[1]);
15075 }
15076 }
15077
15078 if (dumpState->args[0] == DumpStateOrd::TcStartDumpIndexOpCount)
15079 {
15080 static int frequency = 1;
15081 if (signal->getLength() > 1)
15082 frequency = signal->theData[1];
15083 else
15084 if (refToBlock(signal->getSendersBlockRef()) != DBTC)
15085 frequency = 1;
15086
15087 if (frequency)
15088 {
15089 dumpState->args[0] = DumpStateOrd::TcDumpIndexOpCount;
15090 execDUMP_STATE_ORD(signal);
15091 dumpState->args[0] = DumpStateOrd::TcStartDumpIndexOpCount;
15092
15093 Uint32 delay = 1000 * (frequency > 25 ? 25 : frequency);
15094 sendSignalWithDelay(cownref, GSN_DUMP_STATE_ORD, signal, delay, 1);
15095 }
15096 }
15097
15098 if (dumpState->args[0] == DumpStateOrd::TcDumpIndexOpCount)
15099 {
15100 infoEvent("instance: %u, IndexOpCount: pool: %d free: %d",
15101 instance(),
15102 c_theIndexOperationPool.getSize(),
15103 c_theIndexOperationPool.getNoOfFree());
15104 return;
15105 }
15106
15107 if (arg == 2550)
15108 {
15109 jam();
15110 Uint32 len = signal->getLength() - 1;
15111 if (len + 2 > 25)
15112 {
15113 jam();
15114 infoEvent("Too long filter");
15115 return;
15116 }
15117 if (validate_filter(signal))
15118 {
15119 jam();
15120 memmove(signal->theData + 2, signal->theData + 1, 4 * len);
15121 signal->theData[0] = 2551;
15122 signal->theData[1] = 0; // record
15123 sendSignal(reference(), GSN_DUMP_STATE_ORD, signal, len + 2, JBB);
15124
15125 infoEvent("Starting dump of transactions");
15126 }
15127 return;
15128 }
15129
15130 if (arg == 2551)
15131 {
15132 jam();
15133 Uint32 record = signal->theData[1];
15134 Uint32 len = signal->getLength();
15135 ndbassert(len > 1);
15136
15137 ApiConnectRecordPtr ap;
15138 ap.i = record;
15139 ptrAss(ap, apiConnectRecord);
15140
15141 bool print = false;
15142 for (Uint32 i = 0; i<32; i++)
15143 {
15144 jam();
15145 print = match_and_print(signal, ap);
15146
15147 ap.i++;
15148 if (ap.i == capiConnectFilesize || print)
15149 {
15150 jam();
15151 break;
15152 }
15153
15154 ptrAss(ap, apiConnectRecord);
15155 }
15156
15157 if (ap.i == capiConnectFilesize)
15158 {
15159 jam();
15160 infoEvent("End of transaction dump");
15161 return;
15162 }
15163
15164 signal->theData[1] = ap.i;
15165 if (print)
15166 {
15167 jam();
15168 sendSignalWithDelay(reference(), GSN_DUMP_STATE_ORD, signal, 200, len);
15169 }
15170 else
15171 {
15172 jam();
15173 sendSignal(reference(), GSN_DUMP_STATE_ORD, signal, len, JBB);
15174 }
15175 return;
15176 }
15177 #ifdef ERROR_INSERT
15178 if (arg == 2552 || arg == 4002 || arg == 4003)
15179 {
15180 ndbrequire(m_commitAckMarkerPool.getNoOfFree() == m_commitAckMarkerPool.getSize());
15181 return;
15182 }
15183 #endif
15184
15185 if (arg == DumpStateOrd::DihTcSumaNodeFailCompleted &&
15186 signal->getLength() == 2)
15187 {
15188 jam();
15189 NodeId nodeId = signal->theData[1];
15190 if (nodeId < MAX_NODES && nodeId < NDB_ARRAY_SIZE(capiConnectClosing))
15191 {
15192 warningEvent(" DBTC: capiConnectClosing[%u]: %u",
15193 nodeId, capiConnectClosing[nodeId]);
15194 }
15195 else
15196 {
15197 warningEvent(" DBTC: dump-%u to unknown node: %u", arg, nodeId);
15198 }
15199 }
15200
15201 if (arg == DumpStateOrd::TcResourceSnapshot)
15202 {
15203 RSS_OP_SNAPSHOT_SAVE(cConcScanCount);
15204 RSS_AP_SNAPSHOT_SAVE(c_scan_frag_pool);
15205 RSS_AP_SNAPSHOT_SAVE(c_theDefinedTriggerPool);
15206 RSS_AP_SNAPSHOT_SAVE(c_theFiredTriggerPool);
15207 RSS_AP_SNAPSHOT_SAVE(c_theIndexPool);
15208 RSS_AP_SNAPSHOT_SAVE(m_commitAckMarkerPool);
15209 RSS_AP_SNAPSHOT_SAVE(c_theIndexOperationPool);
15210 #ifdef ERROR_INSERT
15211 rss_cconcurrentOp = c_counters.cconcurrentOp;
15212 #endif
15213 }
15214 if (arg == DumpStateOrd::TcResourceCheckLeak)
15215 {
15216 RSS_OP_SNAPSHOT_CHECK(cConcScanCount);
15217 RSS_AP_SNAPSHOT_CHECK(c_scan_frag_pool);
15218 RSS_AP_SNAPSHOT_CHECK(c_theDefinedTriggerPool);
15219 RSS_AP_SNAPSHOT_CHECK(c_theFiredTriggerPool);
15220 RSS_AP_SNAPSHOT_CHECK(c_theIndexPool);
15221 RSS_AP_SNAPSHOT_CHECK(m_commitAckMarkerPool);
15222 RSS_AP_SNAPSHOT_CHECK(c_theIndexOperationPool);
15223 #ifdef ERROR_INSERT
15224 ndbrequire(rss_cconcurrentOp == c_counters.cconcurrentOp);
15225 #endif
15226 }
15227
15228 if (arg == DumpStateOrd::TcDumpPoolLevels)
15229 {
15230 /**
15231 * DUMP 2555 1
15232 * Prints pool levels for instance 1 to cluster log
15233 */
15234 if (signal->getLength() == 2)
15235 {
15236 if (signal->theData[1] != instance())
15237 {
15238 return;
15239 }
15240 infoEvent("TC: instance: %u, Print pool levels", instance());
15241 signal->theData[4] = signal->theData[1];
15242 signal->theData[1] = 1;
15243 signal->theData[2] = 0;
15244 signal->theData[3] = 0;
15245 sendSignal(reference(), GSN_DUMP_STATE_ORD, signal, 5, JBB);
15246 return;
15247 }
15248 if (signal->getLength() != 5)
15249 {
15250 ndbout_c("DUMP TcDumpPoolLevels : Bad signal length : %u", signal->getLength());
15251 return;
15252 }
15253 if (signal->theData[4] != instance())
15254 {
15255 return;
15256 }
15257
15258 Uint32 resource = signal->theData[1];
15259 Uint32 position = signal->theData[2];
15260 Uint32 sum = signal->theData[3];
15261 /* const Uint32 MAX_ITER = 200; */
15262
15263 switch(resource)
15264 {
15265 case 1:
15266 infoEvent("TC : Concurrent operations in use/total : %u/%u (%u bytes each)",
15267 c_counters.cconcurrentOp,
15268 ctcConnectFilesize,
15269 (Uint32) sizeof(TcConnectRecord));
15270 resource++;
15271 position = 0;
15272 sum = 0;
15273 break;
15274 case 2:
15275 infoEvent("TC : Concurrent scans in use/total : %u/%u (%u bytes each)",
15276 cConcScanCount,
15277 cscanrecFileSize,
15278 (Uint32) sizeof(ScanRecord));
15279 resource++;
15280 position = 0;
15281 sum = 0;
15282 break;
15283 case 3:
15284 infoEvent("TC : Scan Frag records in use/total : %u/%u (%u bytes each)",
15285 c_scan_frag_pool.getSize() -
15286 c_scan_frag_pool.getNoOfFree(),
15287 c_scan_frag_pool.getSize(),
15288 (Uint32) sizeof(ScanFragRec));
15289 resource++;
15290 position = 0;
15291 sum = 0;
15292 break;
15293 default:
15294 return;
15295 }
15296
15297 signal->theData[0] = DumpStateOrd::TcDumpPoolLevels;
15298 signal->theData[1] = resource;
15299 signal->theData[2] = position;
15300 signal->theData[3] = sum;
15301 signal->theData[4] = instance();
15302 sendSignal(reference(), GSN_DUMP_STATE_ORD, signal, 5, JBB);
15303 return;
15304 }
15305 }//Dbtc::execDUMP_STATE_ORD()
15306
execDBINFO_SCANREQ(Signal * signal)15307 void Dbtc::execDBINFO_SCANREQ(Signal *signal)
15308 {
15309 DbinfoScanReq req= *(DbinfoScanReq*)signal->theData;
15310 const Ndbinfo::ScanCursor* cursor =
15311 CAST_CONSTPTR(Ndbinfo::ScanCursor, DbinfoScan::getCursorPtr(&req));
15312 Ndbinfo::Ratelimit rl;
15313
15314 jamEntry();
15315
15316 switch(req.tableId){
15317 case Ndbinfo::POOLS_TABLEID:
15318 {
15319 Ndbinfo::pool_entry pools[] =
15320 {
15321 { "Defined Trigger",
15322 c_theDefinedTriggerPool.getUsed(),
15323 c_theDefinedTriggerPool.getSize(),
15324 c_theDefinedTriggerPool.getEntrySize(),
15325 c_theDefinedTriggerPool.getUsedHi(),
15326 { CFG_DB_NO_TRIGGERS,0,0,0 }},
15327 { "Fired Trigger",
15328 c_theFiredTriggerPool.getUsed(),
15329 c_theFiredTriggerPool.getSize(),
15330 c_theFiredTriggerPool.getEntrySize(),
15331 c_theFiredTriggerPool.getUsedHi(),
15332 { CFG_DB_NO_TRIGGER_OPS,0,0,0 }},
15333 { "Index",
15334 c_theIndexPool.getUsed(),
15335 c_theIndexPool.getSize(),
15336 c_theIndexPool.getEntrySize(),
15337 c_theIndexPool.getUsedHi(),
15338 { CFG_DB_NO_TABLES,
15339 CFG_DB_NO_ORDERED_INDEXES,
15340 CFG_DB_NO_UNIQUE_HASH_INDEXES,0 }},
15341 { "Scan Fragment",
15342 c_scan_frag_pool.getUsed(),
15343 c_scan_frag_pool.getSize(),
15344 c_scan_frag_pool.getEntrySize(),
15345 c_scan_frag_pool.getUsedHi(),
15346 { CFG_DB_NO_LOCAL_SCANS,0,0,0 }},
15347 { "Commit ACK Marker",
15348 m_commitAckMarkerPool.getUsed(),
15349 m_commitAckMarkerPool.getSize(),
15350 m_commitAckMarkerPool.getEntrySize(),
15351 m_commitAckMarkerPool.getUsedHi(),
15352 { CFG_DB_NO_TRANSACTIONS,0,0,0 }},
15353 { "Index Op",
15354 c_theIndexOperationPool.getUsed(),
15355 c_theIndexOperationPool.getSize(),
15356 c_theIndexOperationPool.getEntrySize(),
15357 c_theIndexOperationPool.getUsedHi(),
15358 { CFG_DB_NO_INDEX_OPS,0,0,0 }},
15359 { "Operations",
15360 c_counters.cconcurrentOp,
15361 ctcConnectFilesize,
15362 sizeof(TcConnectRecord),
15363 0,
15364 { CFG_DB_NO_TRANSACTIONS,
15365 CFG_DB_NO_OPS,0,0 }},
15366 { "TC Scan Record", /* TC redundantly included to improve readability */
15367 cConcScanCount,
15368 cscanrecFileSize,
15369 sizeof(ScanRecord),
15370 0, /* No HWM */
15371 {CFG_DB_NO_SCANS, 0, 0, 0}},
15372 { NULL, 0,0,0,0,{0,0,0,0} }
15373 };
15374
15375 const size_t num_config_params =
15376 sizeof(pools[0].config_params) / sizeof(pools[0].config_params[0]);
15377 Uint32 pool = cursor->data[0];
15378 BlockNumber bn = blockToMain(number());
15379 while(pools[pool].poolname)
15380 {
15381 jam();
15382 Ndbinfo::Row row(signal, req);
15383 row.write_uint32(getOwnNodeId());
15384 row.write_uint32(bn); // block number
15385 row.write_uint32(instance()); // block instance
15386 row.write_string(pools[pool].poolname);
15387
15388 row.write_uint64(pools[pool].used);
15389 row.write_uint64(pools[pool].total);
15390 row.write_uint64(pools[pool].used_hi);
15391 row.write_uint64(pools[pool].entry_size);
15392 for (size_t i = 0; i < num_config_params; i++)
15393 row.write_uint32(pools[pool].config_params[i]);
15394 ndbinfo_send_row(signal, req, row, rl);
15395 pool++;
15396 if (rl.need_break(req))
15397 {
15398 jam();
15399 ndbinfo_send_scan_break(signal, req, rl, pool);
15400 return;
15401 }
15402 }
15403 break;
15404 }
15405
15406 case Ndbinfo::COUNTERS_TABLEID:
15407 {
15408 Ndbinfo::counter_entry counters[] = {
15409 { Ndbinfo::ATTRINFO_COUNTER, c_counters.cattrinfoCount },
15410 { Ndbinfo::TRANSACTIONS_COUNTER, c_counters.ctransCount },
15411 { Ndbinfo::COMMITS_COUNTER, c_counters.ccommitCount },
15412 { Ndbinfo::READS_COUNTER, c_counters.creadCount },
15413 { Ndbinfo::SIMPLE_READS_COUNTER, c_counters.csimpleReadCount },
15414 { Ndbinfo::WRITES_COUNTER, c_counters.cwriteCount },
15415 { Ndbinfo::ABORTS_COUNTER, c_counters.cabortCount },
15416 { Ndbinfo::TABLE_SCANS_COUNTER, c_counters.c_scan_count },
15417 { Ndbinfo::RANGE_SCANS_COUNTER, c_counters.c_range_scan_count },
15418 { Ndbinfo::LOCAL_READ_COUNTER, c_counters.clocalReadCount },
15419 { Ndbinfo::LOCAL_WRITE_COUNTER, c_counters.clocalWriteCount }
15420 };
15421 const size_t num_counters = sizeof(counters) / sizeof(counters[0]);
15422
15423 Uint32 i = cursor->data[0];
15424 BlockNumber bn = blockToMain(number());
15425 while(i < num_counters)
15426 {
15427 jam();
15428 Ndbinfo::Row row(signal, req);
15429 row.write_uint32(getOwnNodeId());
15430 row.write_uint32(bn); // block number
15431 row.write_uint32(instance()); // block instance
15432 row.write_uint32(counters[i].id);
15433
15434 row.write_uint64(counters[i].val);
15435 ndbinfo_send_row(signal, req, row, rl);
15436 i++;
15437 if (rl.need_break(req))
15438 {
15439 jam();
15440 ndbinfo_send_scan_break(signal, req, rl, i);
15441 return;
15442 }
15443 }
15444
15445 break;
15446 }
15447 case Ndbinfo::TRANSACTIONS_TABLEID:{
15448 ApiConnectRecordPtr ptr;
15449 ptr.i = cursor->data[0];
15450 const Uint32 maxloop = 256;
15451 for (Uint32 i = 0; i < maxloop; i++)
15452 {
15453 ptrCheckGuard(ptr, capiConnectFilesize, apiConnectRecord);
15454 Ndbinfo::Row row(signal, req);
15455 if (ndbinfo_write_trans(row, ptr))
15456 {
15457 jam();
15458 ndbinfo_send_row(signal, req, row, rl);
15459 }
15460
15461 ptr.i ++;
15462 if (ptr.i == capiConnectFilesize)
15463 {
15464 goto done;
15465 }
15466 else if (rl.need_break(req))
15467 {
15468 break;
15469 }
15470 }
15471 ndbinfo_send_scan_break(signal, req, rl, ptr.i);
15472 return;
15473 }
15474 default:
15475 break;
15476 }
15477
15478 done:
15479 ndbinfo_send_scan_conf(signal, req, rl);
15480 }
15481
15482 bool
ndbinfo_write_trans(Ndbinfo::Row & row,ApiConnectRecordPtr transPtr)15483 Dbtc::ndbinfo_write_trans(Ndbinfo::Row & row, ApiConnectRecordPtr transPtr)
15484 {
15485 Uint32 conState = transPtr.p->apiConnectstate;
15486
15487 if (conState == CS_ABORTING && transPtr.p->abortState == AS_IDLE)
15488 {
15489 /**
15490 * These is for all practical purposes equal
15491 */
15492 conState = CS_CONNECTED;
15493 }
15494
15495 if (conState == CS_CONNECTED ||
15496 conState == CS_DISCONNECTED ||
15497 conState == CS_RESTART)
15498 {
15499 return false;
15500 }
15501
15502 row.write_uint32(getOwnNodeId());
15503 row.write_uint32(instance()); // block instance
15504 row.write_uint32(transPtr.i);
15505 row.write_uint32(transPtr.p->ndbapiBlockref);
15506 row.write_uint32(transPtr.p->transid[0]);
15507 row.write_uint32(transPtr.p->transid[1]);
15508 row.write_uint32(conState);
15509 row.write_uint32(transPtr.p->m_flags);
15510 row.write_uint32(transPtr.p->lqhkeyreqrec);
15511 Uint32 outstanding = 0;
15512 switch((ConnectionState)conState) {
15513 case CS_CONNECTED:
15514 case CS_DISCONNECTED:
15515 break;
15516 case CS_STARTED:
15517 case CS_RECEIVING:
15518 case CS_REC_COMMITTING:
15519 case CS_START_COMMITTING:
15520 case CS_SEND_FIRE_TRIG_REQ:
15521 case CS_WAIT_FIRE_TRIG_REQ:
15522 outstanding = transPtr.p->lqhkeyreqrec - transPtr.p->lqhkeyconfrec;
15523 break;
15524 case CS_COMMITTING:
15525 case CS_COMPLETING:
15526 case CS_COMMIT_SENT:
15527 case CS_COMPLETE_SENT:
15528 case CS_ABORTING:
15529 outstanding = transPtr.p->counter;
15530 break;
15531 case CS_PREPARE_TO_COMMIT:
15532 break;
15533 case CS_START_SCAN:
15534 // TODO
15535 break;
15536 case CS_WAIT_ABORT_CONF:
15537 case CS_WAIT_COMMIT_CONF:
15538 case CS_WAIT_COMPLETE_CONF:
15539 // not easily computed :-(
15540 break;
15541 case CS_FAIL_PREPARED:
15542 case CS_FAIL_ABORTED:
15543 // we're assembling a state...
15544 break;
15545 case CS_FAIL_COMMITTING:
15546 case CS_FAIL_COMMITTED:
15547 case CS_FAIL_ABORTING:
15548 case CS_FAIL_COMPLETED:
15549 // not easily computed :_(
15550 break;
15551 case CS_RESTART:
15552 break;
15553 }
15554
15555 row.write_uint32(outstanding);
15556
15557 Uint32 apiTimer = getApiConTimer(transPtr.i);
15558 row.write_uint32(apiTimer ? (ctcTimer - apiTimer) / 100 : 0);
15559 return true;
15560 }
15561
15562 bool
validate_filter(Signal * signal)15563 Dbtc::validate_filter(Signal* signal)
15564 {
15565 Uint32 * start = signal->theData + 1;
15566 Uint32 * end = signal->theData + signal->getLength();
15567 if (start == end)
15568 {
15569 infoEvent("No filter specified, not listing...");
15570 return false;
15571 }
15572
15573 while(start < end)
15574 {
15575 switch(* start){
15576 case 1: // API Node
15577 case 4: // Inactive time
15578 start += 2;
15579 break;
15580 case 2: // Transid
15581 start += 3;
15582 break;
15583 default:
15584 infoEvent("Invalid filter op: 0x%x pos: %ld",
15585 * start,
15586 (long int)(start - (signal->theData + 1)));
15587 return false;
15588 }
15589 }
15590
15591 if (start != end)
15592 {
15593 infoEvent("Invalid filter, unexpected end");
15594 return false;
15595 }
15596
15597 return true;
15598 }
15599
15600 bool
match_and_print(Signal * signal,ApiConnectRecordPtr apiPtr)15601 Dbtc::match_and_print(Signal* signal, ApiConnectRecordPtr apiPtr)
15602 {
15603 Uint32 conState = apiPtr.p->apiConnectstate;
15604 if (conState == CS_CONNECTED ||
15605 conState == CS_DISCONNECTED ||
15606 conState == CS_RESTART)
15607 return false;
15608
15609 Uint32 len = signal->getLength();
15610 Uint32* start = signal->theData + 2;
15611 Uint32* end = signal->theData + len;
15612 Uint32 apiTimer = getApiConTimer(apiPtr.i);
15613 while (start < end)
15614 {
15615 jam();
15616 switch(* start){
15617 case 1:
15618 jam();
15619 if (refToNode(apiPtr.p->ndbapiBlockref) != * (start + 1))
15620 return false;
15621 start += 2;
15622 break;
15623 case 2:
15624 jam();
15625 if (apiPtr.p->transid[0] != * (start + 1) ||
15626 apiPtr.p->transid[1] != * (start + 2))
15627 return false;
15628 start += 3;
15629 break;
15630 case 4:{
15631 jam();
15632 if (apiTimer == 0 || ((ctcTimer - apiTimer) / 100) < * (start + 1))
15633 return false;
15634 start += 2;
15635 break;
15636 }
15637 default:
15638 ndbassert(false);
15639 return false;
15640 }
15641 }
15642
15643 if (start != end)
15644 {
15645 ndbassert(false);
15646 return false;
15647 }
15648
15649 /**
15650 * Do print
15651 */
15652 Uint32 *temp = signal->theData + 25;
15653 memcpy(temp, signal->theData, 4 * len);
15654
15655 char state[10];
15656 const char *stateptr = "";
15657
15658 switch(apiPtr.p->apiConnectstate){
15659 case CS_STARTED:
15660 stateptr = "Prepared";
15661 break;
15662 case CS_RECEIVING:
15663 case CS_REC_COMMITTING:
15664 case CS_START_COMMITTING:
15665 stateptr = "Running";
15666 break;
15667 case CS_COMMITTING:
15668 stateptr = "Committing";
15669 break;
15670 case CS_COMPLETING:
15671 stateptr = "Completing";
15672 break;
15673 case CS_PREPARE_TO_COMMIT:
15674 stateptr = "Prepare to commit";
15675 break;
15676 case CS_COMMIT_SENT:
15677 stateptr = "Commit sent";
15678 break;
15679 case CS_COMPLETE_SENT:
15680 stateptr = "Complete sent";
15681 break;
15682 case CS_ABORTING:
15683 stateptr = "Aborting";
15684 break;
15685 case CS_START_SCAN:
15686 stateptr = "Scanning";
15687 break;
15688 case CS_WAIT_ABORT_CONF:
15689 case CS_WAIT_COMMIT_CONF:
15690 case CS_WAIT_COMPLETE_CONF:
15691 case CS_FAIL_PREPARED:
15692 case CS_FAIL_COMMITTING:
15693 case CS_FAIL_COMMITTED:
15694 case CS_RESTART:
15695 case CS_FAIL_ABORTED:
15696 case CS_DISCONNECTED:
15697 default:
15698 BaseString::snprintf(state, sizeof(state),
15699 "%u", apiPtr.p->apiConnectstate);
15700 stateptr = state;
15701 break;
15702 }
15703
15704 char buf[100];
15705 BaseString::snprintf(buf, sizeof(buf),
15706 "TRX[%u]: API: %d(0x%x)"
15707 "transid: 0x%x 0x%x inactive: %u(%d) state: %s",
15708 apiPtr.i,
15709 refToNode(apiPtr.p->ndbapiBlockref),
15710 refToBlock(apiPtr.p->ndbapiBlockref),
15711 apiPtr.p->transid[0],
15712 apiPtr.p->transid[1],
15713 apiTimer ? (ctcTimer - apiTimer) / 100 : 0,
15714 c_apiConTimer_line[apiPtr.i],
15715 stateptr);
15716 infoEvent("%s", buf);
15717
15718 memcpy(signal->theData, temp, 4*len);
15719 return true;
15720 }
15721
execABORT_ALL_REQ(Signal * signal)15722 void Dbtc::execABORT_ALL_REQ(Signal* signal)
15723 {
15724 jamEntry();
15725 AbortAllReq * req = (AbortAllReq*)&signal->theData[0];
15726 AbortAllRef * ref = (AbortAllRef*)&signal->theData[0];
15727
15728 const Uint32 senderData = req->senderData;
15729 const BlockReference senderRef = req->senderRef;
15730
15731 if(getAllowStartTransaction(refToNode(senderRef), 0) == true && !getNodeState().getSingleUserMode()){
15732 jam();
15733
15734 ref->senderData = senderData;
15735 ref->errorCode = AbortAllRef::InvalidState;
15736 sendSignal(senderRef, GSN_ABORT_ALL_REF, signal,
15737 AbortAllRef::SignalLength, JBB);
15738 return;
15739 }
15740
15741 if(c_abortRec.clientRef != 0){
15742 jam();
15743
15744 ref->senderData = senderData;
15745 ref->errorCode = AbortAllRef::AbortAlreadyInProgress;
15746 sendSignal(senderRef, GSN_ABORT_ALL_REF, signal,
15747 AbortAllRef::SignalLength, JBB);
15748 return;
15749 }
15750
15751 if(refToNode(senderRef) != getOwnNodeId()){
15752 jam();
15753
15754 ref->senderData = senderData;
15755 ref->errorCode = AbortAllRef::FunctionNotImplemented;
15756 sendSignal(senderRef, GSN_ABORT_ALL_REF, signal,
15757 AbortAllRef::SignalLength, JBB);
15758 return;
15759 }
15760
15761 c_abortRec.clientRef = senderRef;
15762 c_abortRec.clientData = senderData;
15763 c_abortRec.oldTimeOutValue = ctimeOutValue;
15764
15765 ctimeOutValue = 0;
15766 const Uint32 sleepTime = (2 * 10 * ctimeOutCheckDelay + 199) / 200;
15767
15768 checkAbortAllTimeout(signal, (sleepTime == 0 ? 1 : sleepTime));
15769 }
15770
checkAbortAllTimeout(Signal * signal,Uint32 sleepTime)15771 void Dbtc::checkAbortAllTimeout(Signal* signal, Uint32 sleepTime)
15772 {
15773
15774 ndbrequire(c_abortRec.clientRef != 0);
15775
15776 if(sleepTime > 0){
15777 jam();
15778
15779 sleepTime -= 1;
15780 signal->theData[0] = TcContinueB::ZWAIT_ABORT_ALL;
15781 signal->theData[1] = sleepTime;
15782 sendSignalWithDelay(reference(), GSN_CONTINUEB, signal, 200, 2);
15783 return;
15784 }
15785
15786 AbortAllConf * conf = (AbortAllConf*)&signal->theData[0];
15787 conf->senderData = c_abortRec.clientData;
15788 sendSignal(c_abortRec.clientRef, GSN_ABORT_ALL_CONF, signal,
15789 AbortAllConf::SignalLength, JBB);
15790
15791 ctimeOutValue = c_abortRec.oldTimeOutValue;
15792 c_abortRec.clientRef = 0;
15793 }
15794
15795 /* **************************************************************** */
15796 /* ---------------------------------------------------------------- */
15797 /* ------------------ TRIGGER AND INDEX HANDLING ------------------ */
15798 /* ---------------------------------------------------------------- */
15799 /* **************************************************************** */
15800
execCREATE_TRIG_IMPL_REQ(Signal * signal)15801 void Dbtc::execCREATE_TRIG_IMPL_REQ(Signal* signal)
15802 {
15803 jamEntry();
15804 if (!assembleFragments(signal))
15805 {
15806 jam();
15807 return;
15808 }
15809
15810 const CreateTrigImplReq* req = (const CreateTrigImplReq*)signal->getDataPtr();
15811 const Uint32 senderRef = req->senderRef;
15812 const Uint32 senderData = req->senderData;
15813
15814 SectionHandle handle(this, signal);
15815 releaseSections(handle); // Not using mask
15816
15817 TcDefinedTriggerData* triggerData;
15818 DefinedTriggerPtr triggerPtr;
15819
15820 triggerPtr.i = req->triggerId;
15821 if (ERROR_INSERTED(8033) ||
15822 !c_theDefinedTriggers.getPool().seizeId(triggerPtr, req->triggerId)) {
15823 jam();
15824 CLEAR_ERROR_INSERT_VALUE;
15825 // Failed to allocate trigger record
15826 ref:
15827 CreateTrigImplRef* ref = (CreateTrigImplRef*)signal->getDataPtrSend();
15828
15829 ref->senderRef = reference();
15830 ref->senderData = senderData;
15831 ref->errorCode = CreateTrigImplRef::InconsistentTC;
15832 ref->errorLine = __LINE__;
15833 sendSignal(senderRef, GSN_CREATE_TRIG_IMPL_REF,
15834 signal, CreateTrigImplRef::SignalLength, JBB);
15835 return;
15836 }
15837 c_theDefinedTriggers.addFirst(triggerPtr);
15838
15839 triggerData = triggerPtr.p;
15840 triggerData->triggerId = req->triggerId;
15841 triggerData->triggerType = TriggerInfo::getTriggerType(req->triggerInfo);
15842 triggerData->triggerEvent = TriggerInfo::getTriggerEvent(req->triggerInfo);
15843 triggerData->oldTriggerIds[0] = RNIL;
15844 triggerData->oldTriggerIds[1] = RNIL;
15845 triggerData->refCount = 0;
15846
15847 switch(triggerData->triggerType){
15848 case TriggerType::SECONDARY_INDEX:
15849 jam();
15850 triggerData->indexId = req->indexId;
15851 break;
15852 case TriggerType::REORG_TRIGGER:
15853 jam();
15854 triggerData->tableId = req->tableId;
15855 break;
15856 case TriggerType::FK_PARENT:
15857 case TriggerType::FK_CHILD:
15858 triggerData->fkId = req->indexId;
15859 break;
15860 default:
15861 c_theDefinedTriggers.release(triggerPtr);
15862 goto ref;
15863 }
15864
15865 if (unlikely(req->triggerId != req->upgradeExtra[1]))
15866 {
15867 /**
15868 * This is nasty upgrade for unique indexes
15869 */
15870 jam();
15871 ndbrequire(req->triggerId == req->upgradeExtra[0]);
15872 ndbrequire(triggerData->triggerType == TriggerType::SECONDARY_INDEX);
15873
15874 DefinedTriggerPtr insertPtr = triggerPtr;
15875 DefinedTriggerPtr updatePtr;
15876 DefinedTriggerPtr deletePtr;
15877 if (c_theDefinedTriggers.getPool().seizeId(updatePtr, req->upgradeExtra[1]) == false)
15878 {
15879 jam();
15880 c_theDefinedTriggers.release(insertPtr);
15881 goto ref;
15882 }
15883 c_theDefinedTriggers.addFirst(updatePtr);
15884
15885 if (c_theDefinedTriggers.getPool().seizeId(deletePtr, req->upgradeExtra[2]) == false)
15886 {
15887 jam();
15888 c_theDefinedTriggers.release(insertPtr);
15889 c_theDefinedTriggers.release(updatePtr);
15890 goto ref;
15891 }
15892 c_theDefinedTriggers.addFirst(deletePtr);
15893
15894 insertPtr.p->triggerEvent = TriggerEvent::TE_INSERT;
15895
15896 updatePtr.p->triggerId = req->upgradeExtra[1];
15897 updatePtr.p->triggerType = TriggerType::SECONDARY_INDEX;
15898 updatePtr.p->triggerEvent = TriggerEvent::TE_UPDATE;
15899 updatePtr.p->oldTriggerIds[0] = RNIL;
15900 updatePtr.p->oldTriggerIds[1] = RNIL;
15901 updatePtr.p->indexId = req->indexId;
15902 updatePtr.p->refCount = 0;
15903
15904 deletePtr.p->triggerId = req->upgradeExtra[2];
15905 deletePtr.p->triggerType = TriggerType::SECONDARY_INDEX;
15906 deletePtr.p->triggerEvent = TriggerEvent::TE_DELETE;
15907 deletePtr.p->oldTriggerIds[0] = RNIL;
15908 deletePtr.p->oldTriggerIds[1] = RNIL;
15909 deletePtr.p->indexId = req->indexId;
15910 deletePtr.p->refCount = 0;
15911 }
15912
15913 CreateTrigImplConf* conf = (CreateTrigImplConf*)signal->getDataPtrSend();
15914 conf->senderRef = reference();
15915 conf->senderData = senderData;
15916 sendSignal(senderRef, GSN_CREATE_TRIG_IMPL_CONF,
15917 signal, CreateTrigImplConf::SignalLength, JBB);
15918 }
15919
execDROP_TRIG_IMPL_REQ(Signal * signal)15920 void Dbtc::execDROP_TRIG_IMPL_REQ(Signal* signal)
15921 {
15922 jamEntry();
15923 const DropTrigImplReq* req = (const DropTrigImplReq*)signal->getDataPtr();
15924 const Uint32 senderRef = req->senderRef;
15925 const Uint32 senderData = req->senderData;
15926
15927 DefinedTriggerPtr triggerPtr;
15928 triggerPtr.i = req->triggerId;
15929
15930 if (ERROR_INSERTED(8035) ||
15931 ((triggerPtr.p = c_theDefinedTriggers.getPtr(req->triggerId)) == NULL))
15932 {
15933 jam();
15934 CLEAR_ERROR_INSERT_VALUE;
15935 // Failed to find find trigger record
15936 DropTrigImplRef* ref = (DropTrigImplRef*)signal->getDataPtrSend();
15937
15938 ref->senderRef = reference();
15939 ref->senderData = senderData;
15940 ref->errorCode = DropTrigImplRef::InconsistentTC;
15941 ref->errorLine = __LINE__;
15942 sendSignal(senderRef, GSN_DROP_TRIG_IMPL_REF,
15943 signal, DropTrigImplRef::SignalLength, JBB);
15944 return;
15945 }
15946
15947 if (triggerPtr.p->refCount > 0)
15948 {
15949 jam();
15950 sendSignalWithDelay(reference(), GSN_DROP_TRIG_IMPL_REQ,
15951 signal, 100, signal->getLength());
15952 return;
15953 }
15954
15955 if (unlikely(triggerPtr.p->oldTriggerIds[0] != RNIL))
15956 {
15957 jam();
15958
15959 const Uint32 * oldId = triggerPtr.p->oldTriggerIds;
15960 if (c_theDefinedTriggers.getPtr(oldId[0])->refCount > 0 ||
15961 c_theDefinedTriggers.getPtr(oldId[1])->refCount > 0)
15962 {
15963 jam();
15964 sendSignalWithDelay(reference(), GSN_DROP_TRIG_IMPL_REQ,
15965 signal, 100, signal->getLength());
15966 return;
15967 }
15968
15969 c_theDefinedTriggers.release(triggerPtr.p->oldTriggerIds[0]);
15970 c_theDefinedTriggers.release(triggerPtr.p->oldTriggerIds[1]);
15971 }
15972
15973 // Release trigger record
15974 c_theDefinedTriggers.release(triggerPtr);
15975
15976 DropTrigImplConf* conf = (DropTrigImplConf*)signal->getDataPtrSend();
15977
15978 conf->senderRef = reference();
15979 conf->senderData = senderData;
15980
15981 sendSignal(senderRef, GSN_DROP_TRIG_IMPL_CONF,
15982 signal, DropTrigImplConf::SignalLength, JBB);
15983 }
15984
execCREATE_INDX_IMPL_REQ(Signal * signal)15985 void Dbtc::execCREATE_INDX_IMPL_REQ(Signal* signal)
15986 {
15987 jamEntry();
15988 const CreateIndxImplReq * const req =
15989 (const CreateIndxImplReq *)signal->getDataPtr();
15990 const Uint32 senderRef = req->senderRef;
15991 const Uint32 senderData = req->senderData;
15992 TcIndexData* indexData;
15993 TcIndexDataPtr indexPtr;
15994
15995 SectionHandle handle(this, signal);
15996 if (ERROR_INSERTED(8034) ||
15997 !c_theIndexes.getPool().seizeId(indexPtr, req->indexId)) {
15998 jam();
15999 CLEAR_ERROR_INSERT_VALUE;
16000 // Failed to allocate index record
16001 CreateIndxImplRef * const ref =
16002 (CreateIndxImplRef *)signal->getDataPtrSend();
16003
16004 ref->senderRef = reference();
16005 ref->senderData = senderData;
16006 ref->errorCode = CreateIndxImplRef::InconsistentTC;
16007 ref->errorLine = __LINE__;
16008 releaseSections(handle);
16009 sendSignal(senderRef, GSN_CREATE_INDX_IMPL_REF,
16010 signal, CreateIndxImplRef::SignalLength, JBB);
16011 return;
16012 }
16013 c_theIndexes.addFirst(indexPtr);
16014 indexData = indexPtr.p;
16015 // Indexes always start in state IS_BUILDING
16016 // Will become IS_ONLINE in execALTER_INDX_IMPL_REQ
16017 indexData->indexState = IS_BUILDING;
16018 indexData->indexId = indexPtr.i;
16019 indexData->primaryTableId = req->tableId;
16020
16021 // So far need only attribute count
16022 SegmentedSectionPtr ssPtr;
16023 handle.getSection(ssPtr, CreateIndxReq::ATTRIBUTE_LIST_SECTION);
16024 SimplePropertiesSectionReader r0(ssPtr, getSectionSegmentPool());
16025 r0.reset(); // undo implicit first()
16026 if (!r0.getWord(&indexData->attributeList.sz) ||
16027 !r0.getWords(indexData->attributeList.id, indexData->attributeList.sz)) {
16028 ndbrequire(false);
16029 }
16030 indexData->primaryKeyPos = indexData->attributeList.sz;
16031
16032 releaseSections(handle);
16033
16034 CreateIndxImplConf * const conf =
16035 (CreateIndxImplConf *)signal->getDataPtrSend();
16036
16037 conf->senderRef = reference();
16038 conf->senderData = senderData;
16039 sendSignal(senderRef, GSN_CREATE_INDX_IMPL_CONF,
16040 signal, CreateIndxImplConf::SignalLength, JBB);
16041 }
16042
execALTER_INDX_IMPL_REQ(Signal * signal)16043 void Dbtc::execALTER_INDX_IMPL_REQ(Signal* signal)
16044 {
16045 jamEntry();
16046 const AlterIndxImplReq * const req =
16047 (const AlterIndxImplReq *)signal->getDataPtr();
16048 const Uint32 senderRef = req->senderRef;
16049 const Uint32 senderData = req->senderData;
16050 TcIndexData* indexData;
16051 const Uint32 requestType = req->requestType;
16052 const Uint32 indexId = req->indexId;
16053
16054 if ((indexData = c_theIndexes.getPtr(indexId)) == NULL) {
16055 jam();
16056 // Failed to find index record
16057 AlterIndxImplRef * const ref =
16058 (AlterIndxImplRef *)signal->getDataPtrSend();
16059
16060 ref->senderRef = reference();
16061 ref->senderData = senderData;
16062 ref->errorCode = AlterIndxImplRef::InconsistentTC;
16063 ref->errorLine = __LINE__;
16064
16065 sendSignal(senderRef, GSN_ALTER_INDX_IMPL_REF,
16066 signal, AlterIndxImplRef::SignalLength, JBB);
16067 return;
16068 }
16069 // Found index record, alter it's state
16070 switch (requestType) {
16071 case AlterIndxImplReq::AlterIndexOnline:
16072 jam();
16073 indexData->indexState = IS_ONLINE;
16074 break;
16075 case AlterIndxImplReq::AlterIndexOffline:
16076 jam();
16077 indexData->indexState = IS_BUILDING; // wl3600_todo ??
16078 break;
16079 default:
16080 ndbrequire(false);
16081 break;
16082 }
16083 AlterIndxImplConf * const conf =
16084 (AlterIndxImplConf *)signal->getDataPtrSend();
16085
16086 conf->senderRef = reference();
16087 conf->senderData = senderData;
16088 sendSignal(senderRef, GSN_ALTER_INDX_IMPL_CONF,
16089 signal, AlterIndxImplConf::SignalLength, JBB);
16090 }
16091
16092 void
execCREATE_FK_IMPL_REQ(Signal * signal)16093 Dbtc::execCREATE_FK_IMPL_REQ(Signal* signal)
16094 {
16095 jamEntry();
16096 CreateFKImplReq reqCopy = * CAST_CONSTPTR(CreateFKImplReq,
16097 signal->getDataPtr());
16098 CreateFKImplReq * req = &reqCopy;
16099
16100 Uint32 errCode = 0;
16101 SectionHandle handle(this, signal);
16102
16103 if (req->requestType == CreateFKImplReq::RT_PREPARE)
16104 {
16105 jam();
16106 Ptr<TcFKData> fkPtr;
16107 if (c_fk_hash.find(fkPtr, req->fkId))
16108 {
16109 jam();
16110 errCode = CreateFKImplRef::ObjectAlreadyExist;
16111 goto error;
16112 }
16113 if (!c_fk_pool.seize(fkPtr))
16114 {
16115 jam();
16116 errCode = CreateFKImplRef::NoMoreObjectRecords;
16117 goto error;
16118 }
16119
16120 fkPtr.p->fkId = req->fkId;
16121 fkPtr.p->bits = req->bits;
16122 fkPtr.p->parentTableId = req->parentTableId;
16123 fkPtr.p->childTableId = req->childTableId;
16124 fkPtr.p->childIndexId = req->childIndexId;
16125
16126 if (req->parentIndexId != RNIL)
16127 {
16128 /**
16129 * Ignore base-table here...we'll only use the index anyway
16130 */
16131 jam();
16132 fkPtr.p->parentTableId = req->parentIndexId;
16133 }
16134
16135 if (req->childIndexId == RNIL)
16136 {
16137 jam();
16138 fkPtr.p->childIndexId = req->childTableId;
16139 }
16140
16141 {
16142 SegmentedSectionPtr ssPtr;
16143 handle.getSection(ssPtr, CreateFKImplReq::PARENT_COLUMNS);
16144 fkPtr.p->parentTableColumns.sz = ssPtr.sz;
16145 if (ssPtr.sz > NDB_ARRAY_SIZE(fkPtr.p->parentTableColumns.id))
16146 {
16147 errCode = CreateFKImplRef::InvalidFormat;
16148 goto error;
16149 }
16150 copy(fkPtr.p->parentTableColumns.id, ssPtr);
16151 }
16152
16153 {
16154 SegmentedSectionPtr ssPtr;
16155 handle.getSection(ssPtr, CreateFKImplReq::CHILD_COLUMNS);
16156 fkPtr.p->childTableColumns.sz = ssPtr.sz;
16157 if (ssPtr.sz > NDB_ARRAY_SIZE(fkPtr.p->childTableColumns.id))
16158 {
16159 errCode = CreateFKImplRef::InvalidFormat;
16160 goto error;
16161 }
16162 copy(fkPtr.p->childTableColumns.id, ssPtr);
16163 }
16164
16165 c_fk_hash.add(fkPtr);
16166 }
16167 else if (req->requestType == CreateFKImplReq::RT_ABORT)
16168 {
16169 jam();
16170 Ptr<TcFKData> fkPtr;
16171 ndbassert(c_fk_hash.find(fkPtr, req->fkId));
16172 if (c_fk_hash.find(fkPtr, req->fkId))
16173 {
16174 jam();
16175 c_fk_hash.release(fkPtr);
16176 }
16177 }
16178 else
16179 {
16180 ndbrequire(false); // No other request should reach TC
16181 }
16182
16183 releaseSections(handle);
16184 {
16185 CreateFKImplConf * conf = CAST_PTR(CreateFKImplConf,
16186 signal->getDataPtrSend());
16187 conf->senderRef = reference();
16188 conf->senderData = req->senderData;
16189 sendSignal(req->senderRef, GSN_CREATE_FK_IMPL_CONF,
16190 signal, CreateFKImplConf::SignalLength, JBB);
16191 }
16192 return;
16193 error:
16194 releaseSections(handle);
16195 CreateFKImplRef * ref = CAST_PTR(CreateFKImplRef,
16196 signal->getDataPtrSend());
16197 ref->senderRef = reference();
16198 ref->senderData = req->senderData;
16199 ref->errorCode = errCode;
16200 sendSignal(req->senderRef, GSN_CREATE_FK_IMPL_REF,
16201 signal, CreateFKImplRef::SignalLength, JBB);
16202 }
16203
16204 void
execDROP_FK_IMPL_REQ(Signal * signal)16205 Dbtc::execDROP_FK_IMPL_REQ(Signal* signal)
16206 {
16207 jamEntry();
16208 DropFKImplReq reqCopy = * CAST_CONSTPTR(DropFKImplReq,
16209 signal->getDataPtr());
16210 DropFKImplReq * req = &reqCopy;
16211
16212 SectionHandle handle(this, signal);
16213 releaseSections(handle);
16214
16215 Ptr<TcFKData> fkPtr;
16216 ndbassert(c_fk_hash.find(fkPtr, req->fkId));
16217 if (c_fk_hash.find(fkPtr, req->fkId))
16218 {
16219 jam();
16220 c_fk_hash.release(fkPtr);
16221
16222 DropFKImplConf * conf = CAST_PTR(DropFKImplConf,
16223 signal->getDataPtrSend());
16224 conf->senderRef = reference();
16225 conf->senderData = req->senderData;
16226 sendSignal(req->senderRef, GSN_DROP_FK_IMPL_CONF,
16227 signal, DropFKImplConf::SignalLength, JBB);
16228 }
16229 else
16230 {
16231 jam();
16232 DropFKImplRef * ref = CAST_PTR(DropFKImplRef,
16233 signal->getDataPtrSend());
16234 ref->senderRef = reference();
16235 ref->senderData = req->senderData;
16236 ref->errorCode = DropFKImplRef::NoSuchObject;
16237 sendSignal(req->senderRef, GSN_DROP_FK_IMPL_REF,
16238 signal, DropFKImplRef::SignalLength, JBB);
16239 }
16240 }
16241
execFIRE_TRIG_ORD(Signal * signal)16242 void Dbtc::execFIRE_TRIG_ORD(Signal* signal)
16243 {
16244 jamEntry();
16245 FireTrigOrd * const fireOrd = (FireTrigOrd *)signal->getDataPtr();
16246 SectionHandle handle(this, signal);
16247 const bool longsignal = handle.m_cnt > 0;
16248
16249 ApiConnectRecordPtr transPtr;
16250 TcConnectRecordPtr opPtr;
16251 bool transIdOk = true;
16252 /* Check the received transaction id
16253 * Older nodes do not send transid info in FIRE_TRIG_ORD
16254 */
16255 const Uint32 sourceNode = refToNode(signal->getSendersBlockRef());
16256 const Uint32 sourceNodeVersion = getNodeInfo(sourceNode).m_version;
16257 bool sigContainsTransId = ndb_fire_trig_ord_transid(sourceNodeVersion);
16258
16259 /* Get triggering operation record */
16260 opPtr.i = fireOrd->getConnectionPtr();
16261 ptrCheckGuard(opPtr, ctcConnectFilesize, tcConnectRecord);
16262
16263 /* Get transaction record */
16264 transPtr.i = opPtr.p->apiConnect;
16265 if (unlikely(transPtr.i == RNIL))
16266 {
16267 /* Looks like the connect record was released
16268 * Treat as a bad transid
16269 */
16270 transIdOk = false;
16271 }
16272 else
16273 {
16274 ptrCheckGuard(transPtr, capiConnectFilesize, apiConnectRecord);
16275
16276 /* Check if signal's trans id and operation's transid are aligned */
16277 transIdOk = (! sigContainsTransId) |
16278 (! ((fireOrd->m_transId1 ^ transPtr.p->transid[0]) |
16279 (fireOrd->m_transId2 ^ transPtr.p->transid[1])));
16280 }
16281
16282 TcFiredTriggerData key;
16283 key.fireingOperation = opPtr.i;
16284 key.nodeId = refToNode(signal->getSendersBlockRef());
16285 FiredTriggerPtr trigPtr;
16286 bool ok = transIdOk;
16287
16288 if (likely(longsignal && transIdOk))
16289 {
16290 jam();
16291 if (likely(c_theFiredTriggerPool.seize(trigPtr)))
16292 {
16293 jam();
16294 trigPtr.p->nodeId = key.nodeId;
16295 trigPtr.p->fireingOperation = key.fireingOperation;
16296 trigPtr.p->triggerId = fireOrd->m_triggerId;
16297 }
16298 else
16299 {
16300 jam();
16301 ok = false;
16302 }
16303 }
16304
16305 Uint32 errorCode = ZTOO_MANY_FIRED_TRIGGERS;
16306 if (likely((longsignal && ok) ||
16307 c_firedTriggerHash.find(trigPtr, key)))
16308 {
16309 jam();
16310 if (!longsignal)
16311 {
16312 jam();
16313 c_firedTriggerHash.remove(trigPtr);
16314 }
16315
16316 trigPtr.p->triggerType = (TriggerType::Value)fireOrd->m_triggerType;
16317 trigPtr.p->triggerEvent = (TriggerEvent::Value)fireOrd->m_triggerEvent;
16318
16319 if (unlikely(signal->getLength() < FireTrigOrd::SignalLength))
16320 {
16321 jam();
16322 ndbrequire(! sigContainsTransId );
16323 Ptr<TcDefinedTriggerData> ptr;
16324 c_theDefinedTriggers.getPtr(ptr, trigPtr.p->triggerId);
16325 trigPtr.p->triggerType = ptr.p->triggerType;
16326 trigPtr.p->triggerEvent = ptr.p->triggerEvent;
16327 }
16328 trigPtr.p->fragId= fireOrd->fragId;
16329 if (longsignal)
16330 {
16331 jam();
16332 AttributeBuffer::DataBufferPool & pool = c_theAttributeBufferPool;
16333 {
16334 //TODO: error insert to make e.g middle append fail
16335 LocalDataBuffer<11> tmp1(pool, trigPtr.p->keyValues);
16336 LocalDataBuffer<11> tmp2(pool, trigPtr.p->beforeValues);
16337 LocalDataBuffer<11> tmp3(pool, trigPtr.p->afterValues);
16338 append(tmp1, handle.m_ptr[0], getSectionSegmentPool());
16339 append(tmp2, handle.m_ptr[1], getSectionSegmentPool());
16340 append(tmp3, handle.m_ptr[2], getSectionSegmentPool());
16341 }
16342 releaseSections(handle);
16343 }
16344
16345 ok &= trigPtr.p->keyValues.getSize() == fireOrd->m_noPrimKeyWords;
16346 ok &= trigPtr.p->afterValues.getSize() == fireOrd->m_noAfterValueWords;
16347 ok &= trigPtr.p->beforeValues.getSize() == fireOrd->m_noBeforeValueWords;
16348
16349 if (ERROR_INSERTED(8085))
16350 {
16351 ok = false;
16352 }
16353
16354 if(likely( ok ))
16355 {
16356 jam();
16357 setApiConTimer(transPtr.i, ctcTimer, __LINE__);
16358 opPtr.p->numReceivedTriggers++;
16359 opPtr.p->triggerExecutionCount++; // Default 1 LQHKEYREQ per trigger
16360
16361 // Insert fired trigger in execution queue
16362 {
16363 LocalDLFifoList<TcFiredTriggerData>
16364 list(c_theFiredTriggerPool, opPtr.p->thePendingTriggers);
16365 list.addLast(trigPtr);
16366 }
16367
16368 if (opPtr.p->numReceivedTriggers == opPtr.p->numFiredTriggers ||
16369 transPtr.p->isExecutingDeferredTriggers())
16370 {
16371 jam();
16372 transPtr.p->theFiredTriggers.appendList(opPtr.p->thePendingTriggers);
16373 executeTriggers(signal, &transPtr);
16374 }
16375 return;
16376 }
16377
16378 /* Trigger entry found but either :
16379 * - Overload resulted in loss of Trig_Attrinfo
16380 * : Release resources + Abort transaction
16381 * - Bad transaction id due to concurrent abort?
16382 * : Release resources
16383 */
16384 jam();
16385 errorCode = ZINCONSISTENT_TRIGGER_STATE;
16386 // Release trigger records
16387 AttributeBuffer::DataBufferPool & pool = c_theAttributeBufferPool;
16388 LocalDataBuffer<11> tmp1(pool, trigPtr.p->keyValues);
16389 tmp1.release();
16390 LocalDataBuffer<11> tmp2(pool, trigPtr.p->beforeValues);
16391 tmp2.release();
16392 LocalDataBuffer<11> tmp3(pool, trigPtr.p->afterValues);
16393 tmp3.release();
16394 c_theFiredTriggerPool.release(trigPtr);
16395 }
16396
16397 releaseSections(handle);
16398
16399 /* Either no trigger entry found, or overload, or
16400 * bad transid
16401 * If transid is ok, abort the transaction.
16402 * else, return.
16403 * (Note small risk of 'abort of innocent' in upgrade
16404 * scenario with no transid in FIRE_TRIG_ORD)
16405 */
16406 jam();
16407 if (transIdOk)
16408 {
16409 jam();
16410 abortTransFromTrigger(signal, transPtr, errorCode);
16411 }
16412
16413 return;
16414 }
16415
execTRIG_ATTRINFO(Signal * signal)16416 void Dbtc::execTRIG_ATTRINFO(Signal* signal)
16417 {
16418 jamEntry();
16419 TrigAttrInfo * const trigAttrInfo = (TrigAttrInfo *)signal->getDataPtr();
16420 Uint32 attrInfoLength = signal->getLength() - TrigAttrInfo::StaticLength;
16421 const Uint32 *src = trigAttrInfo->getData();
16422 FiredTriggerPtr firedTrigPtr;
16423
16424 TcFiredTriggerData key;
16425 key.fireingOperation = trigAttrInfo->getConnectionPtr();
16426 key.nodeId = refToNode(signal->getSendersBlockRef());
16427 if(!c_firedTriggerHash.find(firedTrigPtr, key)){
16428 jam();
16429 /* TODO : Node failure handling (use sig-train assembly) */
16430 if(!c_firedTriggerHash.seize(firedTrigPtr)){
16431 jam();
16432 /**
16433 * Will be handled when FIRE_TRIG_ORD arrives
16434 */
16435 ndbout_c("op: %d node: %d failed to seize",
16436 key.fireingOperation, key.nodeId);
16437 return;
16438 }
16439 ndbrequire(firedTrigPtr.p->keyValues.getSize() == 0 &&
16440 firedTrigPtr.p->beforeValues.getSize() == 0 &&
16441 firedTrigPtr.p->afterValues.getSize() == 0);
16442
16443 firedTrigPtr.p->nodeId = refToNode(signal->getSendersBlockRef());
16444 firedTrigPtr.p->fireingOperation = key.fireingOperation;
16445 firedTrigPtr.p->triggerId = trigAttrInfo->getTriggerId();
16446 c_firedTriggerHash.add(firedTrigPtr);
16447 }
16448
16449 AttributeBuffer::DataBufferPool & pool = c_theAttributeBufferPool;
16450 switch (trigAttrInfo->getAttrInfoType()) {
16451 case(TrigAttrInfo::PRIMARY_KEY):
16452 jam();
16453 {
16454 LocalDataBuffer<11> buf(pool, firedTrigPtr.p->keyValues);
16455 buf.append(src, attrInfoLength);
16456 }
16457 break;
16458 case(TrigAttrInfo::BEFORE_VALUES):
16459 jam();
16460 {
16461 LocalDataBuffer<11> buf(pool, firedTrigPtr.p->beforeValues);
16462 buf.append(src, attrInfoLength);
16463 }
16464 break;
16465 case(TrigAttrInfo::AFTER_VALUES):
16466 jam();
16467 {
16468 LocalDataBuffer<11> buf(pool, firedTrigPtr.p->afterValues);
16469 buf.append(src, attrInfoLength);
16470 }
16471 break;
16472 default:
16473 ndbrequire(false);
16474 }
16475 }
16476
execDROP_INDX_IMPL_REQ(Signal * signal)16477 void Dbtc::execDROP_INDX_IMPL_REQ(Signal* signal)
16478 {
16479 jamEntry();
16480 const DropIndxImplReq * const req =
16481 (const DropIndxImplReq *)signal->getDataPtr();
16482 const Uint32 senderRef = req->senderRef;
16483 const Uint32 senderData = req->senderData;
16484 TcIndexData* indexData;
16485
16486 if (ERROR_INSERTED(8036) ||
16487 (indexData = c_theIndexes.getPtr(req->indexId)) == NULL) {
16488 jam();
16489 CLEAR_ERROR_INSERT_VALUE;
16490 // Failed to find index record
16491 DropIndxImplRef * const ref =
16492 (DropIndxImplRef *)signal->getDataPtrSend();
16493
16494 ref->senderRef = reference();
16495 ref->senderData = senderData;
16496 ref->errorCode = DropIndxImplRef::InconsistentTC;
16497 ref->errorLine = __LINE__;
16498 sendSignal(senderRef, GSN_DROP_INDX_IMPL_REF,
16499 signal, DropIndxImplRef::SignalLength, JBB);
16500 return;
16501 }
16502 // Release index record
16503 c_theIndexes.release(req->indexId);
16504
16505 DropIndxImplConf * const conf =
16506 (DropIndxImplConf *)signal->getDataPtrSend();
16507
16508 conf->senderRef = reference();
16509 conf->senderData = senderData;
16510 sendSignal(senderRef, GSN_DROP_INDX_IMPL_CONF,
16511 signal, DropIndxImplConf::SignalLength, JBB);
16512 }
16513
execTCINDXREQ(Signal * signal)16514 void Dbtc::execTCINDXREQ(Signal* signal)
16515 {
16516 jamEntry();
16517
16518 TcKeyReq * const tcIndxReq = (TcKeyReq *)signal->getDataPtr();
16519 const UintR TapiIndex = tcIndxReq->apiConnectPtr;
16520 Uint32 tcIndxRequestInfo = tcIndxReq->requestInfo;
16521 Uint32 startFlag = tcIndxReq->getStartFlag(tcIndxRequestInfo);
16522 ApiConnectRecordPtr transPtr;
16523 bool isLongTcIndxReq= (signal->getNoOfSections() != 0);
16524 SectionHandle handle(this, signal);
16525
16526 transPtr.i = TapiIndex;
16527 if (transPtr.i >= capiConnectFilesize) {
16528 jam();
16529 warningHandlerLab(signal, __LINE__);
16530 releaseSections(handle);
16531 return;
16532 }//if
16533 ptrAss(transPtr, apiConnectRecord);
16534 ApiConnectRecord * const regApiPtr = transPtr.p;
16535 // Seize index operation
16536 TcIndexOperationPtr indexOpPtr;
16537
16538 #ifdef ERROR_INSERT
16539 if (ERROR_INSERTED(8100))
16540 {
16541 char buf[128];
16542 BaseString::snprintf(buf, sizeof(buf), "Inserted 8100, startFlag %u, regApiPtr->apiConnectstate %u, regApiPtr->abortState %u", startFlag, regApiPtr->apiConnectstate, regApiPtr->abortState);
16543 warningEvent("%s", buf);
16544
16545 if (startFlag == 1)
16546 {
16547 jam();
16548 /*
16549 Phase 1:
16550 Abort the transaction by simulating a fake node failure.
16551 Don't send any TCROLLBACKREP until in next TCINDXREQ call
16552 to simulate a slow signal still in the air.
16553 */
16554 Signal s = *signal;
16555 signal->theData[0] = TcContinueB::ZDEBUG_DELAYED_ABORT;
16556 signal->theData[1] = transPtr.i;
16557 signal->theData[2] = regApiPtr->transid[0];
16558 signal->theData[3] = regApiPtr->transid[1];
16559 signal->theData[4] = ZNODEFAIL_BEFORE_COMMIT;
16560 signal->theData[5] = RS_TCROLLBACKREP;
16561 signal->theData[6] = 8101;
16562 sendSignalWithDelay(reference(), GSN_CONTINUEB, signal, 100, 6);
16563 *signal = s;
16564 }
16565 }
16566 else if (ERROR_INSERTED(8101))
16567 {
16568 char buf[128];
16569 BaseString::snprintf(buf, sizeof(buf), "Inserted 8101, startFlag %u, regApiPtr->apiConnectstate %u, regApiPtr->abortState %u", startFlag, regApiPtr->apiConnectstate, regApiPtr->abortState);
16570 warningEvent("%s", buf);
16571
16572 jam();
16573 /*
16574 Phase 2:
16575 Transaction has been aborted by a fake node failure,
16576 but the API hasn't been informed yet. Force the state
16577 into waiting for pending signals.
16578 */
16579 if (regApiPtr->returncode != ZNODEFAIL_BEFORE_COMMIT ||
16580 regApiPtr->apiConnectstate != CS_ABORTING ||
16581 regApiPtr->abortState != AS_IDLE)
16582 {
16583 /*
16584 We are waiting for abort to complete, but have not reached
16585 the transaction state we want to test. Try again.
16586 */
16587 jam();
16588 sendSignalWithDelay(reference(), GSN_TCINDXREQ, signal, 100,
16589 TcKeyReq::StaticLength, &handle);
16590 return;
16591 }
16592 CLEAR_ERROR_INSERT_VALUE;
16593 }
16594 #endif
16595
16596 if (startFlag == 1 &&
16597 (regApiPtr->apiConnectstate == CS_CONNECTED ||
16598 (regApiPtr->apiConnectstate == CS_STARTED &&
16599 regApiPtr->firstTcConnect == RNIL) ||
16600 (regApiPtr->apiConnectstate == CS_ABORTING &&
16601 regApiPtr->abortState == AS_IDLE)))
16602 {
16603 jam();
16604 // This is a newly started transaction, clean-up from any
16605 // previous transaction.
16606 releaseAllSeizedIndexOperations(regApiPtr);
16607
16608 regApiPtr->apiConnectstate = CS_STARTED;
16609 regApiPtr->transid[0] = tcIndxReq->transId1;
16610 regApiPtr->transid[1] = tcIndxReq->transId2;
16611 }//if (startFlag == 1 && ...
16612 else if (regApiPtr->apiConnectstate == CS_ABORTING)
16613 {
16614 jam();
16615 /*
16616 Transaction has been aborted and we have to do error
16617 handling, but since when we read the index table
16618 the generated TCKEYREQ will do the proper error
16619 handling. Any received TCKEYREF will be forwarded
16620 to the original sender as a TCINDXREF.
16621 */
16622 }//if (regApiPtr->apiConnectstate == CS_ABORTING)
16623
16624 if (getNodeState().startLevel == NodeState::SL_SINGLEUSER &&
16625 getNodeState().getSingleUserApi() !=
16626 refToNode(regApiPtr->ndbapiBlockref))
16627 {
16628 jam();
16629 releaseSections(handle);
16630 terrorCode = ZCLUSTER_IN_SINGLEUSER_MODE;
16631 regApiPtr->m_flags |=
16632 TcKeyReq::getExecuteFlag(tcIndxRequestInfo) ?
16633 ApiConnectRecord::TF_EXEC_FLAG : 0;
16634 apiConnectptr = transPtr;
16635 abortErrorLab(signal);
16636 return;
16637 }
16638
16639 if (ERROR_INSERTED(8036) || !seizeIndexOperation(regApiPtr, indexOpPtr)) {
16640 jam();
16641 releaseSections(handle);
16642 // Failed to allocate index operation
16643 terrorCode = 288;
16644 regApiPtr->m_flags |=
16645 TcKeyReq::getExecuteFlag(tcIndxRequestInfo) ?
16646 ApiConnectRecord::TF_EXEC_FLAG : 0;
16647 apiConnectptr = transPtr;
16648 abortErrorLab(signal);
16649 return;
16650 }
16651 TcIndexOperation* indexOp = indexOpPtr.p;
16652 indexOp->indexOpId = indexOpPtr.i;
16653
16654 // Save original signal
16655 indexOp->tcIndxReq = *tcIndxReq;
16656 indexOp->connectionIndex = TapiIndex;
16657 regApiPtr->accumulatingIndexOp = indexOp->indexOpId;
16658
16659 if (isLongTcIndxReq)
16660 {
16661 jam();
16662 /* KeyInfo and AttrInfo already received into sections */
16663 SegmentedSectionPtr keyInfoSection, attrInfoSection;
16664
16665 /* Store i value for first long section of KeyInfo
16666 * and AttrInfo in Index operation
16667 */
16668 handle.getSection(keyInfoSection,
16669 TcKeyReq::KeyInfoSectionNum);
16670
16671 indexOp->keyInfoSectionIVal= keyInfoSection.i;
16672
16673 if (handle.m_cnt == 2)
16674 {
16675 handle.getSection(attrInfoSection,
16676 TcKeyReq::AttrInfoSectionNum);
16677 indexOp->attrInfoSectionIVal= attrInfoSection.i;
16678 }
16679
16680 if (TcKeyReq::getDeferredConstraints(tcIndxRequestInfo))
16681 {
16682 regApiPtr->m_flags |= ApiConnectRecord::TF_DEFERRED_CONSTRAINTS;
16683 }
16684
16685 if (TcKeyReq::getDisableFkConstraints(tcIndxRequestInfo))
16686 {
16687 regApiPtr->m_flags |= ApiConnectRecord::TF_DISABLE_FK_CONSTRAINTS;
16688 }
16689 indexOp->savedFlags = regApiPtr->m_flags;
16690
16691 /* Detach sections from the handle
16692 * Success path code, or index operation cleanup is
16693 * now responsible for freeing the sections
16694 */
16695 handle.clear();
16696
16697 /* All data received, process */
16698 readIndexTable(signal, regApiPtr, indexOp, 0);
16699 return;
16700 }
16701 else
16702 {
16703 jam();
16704 /* Short TcIndxReq, build up KeyInfo and AttrInfo
16705 * sections from separate signals
16706 */
16707 Uint32 * dataPtr = &tcIndxReq->scanInfo;
16708 Uint32 indexLength = TcKeyReq::getKeyLength(tcIndxRequestInfo);
16709 Uint32 attrLength = TcKeyReq::getAttrinfoLen(tcIndxReq->attrLen);
16710
16711 indexOp->pendingKeyInfo = indexLength;
16712 indexOp->pendingAttrInfo = attrLength;
16713
16714 const Uint32 includedIndexLength = MIN(indexLength, TcKeyReq::MaxKeyInfo);
16715 const Uint32 includedAttrLength = MIN(attrLength, TcKeyReq::MaxAttrInfo);
16716 int ret;
16717
16718 if ((ret = saveINDXKEYINFO(signal,
16719 indexOp,
16720 dataPtr,
16721 includedIndexLength)) == 0)
16722 {
16723 jam();
16724 /* All KI + no AI received, process */
16725 readIndexTable(signal, regApiPtr, indexOp, 0);
16726 return;
16727 }
16728 else if (ret == -1)
16729 {
16730 jam();
16731 return;
16732 }
16733
16734 dataPtr += includedIndexLength;
16735
16736 if (saveINDXATTRINFO(signal,
16737 indexOp,
16738 dataPtr,
16739 includedAttrLength) == 0) {
16740 jam();
16741 /* All KI and AI received, process */
16742 readIndexTable(signal, regApiPtr, indexOp, 0);
16743 return;
16744 }
16745 }
16746 }
16747
execINDXKEYINFO(Signal * signal)16748 void Dbtc::execINDXKEYINFO(Signal* signal)
16749 {
16750 jamEntry();
16751 Uint32 keyInfoLength = signal->getLength() - IndxKeyInfo::HeaderLength;
16752 IndxKeyInfo * const indxKeyInfo = (IndxKeyInfo *)signal->getDataPtr();
16753 const Uint32 *src = indxKeyInfo->getData();
16754 const UintR TconnectIndex = indxKeyInfo->connectPtr;
16755 ApiConnectRecordPtr transPtr;
16756 transPtr.i = TconnectIndex;
16757 if (transPtr.i >= capiConnectFilesize) {
16758 jam();
16759 warningHandlerLab(signal, __LINE__);
16760 return;
16761 }//if
16762 ptrAss(transPtr, apiConnectRecord);
16763 ApiConnectRecord * const regApiPtr = transPtr.p;
16764 TcIndexOperationPtr indexOpPtr;
16765 TcIndexOperation* indexOp;
16766
16767 if (compare_transid(regApiPtr->transid, indxKeyInfo->transId) == false)
16768 {
16769 TCKEY_abort(signal, 19);
16770 return;
16771 }
16772
16773 if (regApiPtr->apiConnectstate == CS_ABORTING)
16774 {
16775 jam();
16776 return;
16777 }
16778
16779 if((indexOpPtr.i = regApiPtr->accumulatingIndexOp) != RNIL)
16780 {
16781 indexOp = c_theIndexOperationPool.getPtr(indexOpPtr.i);
16782
16783 ndbassert( indexOp->pendingKeyInfo > 0 );
16784
16785 if (saveINDXKEYINFO(signal,
16786 indexOp,
16787 src,
16788 keyInfoLength) == 0) {
16789 jam();
16790 /* All KI + AI received, process */
16791 readIndexTable(signal, regApiPtr, indexOp, 0);
16792 }
16793 }
16794 }
16795
execINDXATTRINFO(Signal * signal)16796 void Dbtc::execINDXATTRINFO(Signal* signal)
16797 {
16798 jamEntry();
16799 Uint32 attrInfoLength = signal->getLength() - IndxAttrInfo::HeaderLength;
16800 IndxAttrInfo * const indxAttrInfo = (IndxAttrInfo *)signal->getDataPtr();
16801 const Uint32 *src = indxAttrInfo->getData();
16802 const UintR TconnectIndex = indxAttrInfo->connectPtr;
16803 ApiConnectRecordPtr transPtr;
16804 transPtr.i = TconnectIndex;
16805 if (transPtr.i >= capiConnectFilesize) {
16806 jam();
16807 warningHandlerLab(signal, __LINE__);
16808 return;
16809 }//if
16810 ptrAss(transPtr, apiConnectRecord);
16811 ApiConnectRecord * const regApiPtr = transPtr.p;
16812 TcIndexOperationPtr indexOpPtr;
16813 TcIndexOperation* indexOp;
16814
16815 if (compare_transid(regApiPtr->transid, indxAttrInfo->transId) == false)
16816 {
16817 TCKEY_abort(signal, 19);
16818 return;
16819 }
16820
16821 if (regApiPtr->apiConnectstate == CS_ABORTING)
16822 {
16823 jam();
16824 return;
16825 }
16826
16827 if((indexOpPtr.i = regApiPtr->accumulatingIndexOp) != RNIL)
16828 {
16829 indexOp = c_theIndexOperationPool.getPtr(indexOpPtr.i);
16830
16831 ndbassert( indexOp->pendingAttrInfo > 0 );
16832
16833 if (saveINDXATTRINFO(signal,
16834 indexOp,
16835 src,
16836 attrInfoLength) == 0) {
16837 jam();
16838 /* All KI + AI received, process */
16839 readIndexTable(signal, regApiPtr, indexOp, 0);
16840 return;
16841 }
16842 return;
16843 }
16844 }
16845
16846 /**
16847 * Save received KeyInfo
16848 * Return true if we have received all needed data
16849 */
16850 int
saveINDXKEYINFO(Signal * signal,TcIndexOperation * indexOp,const Uint32 * src,Uint32 len)16851 Dbtc::saveINDXKEYINFO(Signal* signal,
16852 TcIndexOperation* indexOp,
16853 const Uint32 *src,
16854 Uint32 len)
16855 {
16856 if (ERROR_INSERTED(8052) ||
16857 ! appendToSection(indexOp->keyInfoSectionIVal,
16858 src,
16859 len))
16860 {
16861 jam();
16862 // Failed to seize keyInfo, abort transaction
16863 #ifdef VM_TRACE
16864 ndbout_c("Dbtc::saveINDXKEYINFO: Failed to seize buffer for KeyInfo\n");
16865 #endif
16866 // Abort transaction
16867 apiConnectptr.i = indexOp->connectionIndex;
16868 ptrCheckGuard(apiConnectptr, capiConnectFilesize, apiConnectRecord);
16869 releaseIndexOperation(apiConnectptr.p, indexOp);
16870 terrorCode = 289;
16871 if(TcKeyReq::getExecuteFlag(indexOp->tcIndxReq.requestInfo))
16872 apiConnectptr.p->m_flags |= ApiConnectRecord::TF_EXEC_FLAG;
16873 abortErrorLab(signal);
16874 return -1;
16875 }
16876 indexOp->pendingKeyInfo-= len;
16877
16878 if (receivedAllINDXKEYINFO(indexOp) && receivedAllINDXATTRINFO(indexOp)) {
16879 jam();
16880 return 0;
16881 }
16882 return 1;
16883 }
16884
receivedAllINDXKEYINFO(TcIndexOperation * indexOp)16885 bool Dbtc::receivedAllINDXKEYINFO(TcIndexOperation* indexOp)
16886 {
16887 return (indexOp->pendingKeyInfo == 0);
16888 }
16889
16890 /**
16891 * Save signal INDXATTRINFO
16892 * Return true if we have received all needed data
16893 */
16894 int
saveINDXATTRINFO(Signal * signal,TcIndexOperation * indexOp,const Uint32 * src,Uint32 len)16895 Dbtc::saveINDXATTRINFO(Signal* signal,
16896 TcIndexOperation* indexOp,
16897 const Uint32 *src,
16898 Uint32 len)
16899 {
16900 if (ERROR_INSERTED(8051) ||
16901 ! appendToSection(indexOp->attrInfoSectionIVal,
16902 src,
16903 len))
16904 {
16905 jam();
16906 #ifdef VM_TRACE
16907 ndbout_c("Dbtc::saveINDXATTRINFO: Failed to seize buffer for attrInfo\n");
16908 #endif
16909 apiConnectptr.i = indexOp->connectionIndex;
16910 ptrCheckGuard(apiConnectptr, capiConnectFilesize, apiConnectRecord);
16911 releaseIndexOperation(apiConnectptr.p, indexOp);
16912 terrorCode = 289;
16913 if(TcKeyReq::getExecuteFlag(indexOp->tcIndxReq.requestInfo))
16914 apiConnectptr.p->m_flags |= ApiConnectRecord::TF_EXEC_FLAG;
16915 abortErrorLab(signal);
16916 return -1;
16917 }
16918
16919 indexOp->pendingAttrInfo-= len;
16920
16921 if (receivedAllINDXKEYINFO(indexOp) && receivedAllINDXATTRINFO(indexOp)) {
16922 jam();
16923 return 0;
16924 }
16925 return 1;
16926 }
16927
receivedAllINDXATTRINFO(TcIndexOperation * indexOp)16928 bool Dbtc::receivedAllINDXATTRINFO(TcIndexOperation* indexOp)
16929 {
16930 return (indexOp->pendingAttrInfo == 0);
16931 }
16932
16933 #ifdef ERROR_INSERT
16934 extern bool ErrorImportActive;
16935 #endif
16936
saveTRANSID_AI(Signal * signal,TcIndexOperation * indexOp,const Uint32 * src,Uint32 len)16937 Uint32 Dbtc::saveTRANSID_AI(Signal* signal,
16938 TcIndexOperation* indexOp,
16939 const Uint32 *src,
16940 Uint32 len)
16941 {
16942 /* TransID_AI is received as a result of looking up a
16943 * unique index table
16944 * The unique index table is looked up using the index
16945 * key to receive a single attribute containing the
16946 * fragment holding the base table row and the base
16947 * table primary key.
16948 * This is later used to build a TCKEYREQ against the
16949 * base table.
16950 * In this method, we prepare a KEYINFO section for the
16951 * TCKEYREQ as we receive TRANSID_AI words.
16952 *
16953 * Expected TRANSID_AI words :
16954 *
16955 * Word(s) Description States
16956 *
16957 * 0 Attribute header ITAS_WAIT_HEADER
16958 * containing length -> ITAS_WAIT_FRAGID
16959 *
16960 * 1 Fragment Id ITAS_WAIT_FRAGID
16961 * -> ITAS_WAIT_KEY
16962 *
16963 * [2..N] Base table primary ITAS_WAIT_KEY
16964 * key info -> [ ITAS_WAIT_KEY |
16965 * ITAS_WAIT_KEY_FAIL ]
16966 * -> ITAS_ALL_RECEIVED
16967 *
16968 * The outgoing KeyInfo section contains the base
16969 * table primary key info, with the fragment id passed
16970 * as the distribution key.
16971 * ITAS_WAIT_KEY_FAIL state is entered when there is no
16972 * space to store received TRANSID_AI information and
16973 * key collection must fail. Transaction abort is performed
16974 * once all TRANSID_AI is received, and the system waits in
16975 * ITAS_WAIT_KEY_FAIL state until then.
16976 *
16977 */
16978 Uint32 remain= len;
16979
16980 while (remain != 0)
16981 {
16982 switch(indexOp->transIdAIState) {
16983 case ITAS_WAIT_HEADER:
16984 {
16985 jam();
16986 ndbassert(indexOp->transIdAISectionIVal == RNIL);
16987 /* Look at the first AttributeHeader to get the
16988 * expected size of the primary key attribute
16989 */
16990 AttributeHeader* head = (AttributeHeader *) src;
16991 ndbassert(head->getHeaderSize() == 1);
16992 indexOp->pendingTransIdAI = 1 + head->getDataSize();
16993
16994 src++;
16995 remain--;
16996 indexOp->transIdAIState = ITAS_WAIT_FRAGID;
16997 break;
16998 }
16999 case ITAS_WAIT_FRAGID:
17000 {
17001 jam();
17002 ndbassert(indexOp->transIdAISectionIVal == RNIL);
17003 /* Grab the fragment Id word */
17004 indexOp->fragmentId= *src;
17005
17006 src++;
17007 remain--;
17008 indexOp->transIdAIState = ITAS_WAIT_KEY;
17009 break;
17010 }
17011 case ITAS_WAIT_KEY:
17012 {
17013 jam();
17014 /* Add key information to long section */
17015 #ifdef ERROR_INSERT
17016 if (ERROR_INSERTED(8066))
17017 {
17018 ErrorImportActive = true;
17019 }
17020 #endif
17021
17022 bool res = appendToSection(indexOp->transIdAISectionIVal, src, remain);
17023 #ifdef ERROR_INSERT
17024 if (ERROR_INSERTED(8066))
17025 {
17026 ErrorImportActive = false;
17027 }
17028 #endif
17029
17030 if (res)
17031 {
17032 jam();
17033 remain= 0;
17034 break;
17035 }
17036 else
17037 {
17038 jam();
17039 #ifdef VM_TRACE
17040 ndbout_c("Dbtc::saveTRANSID_AI: Failed to seize buffer for TRANSID_AI\n");
17041 #endif
17042 indexOp->transIdAIState= ITAS_WAIT_KEY_FAIL;
17043 /* Fall through to ITAS_WAIT_KEY_FAIL state handling */
17044 }
17045 }
17046
17047 case ITAS_WAIT_KEY_FAIL:
17048 {
17049 /* Failed when collecting key previously - if we have all the
17050 * TRANSID_AI now then we abort
17051 */
17052 if (indexOp->pendingTransIdAI > len)
17053 {
17054 /* Still some TransIdAI to arrive, keep waiting as if we had
17055 * stored it
17056 */
17057 remain= 0;
17058 break;
17059 }
17060
17061 /* All TransIdAI has arrived, abort */
17062 apiConnectptr.i = indexOp->connectionIndex;
17063 ptrCheckGuard(apiConnectptr, capiConnectFilesize, apiConnectRecord);
17064 releaseIndexOperation(apiConnectptr.p, indexOp);
17065 terrorCode = ZGET_DATAREC_ERROR;
17066 abortErrorLab(signal);
17067 return ZGET_DATAREC_ERROR;
17068 }
17069
17070 case ITAS_ALL_RECEIVED:
17071 jam();
17072 // Fall through
17073 default:
17074 jam();
17075 /* Bad state, or bad state to receive TransId_Ai in */
17076 // Todo : Check error handling here.
17077 #ifdef VM_TRACE
17078 ndbout_c("Dbtc::saveTRANSID_AI: Bad state when receiving\n");
17079 #endif
17080 apiConnectptr.i = indexOp->connectionIndex;
17081 ptrCheckGuard(apiConnectptr, capiConnectFilesize, apiConnectRecord);
17082 releaseIndexOperation(apiConnectptr.p, indexOp);
17083 terrorCode = ZINCONSISTENT_INDEX_USE;
17084 abortErrorLab(signal);
17085 return ZINCONSISTENT_INDEX_USE;
17086 } // switch
17087 } // while
17088
17089 if ((indexOp->pendingTransIdAI-= len) == 0)
17090 indexOp->transIdAIState = ITAS_ALL_RECEIVED;
17091
17092 return ZOK;
17093 }
17094
receivedAllTRANSID_AI(TcIndexOperation * indexOp)17095 bool Dbtc::receivedAllTRANSID_AI(TcIndexOperation* indexOp)
17096 {
17097 return (indexOp->transIdAIState == ITAS_ALL_RECEIVED);
17098 }
17099
17100 /**
17101 * Receive signal TCINDXCONF
17102 * This can be either the return of reading an index table
17103 * or performing an index operation
17104 */
execTCKEYCONF(Signal * signal)17105 void Dbtc::execTCKEYCONF(Signal* signal)
17106 {
17107 TcKeyConf * const tcKeyConf = (TcKeyConf *)signal->getDataPtr();
17108 TcIndexOperationPtr indexOpPtr;
17109
17110 jamEntry();
17111 indexOpPtr.i = tcKeyConf->apiConnectPtr;
17112 TcIndexOperation* indexOp = c_theIndexOperationPool.getPtr(indexOpPtr.i);
17113
17114 /**
17115 * Check on TCKEYCONF whether the the transaction was committed
17116 */
17117 ndbassert(TcKeyConf::getCommitFlag(tcKeyConf->confInfo) == false);
17118
17119 indexOpPtr.p = indexOp;
17120 if (!indexOp) {
17121 jam();
17122 // Missing index operation
17123 return;
17124 }
17125 const UintR TconnectIndex = indexOp->connectionIndex;
17126 ApiConnectRecord * const regApiPtr = &apiConnectRecord[TconnectIndex];
17127 apiConnectptr.p = regApiPtr;
17128 apiConnectptr.i = TconnectIndex;
17129 switch(indexOp->indexOpState) {
17130 case(IOS_NOOP): {
17131 jam();
17132 // Should never happen, abort
17133 TcKeyRef * const tcIndxRef = (TcKeyRef *)signal->getDataPtrSend();
17134
17135 tcIndxRef->connectPtr = indexOp->tcIndxReq.senderData;
17136 tcIndxRef->transId[0] = regApiPtr->transid[0];
17137 tcIndxRef->transId[1] = regApiPtr->transid[1];
17138 tcIndxRef->errorCode = ZINCONSISTENT_INDEX_USE;
17139 tcIndxRef->errorData = 0;
17140 sendSignal(regApiPtr->ndbapiBlockref, GSN_TCINDXREF, signal,
17141 TcKeyRef::SignalLength, JBB);
17142 return;
17143 }
17144 case(IOS_INDEX_ACCESS): {
17145 jam();
17146 // Just waiting for the TRANSID_AI now
17147 indexOp->indexOpState = IOS_INDEX_ACCESS_WAIT_FOR_TRANSID_AI;
17148 break;
17149 }
17150 case(IOS_INDEX_ACCESS_WAIT_FOR_TRANSID_AI): {
17151 jam();
17152 // Double TCKEYCONF, should never happen, abort
17153 TcKeyRef * const tcIndxRef = (TcKeyRef *)signal->getDataPtrSend();
17154
17155 tcIndxRef->connectPtr = indexOp->tcIndxReq.senderData;
17156 tcIndxRef->transId[0] = regApiPtr->transid[0];
17157 tcIndxRef->transId[1] = regApiPtr->transid[1];
17158 tcIndxRef->errorCode = ZINCONSISTENT_INDEX_USE;
17159 tcIndxRef->errorData = 0;
17160 sendSignal(regApiPtr->ndbapiBlockref, GSN_TCINDXREF, signal,
17161 TcKeyRef::SignalLength, JBB);
17162 return;
17163 }
17164 case(IOS_INDEX_ACCESS_WAIT_FOR_TCKEYCONF): {
17165 jam();
17166 // Continue with index operation
17167 executeIndexOperation(signal, regApiPtr, indexOp);
17168 break;
17169 }
17170 }
17171 }
17172
execTCKEYREF(Signal * signal)17173 void Dbtc::execTCKEYREF(Signal* signal)
17174 {
17175 TcKeyRef * const tcKeyRef = (TcKeyRef *)signal->getDataPtr();
17176 TcIndexOperationPtr indexOpPtr;
17177
17178 jamEntry();
17179 indexOpPtr.i = tcKeyRef->connectPtr;
17180 TcIndexOperation* indexOp = c_theIndexOperationPool.getPtr(indexOpPtr.i);
17181 indexOpPtr.p = indexOp;
17182 if (!indexOp) {
17183 jam();
17184 // Missing index operation
17185 return;
17186 }
17187 const UintR TconnectIndex = indexOp->connectionIndex;
17188 ApiConnectRecord * const regApiPtr = &apiConnectRecord[TconnectIndex];
17189
17190 switch(indexOp->indexOpState) {
17191 case(IOS_NOOP): {
17192 jam();
17193 // Should never happen, abort
17194 break;
17195 }
17196 case(IOS_INDEX_ACCESS):
17197 case(IOS_INDEX_ACCESS_WAIT_FOR_TRANSID_AI):
17198 case(IOS_INDEX_ACCESS_WAIT_FOR_TCKEYCONF): {
17199 jam();
17200 // Send TCINDXREF
17201
17202 TcKeyReq * const tcIndxReq = &indexOp->tcIndxReq;
17203 TcKeyRef * const tcIndxRef = (TcKeyRef *)signal->getDataPtrSend();
17204
17205 tcIndxRef->connectPtr = tcIndxReq->senderData;
17206 tcIndxRef->transId[0] = tcKeyRef->transId[0];
17207 tcIndxRef->transId[1] = tcKeyRef->transId[1];
17208 tcIndxRef->errorCode = tcKeyRef->errorCode;
17209 tcIndxRef->errorData = 0;
17210
17211 releaseIndexOperation(regApiPtr, indexOp);
17212
17213 sendSignal(regApiPtr->ndbapiBlockref,
17214 GSN_TCINDXREF, signal, TcKeyRef::SignalLength, JBB);
17215 return;
17216 }
17217 }
17218 }
17219
execTRANSID_AI_R(Signal * signal)17220 void Dbtc::execTRANSID_AI_R(Signal* signal){
17221 TransIdAI * const transIdAI = (TransIdAI *)signal->getDataPtr();
17222 Uint32 sigLen = signal->length();
17223 Uint32 dataLen = sigLen - TransIdAI::HeaderLength - 1;
17224 Uint32 recBlockref = transIdAI->attrData[dataLen];
17225
17226 jamEntry();
17227
17228 SectionHandle handle(this, signal);
17229
17230 /**
17231 * Forward signal to final destination
17232 * Truncate last word since that was used to hold the final dest.
17233 */
17234 sendSignal(recBlockref, GSN_TRANSID_AI,
17235 signal, sigLen - 1, JBB,
17236 &handle);
17237 }
17238
execKEYINFO20_R(Signal * signal)17239 void Dbtc::execKEYINFO20_R(Signal* signal){
17240 KeyInfo20 * const keyInfo = (KeyInfo20 *)signal->getDataPtr();
17241 Uint32 sigLen = signal->length();
17242 Uint32 dataLen = sigLen - KeyInfo20::HeaderLength - 1;
17243 Uint32 recBlockref = keyInfo->keyData[dataLen];
17244
17245 jamEntry();
17246
17247 SectionHandle handle(this, signal);
17248
17249 /**
17250 * Forward signal to final destination
17251 * Truncate last word since that was used to hold the final dest.
17252 */
17253 sendSignal(recBlockref, GSN_KEYINFO20,
17254 signal, sigLen - 1, JBB,
17255 &handle);
17256 }
17257
17258
17259 /**
17260 * execTRANSID_AI
17261 *
17262 * TRANSID_AI are received as a result of performing a read on
17263 * the index table as part of a (unique) index operation.
17264 * The data received is the primary key of the base table
17265 * which is then used to perform the index operation on the
17266 * base table.
17267 */
execTRANSID_AI(Signal * signal)17268 void Dbtc::execTRANSID_AI(Signal* signal)
17269 {
17270 TransIdAI * const transIdAI = (TransIdAI *)signal->getDataPtr();
17271
17272 jamEntry();
17273 TcIndexOperationPtr indexOpPtr;
17274 indexOpPtr.i = transIdAI->connectPtr;
17275 TcIndexOperation* indexOp = c_theIndexOperationPool.getPtr(indexOpPtr.i);
17276 indexOpPtr.p = indexOp;
17277 if (!indexOp) {
17278 jam();
17279 // Missing index operation
17280 }
17281 const UintR TconnectIndex = indexOp->connectionIndex;
17282 ApiConnectRecordPtr transPtr;
17283
17284 transPtr.i = TconnectIndex;
17285 ptrCheckGuard(transPtr, capiConnectFilesize, apiConnectRecord);
17286 ApiConnectRecord * const regApiPtr = transPtr.p;
17287
17288 // Acccumulate attribute data
17289 SectionHandle handle(this, signal);
17290 bool longSignal = (handle.m_cnt == 1);
17291 Uint32 errorCode = ZOK;
17292 if (longSignal)
17293 {
17294 SegmentedSectionPtr dataPtr;
17295 Uint32 dataLen;
17296 ndbrequire(handle.getSection(dataPtr, 0));
17297 dataLen = dataPtr.sz;
17298
17299 SectionSegment * ptrP = dataPtr.p;
17300 while (dataLen > NDB_SECTION_SEGMENT_SZ)
17301 {
17302 errorCode = saveTRANSID_AI(signal, indexOp, &ptrP->theData[0],
17303 NDB_SECTION_SEGMENT_SZ);
17304 if (errorCode != ZOK)
17305 {
17306 releaseSections(handle);
17307 goto save_error;
17308 }
17309 dataLen -= NDB_SECTION_SEGMENT_SZ;
17310 ptrP = g_sectionSegmentPool.getPtr(ptrP->m_nextSegment);
17311 }
17312 errorCode = saveTRANSID_AI(signal, indexOp, &ptrP->theData[0], dataLen);
17313 if (errorCode != ZOK)
17314 {
17315 releaseSections(handle);
17316 goto save_error;
17317 }
17318
17319 releaseSections(handle);
17320 }
17321 else
17322 {
17323 /* Short TransId_AI signal */
17324 errorCode = saveTRANSID_AI(signal,
17325 indexOp,
17326 transIdAI->getData(),
17327 signal->getLength() - TransIdAI::HeaderLength);
17328 if (errorCode != ZOK) {
17329 save_error:
17330 jam();
17331 // Failed to allocate space for TransIdAI
17332 // Todo : How will this behave when transaction already aborted
17333 // in saveTRANSID_AI call?
17334 TcKeyRef * const tcIndxRef = (TcKeyRef *)signal->getDataPtrSend();
17335
17336 tcIndxRef->connectPtr = indexOp->tcIndxReq.senderData;
17337 tcIndxRef->transId[0] = regApiPtr->transid[0];
17338 tcIndxRef->transId[1] = regApiPtr->transid[1];
17339 tcIndxRef->errorCode = errorCode;
17340 tcIndxRef->errorData = 0;
17341 sendSignal(regApiPtr->ndbapiBlockref, GSN_TCINDXREF, signal,
17342 TcKeyRef::SignalLength, JBB);
17343 return;
17344 }
17345 }
17346
17347 switch(indexOp->indexOpState) {
17348 case(IOS_NOOP): {
17349 jam();
17350 // Should never happen, abort
17351 TcKeyRef * const tcIndxRef = (TcKeyRef *)signal->getDataPtrSend();
17352
17353 tcIndxRef->connectPtr = indexOp->tcIndxReq.senderData;
17354 tcIndxRef->transId[0] = regApiPtr->transid[0];
17355 tcIndxRef->transId[1] = regApiPtr->transid[1];
17356 tcIndxRef->errorCode = ZINCONSISTENT_INDEX_USE;
17357 tcIndxRef->errorData = 0;
17358 sendSignal(regApiPtr->ndbapiBlockref, GSN_TCINDXREF, signal,
17359 TcKeyRef::SignalLength, JBB);
17360 return;
17361 break;
17362 }
17363 case(IOS_INDEX_ACCESS): {
17364 jam();
17365 // Check if all TRANSID_AI have been received
17366 if (receivedAllTRANSID_AI(indexOp)) {
17367 jam();
17368 // Just waiting for a TCKEYCONF now
17369 indexOp->indexOpState = IOS_INDEX_ACCESS_WAIT_FOR_TCKEYCONF;
17370 }
17371 // else waiting for either TRANSID_AI or TCKEYCONF
17372 break;
17373 }
17374 case(IOS_INDEX_ACCESS_WAIT_FOR_TCKEYCONF): {
17375 jam();
17376 #ifdef VM_TRACE
17377 ndbout_c("Dbtc::execTRANSID_AI: Too many TRANSID_AI, ignore for now\n");
17378 #endif
17379 /*
17380 // Too many TRANSID_AI
17381 TcKeyRef * const tcIndxRef = (TcKeyRef *)signal->getDataPtrSend();
17382
17383 tcIndexRef->connectPtr = indexOp->tcIndxReq.senderData;
17384 tcIndxRef->transId[0] = regApiPtr->transid[0];
17385 tcIndxRef->transId[1] = regApiPtr->transid[1];
17386 tcIndxRef->errorCode = 4349;
17387 tcIndxRef->errorData = 0;
17388 sendSignal(regApiPtr->ndbapiBlockref, GSN_TCINDXREF, signal,
17389 TcKeyRef::SignalLength, JBB);
17390 */
17391 break;
17392 }
17393 case(IOS_INDEX_ACCESS_WAIT_FOR_TRANSID_AI): {
17394 jam();
17395 // Check if all TRANSID_AI have been received
17396 if (receivedAllTRANSID_AI(indexOp)) {
17397 jam();
17398 // Continue with index operation
17399 executeIndexOperation(signal, regApiPtr, indexOp);
17400 }
17401 // else continue waiting for more TRANSID_AI
17402 break;
17403 }
17404 }
17405 }
17406
execTCROLLBACKREP(Signal * signal)17407 void Dbtc::execTCROLLBACKREP(Signal* signal)
17408 {
17409 TcRollbackRep* tcRollbackRep = (TcRollbackRep *)signal->getDataPtr();
17410 jamEntry();
17411 TcIndexOperationPtr indexOpPtr;
17412 indexOpPtr.i = tcRollbackRep->connectPtr;
17413 TcIndexOperation* indexOp = c_theIndexOperationPool.getPtr(indexOpPtr.i);
17414 indexOpPtr.p = indexOp;
17415 tcRollbackRep = (TcRollbackRep *)signal->getDataPtrSend();
17416 tcRollbackRep->connectPtr = indexOp->tcIndxReq.senderData;
17417 sendSignal(apiConnectptr.p->ndbapiBlockref,
17418 GSN_TCROLLBACKREP, signal, TcRollbackRep::SignalLength, JBB);
17419 }
17420
17421 /**
17422 * Read index table with the index attributes as PK
17423 */
readIndexTable(Signal * signal,ApiConnectRecord * regApiPtr,TcIndexOperation * indexOp,Uint32 special_op_flags)17424 void Dbtc::readIndexTable(Signal* signal,
17425 ApiConnectRecord* regApiPtr,
17426 TcIndexOperation* indexOp,
17427 Uint32 special_op_flags)
17428 {
17429 TcKeyReq * const tcKeyReq = (TcKeyReq *)signal->getDataPtrSend();
17430 Uint32 tcKeyRequestInfo = indexOp->tcIndxReq.requestInfo;
17431 TcIndexData* indexData;
17432 Uint32 transId1 = indexOp->tcIndxReq.transId1;
17433 Uint32 transId2 = indexOp->tcIndxReq.transId2;
17434
17435 const Operation_t opType =
17436 (Operation_t)TcKeyReq::getOperationType(tcKeyRequestInfo);
17437
17438 // Find index table
17439 if ((indexData = c_theIndexes.getPtr(indexOp->tcIndxReq.tableId)) == NULL) {
17440 // TODO : Free KeyInfo and AttrInfo sections here if necessary
17441 // How is this operation cleaned up?
17442 jam();
17443 // Failed to find index record
17444 TcKeyRef * const tcIndxRef = (TcKeyRef *)signal->getDataPtrSend();
17445
17446 tcIndxRef->connectPtr = indexOp->tcIndxReq.senderData;
17447 tcIndxRef->transId[0] = regApiPtr->transid[0];
17448 tcIndxRef->transId[1] = regApiPtr->transid[1];
17449 tcIndxRef->errorCode = 4000;
17450 // tcIndxRef->errorData = ??; Where to find indexId
17451 sendSignal(regApiPtr->ndbapiBlockref, GSN_TCINDXREF, signal,
17452 TcKeyRef::SignalLength, JBB);
17453 return;
17454 }
17455 tcKeyReq->transId1 = transId1;
17456 tcKeyReq->transId2 = transId2;
17457 tcKeyReq->tableId = indexData->indexId;
17458 tcKeyReq->tableSchemaVersion = indexOp->tcIndxReq.tableSchemaVersion;
17459 TcKeyReq::setOperationType(tcKeyRequestInfo,
17460 opType == ZREAD ? ZREAD : ZREAD_EX);
17461 TcKeyReq::setAIInTcKeyReq(tcKeyRequestInfo, 0); // No AI in long TCKEYREQ
17462 TcKeyReq::setInterpretedFlag(tcKeyRequestInfo, 0);
17463 tcKeyReq->senderData = indexOp->indexOpId;
17464 indexOp->indexOpState = IOS_INDEX_ACCESS;
17465 regApiPtr->executingIndexOp = regApiPtr->accumulatingIndexOp;
17466 regApiPtr->accumulatingIndexOp = RNIL;
17467 regApiPtr->m_special_op_flags =
17468 TcConnectRecord::SOF_INDEX_TABLE_READ | special_op_flags;
17469
17470 if (ERROR_INSERTED(8037))
17471 {
17472 ndbout_c("shifting index version");
17473 tcKeyReq->tableSchemaVersion = ~(Uint32)indexOp->tcIndxReq.tableSchemaVersion;
17474 }
17475 tcKeyReq->attrLen = 1; // Primary key is stored as one attribute
17476 tcKeyReq->requestInfo = tcKeyRequestInfo;
17477
17478 ndbassert(TcKeyReq::getDirtyFlag(tcKeyRequestInfo) == 0);
17479 ndbassert(TcKeyReq::getSimpleFlag(tcKeyRequestInfo) == 0);
17480
17481 /* Long TCKEYREQ Signal sections
17482 * We attach the KeyInfo section received from the user, and
17483 * create a new AttrInfo section with just one AttributeHeader
17484 * to retrieve the base table primary key
17485 */
17486 Ptr<SectionSegment> indexLookupAttrInfoSection;
17487 Uint32 singleAIWord;
17488
17489 AttributeHeader::init(&singleAIWord, indexData->primaryKeyPos, 0);
17490 if (! import(indexLookupAttrInfoSection,
17491 &singleAIWord,
17492 1))
17493 {
17494 jam();
17495 /* Error creating AttrInfo section to request primary
17496 * key from index table.
17497 */
17498 // TODO - verify error handling
17499 #ifdef VM_TRACE
17500 ndbout_c("Dbtc::readIndexTable: Failed to create AttrInfo section");
17501 #endif
17502 apiConnectptr.i = indexOp->connectionIndex;
17503 ptrCheckGuard(apiConnectptr, capiConnectFilesize, apiConnectRecord);
17504 releaseIndexOperation(apiConnectptr.p, indexOp);
17505 terrorCode = 4000;
17506 abortErrorLab(signal);
17507 return;
17508 }
17509
17510 ndbassert(signal->header.m_noOfSections == 0);
17511
17512 signal->m_sectionPtrI[ TcKeyReq::KeyInfoSectionNum ]
17513 = indexOp->keyInfoSectionIVal;
17514
17515 /* We pass this section to TCKEYREQ next */
17516 indexOp->keyInfoSectionIVal= RNIL;
17517
17518 signal->m_sectionPtrI[ TcKeyReq::AttrInfoSectionNum ]
17519 = indexLookupAttrInfoSection.i;
17520 signal->header.m_noOfSections= 2;
17521
17522 /* Direct execute of long TCKEYREQ
17523 * TCKEYREQ is responsible for freeing the KeyInfo and
17524 * AttrInfo sections passed to it
17525 */
17526 EXECUTE_DIRECT(DBTC, GSN_TCKEYREQ, signal, TcKeyReq::StaticLength);
17527 jamEntry();
17528
17529 if (unlikely(regApiPtr->apiConnectstate == CS_ABORTING))
17530 {
17531 jam();
17532 }
17533 else
17534 {
17535 jam();
17536 /**
17537 * "Fool" TC not to start commiting transaction since it always will
17538 * have one outstanding lqhkeyreq
17539 * This is later decreased when the index read is complete
17540 */
17541 regApiPtr->lqhkeyreqrec++;
17542
17543 /**
17544 * Remember ptr to index read operation
17545 * (used to set correct save point id on index operation later)
17546 */
17547 indexOp->indexReadTcConnect = regApiPtr->lastTcConnect;
17548 }
17549
17550 return;
17551 }
17552
17553 /**
17554 * Execute the index operation with the result from
17555 * the index table read as PK
17556 */
executeIndexOperation(Signal * signal,ApiConnectRecord * regApiPtr,TcIndexOperation * indexOp)17557 void Dbtc::executeIndexOperation(Signal* signal,
17558 ApiConnectRecord* regApiPtr,
17559 TcIndexOperation* indexOp) {
17560
17561 TcKeyReq * const tcIndxReq = &indexOp->tcIndxReq;
17562 TcKeyReq * const tcKeyReq = (TcKeyReq *)signal->getDataPtrSend();
17563 Uint32 tcKeyRequestInfo = tcIndxReq->requestInfo;
17564 TcIndexData* indexData;
17565
17566 // Find index table
17567 if ((indexData = c_theIndexes.getPtr(tcIndxReq->tableId)) == NULL) {
17568 jam();
17569 // Failed to find index record
17570 // TODO : How is this operation cleaned up?
17571 TcKeyRef * const tcIndxRef = (TcKeyRef *)signal->getDataPtrSend();
17572
17573 tcIndxRef->connectPtr = indexOp->tcIndxReq.senderData;
17574 tcIndxRef->transId[0] = regApiPtr->transid[0];
17575 tcIndxRef->transId[1] = regApiPtr->transid[1];
17576 tcIndxRef->errorCode = ZINCONSISTENT_INDEX_USE;
17577 tcIndxRef->errorData = 0;
17578 sendSignal(regApiPtr->ndbapiBlockref, GSN_TCINDXREF, signal,
17579 TcKeyRef::SignalLength, JBB);
17580 return;
17581 }
17582
17583 // Find schema version of primary table
17584 TableRecordPtr tabPtr;
17585 tabPtr.i = indexData->primaryTableId;
17586 ptrCheckGuard(tabPtr, ctabrecFilesize, tableRecord);
17587
17588 tcKeyReq->apiConnectPtr = tcIndxReq->apiConnectPtr;
17589 tcKeyReq->attrLen = tcIndxReq->attrLen;
17590 tcKeyReq->tableId = indexData->primaryTableId;
17591 tcKeyReq->tableSchemaVersion = tabPtr.p->currentSchemaVersion;
17592 tcKeyReq->transId1 = regApiPtr->transid[0];
17593 tcKeyReq->transId2 = regApiPtr->transid[1];
17594 tcKeyReq->senderData = tcIndxReq->senderData; // Needed for TRANSID_AI to API
17595
17596 if (tabPtr.p->get_user_defined_partitioning())
17597 {
17598 jam();
17599 tcKeyReq->scanInfo = indexOp->fragmentId; // As read from Index table
17600 TcKeyReq::setDistributionKeyFlag(tcKeyRequestInfo, 1U);
17601 }
17602 regApiPtr->m_special_op_flags = 0;
17603 regApiPtr->executingIndexOp = 0;
17604
17605 /* KeyInfo section
17606 * Get the KeyInfo we received from the index table lookup
17607 */
17608 SegmentedSectionPtr keyInfoFromTransIdAI;
17609
17610 ndbassert( indexOp->transIdAISectionIVal != RNIL );
17611 getSection(keyInfoFromTransIdAI, indexOp->transIdAISectionIVal);
17612
17613 ndbassert( signal->header.m_noOfSections == 0 );
17614 signal->m_sectionPtrI[ TcKeyReq::KeyInfoSectionNum ]
17615 = indexOp->transIdAISectionIVal;
17616 signal->header.m_noOfSections = 1;
17617
17618 indexOp->transIdAISectionIVal = RNIL;
17619
17620 /* AttrInfo section
17621 * Attach any AttrInfo section from original TCINDXREQ
17622 */
17623 if ( indexOp->attrInfoSectionIVal != RNIL )
17624 {
17625 jam();
17626 SegmentedSectionPtr attrInfoFromInitialReq;
17627
17628 getSection(attrInfoFromInitialReq, indexOp->attrInfoSectionIVal);
17629 signal->m_sectionPtrI[ TcKeyReq::AttrInfoSectionNum ]
17630 = indexOp->attrInfoSectionIVal;
17631 signal->header.m_noOfSections = 2;
17632 indexOp->attrInfoSectionIVal = RNIL;
17633 }
17634
17635 releaseIndexOperation(regApiPtr, indexOp);
17636
17637 TcKeyReq::setKeyLength(tcKeyRequestInfo, keyInfoFromTransIdAI.sz);
17638 TcKeyReq::setAIInTcKeyReq(tcKeyRequestInfo, 0);
17639 TcKeyReq::setCommitFlag(tcKeyRequestInfo, 0);
17640 TcKeyReq::setExecuteFlag(tcKeyRequestInfo, 0);
17641 tcKeyReq->requestInfo = tcKeyRequestInfo;
17642
17643 ndbassert(TcKeyReq::getDirtyFlag(tcKeyRequestInfo) == 0);
17644 ndbassert(TcKeyReq::getSimpleFlag(tcKeyRequestInfo) == 0);
17645
17646 /**
17647 * Decrease lqhkeyreqrec to compensate for addition
17648 * during read of index table
17649 * I.e. let TC start committing when other operations has completed
17650 */
17651 regApiPtr->lqhkeyreqrec--;
17652
17653 /**
17654 * Fix savepoint id -
17655 * fix so that index operation has the same savepoint id
17656 * as the read of the index table (TCINDXREQ)
17657 */
17658 TcConnectRecordPtr tmp;
17659 tmp.i = indexOp->indexReadTcConnect;
17660 ptrCheckGuard(tmp, ctcConnectFilesize, tcConnectRecord);
17661 const Uint32 currSavePointId = regApiPtr->currSavePointId;
17662 const Uint32 triggeringOp = tmp.p->triggeringOperation;
17663 const Uint32 triggerId = tmp.p->currentTriggerId;
17664 regApiPtr->currSavePointId = tmp.p->savePointId;
17665
17666 #ifdef ERROR_INSERT
17667 bool err8072 = ERROR_INSERTED(8072);
17668 if (err8072)
17669 {
17670 CLEAR_ERROR_INSERT_VALUE;
17671 }
17672 #endif
17673
17674 if (triggeringOp != RNIL)
17675 {
17676 jam();
17677 /**
17678 * Carry forward info that this was caused by trigger
17679 * (used by FK)
17680 */
17681 ndbassert(triggerId != RNIL);
17682 ndbassert(tcIndxReq->senderData == triggeringOp);
17683 regApiPtr->m_special_op_flags = TcConnectRecord::SOF_TRIGGER;
17684 regApiPtr->immediateTriggerId = triggerId;
17685 }
17686
17687 /* Execute TCKEYREQ now - it is now responsible for freeing
17688 * the KeyInfo and AttrInfo sections
17689 */
17690 EXECUTE_DIRECT(DBTC, GSN_TCKEYREQ, signal, TcKeyReq::StaticLength);
17691 jamEntry();
17692
17693 #ifdef ERROR_INSERT
17694 if (err8072)
17695 {
17696 SET_ERROR_INSERT_VALUE(8072);
17697 }
17698 #endif
17699
17700 if (unlikely(regApiPtr->apiConnectstate == CS_ABORTING))
17701 {
17702 // TODO : Presumably the abort cleans up the operation
17703 jam();
17704 return;
17705 }
17706
17707 regApiPtr->currSavePointId = currSavePointId;
17708 regApiPtr->immediateTriggerId = RNIL;
17709 }
17710
seizeIndexOperation(ApiConnectRecord * regApiPtr,TcIndexOperationPtr & indexOpPtr)17711 bool Dbtc::seizeIndexOperation(ApiConnectRecord* regApiPtr,
17712 TcIndexOperationPtr& indexOpPtr)
17713 {
17714 if (regApiPtr->theSeizedIndexOperations.seizeFirst(indexOpPtr))
17715 {
17716 jam();
17717 ndbassert(indexOpPtr.p->pendingKeyInfo == 0);
17718 ndbassert(indexOpPtr.p->keyInfoSectionIVal == RNIL);
17719 ndbassert(indexOpPtr.p->pendingAttrInfo == 0);
17720 ndbassert(indexOpPtr.p->attrInfoSectionIVal == RNIL);
17721 ndbassert(indexOpPtr.p->transIdAIState == ITAS_WAIT_HEADER);
17722 ndbassert(indexOpPtr.p->pendingTransIdAI == 0);
17723 ndbassert(indexOpPtr.p->transIdAISectionIVal == RNIL);
17724 return true;
17725 }
17726 jam();
17727 return false;
17728 }
17729
releaseIndexOperation(ApiConnectRecord * regApiPtr,TcIndexOperation * indexOp)17730 void Dbtc::releaseIndexOperation(ApiConnectRecord* regApiPtr,
17731 TcIndexOperation* indexOp)
17732 {
17733 indexOp->indexOpState = IOS_NOOP;
17734 indexOp->pendingKeyInfo = 0;
17735 releaseSection(indexOp->keyInfoSectionIVal);
17736 indexOp->keyInfoSectionIVal= RNIL;
17737 indexOp->pendingAttrInfo = 0;
17738 releaseSection(indexOp->attrInfoSectionIVal);
17739 indexOp->attrInfoSectionIVal= RNIL;
17740 indexOp->transIdAIState = ITAS_WAIT_HEADER;
17741 indexOp->pendingTransIdAI = 0;
17742 releaseSection(indexOp->transIdAISectionIVal);
17743 indexOp->transIdAISectionIVal= RNIL;
17744 regApiPtr->theSeizedIndexOperations.release(indexOp->indexOpId);
17745 }
17746
releaseAllSeizedIndexOperations(ApiConnectRecord * regApiPtr)17747 void Dbtc::releaseAllSeizedIndexOperations(ApiConnectRecord* regApiPtr)
17748 {
17749 TcIndexOperationPtr seizedIndexOpPtr;
17750
17751 regApiPtr->theSeizedIndexOperations.first(seizedIndexOpPtr);
17752 while(seizedIndexOpPtr.i != RNIL) {
17753 jam();
17754 TcIndexOperation* indexOp = seizedIndexOpPtr.p;
17755
17756 indexOp->indexOpState = IOS_NOOP;
17757 indexOp->pendingKeyInfo = 0;
17758 releaseSection(indexOp->keyInfoSectionIVal);
17759 indexOp->keyInfoSectionIVal = RNIL;
17760 indexOp->pendingAttrInfo = 0;
17761 releaseSection(indexOp->attrInfoSectionIVal);
17762 indexOp->attrInfoSectionIVal = RNIL;
17763 indexOp->transIdAIState = ITAS_WAIT_HEADER;
17764 indexOp->pendingTransIdAI = 0;
17765 releaseSection(indexOp->transIdAISectionIVal);
17766 indexOp->transIdAISectionIVal = RNIL;
17767 regApiPtr->theSeizedIndexOperations.next(seizedIndexOpPtr);
17768 }
17769 jam();
17770 while (regApiPtr->theSeizedIndexOperations.releaseFirst())
17771 {
17772 ;
17773 }
17774 jam();
17775 }
17776
saveTriggeringOpState(Signal * signal,TcConnectRecord * trigOp)17777 void Dbtc::saveTriggeringOpState(Signal* signal, TcConnectRecord* trigOp)
17778 {
17779 LqhKeyConf * lqhKeyConf = (LqhKeyConf *)signal->getDataPtr();
17780 copyFromToLen((UintR*)lqhKeyConf,
17781 &trigOp->savedState[0],
17782 LqhKeyConf::SignalLength);
17783 }
17784
17785 void
trigger_op_finished(Signal * signal,ApiConnectRecordPtr regApiPtr,Uint32 trigPtrI,TcConnectRecord * triggeringOp,Uint32 errCode)17786 Dbtc::trigger_op_finished(Signal* signal,
17787 ApiConnectRecordPtr regApiPtr,
17788 Uint32 trigPtrI,
17789 TcConnectRecord* triggeringOp,
17790 Uint32 errCode)
17791 {
17792 if (trigPtrI != RNIL)
17793 {
17794 jam();
17795 Ptr<TcDefinedTriggerData> trigPtr;
17796 c_theDefinedTriggers.getPtr(trigPtr, trigPtrI);
17797 switch(trigPtr.p->triggerType){
17798 case TriggerType::FK_PARENT:
17799 {
17800 if (errCode == ZNOT_FOUND)
17801 {
17802 jam();
17803 break; // good!
17804 }
17805
17806 Ptr<TcFKData> fkPtr;
17807 // TODO make it a pool.getPtr() instead
17808 // by also adding fk_ptr_i to definedTriggerData
17809 ndbrequire(c_fk_hash.find(fkPtr, trigPtr.p->fkId));
17810 if (errCode == 0 && ((fkPtr.p->bits&CreateFKImplReq::FK_ON_ACTION) == 0))
17811 {
17812 jam();
17813 // Only restrict
17814 terrorCode = ZFK_CHILD_ROW_EXISTS;
17815 }
17816 else if (errCode == 0)
17817 {
17818 /**
17819 * Check action performed against expected result...
17820 */
17821 if (triggeringOp->operation == ZDELETE &&
17822 (fkPtr.p->bits & CreateFKImplReq::FK_DELETE_ACTION))
17823 {
17824 jam();
17825 // the on action succeeded, good!
17826 break;
17827 }
17828 else if ((triggeringOp->operation == ZUPDATE || triggeringOp->operation == ZWRITE) &&
17829 (fkPtr.p->bits & CreateFKImplReq::FK_UPDATE_ACTION))
17830 {
17831 jam();
17832 // the on action succeeded, good!
17833 break;
17834 }
17835 jam();
17836 terrorCode = ZFK_CHILD_ROW_EXISTS;
17837 }
17838 else
17839 {
17840 jam();
17841 jamLine(errCode);
17842 terrorCode = errCode;
17843 }
17844 apiConnectptr = regApiPtr;
17845 abortErrorLab(signal);
17846 return;
17847 }
17848 default:
17849 (void)1;
17850 }
17851 }
17852 if (!regApiPtr.p->isExecutingDeferredTriggers())
17853 {
17854 jam();
17855 if (unlikely((triggeringOp->triggerExecutionCount == 0)))
17856 {
17857 printf("%u : 0x%x->triggerExecutionCount == 0\n",
17858 __LINE__,
17859 Uint32(triggeringOp - this->tcConnectRecord));
17860 dump_trans(regApiPtr);
17861 }
17862 ndbrequire(triggeringOp->triggerExecutionCount > 0);
17863 triggeringOp->triggerExecutionCount--;
17864 if (triggeringOp->triggerExecutionCount == 0)
17865 {
17866 /**
17867 * We have completed current trigger execution
17868 * Continue triggering operation
17869 */
17870 jam();
17871 continueTriggeringOp(signal, triggeringOp);
17872 }
17873 }
17874 else
17875 {
17876 jam();
17877 lqhKeyConf_checkTransactionState(signal, regApiPtr);
17878 }
17879 }
17880
continueTriggeringOp(Signal * signal,TcConnectRecord * trigOp)17881 void Dbtc::continueTriggeringOp(Signal* signal, TcConnectRecord* trigOp)
17882 {
17883 LqhKeyConf * lqhKeyConf = (LqhKeyConf *)signal->getDataPtr();
17884 copyFromToLen(&trigOp->savedState[0],
17885 (UintR*)lqhKeyConf,
17886 LqhKeyConf::SignalLength);
17887
17888 ndbassert(trigOp->savedState[LqhKeyConf::SignalLength-1] != ~Uint32(0));
17889 trigOp->savedState[LqhKeyConf::SignalLength-1] = ~Uint32(0);
17890
17891 lqhKeyConf->numFiredTriggers = 0;
17892 trigOp->numReceivedTriggers = 0;
17893
17894 /**
17895 * All triggers executed successfully, continue operation
17896 *
17897 * We have to be careful here not sending too many direct signals in a row.
17898 * This has two consequences, first we are breaking the coding rules if we
17899 * do and thus other signals have a hard time to get their piece of the
17900 * CPU.
17901 * Secondly we can easily run out of stack which can cause all sorts of
17902 * weird errors. We cannot allow any type of completely recursive behaviour
17903 * in the NDB code.
17904 */
17905 c_lqhkeyconf_direct_sent++;
17906 if (c_lqhkeyconf_direct_sent <= 5)
17907 {
17908 jam();
17909 execLQHKEYCONF(signal);
17910 }
17911 else
17912 {
17913 jam();
17914 c_lqhkeyconf_direct_sent = 0;
17915 sendSignal(reference(),
17916 GSN_LQHKEYCONF,
17917 signal,
17918 LqhKeyConf::SignalLength,
17919 JBB);
17920 }
17921 }
17922
executeTriggers(Signal * signal,ApiConnectRecordPtr * transPtr)17923 void Dbtc::executeTriggers(Signal* signal, ApiConnectRecordPtr* transPtr)
17924 {
17925 ApiConnectRecord* regApiPtr = transPtr->p;
17926 TcConnectRecord *localTcConnectRecord = tcConnectRecord;
17927 TcConnectRecordPtr opPtr;
17928 FiredTriggerPtr trigPtr;
17929
17930 if (!regApiPtr->theFiredTriggers.isEmpty()) {
17931 jam();
17932 if ((regApiPtr->apiConnectstate == CS_STARTED) ||
17933 (regApiPtr->apiConnectstate == CS_START_COMMITTING) ||
17934 (regApiPtr->apiConnectstate == CS_SEND_FIRE_TRIG_REQ) ||
17935 (regApiPtr->apiConnectstate == CS_WAIT_FIRE_TRIG_REQ))
17936 {
17937 jam();
17938 regApiPtr->theFiredTriggers.first(trigPtr);
17939 while (trigPtr.i != RNIL) {
17940 jam();
17941 if (regApiPtr->cascading_scans_count >=
17942 MaxCascadingScansPerTransaction)
17943 {
17944 jam();
17945 D("trans: cascading scans " << regApiPtr->cascading_scans_count);
17946 waitToExecutePendingTrigger(signal, *transPtr);
17947 // pause all trigger execution
17948 break;
17949 }
17950 // Execute all ready triggers in parallel
17951 opPtr.i = trigPtr.p->fireingOperation;
17952 ptrCheckGuard(opPtr, ctcConnectFilesize, localTcConnectRecord);
17953 FiredTriggerPtr nextTrigPtr = trigPtr;
17954 regApiPtr->theFiredTriggers.next(nextTrigPtr);
17955 ndbrequire(opPtr.p->apiConnect == transPtr->i);
17956 if (opPtr.p->numReceivedTriggers == opPtr.p->numFiredTriggers ||
17957 regApiPtr->isExecutingDeferredTriggers()) {
17958 jam();
17959 // Fireing operation is ready to have a trigger executing
17960 executeTrigger(signal, trigPtr.p, transPtr, &opPtr);
17961 // Should allow for interleaving here by sending a CONTINUEB and
17962 // return
17963 // Release trigger records
17964 AttributeBuffer::DataBufferPool & pool = c_theAttributeBufferPool;
17965 LocalDataBuffer<11> tmp1(pool, trigPtr.p->keyValues);
17966 tmp1.release();
17967 LocalDataBuffer<11> tmp2(pool, trigPtr.p->beforeValues);
17968 tmp2.release();
17969 LocalDataBuffer<11> tmp3(pool, trigPtr.p->afterValues);
17970 tmp3.release();
17971 regApiPtr->theFiredTriggers.release(trigPtr);
17972 }
17973 trigPtr = nextTrigPtr;
17974 }
17975 return;
17976 // No more triggers, continue transaction after last executed trigger has
17977 // reurned (in execLQHKEYCONF or execLQHKEYREF)
17978 } else {
17979
17980 jam();
17981 /* Not in correct state to fire triggers yet, need to wait
17982 * (or keep waiting)
17983 */
17984
17985 if ((regApiPtr->apiConnectstate == CS_RECEIVING) ||
17986 (regApiPtr->apiConnectstate == CS_REC_COMMITTING))
17987 {
17988 // Wait until transaction is ready to execute a trigger
17989 jam();
17990 D("trans: apiConnectstate " << regApiPtr->apiConnectstate);
17991 waitToExecutePendingTrigger(signal, *transPtr);
17992 }
17993 else
17994 {
17995 /* Transaction has started aborting.
17996 * Forget about unprocessed triggers
17997 */
17998 ndbrequire(regApiPtr->apiConnectstate == CS_ABORTING);
17999 }
18000 }
18001 }
18002 }
18003
18004 void
waitToExecutePendingTrigger(Signal * signal,ApiConnectRecordPtr transPtr)18005 Dbtc::waitToExecutePendingTrigger(Signal* signal, ApiConnectRecordPtr transPtr)
18006 {
18007 if (!tc_testbit(transPtr.p->m_flags,
18008 ApiConnectRecord::TF_TRIGGER_PENDING))
18009 {
18010 jam();
18011 D("trans: send trigger pending");
18012 c_lqhkeyconf_direct_sent = 0;
18013 transPtr.p->m_flags |= ApiConnectRecord::TF_TRIGGER_PENDING;
18014 signal->theData[0] = TcContinueB::TRIGGER_PENDING;
18015 signal->theData[1] = transPtr.i;
18016 signal->theData[2] = transPtr.p->transid[0];
18017 signal->theData[3] = transPtr.p->transid[1];
18018 sendSignal(reference(), GSN_CONTINUEB, signal, 4, JBB);
18019 }
18020 else
18021 {
18022 // We are already waiting for a pending trigger (CONTINUEB)
18023 D("trans: trigger pending already");
18024 }
18025 }
18026
executeTrigger(Signal * signal,TcFiredTriggerData * firedTriggerData,ApiConnectRecordPtr * transPtr,TcConnectRecordPtr * opPtr)18027 void Dbtc::executeTrigger(Signal* signal,
18028 TcFiredTriggerData* firedTriggerData,
18029 ApiConnectRecordPtr* transPtr,
18030 TcConnectRecordPtr* opPtr)
18031 {
18032 TcDefinedTriggerData* definedTriggerData;
18033
18034 if ((definedTriggerData =
18035 c_theDefinedTriggers.getPtr(firedTriggerData->triggerId))
18036 != NULL)
18037 {
18038 transPtr->p->pendingTriggers--;
18039 switch(firedTriggerData->triggerType) {
18040 case(TriggerType::SECONDARY_INDEX):
18041 jam();
18042 executeIndexTrigger(signal, definedTriggerData, firedTriggerData,
18043 transPtr, opPtr);
18044 break;
18045 case TriggerType::REORG_TRIGGER:
18046 jam();
18047 executeReorgTrigger(signal, definedTriggerData, firedTriggerData,
18048 transPtr, opPtr);
18049 break;
18050 case TriggerType::FK_PARENT:
18051 jam();
18052 executeFKParentTrigger(signal, definedTriggerData, firedTriggerData,
18053 transPtr, opPtr);
18054 break;
18055 case TriggerType::FK_CHILD:
18056 jam();
18057 executeFKChildTrigger(signal, definedTriggerData, firedTriggerData,
18058 transPtr, opPtr);
18059 break;
18060 default:
18061 ndbrequire(false);
18062 }
18063 }
18064 }
18065
executeIndexTrigger(Signal * signal,TcDefinedTriggerData * definedTriggerData,TcFiredTriggerData * firedTriggerData,ApiConnectRecordPtr * transPtr,TcConnectRecordPtr * opPtr)18066 void Dbtc::executeIndexTrigger(Signal* signal,
18067 TcDefinedTriggerData* definedTriggerData,
18068 TcFiredTriggerData* firedTriggerData,
18069 ApiConnectRecordPtr* transPtr,
18070 TcConnectRecordPtr* opPtr)
18071 {
18072 TcIndexData* indexData = c_theIndexes.getPtr(definedTriggerData->indexId);
18073 ndbassert(indexData != NULL);
18074
18075 switch (firedTriggerData->triggerEvent) {
18076 case(TriggerEvent::TE_INSERT): {
18077 jam();
18078 insertIntoIndexTable(signal, firedTriggerData, transPtr, opPtr, indexData);
18079 break;
18080 }
18081 case(TriggerEvent::TE_DELETE): {
18082 jam();
18083 deleteFromIndexTable(signal, firedTriggerData, transPtr, opPtr, indexData);
18084 break;
18085 }
18086 case(TriggerEvent::TE_UPDATE): {
18087 jam();
18088 opPtr->p->triggerExecutionCount++; // One is already added...and this is 2
18089 deleteFromIndexTable(signal, firedTriggerData, transPtr, opPtr, indexData);
18090 insertIntoIndexTable(signal, firedTriggerData, transPtr, opPtr, indexData);
18091 break;
18092 }
18093 default:
18094 ndbrequire(false);
18095 }
18096 }
18097
18098 Uint32
fk_constructAttrInfoSetNull(const TcFKData * fkPtrP)18099 Dbtc::fk_constructAttrInfoSetNull(const TcFKData * fkPtrP)
18100 {
18101 Uint32 attrInfo[MAX_ATTRIBUTES_IN_INDEX];
18102 for (Uint32 i = 0; i<fkPtrP->childTableColumns.sz; i++)
18103 {
18104 AttributeHeader::init(attrInfo + i, fkPtrP->childTableColumns.id[i],
18105 0 /* setNull */);
18106 }
18107
18108 Uint32 tmp = RNIL;
18109 if (ERROR_INSERTED(8106))
18110 {
18111 return tmp;
18112 }
18113
18114 appendToSection(tmp, attrInfo, fkPtrP->childTableColumns.sz);
18115 return tmp;
18116 }
18117
18118 Uint32
fk_constructAttrInfoUpdateCascade(const TcFKData * fkPtrP,DataBuffer<11>::Head & srchead)18119 Dbtc::fk_constructAttrInfoUpdateCascade(const TcFKData * fkPtrP,
18120 DataBuffer<11>::Head & srchead)
18121 {
18122 Uint32 tmp = RNIL;
18123 if (ERROR_INSERTED(8103))
18124 {
18125 return tmp;
18126 }
18127
18128 /**
18129 * Construct an update based on the src-data
18130 *
18131 * NOTE: this assumes same order...
18132 */
18133 Uint32 pos = 0;
18134 AttributeBuffer::DataBufferIterator iter;
18135 LocalDataBuffer<11> src(c_theAttributeBufferPool, srchead);
18136 bool moreData= src.first(iter);
18137 const Uint32 segSize= src.getSegmentSize(); // 11
18138
18139 while (moreData)
18140 {
18141 AttributeHeader* attrHeader = (AttributeHeader *) iter.data;
18142 Uint32 dataSize = attrHeader->getDataSize();
18143
18144 AttributeHeader ah(*iter.data);
18145 ah.setAttributeId(fkPtrP->childTableColumns.id[pos++]);// Renumber AttrIds
18146 if (unlikely(!appendToSection(tmp, &ah.m_value, 1)))
18147 {
18148 releaseSection(tmp);
18149 return RNIL;
18150 }
18151
18152 moreData = src.next(iter, 1);
18153 while (dataSize)
18154 {
18155 ndbrequire(moreData);
18156 /* Copy as many contiguous words as possible */
18157 Uint32 contigLeft = segSize - iter.ind;
18158 ndbassert(contigLeft);
18159 Uint32 contigValid = MIN(dataSize, contigLeft);
18160
18161 if (unlikely(!appendToSection(tmp, iter.data, contigValid)))
18162 {
18163 releaseSection(tmp);
18164 return RNIL;
18165 }
18166 moreData = src.next(iter, contigValid);
18167 dataSize -= contigValid;
18168 }
18169 }
18170
18171 return tmp;
18172 }
18173
18174 void
executeFKParentTrigger(Signal * signal,TcDefinedTriggerData * definedTriggerData,TcFiredTriggerData * firedTriggerData,ApiConnectRecordPtr * transPtr,TcConnectRecordPtr * opPtr)18175 Dbtc::executeFKParentTrigger(Signal* signal,
18176 TcDefinedTriggerData* definedTriggerData,
18177 TcFiredTriggerData* firedTriggerData,
18178 ApiConnectRecordPtr* transPtr,
18179 TcConnectRecordPtr* opPtr)
18180 {
18181 Ptr<TcFKData> fkPtr;
18182 // TODO make it a pool.getPtr() instead
18183 // by also adding fk_ptr_i to definedTriggerData
18184 ndbrequire(c_fk_hash.find(fkPtr, definedTriggerData->fkId));
18185
18186 switch (firedTriggerData->triggerEvent) {
18187 case(TriggerEvent::TE_DELETE):
18188 jam();
18189 /**
18190 * Check that before values does not exist in child-table
18191 */
18192 break;
18193 case(TriggerEvent::TE_UPDATE):
18194 jam();
18195 /**
18196 * Check that before values does not exist in child-table
18197 */
18198 break;
18199 default:
18200 ndbrequire(false);
18201 }
18202
18203 Uint32 op = ZREAD;
18204 Uint32 attrValuesPtrI = RNIL; // for cascascade update/setnull
18205 switch(firedTriggerData->triggerEvent){
18206 case TriggerEvent::TE_UPDATE:
18207 if (fkPtr.p->bits & CreateFKImplReq::FK_UPDATE_CASCADE)
18208 {
18209 jam();
18210 /**
18211 * Update child table with after values of parent
18212 */
18213 op = ZUPDATE;
18214 attrValuesPtrI =
18215 fk_constructAttrInfoUpdateCascade(fkPtr.p,
18216 firedTriggerData->afterValues);
18217
18218 if (unlikely(attrValuesPtrI == RNIL))
18219 goto oom;
18220 }
18221 else if (fkPtr.p->bits & CreateFKImplReq::FK_UPDATE_SET_NULL)
18222 {
18223 jam();
18224 /**
18225 * Update child table set null
18226 */
18227 goto setnull;
18228 }
18229 break;
18230 case TriggerEvent::TE_DELETE:
18231 if (fkPtr.p->bits & CreateFKImplReq::FK_DELETE_CASCADE)
18232 {
18233 jam();
18234 /**
18235 * Delete from child table
18236 */
18237 op = ZDELETE;
18238 }
18239 else if (fkPtr.p->bits & CreateFKImplReq::FK_DELETE_SET_NULL)
18240 {
18241 jam();
18242 /**
18243 * Update child table set null
18244 */
18245 goto setnull;
18246 }
18247 break;
18248 default:
18249 ndbrequire(false);
18250 setnull:{
18251 op = ZUPDATE;
18252 attrValuesPtrI = fk_constructAttrInfoSetNull(fkPtr.p);
18253 if (unlikely(attrValuesPtrI == RNIL))
18254 goto oom;
18255 }
18256 }
18257
18258 if (! (fkPtr.p->bits & CreateFKImplReq::FK_CHILD_OI))
18259 {
18260 jam();
18261 fk_readFromChildTable(signal, firedTriggerData, transPtr, opPtr,
18262 fkPtr.p, op, attrValuesPtrI);
18263 }
18264 else
18265 {
18266 jam();
18267 fk_scanFromChildTable(signal, firedTriggerData, transPtr, opPtr,
18268 fkPtr.p, op, attrValuesPtrI);
18269 }
18270 return;
18271 oom:
18272 abortTransFromTrigger(signal, *transPtr, ZGET_DATAREC_ERROR);
18273 }
18274
18275 void
fk_readFromChildTable(Signal * signal,TcFiredTriggerData * firedTriggerData,ApiConnectRecordPtr * transPtr,TcConnectRecordPtr * opPtr,TcFKData * fkData,Uint32 op,Uint32 attrValuesPtrI)18276 Dbtc::fk_readFromChildTable(Signal* signal,
18277 TcFiredTriggerData* firedTriggerData,
18278 ApiConnectRecordPtr* transPtr,
18279 TcConnectRecordPtr* opPtr,
18280 TcFKData* fkData,
18281 Uint32 op,
18282 Uint32 attrValuesPtrI)
18283 {
18284 ApiConnectRecord* regApiPtr = transPtr->p;
18285 TcConnectRecord* opRecord = opPtr->p;
18286 TcKeyReq * const tcKeyReq = (TcKeyReq *)signal->getDataPtrSend();
18287 Uint32 tcKeyRequestInfo = 0;
18288 TableRecordPtr childIndexPtr;
18289
18290 childIndexPtr.i = fkData->childIndexId;
18291 ptrCheckGuard(childIndexPtr, ctabrecFilesize, tableRecord);
18292 tcKeyReq->apiConnectPtr = transPtr->i;
18293 tcKeyReq->senderData = opPtr->i;
18294
18295 // Calculate key length and renumber attribute id:s
18296 AttributeBuffer::DataBufferPool & pool = c_theAttributeBufferPool;
18297 LocalDataBuffer<11> beforeValues(pool, firedTriggerData->beforeValues);
18298
18299 SegmentedSectionGuard guard(this, attrValuesPtrI);
18300 if (beforeValues.getSize() == 0)
18301 {
18302 jam();
18303 ndbrequire(tc_testbit(regApiPtr->m_flags,
18304 ApiConnectRecord::TF_DEFERRED_CONSTRAINTS));
18305 trigger_op_finished(signal, *transPtr, RNIL, opRecord, 0);
18306 return;
18307 }
18308
18309 Uint32 keyIVal= RNIL;
18310 bool hasNull= false;
18311 Uint32 err = fk_buildKeyInfo(keyIVal, hasNull, beforeValues, fkData, false);
18312 guard.add(keyIVal);
18313 if (unlikely(err != 0))
18314 {
18315 abortTransFromTrigger(signal, *transPtr, err);
18316 return;
18317 }
18318
18319 /* If there's Nulls in the values that become the index table's
18320 * PK then we skip this delete
18321 */
18322 if (hasNull)
18323 {
18324 jam();
18325 trigger_op_finished(signal, *transPtr, RNIL, opRecord, 0);
18326 return;
18327 }
18328
18329 /**
18330 * Access child does never need lock...
18331 * as parent is read with lock
18332 */
18333 Uint16 flags = TcConnectRecord::SOF_TRIGGER;
18334 const Uint32 currSavePointId = regApiPtr->currSavePointId;
18335 Uint32 usedSavePointId = currSavePointId;
18336 Uint32 gsn = GSN_TCKEYREQ;
18337 if (op == ZREAD)
18338 {
18339 jam();
18340 flags |= TcConnectRecord::SOF_FK_READ_COMMITTED;
18341 TcKeyReq::setSimpleFlag(tcKeyRequestInfo, 1);
18342 }
18343 else
18344 {
18345 jam();
18346 /**
18347 * Let any DML be made with same save point
18348 * as original DML...but ZREAD reads latest
18349 */
18350 usedSavePointId = opRecord->savePointId;
18351 if (fkData->childTableId != fkData->childIndexId)
18352 {
18353 jam();
18354 gsn = GSN_TCINDXREQ;
18355 }
18356 }
18357 TcKeyReq::setKeyLength(tcKeyRequestInfo, 0);
18358 TcKeyReq::setAIInTcKeyReq(tcKeyRequestInfo, 0);
18359 tcKeyReq->attrLen = 0;
18360 tcKeyReq->tableId = childIndexPtr.i;
18361 TcKeyReq::setOperationType(tcKeyRequestInfo, op);
18362 tcKeyReq->tableSchemaVersion = childIndexPtr.p->currentSchemaVersion;
18363 tcKeyReq->transId1 = regApiPtr->transid[0];
18364 tcKeyReq->transId2 = regApiPtr->transid[1];
18365 tcKeyReq->requestInfo = tcKeyRequestInfo;
18366
18367 /* Attach KeyInfo section to signal */
18368 ndbrequire(signal->header.m_noOfSections == 0);
18369 signal->m_sectionPtrI[ TcKeyReq::KeyInfoSectionNum ] = keyIVal;
18370 signal->header.m_noOfSections = 1;
18371
18372 if (attrValuesPtrI != RNIL)
18373 {
18374 jam();
18375 signal->m_sectionPtrI[ TcKeyReq::AttrInfoSectionNum ] = attrValuesPtrI;
18376 signal->header.m_noOfSections = 2;
18377 }
18378
18379 guard.clear(); // now sections will be handled...
18380
18381 /**
18382 * Handle savepoint id - (see above)
18383 */
18384 regApiPtr->currSavePointId = usedSavePointId;
18385 regApiPtr->m_special_op_flags = flags;
18386 /* Pass trigger Id via ApiConnectRecord (nasty) */
18387 ndbrequire(regApiPtr->immediateTriggerId == RNIL);
18388 regApiPtr->immediateTriggerId= firedTriggerData->triggerId;
18389 if (gsn == GSN_TCKEYREQ)
18390 {
18391 EXECUTE_DIRECT(DBTC, GSN_TCKEYREQ, signal, TcKeyReq::StaticLength);
18392 }
18393 else
18394 {
18395 fk_execTCINDXREQ(signal, * transPtr, * opPtr, op);
18396 }
18397 jamEntry();
18398
18399 /*
18400 * Restore ApiConnectRecord state
18401 */
18402 regApiPtr->immediateTriggerId = RNIL;
18403 regApiPtr->currSavePointId = currSavePointId;
18404 }
18405
18406 void
fk_execTCINDXREQ(Signal * signal,ApiConnectRecordPtr transPtr,TcConnectRecordPtr opPtr,Uint32 operation)18407 Dbtc::fk_execTCINDXREQ(Signal* signal,
18408 ApiConnectRecordPtr transPtr,
18409 TcConnectRecordPtr opPtr,
18410 Uint32 operation)
18411 {
18412 jam();
18413 SectionHandle handle(this, signal);
18414 const TcKeyReq * tcIndxReq = CAST_CONSTPTR(TcKeyReq,
18415 signal->getDataPtr());
18416
18417 /**
18418 * this is a mockup of execTCINDXREQ...
18419 */
18420 TcIndexOperationPtr indexOpPtr;
18421 if (unlikely(!seizeIndexOperation(transPtr.p, indexOpPtr)))
18422 {
18423 releaseSections(handle);
18424 abortTransFromTrigger(signal, transPtr, 288);
18425 return;
18426 }
18427
18428 indexOpPtr.p->indexOpId = indexOpPtr.i;
18429
18430 // Save original signal
18431 indexOpPtr.p->tcIndxReq = *tcIndxReq;
18432 indexOpPtr.p->connectionIndex = transPtr.i;
18433 transPtr.p->accumulatingIndexOp = indexOpPtr.i;
18434
18435 /* KeyInfo and AttrInfo already received into sections */
18436 SegmentedSectionPtr keyInfoSection, attrInfoSection;
18437
18438 /* Store i value for first long section of KeyInfo
18439 * and AttrInfo in Index operation
18440 */
18441 handle.getSection(keyInfoSection, TcKeyReq::KeyInfoSectionNum);
18442 indexOpPtr.p->keyInfoSectionIVal = keyInfoSection.i;
18443
18444 if (handle.m_cnt == 2)
18445 {
18446 handle.getSection(attrInfoSection, TcKeyReq::AttrInfoSectionNum);
18447 indexOpPtr.p->attrInfoSectionIVal = attrInfoSection.i;
18448 }
18449
18450 /* Detach sections from the handle
18451 * Success path code, or index operation cleanup is
18452 * now responsible for freeing the sections
18453 */
18454 handle.clear();
18455
18456 /* All data received, process */
18457 readIndexTable(signal, transPtr.p, indexOpPtr.p,
18458 transPtr.p->m_special_op_flags);
18459
18460 if (unlikely(transPtr.p->apiConnectstate == CS_ABORTING))
18461 {
18462 jam();
18463 }
18464 else
18465 {
18466 /**
18467 * readIndexTable() sets senderData to indexOpPtr.i
18468 * and SOF_TRIGGER assumes triggerOperation is stored in senderData
18469 * so set it correct afterwards...
18470 */
18471 jam();
18472 TcConnectRecordPtr tcPtr;
18473 tcPtr.i = indexOpPtr.p->indexReadTcConnect;
18474 ptrCheckGuard(tcPtr, ctcConnectFilesize, tcConnectRecord);
18475 tcPtr.p->triggeringOperation = opPtr.i;
18476 ndbrequire(hasOp(transPtr, opPtr.i));
18477 }
18478 return;
18479 }
18480
18481 Uint32
fk_buildKeyInfo(Uint32 & keyIVal,bool & hasNull,LocalDataBuffer<11> & values,TcFKData * fkPtrP,bool parent)18482 Dbtc::fk_buildKeyInfo(Uint32& keyIVal, bool& hasNull,
18483 LocalDataBuffer<11> & values,
18484 TcFKData * fkPtrP,
18485 bool parent)
18486 {
18487 if (ERROR_INSERTED(8104))
18488 {
18489 return ZGET_DATAREC_ERROR;
18490 }
18491
18492 IndexAttributeList * list = 0;
18493 if (parent == true)
18494 {
18495 jam();
18496 list = &fkPtrP->childTableColumns;
18497 }
18498 else
18499 {
18500 jam();
18501 list = &fkPtrP->parentTableColumns;
18502 }
18503
18504 AttributeBuffer::DataBufferIterator iter;
18505 bool eof = !values.first(iter);
18506 for (Uint32 i = 0; i < list->sz; i++)
18507 {
18508 Uint32 col = list->id[i];
18509 if (!eof && AttributeHeader(* iter.data).getAttributeId() == col)
18510 {
18511 found:
18512 Uint32 len = AttributeHeader(* iter.data).getDataSize();
18513 if (len == 0)
18514 {
18515 hasNull = true;
18516 return 0;
18517 }
18518 eof = !values.next(iter);
18519 Uint32 err = appendDataToSection(keyIVal, values, iter,
18520 len);
18521 if (unlikely(err != 0))
18522 return err;
18523
18524 eof = iter.isNull();
18525 }
18526 else
18527 {
18528 /**
18529 * Search for column...
18530 */
18531 eof = !values.first(iter);
18532 while (!eof && AttributeHeader(* iter.data).getAttributeId() != col)
18533 {
18534 eof = !values.next(iter,
18535 1 + AttributeHeader(* iter.data).getDataSize());
18536 }
18537 if (unlikely(eof))
18538 {
18539 return ZMISSING_TRIGGER_DATA;
18540 }
18541 ndbassert(AttributeHeader(* iter.data).getAttributeId() == col);
18542 goto found;
18543 }
18544 }
18545
18546 return 0;
18547 }
18548
18549 #define SCAN_FROM_CHILD_PARALLELISM 4
18550
18551 void
fk_scanFromChildTable(Signal * signal,TcFiredTriggerData * firedTriggerData,ApiConnectRecordPtr * transPtr,TcConnectRecordPtr * opPtr,TcFKData * fkData,Uint32 op,Uint32 attrValuesPtrI)18552 Dbtc::fk_scanFromChildTable(Signal* signal,
18553 TcFiredTriggerData* firedTriggerData,
18554 ApiConnectRecordPtr* transPtr,
18555 TcConnectRecordPtr* opPtr,
18556 TcFKData* fkData,
18557 Uint32 op,
18558 Uint32 attrValuesPtrI)
18559 {
18560 ApiConnectRecord* regApiPtr = transPtr->p;
18561
18562 SegmentedSectionGuard guard(this, attrValuesPtrI);
18563
18564 if (unlikely(cfirstfreeScanrec == RNIL))
18565 {
18566 jam();
18567 abortTransFromTrigger(signal, *transPtr, ZNO_SCANREC_ERROR);
18568 return;
18569 }
18570
18571 if (unlikely(cfirstfreeTcConnect == RNIL))
18572 {
18573 jam();
18574 abortTransFromTrigger(signal, *transPtr, ZNO_FREE_TC_CONNECTION);
18575 return;
18576 }
18577
18578 seizeApiConnect(signal);
18579 if (unlikely(terrorCode != ZOK))
18580 {
18581 jam();
18582 abortTransFromTrigger(signal, *transPtr, terrorCode);
18583 return;
18584 }
18585
18586 // seize a TcConnectRecord to keep track of trigger stuff
18587 seizeTcConnect(0);
18588 TcConnectRecordPtr tcPtr = tcConnectptr;
18589
18590 ApiConnectRecordPtr scanApiConnectPtr = apiConnectptr;
18591 scanApiConnectPtr.p->ndbapiBlockref = reference();
18592 scanApiConnectPtr.p->ndbapiConnect = tcPtr.i;
18593
18594 tcPtr.p->apiConnect = scanApiConnectPtr.i;
18595 tcPtr.p->triggeringOperation = opPtr->i;
18596 ndbrequire(hasOp(* transPtr, opPtr->i));
18597 tcPtr.p->currentTriggerId = firedTriggerData->triggerId;
18598 tcPtr.p->triggerErrorCode = ZNOT_FOUND;
18599 tcPtr.p->operation = op;
18600 tcPtr.p->indexOp = attrValuesPtrI; // NOTE! 0x187
18601 tcPtr.p->nextTcFailHash = transPtr->i; // NOTE! 0x188
18602
18603 {
18604 Ptr<TcDefinedTriggerData> trigPtr;
18605 c_theDefinedTriggers.getPtr(trigPtr, tcPtr.p->currentTriggerId);
18606 trigPtr.p->refCount++;
18607 }
18608
18609 TableRecordPtr childIndexPtr;
18610 childIndexPtr.i = fkData->childIndexId;
18611 ptrCheckGuard(childIndexPtr, ctabrecFilesize, tableRecord);
18612
18613 /**
18614 * Construct a index-scan
18615 */
18616 const Uint32 parallelism = SCAN_FROM_CHILD_PARALLELISM;
18617 ScanTabReq * req = CAST_PTR(ScanTabReq, signal->getDataPtrSend());
18618 Uint32 ri = 0;
18619 ScanTabReq::setParallelism(ri, parallelism);
18620 ScanTabReq::setDescendingFlag(ri, 0);
18621 ScanTabReq::setRangeScanFlag(ri, 1);
18622 ScanTabReq::setTupScanFlag(ri, 0);
18623 ScanTabReq::setNoDiskFlag(ri, 1);
18624 if (op == ZREAD)
18625 {
18626 ScanTabReq::setScanBatch(ri, 1);
18627 ScanTabReq::setLockMode(ri, 0);
18628 ScanTabReq::setHoldLockFlag(ri, 0);
18629 ScanTabReq::setReadCommittedFlag(ri, 1);
18630 ScanTabReq::setKeyinfoFlag(ri, 0);
18631 }
18632 else
18633 {
18634 ScanTabReq::setScanBatch(ri, 16);
18635 ScanTabReq::setLockMode(ri, 1);
18636 ScanTabReq::setHoldLockFlag(ri, 1);
18637 ScanTabReq::setReadCommittedFlag(ri, 0);
18638 ScanTabReq::setKeyinfoFlag(ri, 1);
18639 }
18640 ScanTabReq::setDistributionKeyFlag(ri, 0);
18641 ScanTabReq::setViaSPJFlag(ri, 0);
18642 ScanTabReq::setPassAllConfsFlag(ri, 0);
18643 ScanTabReq::set4WordConf(ri, 0);
18644 req->requestInfo = ri;
18645 req->transId1 = regApiPtr->transid[0];
18646 req->transId2 = regApiPtr->transid[1];
18647 req->buddyConPtr = transPtr->i;
18648 req->tableId = childIndexPtr.i;
18649 req->tableSchemaVersion = childIndexPtr.p->currentSchemaVersion;
18650 req->apiConnectPtr = scanApiConnectPtr.i;
18651 req->storedProcId = 0xFFFF;
18652 req->batch_byte_size = 0;
18653 req->first_batch_size = 0;
18654
18655 SegmentedSectionPtr ptr[3];
18656 ptr[0].i = ptr[1].i = ptr[2].i = RNIL;
18657
18658 Uint32 optrs[parallelism];
18659 for (Uint32 i = 0; i<parallelism; i++)
18660 optrs[i] = tcPtr.i;
18661
18662 Uint32 program[] = {
18663 0, 1, 0, 0, 0, Interpreter::ExitLastOK()
18664 };
18665
18666 if (op != ZREAD)
18667 {
18668 program[5] = Interpreter::ExitOK();
18669 }
18670
18671 Uint32 errorCode = ZGET_DATAREC_ERROR;
18672 if (ERROR_INSERTED(8102))
18673 {
18674 goto oom;
18675 }
18676 if (unlikely( !import(ptr[0], optrs, NDB_ARRAY_SIZE(optrs))))
18677 {
18678 jam();
18679 goto oom;
18680 }
18681
18682 if (unlikely( !import(ptr[1], program, NDB_ARRAY_SIZE(program))))
18683 {
18684 jam();
18685 goto oom;
18686 }
18687
18688 {
18689 AttributeBuffer::DataBufferPool & pool = c_theAttributeBufferPool;
18690 LocalDataBuffer<11> beforeValues(pool, firedTriggerData->beforeValues);
18691 if (unlikely((errorCode=fk_buildBounds(ptr[2], beforeValues, fkData)) != 0))
18692 {
18693 jam();
18694 goto oom;
18695 }
18696 }
18697
18698 guard.clear(); // now sections will be handled...
18699
18700 signal->header.m_noOfSections= 3;
18701 signal->m_sectionPtrI[0] = ptr[0].i;
18702 signal->m_sectionPtrI[1] = ptr[1].i;
18703 signal->m_sectionPtrI[2] = ptr[2].i;
18704 execSCAN_TABREQ(signal);
18705
18706 transPtr->p->lqhkeyreqrec++; // Make sure that execution is stalled
18707 D("trans: cascading scans++ " << transPtr->p->cascading_scans_count);
18708 ndbrequire(transPtr->p->cascading_scans_count < MaxCascadingScansPerTransaction);
18709 transPtr->p->cascading_scans_count++;
18710 return;
18711
18712 oom:
18713 for (Uint32 i = 0; i < 3; i++)
18714 {
18715 if (ptr[i].i != RNIL)
18716 {
18717 release(ptr[i]);
18718 }
18719 }
18720 tcConnectptr = tcPtr;
18721 releaseTcCon();
18722 releaseApiCon(signal, scanApiConnectPtr.i);
18723 abortTransFromTrigger(signal, *transPtr, errorCode);
18724 return;
18725 }
18726
18727 void
execKEYINFO20(Signal * signal)18728 Dbtc::execKEYINFO20(Signal* signal)
18729 {
18730 jamEntry();
18731 const KeyInfo20 * conf = CAST_CONSTPTR(KeyInfo20, signal->getDataPtr());
18732
18733 Uint32 transId[] = {
18734 conf->transId1,
18735 conf->transId2
18736 };
18737
18738 Uint32 keyLen = conf->keyLen;
18739 Uint32 scanInfo = conf->scanInfo_Node;
18740
18741 TcConnectRecordPtr tcPtr;
18742 tcPtr.i = conf->clientOpPtr;
18743 ptrCheckGuard(tcPtr, ctcConnectFilesize, tcConnectRecord);
18744
18745 ApiConnectRecordPtr scanApiConnectPtr;
18746 scanApiConnectPtr.i = tcPtr.p->apiConnect;
18747 ptrCheckGuard(scanApiConnectPtr, capiConnectFilesize, apiConnectRecord);
18748
18749 if (! (transId[0] == scanApiConnectPtr.p->transid[0] &&
18750 transId[1] == scanApiConnectPtr.p->transid[1]))
18751 {
18752 jam();
18753
18754 /**
18755 * incorrect transid...no known scenario where this can happen
18756 */
18757 ndbassert(false);
18758 return;
18759 }
18760
18761 /**
18762 * Validate base transaction
18763 */
18764 Uint32 orgTransPtrI = tcPtr.p->nextTcFailHash; // NOTE: 0x188
18765 ApiConnectRecordPtr transPtr;
18766 transPtr.i = orgTransPtrI;
18767 ptrCheckGuard(transPtr, capiConnectFilesize, apiConnectRecord);
18768
18769 if (unlikely(! (transId[0] == transPtr.p->transid[0] &&
18770 transId[1] == transPtr.p->transid[1] &&
18771 transPtr.p->apiConnectstate != CS_ABORTING)))
18772 {
18773 jam();
18774
18775 /**
18776 * The "base" transaction has been aborted...
18777 * terminate scan directly
18778 */
18779 fk_scanFromChildTable_abort(signal, tcPtr);
18780 return;
18781 }
18782
18783 Ptr<TcDefinedTriggerData> trigPtr;
18784 c_theDefinedTriggers.getPtr(trigPtr, tcPtr.p->currentTriggerId);
18785
18786 /* Extract KeyData */
18787 Uint32 keyInfoPtrI = RNIL;
18788 if (signal->header.m_noOfSections == 0)
18789 {
18790 jam();
18791 Ptr<SectionSegment> keyInfo;
18792 if (unlikely(! import(keyInfo, conf->keyData, keyLen)))
18793 {
18794 abortTransFromTrigger(signal, transPtr, ZGET_DATAREC_ERROR);
18795 return;
18796 }
18797 keyInfoPtrI = keyInfo.i;
18798 }
18799 else
18800 {
18801 jam();
18802 ndbrequire(signal->header.m_noOfSections == 1); // key is already here...
18803 keyInfoPtrI = signal->m_sectionPtrI[0];
18804 signal->header.m_noOfSections = 0;
18805 }
18806
18807 Ptr<TcFKData> fkPtr;
18808 // TODO make it a pool.getPtr() instead
18809 // by also adding fk_ptr_i to definedTriggerData
18810 ndbrequire(c_fk_hash.find(fkPtr, trigPtr.p->fkId));
18811
18812 /**
18813 * Construct a DELETE/UPDATE
18814 * NOTE: on table...not index
18815 */
18816 Uint32 op = tcPtr.p->operation;
18817 TcKeyReq * const tcKeyReq = CAST_PTR(TcKeyReq, signal->getDataPtrSend());
18818 TableRecordPtr childTabPtr;
18819
18820 childTabPtr.i = fkPtr.p->childTableId;
18821 ptrCheckGuard(childTabPtr, ctabrecFilesize, tableRecord);
18822 tcKeyReq->apiConnectPtr = orgTransPtrI;
18823 tcKeyReq->senderData = tcPtr.p->triggeringOperation;
18824
18825 tcKeyReq->attrLen = 0;
18826 tcKeyReq->tableId = childTabPtr.i;
18827 tcKeyReq->tableSchemaVersion = childTabPtr.p->currentSchemaVersion;
18828 tcKeyReq->transId1 = transPtr.p->transid[0];
18829 tcKeyReq->transId2 = transPtr.p->transid[1];
18830 Uint32 tcKeyRequestInfo = 0;
18831 TcKeyReq::setKeyLength(tcKeyRequestInfo, 0);
18832 TcKeyReq::setAIInTcKeyReq(tcKeyRequestInfo, 0);
18833 TcKeyReq::setOperationType(tcKeyRequestInfo, op);
18834 const bool use_scan_takeover = false;
18835 if (use_scan_takeover)
18836 {
18837 TcKeyReq::setScanIndFlag(tcKeyRequestInfo, 1);
18838 }
18839 tcKeyReq->requestInfo = tcKeyRequestInfo;
18840 if (use_scan_takeover)
18841 {
18842 tcKeyReq->scanInfo = (scanInfo << 1) + 1; // TODO cleanup
18843 }
18844 signal->m_sectionPtrI[ TcKeyReq::KeyInfoSectionNum ] = keyInfoPtrI;
18845 signal->header.m_noOfSections= 1;
18846
18847 if (tcPtr.p->indexOp != RNIL)
18848 {
18849 /**
18850 * attrValues save in indexOp
18851 */
18852 Uint32 tmp = RNIL;
18853 if (unlikely( !dupSection(tmp, tcPtr.p->indexOp)))
18854 {
18855 jam();
18856 releaseSection(keyInfoPtrI);
18857 signal->header.m_noOfSections = 0;
18858 abortTransFromTrigger(signal, transPtr, ZGET_DATAREC_ERROR);
18859 return;
18860 }
18861 signal->m_sectionPtrI[ TcKeyReq::AttrInfoSectionNum ] = tmp;
18862 signal->header.m_noOfSections= 2;
18863 }
18864
18865 TcConnectRecordPtr opPtr; // triggering operation
18866 opPtr.i = tcPtr.p->triggeringOperation;
18867 ptrCheckGuard(opPtr, ctcConnectFilesize, tcConnectRecord);
18868
18869 /**
18870 * Fix savepoint id -
18871 * fix so that op has same savepoint id as triggering operation
18872 */
18873 Uint32 currSavePointId = transPtr.p->currSavePointId;
18874 transPtr.p->currSavePointId = opPtr.p->savePointId;
18875 transPtr.p->m_special_op_flags = TcConnectRecord::SOF_TRIGGER;
18876 /* Pass trigger Id via ApiConnectRecord (nasty) */
18877 ndbrequire(transPtr.p->immediateTriggerId == RNIL);
18878 transPtr.p->immediateTriggerId = tcPtr.p->currentTriggerId;
18879 EXECUTE_DIRECT(DBTC, GSN_TCKEYREQ, signal, TcKeyReq::StaticLength +
18880 (use_scan_takeover ? 1 : 0));
18881 jamEntry();
18882
18883 /*
18884 * Restore ApiConnectRecord state
18885 */
18886 transPtr.p->immediateTriggerId = RNIL;
18887 transPtr.p->currSavePointId = currSavePointId;
18888
18889 /**
18890 * Update counter of how many trigger executed...
18891 */
18892 opPtr.p->triggerExecutionCount++;
18893 }
18894
18895 void
execSCAN_TABCONF(Signal * signal)18896 Dbtc::execSCAN_TABCONF(Signal* signal)
18897 {
18898 jamEntry();
18899 const ScanTabConf * conf = CAST_CONSTPTR(ScanTabConf, signal->getDataPtr());
18900
18901 Uint32 transId[] = {
18902 conf->transId1,
18903 conf->transId2
18904 };
18905
18906 TcConnectRecordPtr tcPtr;
18907 tcPtr.i = conf->apiConnectPtr;
18908 ptrCheckGuard(tcPtr, ctcConnectFilesize, tcConnectRecord);
18909
18910 ApiConnectRecordPtr scanApiConnectPtr;
18911 scanApiConnectPtr.i = tcPtr.p->apiConnect;
18912 ptrCheckGuard(scanApiConnectPtr, capiConnectFilesize, apiConnectRecord);
18913
18914 if (! (transId[0] == scanApiConnectPtr.p->transid[0] &&
18915 transId[1] == scanApiConnectPtr.p->transid[1]))
18916 {
18917 jam();
18918
18919 /**
18920 * incorrect transid...no known scenario where this can happen
18921 */
18922 ndbassert(false);
18923 return;
18924 }
18925
18926 /**
18927 * Validate base transaction
18928 */
18929 Uint32 orgTransPtrI = tcPtr.p->nextTcFailHash; // NOTE: 0x188
18930 ApiConnectRecordPtr orgApiConnectPtr;
18931 orgApiConnectPtr.i = orgTransPtrI;
18932 ptrCheckGuard(orgApiConnectPtr, capiConnectFilesize, apiConnectRecord);
18933
18934 if (unlikely(! (transId[0] == orgApiConnectPtr.p->transid[0] &&
18935 transId[1] == orgApiConnectPtr.p->transid[1] &&
18936 orgApiConnectPtr.p->apiConnectstate != CS_ABORTING)))
18937 {
18938 jam();
18939
18940 /**
18941 * The "base" transaction has been aborted...
18942 * terminate scan directly
18943 */
18944 if (conf->requestInfo & ScanTabConf::EndOfData)
18945 {
18946 jam();
18947 fk_scanFromChildTable_done(signal, tcPtr);
18948 }
18949 else
18950 {
18951 jam();
18952 fk_scanFromChildTable_abort(signal, tcPtr);
18953 }
18954 return;
18955 }
18956
18957 Ptr<TcDefinedTriggerData> trigPtr;
18958 c_theDefinedTriggers.getPtr(trigPtr, tcPtr.p->currentTriggerId);
18959
18960 Ptr<TcFKData> fkPtr;
18961 // TODO make it a pool.getPtr() instead
18962 // by also adding fk_ptr_i to definedTriggerData
18963 ndbrequire(c_fk_hash.find(fkPtr, trigPtr.p->fkId));
18964
18965 Uint32 rows = 0;
18966 const Uint32 ops = (conf->requestInfo >> OPERATIONS_SHIFT) & OPERATIONS_MASK;
18967 for (Uint32 i = 0; i<ops; i++)
18968 {
18969 jam();
18970 ScanTabConf::OpData * op = (ScanTabConf::OpData*)
18971 (signal->getDataPtr() + ScanTabConf::SignalLength + 3 * i);
18972 rows += ScanTabConf::getRows(op->rows);
18973 }
18974
18975 if (rows && tcPtr.p->operation != ZREAD)
18976 {
18977 jam();
18978 TcConnectRecordPtr opPtr; // triggering operation
18979 opPtr.i = tcPtr.p->triggeringOperation;
18980 ptrCheckGuard(opPtr, ctcConnectFilesize, tcConnectRecord);
18981 TcConnectRecord * triggeringOp = opPtr.p;
18982 if (triggeringOp->operation == ZDELETE &&
18983 (fkPtr.p->bits & (CreateFKImplReq::FK_DELETE_CASCADE | CreateFKImplReq::FK_DELETE_SET_NULL)))
18984 {
18985 /**
18986 * don't abort scan
18987 */
18988 jam();
18989 rows = 0;
18990 }
18991 else if ((triggeringOp->operation == ZUPDATE || triggeringOp->operation == ZWRITE) &&
18992 (fkPtr.p->bits & (CreateFKImplReq::FK_UPDATE_CASCADE | CreateFKImplReq::FK_UPDATE_SET_NULL)))
18993 {
18994 /**
18995 * don't abort scan
18996 */
18997 jam();
18998 rows = 0;
18999 }
19000 }
19001
19002 if (rows)
19003 {
19004 jam();
19005 tcPtr.p->triggerErrorCode = ZFK_CHILD_ROW_EXISTS;
19006 }
19007
19008 if (conf->requestInfo & ScanTabConf::EndOfData)
19009 {
19010 jam();
19011 fk_scanFromChildTable_done(signal, tcPtr);
19012 }
19013 else if (rows)
19014 {
19015 jam();
19016 /**
19017 * Abort scan...we already know that ZFK_CHILD_ROW_EXISTS
19018 */
19019 fk_scanFromChildTable_abort(signal, tcPtr);
19020 }
19021 else
19022 {
19023 jam();
19024 /**
19025 * Continue scanning...
19026 */
19027 const Uint32 parallelism = SCAN_FROM_CHILD_PARALLELISM;
19028 Uint32 cnt = 0;
19029 Uint32 operations[parallelism];
19030 for (Uint32 i = 0; i<ops; i++)
19031 {
19032 jam();
19033 ScanTabConf::OpData * op = (ScanTabConf::OpData*)
19034 (signal->getDataPtr() + ScanTabConf::SignalLength + 3 * i);
19035 if (op->tcPtrI != RNIL)
19036 {
19037 ndbrequire(cnt < NDB_ARRAY_SIZE(operations));
19038 operations[cnt++] = op->tcPtrI;
19039 }
19040 }
19041 if (cnt)
19042 {
19043 jam();
19044 ScanNextReq* req = CAST_PTR(ScanNextReq, signal->getDataPtrSend());
19045 req->apiConnectPtr = scanApiConnectPtr.i;
19046 req->stopScan = 0;
19047 req->transId1 = scanApiConnectPtr.p->transid[0];
19048 req->transId2 = scanApiConnectPtr.p->transid[1];
19049 memcpy(signal->getDataPtrSend() + ScanNextReq::SignalLength,
19050 operations, 4 * cnt);
19051 sendSignal(reference(), GSN_SCAN_NEXTREQ, signal,
19052 ScanNextReq::SignalLength + cnt, JBB);
19053 }
19054 }
19055 }
19056
19057 void
fk_scanFromChildTable_abort(Signal * signal,TcConnectRecordPtr tcPtr)19058 Dbtc::fk_scanFromChildTable_abort(Signal* signal, TcConnectRecordPtr tcPtr)
19059 {
19060 ApiConnectRecordPtr scanApiConnectPtr;
19061 scanApiConnectPtr.i = tcPtr.p->apiConnect;
19062 ptrCheckGuard(scanApiConnectPtr, capiConnectFilesize, apiConnectRecord);
19063
19064 /**
19065 * Check that the scan has not already completed
19066 * - so we can abort aggresively
19067 */
19068 if (scanApiConnectPtr.p->apiConnectstate != CS_START_SCAN)
19069 {
19070 jam();
19071 /**
19072 * Scan has already completed...we just haven't received the EOD yet
19073 *
19074 * wait for it...
19075 */
19076 return;
19077 }
19078
19079 ScanNextReq* req = CAST_PTR(ScanNextReq, signal->getDataPtrSend());
19080 req->apiConnectPtr = scanApiConnectPtr.i;
19081 req->stopScan = 1;
19082 req->transId1 = scanApiConnectPtr.p->transid[0];
19083 req->transId2 = scanApiConnectPtr.p->transid[1];
19084
19085 /**
19086 * Here we need to use EXECUTE_DIRECT
19087 * or this signal will race with state-changes in scan-record
19088 *
19089 * NOTE: A better alternative would be to fix Dbtc/protocol to handle
19090 * these races...
19091 */
19092 EXECUTE_DIRECT(DBTC, GSN_SCAN_NEXTREQ, signal, ScanNextReq::SignalLength);
19093 }
19094
19095 void
fk_scanFromChildTable_done(Signal * signal,TcConnectRecordPtr tcPtr)19096 Dbtc::fk_scanFromChildTable_done(Signal* signal, TcConnectRecordPtr tcPtr)
19097 {
19098 ApiConnectRecordPtr scanApiConnectPtr;
19099 scanApiConnectPtr.i = tcPtr.p->apiConnect;
19100 ptrCheckGuard(scanApiConnectPtr, capiConnectFilesize, apiConnectRecord);
19101
19102 ndbrequire(scanApiConnectPtr.p->ndbapiConnect == tcPtr.i);
19103
19104 /**
19105 * save things needed to finish this trigger op
19106 */
19107 Uint32 transId[] = {
19108 scanApiConnectPtr.p->transid[0],
19109 scanApiConnectPtr.p->transid[1]
19110 };
19111
19112 Uint32 errCode = tcPtr.p->triggerErrorCode;
19113 Uint32 triggerId = tcPtr.p->currentTriggerId;
19114 Uint32 orgTransPtrI = tcPtr.p->nextTcFailHash; // NOTE: 0x188
19115
19116 TcConnectRecordPtr opPtr; // triggering operation
19117 opPtr.i = tcPtr.p->triggeringOperation;
19118
19119 /**
19120 * release extra allocated resources
19121 */
19122 if (tcPtr.p->indexOp != RNIL) // NOTE: 0x187
19123 {
19124 releaseSection(tcPtr.p->indexOp);
19125 }
19126 tcConnectptr = tcPtr;
19127 releaseTcCon();
19128 releaseApiCon(signal, scanApiConnectPtr.i);
19129
19130 ApiConnectRecordPtr orgApiConnectPtr;
19131 orgApiConnectPtr.i = orgTransPtrI;
19132 ptrCheckGuard(orgApiConnectPtr, capiConnectFilesize, apiConnectRecord);
19133
19134 if (! (transId[0] == orgApiConnectPtr.p->transid[0] &&
19135 transId[1] == orgApiConnectPtr.p->transid[1] &&
19136 orgApiConnectPtr.p->apiConnectstate != CS_ABORTING))
19137 {
19138 jam();
19139 /**
19140 * The "base" transaction has been aborted...
19141 * we need just throw away our scan...
19142 * any DML caused by it...is anyway put onto "real" transaction
19143 */
19144 return;
19145 }
19146
19147 ptrCheckGuard(opPtr, ctcConnectFilesize, tcConnectRecord);
19148 if (opPtr.p->apiConnect != orgApiConnectPtr.i)
19149 {
19150 jam();
19151 ndbassert(false);
19152 /**
19153 * this should not happen :-)
19154 *
19155 * triggering operation has been moved to different transaction...
19156 * this should not happen since then the original trans should be aborted
19157 * (or aborted and restarted) this is checked above...
19158 *
19159 */
19160 return;
19161 }
19162
19163 ndbrequire(orgApiConnectPtr.p->lqhkeyreqrec > 0);
19164 ndbrequire(orgApiConnectPtr.p->lqhkeyreqrec > orgApiConnectPtr.p->lqhkeyconfrec);
19165 orgApiConnectPtr.p->lqhkeyreqrec--;
19166
19167 D("trans: cascading scans-- " << orgApiConnectPtr.p->cascading_scans_count);
19168 ndbrequire(orgApiConnectPtr.p->cascading_scans_count > 0);
19169 orgApiConnectPtr.p->cascading_scans_count--;
19170
19171 trigger_op_finished(signal, orgApiConnectPtr, triggerId, opPtr.p, errCode);
19172 }
19173
19174 void
execSCAN_TABREF(Signal * signal)19175 Dbtc::execSCAN_TABREF(Signal* signal)
19176 {
19177 jamEntry();
19178
19179 const ScanTabRef * ref = CAST_CONSTPTR(ScanTabRef, signal->getDataPtr());
19180
19181 Uint32 transId[] = {
19182 ref->transId1,
19183 ref->transId2
19184 };
19185
19186 TcConnectRecordPtr tcPtr;
19187 tcPtr.i = ref->apiConnectPtr;
19188 ptrCheckGuard(tcPtr, ctcConnectFilesize, tcConnectRecord);
19189
19190 ApiConnectRecordPtr scanApiConnectPtr;
19191 scanApiConnectPtr.i = tcPtr.p->apiConnect;
19192 ptrCheckGuard(scanApiConnectPtr, capiConnectFilesize, apiConnectRecord);
19193
19194 if (! (transId[0] == scanApiConnectPtr.p->transid[0] &&
19195 transId[1] == scanApiConnectPtr.p->transid[1]))
19196 {
19197 jam();
19198
19199 /**
19200 * incorrect transid...no known scenario where this can happen
19201 */
19202 ndbassert(false);
19203 return;
19204 }
19205
19206 tcPtr.p->triggerErrorCode = ref->errorCode;
19207 if (ref->closeNeeded)
19208 {
19209 jam();
19210 fk_scanFromChildTable_abort(signal, tcPtr);
19211 }
19212 else
19213 {
19214 jam();
19215 fk_scanFromChildTable_done(signal, tcPtr);
19216 }
19217 }
19218
19219 Uint32
fk_buildBounds(SegmentedSectionPtr & dst,LocalDataBuffer<11> & src,TcFKData * fkData)19220 Dbtc::fk_buildBounds(SegmentedSectionPtr & dst,
19221 LocalDataBuffer<11> & src,
19222 TcFKData* fkData)
19223 {
19224 dst.i = RNIL;
19225 Uint32 dstPtrI = RNIL;
19226
19227 IndexAttributeList * list = &fkData->parentTableColumns;
19228
19229 AttributeBuffer::DataBufferIterator iter;
19230 bool eof = !src.first(iter);
19231 for (Uint32 i = 0; i < list->sz; i++)
19232 {
19233 Uint32 col = list->id[i];
19234 if (!eof && AttributeHeader(* iter.data).getAttributeId() == col)
19235 {
19236 found:
19237 Uint32 byteSize = AttributeHeader(* iter.data).getByteSize();
19238 Uint32 len32 = (byteSize + 3) / 4;
19239 if (len32 == 0)
19240 {
19241 // ?? TODO what to do
19242 }
19243 eof = !src.next(iter);
19244
19245 Uint32 data[2];
19246 data[0] = TuxBoundInfo::BoundEQ;
19247 AttributeHeader::init(data+1, i, byteSize);
19248 if (unlikely(!appendToSection(dstPtrI, data, NDB_ARRAY_SIZE(data))))
19249 {
19250 dst.i = dstPtrI;
19251 return ZGET_DATAREC_ERROR;
19252 }
19253
19254 Uint32 err = appendDataToSection(dstPtrI, src, iter,
19255 len32);
19256 if (unlikely(err != 0))
19257 {
19258 dst.i = dstPtrI;
19259 return err;
19260 }
19261
19262 eof = iter.isNull();
19263 }
19264 else
19265 {
19266 /**
19267 * Search for column...
19268 */
19269 eof = !src.first(iter);
19270 while (!eof && AttributeHeader(* iter.data).getAttributeId() != col)
19271 {
19272 eof = !src.next(iter,
19273 1 + AttributeHeader(* iter.data).getDataSize());
19274 }
19275 if (unlikely(eof))
19276 {
19277 dst.i = dstPtrI;
19278 return ZMISSING_TRIGGER_DATA;
19279 }
19280 ndbassert(AttributeHeader(* iter.data).getAttributeId() == col);
19281 goto found;
19282 }
19283 }
19284
19285 dst.i = dstPtrI;
19286 return 0;
19287 }
19288
19289 void
executeFKChildTrigger(Signal * signal,TcDefinedTriggerData * definedTriggerData,TcFiredTriggerData * firedTriggerData,ApiConnectRecordPtr * transPtr,TcConnectRecordPtr * opPtr)19290 Dbtc::executeFKChildTrigger(Signal* signal,
19291 TcDefinedTriggerData* definedTriggerData,
19292 TcFiredTriggerData* firedTriggerData,
19293 ApiConnectRecordPtr* transPtr,
19294 TcConnectRecordPtr* opPtr)
19295 {
19296 Ptr<TcFKData> fkPtr;
19297 // TODO make it a pool.getPtr() instead
19298 // by also adding fk_ptr_i to definedTriggerData
19299 ndbrequire(c_fk_hash.find(fkPtr, definedTriggerData->fkId));
19300
19301 switch (firedTriggerData->triggerEvent) {
19302 case(TriggerEvent::TE_INSERT):
19303 jam();
19304 /**
19305 * Check that after values exists in parent table
19306 */
19307 fk_readFromParentTable(signal, firedTriggerData, transPtr, opPtr, fkPtr.p);
19308 break;
19309 case(TriggerEvent::TE_UPDATE):
19310 jam();
19311 /**
19312 * Check that after values exists in parent table
19313 */
19314 fk_readFromParentTable(signal, firedTriggerData, transPtr, opPtr, fkPtr.p);
19315 break;
19316 default:
19317 ndbrequire(false);
19318 }
19319 }
19320
19321 void
fk_readFromParentTable(Signal * signal,TcFiredTriggerData * firedTriggerData,ApiConnectRecordPtr * transPtr,TcConnectRecordPtr * opPtr,TcFKData * fkData)19322 Dbtc::fk_readFromParentTable(Signal* signal,
19323 TcFiredTriggerData* firedTriggerData,
19324 ApiConnectRecordPtr* transPtr,
19325 TcConnectRecordPtr* opPtr,
19326 TcFKData* fkData)
19327 {
19328 ApiConnectRecord* regApiPtr = transPtr->p;
19329 TcConnectRecord* opRecord = opPtr->p;
19330 TcKeyReq * const tcKeyReq = (TcKeyReq *)signal->getDataPtrSend();
19331 Uint32 tcKeyRequestInfo = 0;
19332 TableRecordPtr parentTabPtr;
19333
19334 parentTabPtr.i = fkData->parentTableId;
19335 ptrCheckGuard(parentTabPtr, ctabrecFilesize, tableRecord);
19336 tcKeyReq->apiConnectPtr = transPtr->i;
19337 tcKeyReq->senderData = opPtr->i;
19338
19339 // Calculate key length and renumber attribute id:s
19340 AttributeBuffer::DataBufferPool & pool = c_theAttributeBufferPool;
19341 LocalDataBuffer<11> afterValues(pool, firedTriggerData->afterValues);
19342
19343 if (afterValues.getSize() == 0)
19344 {
19345 jam();
19346 ndbrequire(tc_testbit(regApiPtr->m_flags,
19347 ApiConnectRecord::TF_DEFERRED_CONSTRAINTS));
19348 trigger_op_finished(signal, *transPtr, RNIL, opRecord, 0);
19349 return;
19350 }
19351
19352 Uint32 keyIVal= RNIL;
19353 bool hasNull= false;
19354 Uint32 err = fk_buildKeyInfo(keyIVal, hasNull, afterValues, fkData, true);
19355 SegmentedSectionGuard guard(this, keyIVal);
19356 if (unlikely(err != 0))
19357 {
19358 abortTransFromTrigger(signal, *transPtr, err);
19359 return;
19360 }
19361
19362 /* If there's Nulls in the values that become the index table's
19363 * PK then we skip this delete
19364 */
19365 if (hasNull)
19366 {
19367 jam();
19368 trigger_op_finished(signal, *transPtr, RNIL, opRecord, 0);
19369 return;
19370 }
19371
19372 Uint16 flags = TcConnectRecord::SOF_TRIGGER;
19373 if (((fkData->bits & CreateFKImplReq::FK_ACTION_MASK) == 0) ||
19374 transPtr->p->isExecutingDeferredTriggers())
19375 {
19376 jam();
19377 /**
19378 * We don't need any locks here
19379 */
19380 flags |= TcConnectRecord::SOF_FK_READ_COMMITTED;
19381 TcKeyReq::setSimpleFlag(tcKeyRequestInfo, 1);
19382 }
19383
19384 TcKeyReq::setKeyLength(tcKeyRequestInfo, 0);
19385 TcKeyReq::setAIInTcKeyReq(tcKeyRequestInfo, 0);
19386 tcKeyReq->attrLen = 0;
19387 tcKeyReq->tableId = parentTabPtr.i;
19388 TcKeyReq::setOperationType(tcKeyRequestInfo, ZREAD);
19389 tcKeyReq->tableSchemaVersion = parentTabPtr.p->currentSchemaVersion;
19390 tcKeyReq->transId1 = regApiPtr->transid[0];
19391 tcKeyReq->transId2 = regApiPtr->transid[1];
19392 tcKeyReq->requestInfo = tcKeyRequestInfo;
19393
19394 guard.clear(); // now sections will be handled...
19395
19396 /* Attach KeyInfo section to signal */
19397 ndbrequire(signal->header.m_noOfSections == 0);
19398 signal->m_sectionPtrI[ TcKeyReq::KeyInfoSectionNum ] = keyIVal;
19399 signal->header.m_noOfSections = 1;
19400
19401 /**
19402 * Don't fix savepoint id -
19403 * read latest copy??
19404 */
19405 regApiPtr->m_special_op_flags = flags;
19406 /* Pass trigger Id via ApiConnectRecord (nasty) */
19407 ndbrequire(regApiPtr->immediateTriggerId == RNIL);
19408 regApiPtr->immediateTriggerId= firedTriggerData->triggerId;
19409 EXECUTE_DIRECT(DBTC, GSN_TCKEYREQ, signal, TcKeyReq::StaticLength);
19410 jamEntry();
19411
19412 /*
19413 * Restore ApiConnectRecord state
19414 */
19415 regApiPtr->immediateTriggerId = RNIL;
19416 }
19417
releaseFiredTriggerData(DLFifoList<TcFiredTriggerData> * triggers)19418 void Dbtc::releaseFiredTriggerData(DLFifoList<TcFiredTriggerData>* triggers)
19419 {
19420 FiredTriggerPtr trigPtr;
19421
19422 triggers->first(trigPtr);
19423 while (trigPtr.i != RNIL) {
19424 jam();
19425 // Release trigger records
19426
19427 AttributeBuffer::DataBufferPool & pool = c_theAttributeBufferPool;
19428 LocalDataBuffer<11> tmp1(pool, trigPtr.p->keyValues);
19429 tmp1.release();
19430 LocalDataBuffer<11> tmp2(pool, trigPtr.p->beforeValues);
19431 tmp2.release();
19432 LocalDataBuffer<11> tmp3(pool, trigPtr.p->afterValues);
19433 tmp3.release();
19434
19435 triggers->next(trigPtr);
19436 }
19437 while (triggers->releaseFirst());
19438 }
19439
releaseFiredTriggerData(LocalDLFifoList<TcFiredTriggerData> * triggers)19440 void Dbtc::releaseFiredTriggerData(LocalDLFifoList<TcFiredTriggerData>*
19441 triggers)
19442 {
19443 FiredTriggerPtr trigPtr;
19444
19445 triggers->first(trigPtr);
19446 while (trigPtr.i != RNIL)
19447 {
19448 jam();
19449 // Release trigger records
19450
19451 AttributeBuffer::DataBufferPool & pool = c_theAttributeBufferPool;
19452 LocalDataBuffer<11> tmp1(pool, trigPtr.p->keyValues);
19453 tmp1.release();
19454 LocalDataBuffer<11> tmp2(pool, trigPtr.p->beforeValues);
19455 tmp2.release();
19456 LocalDataBuffer<11> tmp3(pool, trigPtr.p->afterValues);
19457 tmp3.release();
19458 FiredTriggerPtr save = trigPtr;
19459 triggers->next(trigPtr);
19460 triggers->release(save);
19461 }
19462 }
19463
19464 /**
19465 * abortTransFromTrigger
19466 *
19467 * This method is called when there is a problem with trigger
19468 * handling and the transaction should be aborted with the
19469 * given error code
19470 */
abortTransFromTrigger(Signal * signal,const ApiConnectRecordPtr & transPtr,Uint32 error)19471 void Dbtc::abortTransFromTrigger(Signal* signal,
19472 const ApiConnectRecordPtr& transPtr,
19473 Uint32 error)
19474 {
19475 jam();
19476 terrorCode = error;
19477
19478 apiConnectptr = transPtr;
19479
19480 abortErrorLab(signal);
19481 }
19482
19483 Uint32
appendDataToSection(Uint32 & sectionIVal,DataBuffer<11> & src,DataBuffer<11>::DataBufferIterator & iter,Uint32 len)19484 Dbtc::appendDataToSection(Uint32& sectionIVal,
19485 DataBuffer<11> & src,
19486 DataBuffer<11>::DataBufferIterator & iter,
19487 Uint32 len)
19488 {
19489 const Uint32 segSize = src.getSegmentSize(); // 11
19490 while (len)
19491 {
19492 /* Copy as many contiguous words as possible */
19493 Uint32 contigLeft = segSize - iter.ind;
19494 ndbassert(contigLeft);
19495 Uint32 contigValid = MIN(len, contigLeft);
19496
19497 if (unlikely(!appendToSection(sectionIVal,
19498 iter.data,
19499 contigValid)))
19500 {
19501 goto full;
19502 }
19503 len -= contigValid;
19504 bool hasMore = src.next(iter, contigValid);
19505
19506 if (len == 0)
19507 break;
19508
19509 if (unlikely(! hasMore))
19510 {
19511 ndbassert(false); // this is internal error...
19512 goto fail;
19513 }
19514 }
19515 return 0;
19516
19517 full:
19518 jam();
19519 releaseSection(sectionIVal);
19520 sectionIVal= RNIL;
19521 return ZGET_DATAREC_ERROR;
19522
19523 fail:
19524 jam();
19525 releaseSection(sectionIVal);
19526 sectionIVal= RNIL;
19527 return ZMISSING_TRIGGER_DATA;
19528 }
19529
19530 /**
19531 * appendAttrDataToSection
19532 *
19533 * Copy data in AttrInfo form from the given databuffer
19534 * to the given section IVal (can be RNIL).
19535 * If attribute headers are to be copied they will be
19536 * renumbered consecutively, starting with the given
19537 * attrId.
19538 * hasNull is updated to indicate whether any Nulls
19539 * were encountered.
19540 */
appendAttrDataToSection(Uint32 & sectionIVal,DataBuffer<11> & values,bool withHeaders,Uint32 & attrId,bool & hasNull)19541 bool Dbtc::appendAttrDataToSection(Uint32& sectionIVal,
19542 DataBuffer<11>& values,
19543 bool withHeaders,
19544 Uint32& attrId,
19545 bool& hasNull)
19546 {
19547 AttributeBuffer::DataBufferIterator iter;
19548 bool moreData= values.first(iter);
19549 hasNull= false;
19550 const Uint32 segSize= values.getSegmentSize(); // 11
19551
19552 while (moreData)
19553 {
19554 AttributeHeader* attrHeader = (AttributeHeader *) iter.data;
19555 Uint32 dataSize= attrHeader->getDataSize();
19556 hasNull |= (dataSize == 0);
19557
19558 if (withHeaders)
19559 {
19560 AttributeHeader ah(*iter.data);
19561 ah.setAttributeId(attrId); // Renumber AttrIds
19562 if (unlikely(!appendToSection(sectionIVal,
19563 &ah.m_value,
19564 1)))
19565 {
19566 releaseSection(sectionIVal);
19567 sectionIVal= RNIL;
19568 return false;
19569 }
19570 }
19571
19572 moreData= values.next(iter, 1);
19573
19574 while (dataSize)
19575 {
19576 ndbrequire(moreData);
19577 /* Copy as many contiguous words as possible */
19578 Uint32 contigLeft= segSize - iter.ind;
19579 ndbassert(contigLeft);
19580 Uint32 contigValid= MIN(dataSize, contigLeft);
19581
19582 if (unlikely(!appendToSection(sectionIVal,
19583 iter.data,
19584 contigValid)))
19585 {
19586 releaseSection(sectionIVal);
19587 sectionIVal= RNIL;
19588 return false;
19589 }
19590 moreData= values.next(iter, contigValid);
19591 dataSize-= contigValid;
19592 }
19593 attrId++;
19594 }
19595
19596 return true;
19597 }
19598
insertIntoIndexTable(Signal * signal,TcFiredTriggerData * firedTriggerData,ApiConnectRecordPtr * transPtr,TcConnectRecordPtr * opPtr,TcIndexData * indexData)19599 void Dbtc::insertIntoIndexTable(Signal* signal,
19600 TcFiredTriggerData* firedTriggerData,
19601 ApiConnectRecordPtr* transPtr,
19602 TcConnectRecordPtr* opPtr,
19603 TcIndexData* indexData)
19604 {
19605 ApiConnectRecord* regApiPtr = transPtr->p;
19606 TcConnectRecord* opRecord = opPtr->p;
19607 TcKeyReq * const tcKeyReq = (TcKeyReq *)signal->getDataPtrSend();
19608 Uint32 tcKeyRequestInfo = 0;
19609 TableRecordPtr indexTabPtr;
19610
19611 jam();
19612
19613 indexTabPtr.i = indexData->indexId;
19614 ptrCheckGuard(indexTabPtr, ctabrecFilesize, tableRecord);
19615 tcKeyReq->apiConnectPtr = transPtr->i;
19616 tcKeyReq->senderData = opPtr->i;
19617
19618 /* Key for insert to unique index table is the afterValues from the
19619 * base table operation (from update or insert on base).
19620 * Data for insert to unique index table is the afterValues from the
19621 * base table operation plus the fragment id and packed keyValues from
19622 * the base table operation
19623 */
19624 // Calculate key length and renumber attribute id:s
19625 AttributeBuffer::DataBufferPool & pool = c_theAttributeBufferPool;
19626 LocalDataBuffer<11> afterValues(pool, firedTriggerData->afterValues);
19627 LocalDataBuffer<11> keyValues(pool, firedTriggerData->keyValues);
19628
19629 if (afterValues.getSize() == 0)
19630 {
19631 jam();
19632 ndbrequire(tc_testbit(regApiPtr->m_flags,
19633 ApiConnectRecord::TF_DEFERRED_CONSTRAINTS));
19634 trigger_op_finished(signal, *transPtr, RNIL, opRecord, 0);
19635 return;
19636 }
19637
19638 Uint32 keyIVal= RNIL;
19639 Uint32 attrIVal= RNIL;
19640 bool appendOk= false;
19641 do
19642 {
19643 Uint32 attrId= 0;
19644 bool hasNull= false;
19645
19646 /* Build Insert KeyInfo section from aftervalues */
19647 if (unlikely(! appendAttrDataToSection(keyIVal,
19648 afterValues,
19649 false, // No AttributeHeaders
19650 attrId,
19651 hasNull)))
19652 {
19653 jam();
19654 break;
19655 }
19656
19657 if(ERROR_INSERTED(8086))
19658 {
19659 /* Simulate SS exhaustion */
19660 break;
19661 }
19662
19663 /* If there's Nulls in the values that become the index table's
19664 * PK then we skip this insert
19665 */
19666 if (hasNull)
19667 {
19668 jam();
19669 releaseSection(keyIVal);
19670 trigger_op_finished(signal, *transPtr, RNIL, opRecord, 0);
19671 return;
19672 }
19673
19674 /* Build Insert AttrInfo section from aftervalues,
19675 * fragment id + keyvalues
19676 */
19677 AttributeHeader ah(attrId, 0); // Length tbd.
19678 attrId= 0;
19679 if (unlikely((! appendAttrDataToSection(attrIVal,
19680 afterValues,
19681 true, // Include AttributeHeaders,
19682 attrId,
19683 hasNull)) ||
19684 (! appendToSection(attrIVal,
19685 &ah.m_value,
19686 1))))
19687 {
19688 jam();
19689 break;
19690 }
19691
19692 AttributeHeader* pkHeader= (AttributeHeader*) getLastWordPtr(attrIVal);
19693 Uint32 startSz= getSectionSz(attrIVal);
19694 if (unlikely((! appendToSection(attrIVal,
19695 &firedTriggerData->fragId,
19696 1)) ||
19697 (! appendAttrDataToSection(attrIVal,
19698 keyValues,
19699 false, // No AttributeHeaders
19700 attrId,
19701 hasNull))))
19702 {
19703 jam();
19704 break;
19705 }
19706
19707 appendOk= true;
19708
19709 /* Now go back and set pk header length */
19710 pkHeader->setDataSize(getSectionSz(attrIVal) - startSz);
19711 } while(0);
19712
19713 if (unlikely(!appendOk))
19714 {
19715 /* Some failure building up KeyInfo and AttrInfo */
19716 releaseSection(keyIVal);
19717 releaseSection(attrIVal);
19718 abortTransFromTrigger(signal, *transPtr, ZGET_DATAREC_ERROR);
19719 return;
19720 }
19721
19722 /* Now build TcKeyReq for insert */
19723 TcKeyReq::setKeyLength(tcKeyRequestInfo, 0);
19724 tcKeyReq->attrLen = 0;
19725 TcKeyReq::setAIInTcKeyReq(tcKeyRequestInfo, 0);
19726 tcKeyReq->tableId = indexData->indexId;
19727 TcKeyReq::setOperationType(tcKeyRequestInfo, ZINSERT);
19728 tcKeyReq->tableSchemaVersion = indexTabPtr.p->currentSchemaVersion;
19729 tcKeyReq->transId1 = regApiPtr->transid[0];
19730 tcKeyReq->transId2 = regApiPtr->transid[1];
19731 tcKeyReq->requestInfo = tcKeyRequestInfo;
19732
19733 /* Attach Key and AttrInfo sections to signal */
19734 ndbrequire(signal->header.m_noOfSections == 0);
19735 signal->m_sectionPtrI[ TcKeyReq::KeyInfoSectionNum ] = keyIVal;
19736 signal->m_sectionPtrI[ TcKeyReq::AttrInfoSectionNum ] = attrIVal;
19737 signal->header.m_noOfSections= 2;
19738
19739 /*
19740 * Fix savepoint id -
19741 * fix so that insert has same savepoint id as triggering operation
19742 */
19743 const Uint32 currSavePointId = regApiPtr->currSavePointId;
19744 regApiPtr->currSavePointId = opRecord->savePointId;
19745 regApiPtr->m_special_op_flags = TcConnectRecord::SOF_TRIGGER;
19746 /* Pass trigger Id via ApiConnectRecord (nasty) */
19747 ndbrequire(regApiPtr->immediateTriggerId == RNIL);
19748 regApiPtr->immediateTriggerId= firedTriggerData->triggerId;
19749
19750 EXECUTE_DIRECT(DBTC, GSN_TCKEYREQ, signal, TcKeyReq::StaticLength);
19751 jamEntry();
19752
19753 /*
19754 * Restore ApiConnectRecord state
19755 */
19756 regApiPtr->currSavePointId = currSavePointId;
19757 regApiPtr->immediateTriggerId = RNIL;
19758 }
19759
deleteFromIndexTable(Signal * signal,TcFiredTriggerData * firedTriggerData,ApiConnectRecordPtr * transPtr,TcConnectRecordPtr * opPtr,TcIndexData * indexData)19760 void Dbtc::deleteFromIndexTable(Signal* signal,
19761 TcFiredTriggerData* firedTriggerData,
19762 ApiConnectRecordPtr* transPtr,
19763 TcConnectRecordPtr* opPtr,
19764 TcIndexData* indexData)
19765 {
19766 ApiConnectRecord* regApiPtr = transPtr->p;
19767 TcConnectRecord* opRecord = opPtr->p;
19768 TcKeyReq * const tcKeyReq = (TcKeyReq *)signal->getDataPtrSend();
19769 Uint32 tcKeyRequestInfo = 0;
19770 TableRecordPtr indexTabPtr;
19771
19772 indexTabPtr.i = indexData->indexId;
19773 ptrCheckGuard(indexTabPtr, ctabrecFilesize, tableRecord);
19774 tcKeyReq->apiConnectPtr = transPtr->i;
19775 tcKeyReq->senderData = opPtr->i;
19776
19777 // Calculate key length and renumber attribute id:s
19778 AttributeBuffer::DataBufferPool & pool = c_theAttributeBufferPool;
19779 LocalDataBuffer<11> beforeValues(pool, firedTriggerData->beforeValues);
19780
19781 Uint32 keyIVal= RNIL;
19782 Uint32 attrId= 0;
19783 bool hasNull= false;
19784
19785 if (beforeValues.getSize() == 0)
19786 {
19787 jam();
19788 ndbrequire(tc_testbit(regApiPtr->m_flags,
19789 ApiConnectRecord::TF_DEFERRED_CONSTRAINTS));
19790 trigger_op_finished(signal, *transPtr, RNIL, opRecord, 0);
19791 return;
19792 }
19793
19794 /* Build Delete KeyInfo section from beforevalues */
19795 if (unlikely((! appendAttrDataToSection(keyIVal,
19796 beforeValues,
19797 false, // No AttributeHeaders
19798 attrId,
19799 hasNull)) ||
19800 ERROR_INSERTED(8086)))
19801 {
19802 jam();
19803 releaseSection(keyIVal);
19804 abortTransFromTrigger(signal, *transPtr, ZGET_DATAREC_ERROR);
19805 return;
19806 }
19807
19808 /* If there's Nulls in the values that become the index table's
19809 * PK then we skip this delete
19810 */
19811 if (hasNull)
19812 {
19813 jam();
19814 releaseSection(keyIVal);
19815 trigger_op_finished(signal, *transPtr, RNIL, opRecord, 0);
19816 return;
19817 }
19818
19819 TcKeyReq::setKeyLength(tcKeyRequestInfo, 0);
19820 TcKeyReq::setAIInTcKeyReq(tcKeyRequestInfo, 0);
19821 tcKeyReq->attrLen = 0;
19822 tcKeyReq->tableId = indexData->indexId;
19823 TcKeyReq::setOperationType(tcKeyRequestInfo, ZDELETE);
19824 tcKeyReq->tableSchemaVersion = indexTabPtr.p->currentSchemaVersion;
19825 tcKeyReq->transId1 = regApiPtr->transid[0];
19826 tcKeyReq->transId2 = regApiPtr->transid[1];
19827 tcKeyReq->requestInfo = tcKeyRequestInfo;
19828
19829 /* Attach KeyInfo section to signal */
19830 ndbrequire(signal->header.m_noOfSections == 0);
19831 signal->m_sectionPtrI[ TcKeyReq::KeyInfoSectionNum ] = keyIVal;
19832 signal->header.m_noOfSections= 1;
19833
19834 /**
19835 * Fix savepoint id -
19836 * fix so that delete has same savepoint id as triggering operation
19837 */
19838 const Uint32 currSavePointId = regApiPtr->currSavePointId;
19839 regApiPtr->currSavePointId = opRecord->savePointId;
19840 regApiPtr->m_special_op_flags = TcConnectRecord::SOF_TRIGGER;
19841 /* Pass trigger Id via ApiConnectRecord (nasty) */
19842 ndbrequire(regApiPtr->immediateTriggerId == RNIL);
19843 regApiPtr->immediateTriggerId= firedTriggerData->triggerId;
19844 EXECUTE_DIRECT(DBTC, GSN_TCKEYREQ, signal, TcKeyReq::StaticLength);
19845 jamEntry();
19846
19847 /*
19848 * Restore ApiConnectRecord state
19849 */
19850 regApiPtr->currSavePointId = currSavePointId;
19851 regApiPtr->immediateTriggerId = RNIL;
19852 }
19853
19854 Uint32
getErrorCode(Uint32 schemaVersion) const19855 Dbtc::TableRecord::getErrorCode(Uint32 schemaVersion) const {
19856 if(!get_enabled())
19857 return ZNO_SUCH_TABLE;
19858 if(get_dropping())
19859 return ZDROP_TABLE_IN_PROGRESS;
19860 if(table_version_major(schemaVersion) != table_version_major(currentSchemaVersion))
19861 return ZWRONG_SCHEMA_VERSION_ERROR;
19862 ErrorReporter::handleAssert("Dbtc::TableRecord::getErrorCode",
19863 __FILE__, __LINE__);
19864 return 0;
19865 }
19866
executeReorgTrigger(Signal * signal,TcDefinedTriggerData * definedTriggerData,TcFiredTriggerData * firedTriggerData,ApiConnectRecordPtr * transPtr,TcConnectRecordPtr * opPtr)19867 void Dbtc::executeReorgTrigger(Signal* signal,
19868 TcDefinedTriggerData* definedTriggerData,
19869 TcFiredTriggerData* firedTriggerData,
19870 ApiConnectRecordPtr* transPtr,
19871 TcConnectRecordPtr* opPtr)
19872 {
19873
19874 ApiConnectRecord* regApiPtr = transPtr->p;
19875 TcConnectRecord* opRecord = opPtr->p;
19876 TcKeyReq * tcKeyReq = (TcKeyReq *)signal->getDataPtrSend();
19877
19878 tcKeyReq->apiConnectPtr = transPtr->i;
19879 tcKeyReq->senderData = opPtr->i;
19880
19881 AttributeBuffer::DataBufferPool & pool = c_theAttributeBufferPool;
19882 LocalDataBuffer<11> keyValues(pool, firedTriggerData->keyValues);
19883 LocalDataBuffer<11> attrValues(pool, firedTriggerData->afterValues);
19884
19885 Uint32 optype;
19886 bool sendAttrInfo= true;
19887
19888 switch (firedTriggerData->triggerEvent) {
19889 case TriggerEvent::TE_INSERT:
19890 optype = ZINSERT;
19891 break;
19892 case TriggerEvent::TE_UPDATE:
19893 /**
19894 * Only update should be write, as COPY is done as update
19895 * a (maybe) better solution would be to have a different
19896 * trigger event for COPY
19897 */
19898 optype = ZWRITE;
19899 break;
19900 case TriggerEvent::TE_DELETE:
19901 optype = ZDELETE;
19902 sendAttrInfo= false;
19903 break;
19904 default:
19905 ndbrequire(false);
19906 }
19907
19908 Ptr<TableRecord> tablePtr;
19909 tablePtr.i = definedTriggerData->tableId;
19910 ptrCheckGuard(tablePtr, ctabrecFilesize, tableRecord);
19911 Uint32 tableVersion = tablePtr.p->currentSchemaVersion;
19912
19913 Uint32 tcKeyRequestInfo = 0;
19914 TcKeyReq::setKeyLength(tcKeyRequestInfo, 0);
19915 TcKeyReq::setOperationType(tcKeyRequestInfo, optype);
19916 TcKeyReq::setAIInTcKeyReq(tcKeyRequestInfo, 0);
19917 tcKeyReq->attrLen = 0;
19918 tcKeyReq->tableId = tablePtr.i;
19919 tcKeyReq->requestInfo = tcKeyRequestInfo;
19920 tcKeyReq->tableSchemaVersion = tableVersion;
19921 tcKeyReq->transId1 = regApiPtr->transid[0];
19922 tcKeyReq->transId2 = regApiPtr->transid[1];
19923
19924 Uint32 keyIVal= RNIL;
19925 Uint32 attrIVal= RNIL;
19926 Uint32 attrId= 0;
19927 bool hasNull= false;
19928
19929 /* Prepare KeyInfo section */
19930 if (unlikely(!appendAttrDataToSection(keyIVal,
19931 keyValues,
19932 false, // No AttributeHeaders
19933 attrId,
19934 hasNull)))
19935 {
19936 releaseSection(keyIVal);
19937 abortTransFromTrigger(signal, *transPtr, ZGET_DATAREC_ERROR);
19938 return;
19939 }
19940
19941 ndbrequire(!hasNull);
19942
19943 if (sendAttrInfo)
19944 {
19945 /* Prepare AttrInfo section from Key values and
19946 * After values
19947 */
19948 LocalDataBuffer<11>::Iterator attrIter;
19949 LocalDataBuffer<11>* buffers[2];
19950 buffers[0]= &keyValues;
19951 buffers[1]= &attrValues;
19952 const Uint32 segSize= keyValues.getSegmentSize(); // 11
19953 for (int buf=0; buf < 2; buf++)
19954 {
19955 Uint32 dataSize= buffers[buf]->getSize();
19956 bool moreData= buffers[buf]->first(attrIter);
19957
19958 while(dataSize)
19959 {
19960 ndbrequire(moreData);
19961 Uint32 contigLeft= segSize - attrIter.ind;
19962 Uint32 contigValid= MIN(dataSize, contigLeft);
19963
19964 if (unlikely(!appendToSection(attrIVal,
19965 attrIter.data,
19966 contigValid)))
19967 {
19968 releaseSection(keyIVal);
19969 releaseSection(attrIVal);
19970 abortTransFromTrigger(signal, *transPtr, ZGET_DATAREC_ERROR);
19971 return;
19972 }
19973 moreData= buffers[buf]->next(attrIter, contigValid);
19974 dataSize-= contigValid;
19975 }
19976 ndbassert(!moreData);
19977 }
19978 }
19979
19980 /* Attach Key and optional AttrInfo sections to signal */
19981 ndbrequire(signal->header.m_noOfSections == 0);
19982 signal->m_sectionPtrI[ TcKeyReq::KeyInfoSectionNum ] = keyIVal;
19983 signal->m_sectionPtrI[ TcKeyReq::AttrInfoSectionNum ] = attrIVal;
19984 signal->header.m_noOfSections= sendAttrInfo? 2 : 1;
19985
19986 /**
19987 * Fix savepoint id -
19988 * fix so that the op has same savepoint id as triggering operation
19989 */
19990 const Uint32 currSavePointId = regApiPtr->currSavePointId;
19991 regApiPtr->currSavePointId = opRecord->savePointId;
19992 regApiPtr->m_special_op_flags = TcConnectRecord::SOF_REORG_TRIGGER;
19993 /* Pass trigger Id via ApiConnectRecord (nasty) */
19994 ndbrequire(regApiPtr->immediateTriggerId == RNIL);
19995
19996 regApiPtr->immediateTriggerId= firedTriggerData->triggerId;
19997 EXECUTE_DIRECT(DBTC, GSN_TCKEYREQ, signal, TcKeyReq::StaticLength);
19998 jamEntry();
19999
20000 /*
20001 * Restore ApiConnectRecord state
20002 */
20003 regApiPtr->currSavePointId = currSavePointId;
20004 regApiPtr->immediateTriggerId = RNIL;
20005 }
20006
20007 void
execROUTE_ORD(Signal * signal)20008 Dbtc::execROUTE_ORD(Signal* signal)
20009 {
20010 jamEntry();
20011 if(!assembleFragments(signal)){
20012 jam();
20013 return;
20014 }
20015
20016 SectionHandle handle(this, signal);
20017
20018 RouteOrd* ord = (RouteOrd*)signal->getDataPtr();
20019 Uint32 dstRef = ord->dstRef;
20020 Uint32 srcRef = ord->srcRef;
20021 Uint32 gsn = ord->gsn;
20022
20023 if (likely(getNodeInfo(refToNode(dstRef)).m_connected))
20024 {
20025 jam();
20026 Uint32 secCount = handle.m_cnt;
20027 ndbrequire(secCount >= 1 && secCount <= 3);
20028
20029 jamLine(secCount);
20030
20031 /**
20032 * Put section 0 in signal->theData
20033 */
20034 Uint32 sigLen = handle.m_ptr[0].sz;
20035 ndbrequire(sigLen <= 25);
20036 copy(signal->theData, handle.m_ptr[0]);
20037
20038 SegmentedSectionPtr save = handle.m_ptr[0];
20039 for (Uint32 i = 0; i < secCount - 1; i++)
20040 handle.m_ptr[i] = handle.m_ptr[i+1];
20041 handle.m_cnt--;
20042
20043 sendSignal(dstRef, gsn, signal, sigLen, JBB, &handle);
20044
20045 handle.m_cnt = 1;
20046 handle.m_ptr[0] = save;
20047 releaseSections(handle);
20048 return ;
20049 }
20050
20051 releaseSections(handle);
20052 warningEvent("Unable to route GSN: %d from %x to %x",
20053 gsn, srcRef, dstRef);
20054
20055 }
20056