1 /* Copyright (c) 2003-2007 MySQL AB
2 Use is subject to license terms
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; version 2 of the License.
7
8 This program is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 GNU General Public License for more details.
12
13 You should have received a copy of the GNU General Public License
14 along with this program; if not, write to the Free Software
15 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */
16
17 #include <ndb_global.h>
18 #include <NdbOut.hpp>
19 #include <NdbTransaction.hpp>
20 #include <NdbOperation.hpp>
21 #include <NdbScanOperation.hpp>
22 #include <NdbIndexScanOperation.hpp>
23 #include <NdbIndexOperation.hpp>
24 #include "NdbApiSignal.hpp"
25 #include "TransporterFacade.hpp"
26 #include "API.hpp"
27 #include "NdbBlob.hpp"
28
29 #include <signaldata/TcKeyConf.hpp>
30 #include <signaldata/TcIndx.hpp>
31 #include <signaldata/TcCommit.hpp>
32 #include <signaldata/TcKeyFailConf.hpp>
33 #include <signaldata/TcHbRep.hpp>
34 #include <signaldata/TcRollbackRep.hpp>
35
36 /*****************************************************************************
37 NdbTransaction( Ndb* aNdb );
38
39 Return Value: None
40 Parameters: aNdb: Pointers to the Ndb object
41 Remark: Creates a connection object.
42 *****************************************************************************/
NdbTransaction(Ndb * aNdb)43 NdbTransaction::NdbTransaction( Ndb* aNdb ) :
44 theSendStatus(NotInit),
45 theCallbackFunction(NULL),
46 theCallbackObject(NULL),
47 theTransArrayIndex(0),
48 theStartTransTime(0),
49 theErrorLine(0),
50 theErrorOperation(NULL),
51 theNdb(aNdb),
52 theNext(NULL),
53 theFirstOpInList(NULL),
54 theLastOpInList(NULL),
55 theFirstExecOpInList(NULL),
56 theLastExecOpInList(NULL),
57 theCompletedFirstOp(NULL),
58 theCompletedLastOp(NULL),
59 theNoOfOpSent(0),
60 theNoOfOpCompleted(0),
61 theMyRef(0),
62 theTCConPtr(0),
63 theTransactionId(0),
64 theGlobalCheckpointId(0),
65 p_latest_trans_gci(0),
66 theStatus(NotConnected),
67 theCompletionStatus(NotCompleted),
68 theCommitStatus(NotStarted),
69 theMagicNumber(0xFE11DC),
70 theTransactionIsStarted(false),
71 theDBnode(0),
72 theReleaseOnClose(false),
73 // Scan operations
74 m_waitForReply(true),
75 m_theFirstScanOperation(NULL),
76 m_theLastScanOperation(NULL),
77 m_firstExecutedScanOp(NULL),
78 // Scan operations
79 theScanningOp(NULL),
80 theBuddyConPtr(0xFFFFFFFF),
81 theBlobFlag(false),
82 thePendingBlobOps(0)
83 {
84 theListState = NotInList;
85 theError.code = 0;
86 //theId = NdbObjectIdMap::InvalidId;
87 theId = theNdb->theImpl->theNdbObjectIdMap.map(this);
88
89 #define CHECK_SZ(mask, sz) assert((sizeof(mask)/sizeof(mask[0])) == sz)
90
91 CHECK_SZ(m_db_nodes, NdbNodeBitmask::Size);
92 CHECK_SZ(m_failed_db_nodes, NdbNodeBitmask::Size);
93 }//NdbTransaction::NdbTransaction()
94
95 /*****************************************************************************
96 ~NdbTransaction();
97
98 Remark: Deletes the connection object.
99 *****************************************************************************/
~NdbTransaction()100 NdbTransaction::~NdbTransaction()
101 {
102 DBUG_ENTER("NdbTransaction::~NdbTransaction");
103 theNdb->theImpl->theNdbObjectIdMap.unmap(theId, this);
104 DBUG_VOID_RETURN;
105 }//NdbTransaction::~NdbTransaction()
106
107 /*****************************************************************************
108 void init();
109
110 Remark: Initialise connection object for new transaction.
111 *****************************************************************************/
112 int
init()113 NdbTransaction::init()
114 {
115 theListState = NotInList;
116 theInUseState = true;
117 theTransactionIsStarted = false;
118 theNext = NULL;
119
120 theFirstOpInList = NULL;
121 theLastOpInList = NULL;
122
123 theScanningOp = NULL;
124
125 theFirstExecOpInList = NULL;
126 theLastExecOpInList = NULL;
127
128 theCompletedFirstOp = NULL;
129 theCompletedLastOp = NULL;
130
131 theGlobalCheckpointId = 0;
132 p_latest_trans_gci =
133 theNdb->theImpl->m_ndb_cluster_connection.get_latest_trans_gci();
134 theCommitStatus = Started;
135 theCompletionStatus = NotCompleted;
136
137 theError.code = 0;
138 theErrorLine = 0;
139 theErrorOperation = NULL;
140
141 theReleaseOnClose = false;
142 theSimpleState = true;
143 theSendStatus = InitState;
144 theMagicNumber = 0x37412619;
145 // Scan operations
146 m_waitForReply = true;
147 m_theFirstScanOperation = NULL;
148 m_theLastScanOperation = NULL;
149 m_firstExecutedScanOp = 0;
150 theBuddyConPtr = 0xFFFFFFFF;
151 //
152 theBlobFlag = false;
153 thePendingBlobOps = 0;
154 if (theId == NdbObjectIdMap::InvalidId)
155 {
156 theId = theNdb->theImpl->theNdbObjectIdMap.map(this);
157 if (theId == NdbObjectIdMap::InvalidId)
158 {
159 theError.code = 4000;
160 return -1;
161 }
162 }
163 return 0;
164
165 }//NdbTransaction::init()
166
167 /*****************************************************************************
168 setOperationErrorCode(int error);
169
170 Remark: Sets an error code on the connection object from an
171 operation object.
172 *****************************************************************************/
173 void
setOperationErrorCode(int error)174 NdbTransaction::setOperationErrorCode(int error)
175 {
176 DBUG_ENTER("NdbTransaction::setOperationErrorCode");
177 setErrorCode(error);
178 DBUG_VOID_RETURN;
179 }
180
181 /*****************************************************************************
182 setOperationErrorCodeAbort(int error);
183
184 Remark: Sets an error code on the connection object from an
185 operation object.
186 *****************************************************************************/
187 void
setOperationErrorCodeAbort(int error,int abortOption)188 NdbTransaction::setOperationErrorCodeAbort(int error, int abortOption)
189 {
190 DBUG_ENTER("NdbTransaction::setOperationErrorCodeAbort");
191 if (theTransactionIsStarted == false) {
192 theCommitStatus = Aborted;
193 } else if ((theCommitStatus != Committed) &&
194 (theCommitStatus != Aborted)) {
195 theCommitStatus = NeedAbort;
196 }//if
197 setErrorCode(error);
198 DBUG_VOID_RETURN;
199 }
200
201 /*****************************************************************************
202 setErrorCode(int anErrorCode);
203
204 Remark: Sets an error indication on the connection object.
205 *****************************************************************************/
206 void
setErrorCode(int error)207 NdbTransaction::setErrorCode(int error)
208 {
209 DBUG_ENTER("NdbTransaction::setErrorCode");
210 DBUG_PRINT("enter", ("error: %d, theError.code: %d", error, theError.code));
211
212 if (theError.code == 0)
213 theError.code = error;
214
215 DBUG_VOID_RETURN;
216 }//NdbTransaction::setErrorCode()
217
218 int
restart()219 NdbTransaction::restart(){
220 DBUG_ENTER("NdbTransaction::restart");
221 if(theCompletionStatus == CompletedSuccess){
222 releaseCompletedOperations();
223 Uint64 tTransid = theNdb->theFirstTransId;
224 theTransactionId = tTransid;
225 if ((tTransid & 0xFFFFFFFF) == 0xFFFFFFFF) {
226 theNdb->theFirstTransId = (tTransid >> 32) << 32;
227 } else {
228 theNdb->theFirstTransId = tTransid + 1;
229 }
230 theCommitStatus = Started;
231 theCompletionStatus = NotCompleted;
232 theTransactionIsStarted = false;
233 DBUG_RETURN(0);
234 }
235 DBUG_PRINT("error",("theCompletionStatus != CompletedSuccess"));
236 DBUG_RETURN(-1);
237 }
238
239 /*****************************************************************************
240 void handleExecuteCompletion(void);
241
242 Remark: Handle time-out on a transaction object.
243 *****************************************************************************/
244 void
handleExecuteCompletion()245 NdbTransaction::handleExecuteCompletion()
246 {
247 /***************************************************************************
248 * Move the NdbOperation objects from the list of executing
249 * operations to list of completed
250 **************************************************************************/
251 NdbOperation* tFirstExecOp = theFirstExecOpInList;
252 NdbOperation* tLastExecOp = theLastExecOpInList;
253 if (tLastExecOp != NULL) {
254 tLastExecOp->next(theCompletedFirstOp);
255 theCompletedFirstOp = tFirstExecOp;
256 if (theCompletedLastOp == NULL)
257 theCompletedLastOp = tLastExecOp;
258 theFirstExecOpInList = NULL;
259 theLastExecOpInList = NULL;
260 }//if
261 theSendStatus = InitState;
262 return;
263 }//NdbTransaction::handleExecuteCompletion()
264
265 /*****************************************************************************
266 int execute(ExecType aTypeOfExec, CommitType aTypeOfCommit, int forceSend);
267
268 Return Value: Return 0 : execute was successful.
269 Return -1: In all other case.
270 Parameters : aTypeOfExec: Type of execute.
271 Remark: Initialise connection object for new transaction.
272 *****************************************************************************/
273 int
execute(ExecType aTypeOfExec,NdbOperation::AbortOption abortOption,int forceSend)274 NdbTransaction::execute(ExecType aTypeOfExec,
275 NdbOperation::AbortOption abortOption,
276 int forceSend)
277 {
278 NdbError savedError= theError;
279 DBUG_ENTER("NdbTransaction::execute");
280 DBUG_PRINT("enter", ("aTypeOfExec: %d, abortOption: %d",
281 aTypeOfExec, abortOption));
282
283 if (! theBlobFlag)
284 DBUG_RETURN(executeNoBlobs(aTypeOfExec, abortOption, forceSend));
285
286 /*
287 * execute prepared ops in batches, as requested by blobs
288 * - blob error does not terminate execution
289 * - blob error sets error on operation
290 * - if error on operation skip blob calls
291 */
292
293 ExecType tExecType;
294 NdbOperation* tPrepOp;
295 NdbOperation* tCompletedFirstOp = NULL;
296 NdbOperation* tCompletedLastOp = NULL;
297
298 int ret = 0;
299 do {
300 tExecType = aTypeOfExec;
301 tPrepOp = theFirstOpInList;
302 while (tPrepOp != NULL) {
303 if (tPrepOp->theError.code == 0) {
304 bool batch = false;
305 NdbBlob* tBlob = tPrepOp->theBlobList;
306 while (tBlob != NULL) {
307 if (tBlob->preExecute(tExecType, batch) == -1)
308 {
309 ret = -1;
310 if(savedError.code==0)
311 savedError= theError;
312 }
313 tBlob = tBlob->theNext;
314 }
315 if (batch) {
316 // blob asked to execute all up to here now
317 tExecType = NoCommit;
318 break;
319 }
320 }
321 tPrepOp = tPrepOp->next();
322 }
323
324 // save rest of prepared ops if batch
325 NdbOperation* tRestOp= 0;
326 NdbOperation* tLastOp= 0;
327 if (tPrepOp != NULL) {
328 tRestOp = tPrepOp->next();
329 tPrepOp->next(NULL);
330 tLastOp = theLastOpInList;
331 theLastOpInList = tPrepOp;
332 }
333
334 if (tExecType == Commit) {
335 NdbOperation* tOp = theCompletedFirstOp;
336 while (tOp != NULL) {
337 if (tOp->theError.code == 0) {
338 NdbBlob* tBlob = tOp->theBlobList;
339 while (tBlob != NULL) {
340 if (tBlob->preCommit() == -1)
341 {
342 ret = -1;
343 if(savedError.code==0)
344 savedError= theError;
345 }
346 tBlob = tBlob->theNext;
347 }
348 }
349 tOp = tOp->next();
350 }
351 }
352
353 // completed ops are in unspecified order
354 if (theCompletedFirstOp != NULL) {
355 if (tCompletedFirstOp == NULL) {
356 tCompletedFirstOp = theCompletedFirstOp;
357 tCompletedLastOp = theCompletedLastOp;
358 } else {
359 tCompletedLastOp->next(theCompletedFirstOp);
360 tCompletedLastOp = theCompletedLastOp;
361 }
362 theCompletedFirstOp = NULL;
363 theCompletedLastOp = NULL;
364 }
365
366 if (executeNoBlobs(tExecType,
367 NdbOperation::DefaultAbortOption,
368 forceSend) == -1)
369 {
370 if(savedError.code==0)
371 savedError= theError;
372
373 DBUG_RETURN(-1);
374 }
375
376 #ifdef ndb_api_crash_on_complex_blob_abort
377 assert(theFirstOpInList == NULL && theLastOpInList == NULL);
378 #else
379 theFirstOpInList = theLastOpInList = NULL;
380 #endif
381
382 {
383 NdbOperation* tOp = theCompletedFirstOp;
384 while (tOp != NULL) {
385 if (tOp->theError.code == 0) {
386 NdbBlob* tBlob = tOp->theBlobList;
387 while (tBlob != NULL) {
388 // may add new operations if batch
389 if (tBlob->postExecute(tExecType) == -1)
390 {
391 ret = -1;
392 if(savedError.code==0)
393 savedError= theError;
394 }
395 tBlob = tBlob->theNext;
396 }
397 }
398 tOp = tOp->next();
399 }
400 }
401
402 // add saved prepared ops if batch
403 if (tPrepOp != NULL && tRestOp != NULL) {
404 if (theFirstOpInList == NULL)
405 theFirstOpInList = tRestOp;
406 else
407 theLastOpInList->next(tRestOp);
408 theLastOpInList = tLastOp;
409 }
410 assert(theFirstOpInList == NULL || tExecType == NoCommit);
411 } while (theFirstOpInList != NULL || tExecType != aTypeOfExec);
412
413 if (tCompletedFirstOp != NULL) {
414 tCompletedLastOp->next(theCompletedFirstOp);
415 theCompletedFirstOp = tCompletedFirstOp;
416 if (theCompletedLastOp == NULL)
417 theCompletedLastOp = tCompletedLastOp;
418 }
419 #if ndb_api_count_completed_ops_after_blob_execute
420 { NdbOperation* tOp; unsigned n = 0;
421 for (tOp = theCompletedFirstOp; tOp != NULL; tOp = tOp->next()) n++;
422 ndbout << "completed ops: " << n << endl;
423 }
424 #endif
425
426 if(savedError.code!=0 && theError.code==4350) // Trans already aborted
427 theError= savedError;
428
429 DBUG_RETURN(ret);
430 }
431
432 int
executeNoBlobs(NdbTransaction::ExecType aTypeOfExec,NdbOperation::AbortOption abortOption,int forceSend)433 NdbTransaction::executeNoBlobs(NdbTransaction::ExecType aTypeOfExec,
434 NdbOperation::AbortOption abortOption,
435 int forceSend)
436 {
437 DBUG_ENTER("NdbTransaction::executeNoBlobs");
438 DBUG_PRINT("enter", ("aTypeOfExec: %d, abortOption: %d",
439 aTypeOfExec, abortOption));
440
441 //------------------------------------------------------------------------
442 // We will start by preparing all operations in the transaction defined
443 // since last execute or since beginning. If this works ok we will continue
444 // by calling the poll with wait method. This method will return when
445 // the NDB kernel has completed its task or when 10 seconds have passed.
446 // The NdbTransactionCallBack-method will receive the return code of the
447 // transaction. The normal methods of reading error codes still apply.
448 //------------------------------------------------------------------------
449 Ndb* tNdb = theNdb;
450
451 Uint32 timeout = theNdb->theImpl->m_transporter_facade->m_waitfor_timeout;
452 m_waitForReply = false;
453 executeAsynchPrepare(aTypeOfExec, NULL, NULL, abortOption);
454 if (m_waitForReply){
455 while (1) {
456 int noOfComp = tNdb->sendPollNdb(3 * timeout, 1, forceSend);
457 if (noOfComp == 0) {
458 /*
459 * Just for fun, this is only one of two places where
460 * we could hit this error... It's quite possible we
461 * hit it in Ndbif.cpp in Ndb::check_send_timeout()
462 *
463 * We behave rather similarly in both places.
464 * Hitting this is certainly a bug though...
465 */
466 g_eventLogger.error("WARNING: Timeout in executeNoBlobs() waiting for "
467 "response from NDB data nodes. This should NEVER "
468 "occur. You have likely hit a NDB Bug. Please "
469 "file a bug.");
470 DBUG_PRINT("error",("This timeout should never occure, execute()"));
471 g_eventLogger.error("Forcibly trying to rollback txn (%p"
472 ") to try to clean up data node resources.",
473 this);
474 executeNoBlobs(NdbTransaction::Rollback);
475 theError.code = 4012;
476 theError.status= NdbError::PermanentError;
477 theError.classification= NdbError::TimeoutExpired;
478 setOperationErrorCodeAbort(4012); // ndbd timeout
479 DBUG_RETURN(-1);
480 }//if
481
482 /*
483 * Check that the completed transactions include this one. There
484 * could be another thread running asynchronously. Even in pure
485 * async case rollback is done synchronously.
486 */
487 if (theListState != NotInList)
488 continue;
489 #ifdef VM_TRACE
490 unsigned anyway = 0;
491 for (unsigned i = 0; i < theNdb->theNoOfPreparedTransactions; i++)
492 anyway += theNdb->thePreparedTransactionsArray[i] == this;
493 for (unsigned i = 0; i < theNdb->theNoOfSentTransactions; i++)
494 anyway += theNdb->theSentTransactionsArray[i] == this;
495 for (unsigned i = 0; i < theNdb->theNoOfCompletedTransactions; i++)
496 anyway += theNdb->theCompletedTransactionsArray[i] == this;
497 if (anyway) {
498 theNdb->printState("execute %x", this);
499 abort();
500 }
501 #endif
502 if (theReturnStatus == ReturnFailure) {
503 DBUG_RETURN(-1);
504 }//if
505 break;
506 }
507 }
508 thePendingBlobOps = 0;
509 DBUG_RETURN(0);
510 }//NdbTransaction::execute()
511
512 /*****************************************************************************
513 void executeAsynchPrepare(ExecType aTypeOfExec,
514 NdbAsynchCallback callBack,
515 void* anyObject,
516 CommitType aTypeOfCommit);
517
518 Return Value: No return value
519 Parameters : aTypeOfExec: Type of execute.
520 anyObject: An object provided in the callback method
521 callBack: The callback method
522 aTypeOfCommit: What to do when read/updated/deleted records
523 are missing or inserted records already exist.
524
525 Remark: Prepare a part of a transaction in an asynchronous manner.
526 *****************************************************************************/
527 void
executeAsynchPrepare(NdbTransaction::ExecType aTypeOfExec,NdbAsynchCallback aCallback,void * anyObject,NdbOperation::AbortOption abortOption)528 NdbTransaction::executeAsynchPrepare(NdbTransaction::ExecType aTypeOfExec,
529 NdbAsynchCallback aCallback,
530 void* anyObject,
531 NdbOperation::AbortOption abortOption)
532 {
533 DBUG_ENTER("NdbTransaction::executeAsynchPrepare");
534 DBUG_PRINT("enter", ("aTypeOfExec: %d, aCallback: 0x%lx, anyObject: Ox%lx",
535 aTypeOfExec, (long) aCallback, (long) anyObject));
536
537 /**
538 * Reset error.code on execute
539 */
540 if (theError.code != 0)
541 DBUG_PRINT("enter", ("Resetting error %d on execute", theError.code));
542 /**
543 * for timeout (4012) we want sendROLLBACK to behave differently.
544 * Else, normal behaviour of reset errcode
545 */
546 if (theError.code != 4012)
547 theError.code = 0;
548 NdbScanOperation* tcOp = m_theFirstScanOperation;
549 if (tcOp != 0){
550 // Execute any cursor operations
551 while (tcOp != NULL) {
552 int tReturnCode;
553 tReturnCode = tcOp->executeCursor(theDBnode);
554 if (tReturnCode == -1) {
555 DBUG_VOID_RETURN;
556 }//if
557 tcOp = (NdbScanOperation*)tcOp->next();
558 } // while
559 m_theLastScanOperation->next(m_firstExecutedScanOp);
560 m_firstExecutedScanOp = m_theFirstScanOperation;
561 // Discard cursor operations, since these are also
562 // in the complete operations list we do not need
563 // to release them.
564 m_theFirstScanOperation = m_theLastScanOperation = NULL;
565 }
566
567 bool tTransactionIsStarted = theTransactionIsStarted;
568 NdbOperation* tLastOp = theLastOpInList;
569 Ndb* tNdb = theNdb;
570 CommitStatusType tCommitStatus = theCommitStatus;
571 Uint32 tnoOfPreparedTransactions = tNdb->theNoOfPreparedTransactions;
572
573 theReturnStatus = ReturnSuccess;
574 theCallbackFunction = aCallback;
575 theCallbackObject = anyObject;
576 m_waitForReply = true;
577 tNdb->thePreparedTransactionsArray[tnoOfPreparedTransactions] = this;
578 theTransArrayIndex = tnoOfPreparedTransactions;
579 theListState = InPreparedList;
580 tNdb->theNoOfPreparedTransactions = tnoOfPreparedTransactions + 1;
581
582 if ((tCommitStatus != Started) ||
583 (aTypeOfExec == Rollback)) {
584 /*****************************************************************************
585 * Rollback have been ordered on a started transaction. Call rollback.
586 * Could also be state problem or previous problem which leads to the
587 * same action.
588 ****************************************************************************/
589 if (aTypeOfExec == Rollback) {
590 if (theTransactionIsStarted == false || theSimpleState) {
591 theCommitStatus = Aborted;
592 theSendStatus = sendCompleted;
593 } else {
594 theSendStatus = sendABORT;
595 }
596 } else {
597 theSendStatus = sendABORTfail;
598 }//if
599 if (theCommitStatus == Aborted){
600 DBUG_PRINT("exit", ("theCommitStatus: Aborted"));
601 setErrorCode(4350);
602 }
603 DBUG_VOID_RETURN;
604 }//if
605 if (tTransactionIsStarted == true) {
606 if (tLastOp != NULL) {
607 if (aTypeOfExec == Commit) {
608 /*****************************************************************************
609 * Set commit indicator on last operation when commit has been ordered
610 * and also a number of operations.
611 ******************************************************************************/
612 tLastOp->theCommitIndicator = 1;
613 }//if
614 } else {
615 if (aTypeOfExec == Commit && !theSimpleState) {
616 /**********************************************************************
617 * A Transaction have been started and no more operations exist.
618 * We will use the commit method.
619 *********************************************************************/
620 theSendStatus = sendCOMMITstate;
621 DBUG_VOID_RETURN;
622 } else {
623 /**********************************************************************
624 * We need to put it into the array of completed transactions to
625 * ensure that we report the completion in a proper way.
626 * We cannot do this here since that would endanger the completed
627 * transaction array since that is also updated from the receiver
628 * thread and thus we need to do it under mutex lock and thus we
629 * set the sendStatus to ensure that the send method will
630 * put it into the completed array.
631 **********************************************************************/
632 theSendStatus = sendCompleted;
633 DBUG_VOID_RETURN; // No Commit with no operations is OK
634 }//if
635 }//if
636 } else if (tTransactionIsStarted == false) {
637 NdbOperation* tFirstOp = theFirstOpInList;
638 if (tLastOp != NULL) {
639 tFirstOp->setStartIndicator();
640 if (aTypeOfExec == Commit) {
641 tLastOp->theCommitIndicator = 1;
642 }//if
643 } else {
644 /***********************************************************************
645 * No operations are defined and we have not started yet.
646 * Simply return OK. Set commit status if Commit.
647 ***********************************************************************/
648 if (aTypeOfExec == Commit) {
649 theCommitStatus = Committed;
650 }//if
651 /***********************************************************************
652 * We need to put it into the array of completed transactions to
653 * ensure that we report the completion in a proper way. We
654 * cannot do this here since that would endanger the completed
655 * transaction array since that is also updated from the
656 * receiver thread and thus we need to do it under mutex lock
657 * and thus we set the sendStatus to ensure that the send method
658 * will put it into the completed array.
659 ***********************************************************************/
660 theSendStatus = sendCompleted;
661 DBUG_VOID_RETURN;
662 }//if
663 }
664
665 NdbOperation* tOp = theFirstOpInList;
666 theCompletionStatus = NotCompleted;
667 while (tOp) {
668 int tReturnCode;
669 NdbOperation* tNextOp = tOp->next();
670 tReturnCode = tOp->prepareSend(theTCConPtr, theTransactionId, abortOption);
671 if (tReturnCode == -1) {
672 theSendStatus = sendABORTfail;
673 DBUG_VOID_RETURN;
674 }//if
675
676 /*************************************************************************
677 * Now that we have successfully prepared the send of this operation we
678 * move it to the list of executing operations and remove it from the
679 * list of defined operations.
680 ************************************************************************/
681 tOp = tNextOp;
682 }
683
684 NdbOperation* tLastOpInList = theLastOpInList;
685 NdbOperation* tFirstOpInList = theFirstOpInList;
686
687 theFirstOpInList = NULL;
688 theLastOpInList = NULL;
689 theFirstExecOpInList = tFirstOpInList;
690 theLastExecOpInList = tLastOpInList;
691
692 theCompletionStatus = CompletedSuccess;
693 theNoOfOpSent = 0;
694 theNoOfOpCompleted = 0;
695 theSendStatus = sendOperations;
696 NdbNodeBitmask::clear(m_db_nodes);
697 NdbNodeBitmask::clear(m_failed_db_nodes);
698 DBUG_VOID_RETURN;
699 }//NdbTransaction::executeAsynchPrepare()
700
701 void
executeAsynch(ExecType aTypeOfExec,NdbAsynchCallback aCallback,void * anyObject,NdbOperation::AbortOption abortOption,int forceSend)702 NdbTransaction::executeAsynch(ExecType aTypeOfExec,
703 NdbAsynchCallback aCallback,
704 void* anyObject,
705 NdbOperation::AbortOption abortOption,
706 int forceSend)
707 {
708 executeAsynchPrepare(aTypeOfExec, aCallback, anyObject, abortOption);
709 theNdb->sendPreparedTransactions(forceSend);
710 }
711
close()712 void NdbTransaction::close()
713 {
714 theNdb->closeTransaction(this);
715 }
716
refresh()717 int NdbTransaction::refresh(){
718 return sendTC_HBREP();
719 }
720
721 /*****************************************************************************
722 int sendTC_HBREP();
723
724 Return Value: No return value.
725 Parameters : None.
726 Remark: Order NDB to refresh the timeout counter of the transaction.
727 ******************************************************************************/
728 int
sendTC_HBREP()729 NdbTransaction::sendTC_HBREP() // Send a TC_HBREP signal;
730 {
731 NdbApiSignal* tSignal;
732 Ndb* tNdb = theNdb;
733 Uint32 tTransId1, tTransId2;
734
735 tSignal = tNdb->getSignal();
736 if (tSignal == NULL) {
737 return -1;
738 }
739
740 if (tSignal->setSignal(GSN_TC_HBREP) == -1) {
741 return -1;
742 }
743
744 TcHbRep * const tcHbRep = CAST_PTR(TcHbRep, tSignal->getDataPtrSend());
745
746 tcHbRep->apiConnectPtr = theTCConPtr;
747
748 tTransId1 = (Uint32) theTransactionId;
749 tTransId2 = (Uint32) (theTransactionId >> 32);
750 tcHbRep->transId1 = tTransId1;
751 tcHbRep->transId2 = tTransId2;
752
753 TransporterFacade *tp = theNdb->theImpl->m_transporter_facade;
754 tp->lock_mutex();
755 const int res = tp->sendSignal(tSignal,theDBnode);
756 tp->unlock_mutex();
757 tNdb->releaseSignal(tSignal);
758
759 if (res == -1){
760 return -1;
761 }
762
763 return 0;
764 }//NdbTransaction::sendTC_HBREP()
765
766 /*****************************************************************************
767 int doSend();
768
769 Return Value: Return 0 : send was successful.
770 Return -1: In all other case.
771 Remark: Send all operations belonging to this connection.
772 The caller of this method has the responsibility to remove the
773 object from the prepared transactions array on the Ndb-object.
774 *****************************************************************************/
775 int
doSend()776 NdbTransaction::doSend()
777 {
778 DBUG_ENTER("NdbTransaction::doSend");
779
780 /*
781 This method assumes that at least one operation have been defined. This
782 is ensured by the caller of this routine (=execute).
783 */
784
785 switch(theSendStatus){
786 case sendOperations: {
787 NdbOperation * tOp = theFirstExecOpInList;
788 do {
789 NdbOperation* tNextOp = tOp->next();
790 const Uint32 lastFlag = ((tNextOp == NULL) ? 1 : 0);
791 const int tReturnCode = tOp->doSend(theDBnode, lastFlag);
792 if (tReturnCode == -1) {
793 theReturnStatus = ReturnFailure;
794 break;
795 }//if
796 tOp = tNextOp;
797 } while (tOp != NULL);
798 Ndb* tNdb = theNdb;
799 theSendStatus = sendTC_OP;
800 theTransactionIsStarted = true;
801 tNdb->insert_sent_list(this);
802 DBUG_RETURN(0);
803 }//case
804 case sendABORT:
805 case sendABORTfail:{
806 /***********************************************************************
807 * Rollback have been ordered on a not started transaction.
808 * Simply return OK and set abort status.
809 ***********************************************************************/
810 if (theSendStatus == sendABORTfail) {
811 theReturnStatus = ReturnFailure;
812 }//if
813 if (sendROLLBACK() == 0) {
814 DBUG_RETURN(0);
815 }//if
816 break;
817 }//case
818 case sendCOMMITstate:
819 if (sendCOMMIT() == 0) {
820 DBUG_RETURN(0);
821 }//if
822 break;
823 case sendCompleted:
824 theNdb->insert_completed_list(this);
825 DBUG_RETURN(0);
826 default:
827 ndbout << "Inconsistent theSendStatus = "
828 << (Uint32) theSendStatus << endl;
829 abort();
830 break;
831 }//switch
832 setOperationErrorCodeAbort(4002);
833 theReleaseOnClose = true;
834 theTransactionIsStarted = false;
835 theCommitStatus = Aborted;
836 DBUG_RETURN(-1);
837 }//NdbTransaction::doSend()
838
839 /**************************************************************************
840 int sendROLLBACK();
841
842 Return Value: Return -1 if send unsuccessful.
843 Parameters : None.
844 Remark: Order NDB to rollback the transaction.
845 **************************************************************************/
846 int
sendROLLBACK()847 NdbTransaction::sendROLLBACK() // Send a TCROLLBACKREQ signal;
848 {
849 Ndb* tNdb = theNdb;
850 if ((theTransactionIsStarted == true) &&
851 (theCommitStatus != Committed) &&
852 (theCommitStatus != Aborted)) {
853 /**************************************************************************
854 * The user did not perform any rollback but simply closed the
855 * transaction. We must rollback Ndb since Ndb have been contacted.
856 *************************************************************************/
857 NdbApiSignal tSignal(tNdb->theMyRef);
858 Uint32 tTransId1, tTransId2;
859 TransporterFacade *tp = theNdb->theImpl->m_transporter_facade;
860 int tReturnCode;
861
862 tTransId1 = (Uint32) theTransactionId;
863 tTransId2 = (Uint32) (theTransactionId >> 32);
864 tSignal.setSignal(GSN_TCROLLBACKREQ);
865 tSignal.setData(theTCConPtr, 1);
866 tSignal.setData(tTransId1, 2);
867 tSignal.setData(tTransId2, 3);
868 if(theError.code == 4012)
869 {
870 g_eventLogger.error("Sending TCROLLBACKREQ with Bad flag");
871 tSignal.setLength(tSignal.getLength() + 1); // + flags
872 tSignal.setData(0x1, 4); // potentially bad data
873 }
874 tReturnCode = tp->sendSignal(&tSignal,theDBnode);
875 if (tReturnCode != -1) {
876 theSendStatus = sendTC_ROLLBACK;
877 tNdb->insert_sent_list(this);
878 return 0;
879 }//if
880 /*********************************************************************
881 * It was not possible to abort the transaction towards the NDB kernel
882 * and thus we put it into the array of completed transactions that
883 * are ready for reporting to the application.
884 *********************************************************************/
885 return -1;
886 } else {
887 /*
888 It is not necessary to abort the transaction towards the NDB kernel and
889 thus we put it into the array of completed transactions that are ready
890 for reporting to the application.
891 */
892 theSendStatus = sendCompleted;
893 tNdb->insert_completed_list(this);
894 return 0;
895 ;
896 }//if
897 }//NdbTransaction::sendROLLBACK()
898
899 /***************************************************************************
900 int sendCOMMIT();
901
902 Return Value: Return 0 : send was successful.
903 Return -1: In all other case.
904 Parameters : None.
905 Remark: Order NDB to commit the transaction.
906 ***************************************************************************/
907 int
sendCOMMIT()908 NdbTransaction::sendCOMMIT() // Send a TC_COMMITREQ signal;
909 {
910 NdbApiSignal tSignal(theNdb->theMyRef);
911 Uint32 tTransId1, tTransId2;
912 TransporterFacade *tp = theNdb->theImpl->m_transporter_facade;
913 int tReturnCode;
914
915 tTransId1 = (Uint32) theTransactionId;
916 tTransId2 = (Uint32) (theTransactionId >> 32);
917 tSignal.setSignal(GSN_TC_COMMITREQ);
918 tSignal.setData(theTCConPtr, 1);
919 tSignal.setData(tTransId1, 2);
920 tSignal.setData(tTransId2, 3);
921
922 tReturnCode = tp->sendSignal(&tSignal,theDBnode);
923 if (tReturnCode != -1) {
924 theSendStatus = sendTC_COMMIT;
925 theNdb->insert_sent_list(this);
926 return 0;
927 } else {
928 return -1;
929 }//if
930 }//NdbTransaction::sendCOMMIT()
931
932 /******************************************************************************
933 void release();
934
935 Remark: Release all operations.
936 ******************************************************************************/
937 void
release()938 NdbTransaction::release(){
939 releaseOperations();
940 if ( (theTransactionIsStarted == true) &&
941 ((theCommitStatus != Committed) &&
942 (theCommitStatus != Aborted))) {
943 /************************************************************************
944 * The user did not perform any rollback but simply closed the
945 * transaction. We must rollback Ndb since Ndb have been contacted.
946 ************************************************************************/
947 if (!theSimpleState)
948 {
949 execute(Rollback);
950 }
951 }//if
952 theMagicNumber = 0xFE11DC;
953 theInUseState = false;
954 #ifdef VM_TRACE
955 if (theListState != NotInList) {
956 theNdb->printState("release %x", this);
957 abort();
958 }
959 #endif
960 }//NdbTransaction::release()
961
962 void
releaseOps(NdbOperation * tOp)963 NdbTransaction::releaseOps(NdbOperation* tOp){
964 while (tOp != NULL) {
965 NdbOperation* tmp = tOp;
966 tOp->release();
967 tOp = tOp->next();
968 theNdb->releaseOperation(tmp);
969 }//while
970 }
971
972 /******************************************************************************
973 void releaseOperations();
974
975 Remark: Release all operations.
976 ******************************************************************************/
977 void
releaseOperations()978 NdbTransaction::releaseOperations()
979 {
980 // Release any open scans
981 releaseScanOperations(m_theFirstScanOperation);
982 releaseScanOperations(m_firstExecutedScanOp);
983
984 releaseOps(theCompletedFirstOp);
985 releaseOps(theFirstOpInList);
986 releaseOps(theFirstExecOpInList);
987
988 theCompletedFirstOp = NULL;
989 theCompletedLastOp = NULL;
990 theFirstOpInList = NULL;
991 theFirstExecOpInList = NULL;
992 theLastOpInList = NULL;
993 theLastExecOpInList = NULL;
994 theScanningOp = NULL;
995 m_theFirstScanOperation = NULL;
996 m_theLastScanOperation = NULL;
997 m_firstExecutedScanOp = NULL;
998 }//NdbTransaction::releaseOperations()
999
1000 void
releaseCompletedOperations()1001 NdbTransaction::releaseCompletedOperations()
1002 {
1003 releaseOps(theCompletedFirstOp);
1004 theCompletedFirstOp = NULL;
1005 theCompletedLastOp = NULL;
1006 }//NdbTransaction::releaseOperations()
1007
1008 /******************************************************************************
1009 void releaseScanOperations();
1010
1011 Remark: Release all cursor operations.
1012 (NdbScanOperation and NdbIndexOperation)
1013 ******************************************************************************/
1014 void
releaseScanOperations(NdbIndexScanOperation * cursorOp)1015 NdbTransaction::releaseScanOperations(NdbIndexScanOperation* cursorOp)
1016 {
1017 while(cursorOp != 0){
1018 NdbIndexScanOperation* next = (NdbIndexScanOperation*)cursorOp->next();
1019 cursorOp->release();
1020 theNdb->releaseScanOperation(cursorOp);
1021 cursorOp = next;
1022 }
1023 }//NdbTransaction::releaseScanOperations()
1024
1025 /*****************************************************************************
1026 void releaseScanOperation();
1027
1028 Remark: Release scan op when hupp'ed trans closed (save memory)
1029 ******************************************************************************/
1030 void
releaseExecutedScanOperation(NdbIndexScanOperation * cursorOp)1031 NdbTransaction::releaseExecutedScanOperation(NdbIndexScanOperation* cursorOp)
1032 {
1033 DBUG_ENTER("NdbTransaction::releaseExecutedScanOperation");
1034 DBUG_PRINT("enter", ("this: 0x%lx op: 0x%lx", (long) this, (long) cursorOp));
1035
1036 releaseScanOperation(&m_firstExecutedScanOp, 0, cursorOp);
1037
1038 DBUG_VOID_RETURN;
1039 }//NdbTransaction::releaseExecutedScanOperation()
1040
1041 bool
releaseScanOperation(NdbIndexScanOperation ** listhead,NdbIndexScanOperation ** listtail,NdbIndexScanOperation * op)1042 NdbTransaction::releaseScanOperation(NdbIndexScanOperation** listhead,
1043 NdbIndexScanOperation** listtail,
1044 NdbIndexScanOperation* op)
1045 {
1046 if (* listhead == op)
1047 {
1048 * listhead = (NdbIndexScanOperation*)op->theNext;
1049 if (listtail && *listtail == op)
1050 {
1051 assert(* listhead == 0);
1052 * listtail = 0;
1053 }
1054
1055 }
1056 else
1057 {
1058 NdbIndexScanOperation* tmp = * listhead;
1059 while (tmp != NULL)
1060 {
1061 if (tmp->theNext == op)
1062 {
1063 tmp->theNext = (NdbIndexScanOperation*)op->theNext;
1064 if (listtail && *listtail == op)
1065 {
1066 assert(op->theNext == 0);
1067 *listtail = tmp;
1068 }
1069 break;
1070 }
1071 tmp = (NdbIndexScanOperation*)tmp->theNext;
1072 }
1073 if (tmp == NULL)
1074 op = NULL;
1075 }
1076
1077 if (op != NULL)
1078 {
1079 op->release();
1080 theNdb->releaseScanOperation(op);
1081 return true;
1082 }
1083
1084 return false;
1085 }
1086
1087 /*****************************************************************************
1088 NdbOperation* getNdbOperation(const char* aTableName);
1089
1090 Return Value Return a pointer to a NdbOperation object if getNdbOperation
1091 was succesful.
1092 Return NULL : In all other case.
1093 Parameters: aTableName : Name of the database table.
1094 Remark: Get an operation from NdbOperation idlelist and get the
1095 NdbTransaction object
1096 who was fetch by startTransaction pointing to this operation
1097 getOperation will set the theTableId in the NdbOperation object.
1098 synchronous
1099 ******************************************************************************/
1100 NdbOperation*
getNdbOperation(const char * aTableName)1101 NdbTransaction::getNdbOperation(const char* aTableName)
1102 {
1103 if (theCommitStatus == Started){
1104 NdbTableImpl* table = theNdb->theDictionary->getTable(aTableName);
1105 if (table != 0){
1106 return getNdbOperation(table);
1107 } else {
1108 setErrorCode(theNdb->theDictionary->getNdbError().code);
1109 return NULL;
1110 }//if
1111 }
1112
1113 setOperationErrorCodeAbort(4114);
1114
1115 return NULL;
1116 }//NdbTransaction::getNdbOperation()
1117
1118 /*****************************************************************************
1119 NdbOperation* getNdbOperation(int aTableId);
1120
1121 Return Value Return a pointer to a NdbOperation object if getNdbOperation
1122 was succesful.
1123 Return NULL: In all other case.
1124 Parameters: tableId : Id of the database table beeing deleted.
1125 Remark: Get an operation from NdbOperation object idlelist and
1126 get the NdbTransaction object who was fetch by
1127 startTransaction pointing to this operation
1128 getOperation will set the theTableId in the NdbOperation
1129 object, synchronous.
1130 *****************************************************************************/
1131 NdbOperation*
getNdbOperation(const NdbTableImpl * tab,NdbOperation * aNextOp)1132 NdbTransaction::getNdbOperation(const NdbTableImpl * tab, NdbOperation* aNextOp)
1133 {
1134 NdbOperation* tOp;
1135
1136 if (theScanningOp != NULL){
1137 setErrorCode(4607);
1138 return NULL;
1139 }
1140
1141 tOp = theNdb->getOperation();
1142 if (tOp == NULL)
1143 goto getNdbOp_error1;
1144 if (aNextOp == NULL) {
1145 if (theLastOpInList != NULL) {
1146 theLastOpInList->next(tOp);
1147 theLastOpInList = tOp;
1148 } else {
1149 theLastOpInList = tOp;
1150 theFirstOpInList = tOp;
1151 }//if
1152 tOp->next(NULL);
1153 } else {
1154 // add before the given op
1155 if (theFirstOpInList == aNextOp) {
1156 theFirstOpInList = tOp;
1157 } else {
1158 NdbOperation* aLoopOp = theFirstOpInList;
1159 while (aLoopOp != NULL && aLoopOp->next() != aNextOp)
1160 aLoopOp = aLoopOp->next();
1161 assert(aLoopOp != NULL);
1162 aLoopOp->next(tOp);
1163 }
1164 tOp->next(aNextOp);
1165 }
1166 if (tOp->init(tab, this) != -1) {
1167 return tOp;
1168 } else {
1169 theNdb->releaseOperation(tOp);
1170 }//if
1171 return NULL;
1172
1173 getNdbOp_error1:
1174 setOperationErrorCodeAbort(4000);
1175 return NULL;
1176 }//NdbTransaction::getNdbOperation()
1177
getNdbOperation(const NdbDictionary::Table * table)1178 NdbOperation* NdbTransaction::getNdbOperation(const NdbDictionary::Table * table)
1179 {
1180 if (table)
1181 return getNdbOperation(& NdbTableImpl::getImpl(*table));
1182 else
1183 return NULL;
1184 }//NdbTransaction::getNdbOperation()
1185
1186 // NdbScanOperation
1187 /*****************************************************************************
1188 NdbScanOperation* getNdbScanOperation(const char* aTableName);
1189
1190 Return Value Return a pointer to a NdbScanOperation object if getNdbScanOperation was succesful.
1191 Return NULL : In all other case.
1192 Parameters: aTableName : Name of the database table.
1193 Remark: Get an operation from NdbScanOperation idlelist and get the NdbTransaction object
1194 who was fetch by startTransaction pointing to this operation
1195 getOperation will set the theTableId in the NdbOperation object.synchronous
1196 ******************************************************************************/
1197 NdbScanOperation*
getNdbScanOperation(const char * aTableName)1198 NdbTransaction::getNdbScanOperation(const char* aTableName)
1199 {
1200 if (theCommitStatus == Started){
1201 NdbTableImpl* tab = theNdb->theDictionary->getTable(aTableName);
1202 if (tab != 0){
1203 return getNdbScanOperation(tab);
1204 } else {
1205 setOperationErrorCodeAbort(theNdb->theDictionary->m_error.code);
1206 return NULL;
1207 }//if
1208 }
1209
1210 setOperationErrorCodeAbort(4114);
1211 return NULL;
1212 }//NdbTransaction::getNdbScanOperation()
1213
1214 /*****************************************************************************
1215 NdbScanOperation* getNdbIndexScanOperation(const char* anIndexName, const char* aTableName);
1216
1217 Return Value Return a pointer to a NdbIndexScanOperation object if getNdbIndexScanOperation was succesful.
1218 Return NULL : In all other case.
1219 Parameters: anIndexName : Name of the index to use.
1220 aTableName : Name of the database table.
1221 Remark: Get an operation from NdbIndexScanOperation idlelist and get the NdbTransaction object
1222 who was fetch by startTransaction pointing to this operation
1223 getOperation will set the theTableId in the NdbIndexScanOperation object.synchronous
1224 ******************************************************************************/
1225 NdbIndexScanOperation*
getNdbIndexScanOperation(const char * anIndexName,const char * aTableName)1226 NdbTransaction::getNdbIndexScanOperation(const char* anIndexName,
1227 const char* aTableName)
1228 {
1229 NdbIndexImpl* index =
1230 theNdb->theDictionary->getIndex(anIndexName, aTableName);
1231 if (index == 0)
1232 {
1233 setOperationErrorCodeAbort(theNdb->theDictionary->getNdbError().code);
1234 return 0;
1235 }
1236 NdbTableImpl* table = theNdb->theDictionary->getTable(aTableName);
1237 if (table == 0)
1238 {
1239 setOperationErrorCodeAbort(theNdb->theDictionary->getNdbError().code);
1240 return 0;
1241 }
1242
1243 return getNdbIndexScanOperation(index, table);
1244 }
1245
1246 NdbIndexScanOperation*
getNdbIndexScanOperation(const NdbIndexImpl * index,const NdbTableImpl * table)1247 NdbTransaction::getNdbIndexScanOperation(const NdbIndexImpl* index,
1248 const NdbTableImpl* table)
1249 {
1250 if (theCommitStatus == Started){
1251 const NdbTableImpl * indexTable = index->getIndexTable();
1252 if (indexTable != 0){
1253 NdbIndexScanOperation* tOp = getNdbScanOperation(indexTable);
1254 if(tOp)
1255 {
1256 tOp->m_currentTable = table;
1257 // Mark that this really an NdbIndexScanOperation
1258 tOp->m_type = NdbOperation::OrderedIndexScan;
1259 }
1260 return tOp;
1261 } else {
1262 setOperationErrorCodeAbort(4271);
1263 return NULL;
1264 }//if
1265 }
1266
1267 setOperationErrorCodeAbort(4114);
1268 return NULL;
1269 }//NdbTransaction::getNdbIndexScanOperation()
1270
1271 NdbIndexScanOperation*
getNdbIndexScanOperation(const NdbDictionary::Index * index)1272 NdbTransaction::getNdbIndexScanOperation(const NdbDictionary::Index * index)
1273 {
1274 if (index)
1275 {
1276 const NdbDictionary::Table *table=
1277 theNdb->theDictionary->getTable(index->getTable());
1278
1279 if (table)
1280 return getNdbIndexScanOperation(index, table);
1281
1282 setOperationErrorCodeAbort(theNdb->theDictionary->getNdbError().code);
1283 return NULL;
1284 }
1285 setOperationErrorCodeAbort(4271);
1286 return NULL;
1287 }
1288
1289 NdbIndexScanOperation*
getNdbIndexScanOperation(const NdbDictionary::Index * index,const NdbDictionary::Table * table)1290 NdbTransaction::getNdbIndexScanOperation(const NdbDictionary::Index * index,
1291 const NdbDictionary::Table * table)
1292 {
1293 if (index && table)
1294 return getNdbIndexScanOperation(& NdbIndexImpl::getImpl(*index),
1295 & NdbTableImpl::getImpl(*table));
1296 setOperationErrorCodeAbort(4271);
1297 return NULL;
1298 }//NdbTransaction::getNdbIndexScanOperation()
1299
1300 /*****************************************************************************
1301 NdbScanOperation* getNdbScanOperation(int aTableId);
1302
1303 Return Value Return a pointer to a NdbScanOperation object if getNdbScanOperation was succesful.
1304 Return NULL: In all other case.
1305 Parameters: tableId : Id of the database table beeing deleted.
1306 Remark: Get an operation from NdbScanOperation object idlelist and get the NdbTransaction
1307 object who was fetch by startTransaction pointing to this operation
1308 getOperation will set the theTableId in the NdbScanOperation object, synchronous.
1309 *****************************************************************************/
1310 NdbIndexScanOperation*
getNdbScanOperation(const NdbTableImpl * tab)1311 NdbTransaction::getNdbScanOperation(const NdbTableImpl * tab)
1312 {
1313 NdbIndexScanOperation* tOp;
1314
1315 tOp = theNdb->getScanOperation();
1316 if (tOp == NULL)
1317 goto getNdbOp_error1;
1318
1319 if (tOp->init(tab, this) != -1) {
1320 define_scan_op(tOp);
1321 // Mark that this NdbIndexScanOperation is used as NdbScanOperation
1322 tOp->m_type = NdbOperation::TableScan;
1323 return tOp;
1324 } else {
1325 theNdb->releaseScanOperation(tOp);
1326 }//if
1327 return NULL;
1328
1329 getNdbOp_error1:
1330 setOperationErrorCodeAbort(4000);
1331 return NULL;
1332 }//NdbTransaction::getNdbScanOperation()
1333
1334 void
remove_list(NdbOperation * & list,NdbOperation * op)1335 NdbTransaction::remove_list(NdbOperation*& list, NdbOperation* op){
1336 NdbOperation* tmp= list;
1337 if(tmp == op)
1338 list = op->next();
1339 else {
1340 while(tmp && tmp->next() != op) tmp = tmp->next();
1341 if(tmp)
1342 tmp->next(op->next());
1343 }
1344 op->next(NULL);
1345 }
1346
1347 void
define_scan_op(NdbIndexScanOperation * tOp)1348 NdbTransaction::define_scan_op(NdbIndexScanOperation * tOp){
1349 // Link scan operation into list of cursor operations
1350 if (m_theLastScanOperation == NULL)
1351 m_theFirstScanOperation = m_theLastScanOperation = tOp;
1352 else {
1353 m_theLastScanOperation->next(tOp);
1354 m_theLastScanOperation = tOp;
1355 }
1356 tOp->next(NULL);
1357 }
1358
1359 NdbScanOperation*
getNdbScanOperation(const NdbDictionary::Table * table)1360 NdbTransaction::getNdbScanOperation(const NdbDictionary::Table * table)
1361 {
1362 if (table)
1363 return getNdbScanOperation(& NdbTableImpl::getImpl(*table));
1364 else
1365 return NULL;
1366 }//NdbTransaction::getNdbScanOperation()
1367
1368
1369 // IndexOperation
1370 /*****************************************************************************
1371 NdbIndexOperation* getNdbIndexOperation(const char* anIndexName,
1372 const char* aTableName);
1373
1374 Return Value Return a pointer to a NdbOperation object if getNdbIndexOperation was succesful.
1375 Return NULL : In all other case.
1376 Parameters: aTableName : Name of the database table.
1377 Remark: Get an operation from NdbIndexOperation idlelist and get the NdbTransaction object
1378 who was fetch by startTransaction pointing to this operation
1379 getOperation will set the theTableId in the NdbIndexOperation object.synchronous
1380 ******************************************************************************/
1381 NdbIndexOperation*
getNdbIndexOperation(const char * anIndexName,const char * aTableName)1382 NdbTransaction::getNdbIndexOperation(const char* anIndexName,
1383 const char* aTableName)
1384 {
1385 if (theCommitStatus == Started) {
1386 NdbTableImpl * table = theNdb->theDictionary->getTable(aTableName);
1387 NdbIndexImpl * index;
1388
1389 if (table == 0)
1390 {
1391 setOperationErrorCodeAbort(theNdb->theDictionary->getNdbError().code);
1392 return NULL;
1393 }
1394
1395 if (table->m_frm.get_data())
1396 {
1397 // This unique index is defined from SQL level
1398 static const char* uniqueSuffix= "$unique";
1399 BaseString uniqueIndexName(anIndexName);
1400 uniqueIndexName.append(uniqueSuffix);
1401 index = theNdb->theDictionary->getIndex(uniqueIndexName.c_str(),
1402 aTableName);
1403 }
1404 else
1405 index = theNdb->theDictionary->getIndex(anIndexName,
1406 aTableName);
1407 if(table != 0 && index != 0){
1408 return getNdbIndexOperation(index, table);
1409 }
1410
1411 if(index == 0){
1412 setOperationErrorCodeAbort(4243);
1413 return NULL;
1414 }
1415
1416 setOperationErrorCodeAbort(4243);
1417 return NULL;
1418 }
1419
1420 setOperationErrorCodeAbort(4114);
1421 return 0;
1422 }//NdbTransaction::getNdbIndexOperation()
1423
1424 /*****************************************************************************
1425 NdbIndexOperation* getNdbIndexOperation(int anIndexId, int aTableId);
1426
1427 Return Value Return a pointer to a NdbIndexOperation object if getNdbIndexOperation was succesful.
1428 Return NULL: In all other case.
1429 Parameters: tableId : Id of the database table beeing deleted.
1430 Remark: Get an operation from NdbIndexOperation object idlelist and get the NdbTransaction
1431 object who was fetch by startTransaction pointing to this operation
1432 getOperation will set the theTableId in the NdbIndexOperation object, synchronous.
1433 *****************************************************************************/
1434 NdbIndexOperation*
getNdbIndexOperation(const NdbIndexImpl * anIndex,const NdbTableImpl * aTable,NdbOperation * aNextOp)1435 NdbTransaction::getNdbIndexOperation(const NdbIndexImpl * anIndex,
1436 const NdbTableImpl * aTable,
1437 NdbOperation* aNextOp)
1438 {
1439 NdbIndexOperation* tOp;
1440
1441 tOp = theNdb->getIndexOperation();
1442 if (tOp == NULL)
1443 goto getNdbOp_error1;
1444 if (aNextOp == NULL) {
1445 if (theLastOpInList != NULL) {
1446 theLastOpInList->next(tOp);
1447 theLastOpInList = tOp;
1448 } else {
1449 theLastOpInList = tOp;
1450 theFirstOpInList = tOp;
1451 }//if
1452 tOp->next(NULL);
1453 } else {
1454 // add before the given op
1455 if (theFirstOpInList == aNextOp) {
1456 theFirstOpInList = tOp;
1457 } else {
1458 NdbOperation* aLoopOp = theFirstOpInList;
1459 while (aLoopOp != NULL && aLoopOp->next() != aNextOp)
1460 aLoopOp = aLoopOp->next();
1461 assert(aLoopOp != NULL);
1462 aLoopOp->next(tOp);
1463 }
1464 tOp->next(aNextOp);
1465 }
1466 if (tOp->indxInit(anIndex, aTable, this)!= -1) {
1467 return tOp;
1468 } else {
1469 theNdb->releaseOperation(tOp);
1470 }//if
1471 return NULL;
1472
1473 getNdbOp_error1:
1474 setOperationErrorCodeAbort(4000);
1475 return NULL;
1476 }//NdbTransaction::getNdbIndexOperation()
1477
1478 NdbIndexOperation*
getNdbIndexOperation(const NdbDictionary::Index * index)1479 NdbTransaction::getNdbIndexOperation(const NdbDictionary::Index * index)
1480 {
1481 if (index)
1482 {
1483 const NdbDictionary::Table *table=
1484 theNdb->theDictionary->getTable(index->getTable());
1485
1486 if (table)
1487 return getNdbIndexOperation(index, table);
1488
1489 setOperationErrorCodeAbort(theNdb->theDictionary->getNdbError().code);
1490 return NULL;
1491 }
1492 setOperationErrorCodeAbort(4271);
1493 return NULL;
1494 }
1495
1496 NdbIndexOperation*
getNdbIndexOperation(const NdbDictionary::Index * index,const NdbDictionary::Table * table)1497 NdbTransaction::getNdbIndexOperation(const NdbDictionary::Index * index,
1498 const NdbDictionary::Table * table)
1499 {
1500 if (index && table)
1501 return getNdbIndexOperation(& NdbIndexImpl::getImpl(*index),
1502 & NdbTableImpl::getImpl(*table));
1503
1504 setOperationErrorCodeAbort(4271);
1505 return NULL;
1506 }//NdbTransaction::getNdbIndexOperation()
1507
1508
1509 /*******************************************************************************
1510 int receiveDIHNDBTAMPER(NdbApiSignal* aSignal)
1511
1512 Return Value: Return 0 : receiveDIHNDBTAMPER was successful.
1513 Return -1: In all other case.
1514 Parameters: aSignal: The signal object pointer.
1515 Remark: Sets theRestartGCI in the NDB object.
1516 *******************************************************************************/
1517 int
receiveDIHNDBTAMPER(NdbApiSignal * aSignal)1518 NdbTransaction::receiveDIHNDBTAMPER(NdbApiSignal* aSignal)
1519 {
1520 if (theStatus != Connecting) {
1521 return -1;
1522 } else {
1523 theNdb->RestartGCI((Uint32)aSignal->readData(2));
1524 theStatus = Connected;
1525 }//if
1526 return 0;
1527 }//NdbTransaction::receiveDIHNDBTAMPER()
1528
1529 /*******************************************************************************
1530 int receiveTCSEIZECONF(NdbApiSignal* aSignal);
1531
1532 Return Value: Return 0 : receiveTCSEIZECONF was successful.
1533 Return -1: In all other case.
1534 Parameters: aSignal: The signal object pointer.
1535 Remark: Sets TC Connect pointer at reception of TCSEIZECONF.
1536 *******************************************************************************/
1537 int
receiveTCSEIZECONF(NdbApiSignal * aSignal)1538 NdbTransaction::receiveTCSEIZECONF(NdbApiSignal* aSignal)
1539 {
1540 if (theStatus != Connecting)
1541 {
1542 return -1;
1543 } else
1544 {
1545 theTCConPtr = (Uint32)aSignal->readData(2);
1546 theStatus = Connected;
1547 }
1548 return 0;
1549 }//NdbTransaction::receiveTCSEIZECONF()
1550
1551 /*******************************************************************************
1552 int receiveTCSEIZEREF(NdbApiSignal* aSignal);
1553
1554 Return Value: Return 0 : receiveTCSEIZEREF was successful.
1555 Return -1: In all other case.
1556 Parameters: aSignal: The signal object pointer.
1557 Remark: Sets TC Connect pointer.
1558 *******************************************************************************/
1559 int
receiveTCSEIZEREF(NdbApiSignal * aSignal)1560 NdbTransaction::receiveTCSEIZEREF(NdbApiSignal* aSignal)
1561 {
1562 DBUG_ENTER("NdbTransaction::receiveTCSEIZEREF");
1563 if (theStatus != Connecting)
1564 {
1565 DBUG_RETURN(-1);
1566 } else
1567 {
1568 theStatus = ConnectFailure;
1569 theNdb->theError.code = aSignal->readData(2);
1570 DBUG_PRINT("info",("error code %d, %s",
1571 theNdb->getNdbError().code,
1572 theNdb->getNdbError().message));
1573 DBUG_RETURN(0);
1574 }
1575 }//NdbTransaction::receiveTCSEIZEREF()
1576
1577 /*******************************************************************************
1578 int receiveTCRELEASECONF(NdbApiSignal* aSignal);
1579
1580 Return Value: Return 0 : receiveTCRELEASECONF was successful.
1581 Return -1: In all other case.
1582 Parameters: aSignal: The signal object pointer.
1583 Remark: DisConnect TC Connect pointer to NDBAPI.
1584 *******************************************************************************/
1585 int
receiveTCRELEASECONF(NdbApiSignal * aSignal)1586 NdbTransaction::receiveTCRELEASECONF(NdbApiSignal* aSignal)
1587 {
1588 if (theStatus != DisConnecting)
1589 {
1590 return -1;
1591 } else
1592 {
1593 theStatus = NotConnected;
1594 }
1595 return 0;
1596 }//NdbTransaction::receiveTCRELEASECONF()
1597
1598 /*******************************************************************************
1599 int receiveTCRELEASEREF(NdbApiSignal* aSignal);
1600
1601 Return Value: Return 0 : receiveTCRELEASEREF was successful.
1602 Return -1: In all other case.
1603 Parameters: aSignal: The signal object pointer.
1604 Remark: DisConnect TC Connect pointer to NDBAPI Failure.
1605 *******************************************************************************/
1606 int
receiveTCRELEASEREF(NdbApiSignal * aSignal)1607 NdbTransaction::receiveTCRELEASEREF(NdbApiSignal* aSignal)
1608 {
1609 if (theStatus != DisConnecting) {
1610 return -1;
1611 } else {
1612 theStatus = ConnectFailure;
1613 theNdb->theError.code = aSignal->readData(2);
1614 return 0;
1615 }//if
1616 }//NdbTransaction::receiveTCRELEASEREF()
1617
1618 /******************************************************************************
1619 int receiveTC_COMMITCONF(NdbApiSignal* aSignal);
1620
1621 Return Value: Return 0 : receiveTC_COMMITCONF was successful.
1622 Return -1: In all other case.
1623 Parameters: aSignal: The signal object pointer.
1624 Remark:
1625 ******************************************************************************/
1626 int
receiveTC_COMMITCONF(const TcCommitConf * commitConf)1627 NdbTransaction::receiveTC_COMMITCONF(const TcCommitConf * commitConf)
1628 {
1629 if(checkState_TransId(&commitConf->transId1)){
1630 theCommitStatus = Committed;
1631 theCompletionStatus = CompletedSuccess;
1632 theGlobalCheckpointId = commitConf->gci;
1633 // theGlobalCheckpointId == 0 if NoOp transaction
1634 if (theGlobalCheckpointId)
1635 *p_latest_trans_gci = theGlobalCheckpointId;
1636 return 0;
1637 } else {
1638 #ifdef NDB_NO_DROPPED_SIGNAL
1639 abort();
1640 #endif
1641 }
1642 return -1;
1643 }//NdbTransaction::receiveTC_COMMITCONF()
1644
1645 /******************************************************************************
1646 int receiveTC_COMMITREF(NdbApiSignal* aSignal);
1647
1648 Return Value: Return 0 : receiveTC_COMMITREF was successful.
1649 Return -1: In all other case.
1650 Parameters: aSignal: The signal object pointer.
1651 Remark:
1652 ******************************************************************************/
1653 int
receiveTC_COMMITREF(NdbApiSignal * aSignal)1654 NdbTransaction::receiveTC_COMMITREF(NdbApiSignal* aSignal)
1655 {
1656 const TcCommitRef * ref = CAST_CONSTPTR(TcCommitRef, aSignal->getDataPtr());
1657 if(checkState_TransId(&ref->transId1)){
1658 setOperationErrorCodeAbort(ref->errorCode);
1659 theCommitStatus = Aborted;
1660 theCompletionStatus = CompletedFailure;
1661 theReturnStatus = ReturnFailure;
1662 return 0;
1663 } else {
1664 #ifdef NDB_NO_DROPPED_SIGNAL
1665 abort();
1666 #endif
1667 }
1668
1669 return -1;
1670 }//NdbTransaction::receiveTC_COMMITREF()
1671
1672 /******************************************************************************
1673 int receiveTCROLLBACKCONF(NdbApiSignal* aSignal);
1674
1675 Return Value: Return 0 : receiveTCROLLBACKCONF was successful.
1676 Return -1: In all other case.
1677 Parameters: aSignal: The signal object pointer.
1678 Remark:
1679 ******************************************************************************/
1680 int
receiveTCROLLBACKCONF(NdbApiSignal * aSignal)1681 NdbTransaction::receiveTCROLLBACKCONF(NdbApiSignal* aSignal)
1682 {
1683 if(checkState_TransId(aSignal->getDataPtr() + 1)){
1684 theCommitStatus = Aborted;
1685 theCompletionStatus = CompletedSuccess;
1686 return 0;
1687 } else {
1688 #ifdef NDB_NO_DROPPED_SIGNAL
1689 abort();
1690 #endif
1691 }
1692
1693 return -1;
1694 }//NdbTransaction::receiveTCROLLBACKCONF()
1695
1696 /*******************************************************************************
1697 int receiveTCROLLBACKREF(NdbApiSignal* aSignal);
1698
1699 Return Value: Return 0 : receiveTCROLLBACKREF was successful.
1700 Return -1: In all other case.
1701 Parameters: aSignal: The signal object pointer.
1702 Remark:
1703 *******************************************************************************/
1704 int
receiveTCROLLBACKREF(NdbApiSignal * aSignal)1705 NdbTransaction::receiveTCROLLBACKREF(NdbApiSignal* aSignal)
1706 {
1707 if(checkState_TransId(aSignal->getDataPtr() + 1)){
1708 setOperationErrorCodeAbort(aSignal->readData(4));
1709 theCommitStatus = Aborted;
1710 theCompletionStatus = CompletedFailure;
1711 theReturnStatus = ReturnFailure;
1712 return 0;
1713 } else {
1714 #ifdef NDB_NO_DROPPED_SIGNAL
1715 abort();
1716 #endif
1717 }
1718
1719 return -1;
1720 }//NdbTransaction::receiveTCROLLBACKREF()
1721
1722 /*****************************************************************************
1723 int receiveTCROLLBACKREP( NdbApiSignal* aSignal)
1724
1725 Return Value: Return 0 : send was succesful.
1726 Return -1: In all other case.
1727 Parameters: aSignal: the signal object that contains the
1728 TCROLLBACKREP signal from TC.
1729 Remark: Handles the reception of the ROLLBACKREP signal.
1730 *****************************************************************************/
1731 int
receiveTCROLLBACKREP(NdbApiSignal * aSignal)1732 NdbTransaction::receiveTCROLLBACKREP( NdbApiSignal* aSignal)
1733 {
1734 DBUG_ENTER("NdbTransaction::receiveTCROLLBACKREP");
1735
1736 /****************************************************************************
1737 Check that we are expecting signals from this transaction and that it doesn't
1738 belong to a transaction already completed. Simply ignore messages from other
1739 transactions.
1740 ****************************************************************************/
1741 if(checkState_TransId(aSignal->getDataPtr() + 1)){
1742 theError.code = aSignal->readData(4);// Override any previous errors
1743 if (aSignal->getLength() == TcRollbackRep::SignalLength)
1744 {
1745 // Signal may contain additional error data
1746 theError.details = (char *) aSignal->readData(5);
1747 }
1748
1749 /**********************************************************************/
1750 /* A serious error has occured. This could be due to deadlock or */
1751 /* lack of resources or simply a programming error in NDB. This */
1752 /* transaction will be aborted. Actually it has already been */
1753 /* and we only need to report completion and return with the */
1754 /* error code to the application. */
1755 /**********************************************************************/
1756 theCompletionStatus = CompletedFailure;
1757 theCommitStatus = Aborted;
1758 theReturnStatus = ReturnFailure;
1759 DBUG_RETURN(0);
1760 } else {
1761 #ifdef NDB_NO_DROPPED_SIGNAL
1762 abort();
1763 #endif
1764 }
1765
1766 DBUG_RETURN(-1);
1767 }//NdbTransaction::receiveTCROLLBACKREP()
1768
1769 /*******************************************************************************
1770 int receiveTCKEYCONF(NdbApiSignal* aSignal, Uint32 long_short_ind);
1771
1772 Return Value: Return 0 : receiveTCKEYCONF was successful.
1773 Return -1: In all other case.
1774 Parameters: aSignal: The signal object pointer.
1775 Remark:
1776 *******************************************************************************/
1777 int
receiveTCKEYCONF(const TcKeyConf * keyConf,Uint32 aDataLength)1778 NdbTransaction::receiveTCKEYCONF(const TcKeyConf * keyConf, Uint32 aDataLength)
1779 {
1780 NdbReceiver* tOp;
1781 const Uint32 tTemp = keyConf->confInfo;
1782 /***************************************************************************
1783 Check that we are expecting signals from this transaction and that it
1784 doesn't belong to a transaction already completed. Simply ignore messages
1785 from other transactions.
1786 ***************************************************************************/
1787 if(checkState_TransId(&keyConf->transId1)){
1788
1789 const Uint32 tNoOfOperations = TcKeyConf::getNoOfOperations(tTemp);
1790 const Uint32 tCommitFlag = TcKeyConf::getCommitFlag(tTemp);
1791
1792 const Uint32* tPtr = (Uint32 *)&keyConf->operations[0];
1793 Uint32 tNoComp = theNoOfOpCompleted;
1794 for (Uint32 i = 0; i < tNoOfOperations ; i++) {
1795 tOp = theNdb->void2rec(theNdb->int2void(*tPtr++));
1796 const Uint32 tAttrInfoLen = *tPtr++;
1797 if (tOp && tOp->checkMagicNumber()) {
1798 Uint32 done = tOp->execTCOPCONF(tAttrInfoLen);
1799 if(tAttrInfoLen > TcKeyConf::DirtyReadBit){
1800 Uint32 node = tAttrInfoLen & (~TcKeyConf::DirtyReadBit);
1801 NdbNodeBitmask::set(m_db_nodes, node);
1802 if(NdbNodeBitmask::get(m_failed_db_nodes, node) && !done)
1803 {
1804 done = 1;
1805 tOp->setErrorCode(4119);
1806 theCompletionStatus = CompletedFailure;
1807 theReturnStatus = NdbTransaction::ReturnFailure;
1808 }
1809 }
1810 tNoComp += done;
1811 } else {
1812 return -1;
1813 }//if
1814 }//for
1815 Uint32 tNoSent = theNoOfOpSent;
1816 theNoOfOpCompleted = tNoComp;
1817 Uint32 tGCI = keyConf->gci;
1818 if (tCommitFlag == 1) {
1819 theCommitStatus = Committed;
1820 theGlobalCheckpointId = tGCI;
1821 if (tGCI) // Read(dirty) only transaction doesnt get GCI
1822 {
1823 *p_latest_trans_gci = tGCI;
1824 }
1825 } else if ((tNoComp >= tNoSent) &&
1826 (theLastExecOpInList->theCommitIndicator == 1)){
1827
1828
1829 /**********************************************************************/
1830 // We sent the transaction with Commit flag set and received a CONF with
1831 // no Commit flag set. This is clearly an anomaly.
1832 /**********************************************************************/
1833 theError.code = 4011;
1834 theCompletionStatus = CompletedFailure;
1835 theReturnStatus = NdbTransaction::ReturnFailure;
1836 theCommitStatus = Aborted;
1837 return 0;
1838 }//if
1839 if (tNoComp >= tNoSent) {
1840 return 0; // No more operations to wait for
1841 }//if
1842 // Not completed the reception yet.
1843 } else {
1844 #ifdef NDB_NO_DROPPED_SIGNAL
1845 abort();
1846 #endif
1847 }
1848
1849 return -1;
1850 }//NdbTransaction::receiveTCKEYCONF()
1851
1852 /*****************************************************************************
1853 int receiveTCKEY_FAILCONF( NdbApiSignal* aSignal)
1854
1855 Return Value: Return 0 : receive was completed.
1856 Return -1: In all other case.
1857 Parameters: aSignal: the signal object that contains the
1858 TCKEY_FAILCONF signal from TC.
1859 Remark: Handles the reception of the TCKEY_FAILCONF signal.
1860 *****************************************************************************/
1861 int
receiveTCKEY_FAILCONF(const TcKeyFailConf * failConf)1862 NdbTransaction::receiveTCKEY_FAILCONF(const TcKeyFailConf * failConf)
1863 {
1864 NdbOperation* tOp;
1865 /*
1866 Check that we are expecting signals from this transaction and that it
1867 doesn't belong to a transaction already completed. Simply ignore
1868 messages from other transactions.
1869 */
1870 if(checkState_TransId(&failConf->transId1)){
1871 /*
1872 A node failure of the TC node occured. The transaction has
1873 been committed.
1874 */
1875 theCommitStatus = Committed;
1876 tOp = theFirstExecOpInList;
1877 while (tOp != NULL) {
1878 /*
1879 * Check if the transaction expected read values...
1880 * If it did some of them might have gotten lost even if we succeeded
1881 * in committing the transaction.
1882 */
1883 switch(tOp->theOperationType){
1884 case NdbOperation::UpdateRequest:
1885 case NdbOperation::InsertRequest:
1886 case NdbOperation::DeleteRequest:
1887 case NdbOperation::WriteRequest:
1888 tOp = tOp->next();
1889 break;
1890 case NdbOperation::ReadRequest:
1891 case NdbOperation::ReadExclusive:
1892 case NdbOperation::OpenScanRequest:
1893 case NdbOperation::OpenRangeScanRequest:
1894 theCompletionStatus = CompletedFailure;
1895 theReturnStatus = NdbTransaction::ReturnFailure;
1896 setOperationErrorCodeAbort(4115);
1897 tOp = NULL;
1898 break;
1899 case NdbOperation::NotDefined:
1900 case NdbOperation::NotDefined2:
1901 assert(false);
1902 break;
1903 }//if
1904 }//while
1905 theReleaseOnClose = true;
1906 return 0;
1907 } else {
1908 #ifdef VM_TRACE
1909 ndbout_c("Recevied TCKEY_FAILCONF wo/ operation");
1910 #endif
1911 }
1912 return -1;
1913 }//NdbTransaction::receiveTCKEY_FAILCONF()
1914
1915 /*************************************************************************
1916 int receiveTCKEY_FAILREF( NdbApiSignal* aSignal)
1917
1918 Return Value: Return 0 : receive was completed.
1919 Return -1: In all other case.
1920 Parameters: aSignal: the signal object that contains the
1921 TCKEY_FAILREF signal from TC.
1922 Remark: Handles the reception of the TCKEY_FAILREF signal.
1923 **************************************************************************/
1924 int
receiveTCKEY_FAILREF(NdbApiSignal * aSignal)1925 NdbTransaction::receiveTCKEY_FAILREF(NdbApiSignal* aSignal)
1926 {
1927 /*
1928 Check that we are expecting signals from this transaction and
1929 that it doesn't belong to a transaction already
1930 completed. Simply ignore messages from other transactions.
1931 */
1932 if(checkState_TransId(aSignal->getDataPtr()+1)){
1933 /*
1934 We received an indication of that this transaction was aborted due to a
1935 node failure.
1936 */
1937 if (theSendStatus == NdbTransaction::sendTC_ROLLBACK) {
1938 /*
1939 We were in the process of sending a rollback anyways. We will
1940 report it as a success.
1941 */
1942 theCompletionStatus = NdbTransaction::CompletedSuccess;
1943 } else {
1944 theReturnStatus = NdbTransaction::ReturnFailure;
1945 theCompletionStatus = NdbTransaction::CompletedFailure;
1946 theError.code = 4031;
1947 }//if
1948 theReleaseOnClose = true;
1949 theCommitStatus = NdbTransaction::Aborted;
1950 return 0;
1951 } else {
1952 #ifdef VM_TRACE
1953 ndbout_c("Recevied TCKEY_FAILREF wo/ operation");
1954 #endif
1955 }
1956 return -1;
1957 }//NdbTransaction::receiveTCKEY_FAILREF()
1958
1959 /******************************************************************************
1960 int receiveTCINDXCONF(NdbApiSignal* aSignal, Uint32 long_short_ind);
1961
1962 Return Value: Return 0 : receiveTCINDXCONF was successful.
1963 Return -1: In all other case.
1964 Parameters: aSignal: The signal object pointer.
1965 Remark:
1966 ******************************************************************************/
1967 int
receiveTCINDXCONF(const TcIndxConf * indxConf,Uint32 aDataLength)1968 NdbTransaction::receiveTCINDXCONF(const TcIndxConf * indxConf,
1969 Uint32 aDataLength)
1970 {
1971 if(checkState_TransId(&indxConf->transId1)){
1972 const Uint32 tTemp = indxConf->confInfo;
1973 const Uint32 tNoOfOperations = TcIndxConf::getNoOfOperations(tTemp);
1974 const Uint32 tCommitFlag = TcKeyConf::getCommitFlag(tTemp);
1975
1976 const Uint32* tPtr = (Uint32 *)&indxConf->operations[0];
1977 Uint32 tNoComp = theNoOfOpCompleted;
1978 for (Uint32 i = 0; i < tNoOfOperations ; i++) {
1979 NdbReceiver* tOp = theNdb->void2rec(theNdb->int2void(*tPtr));
1980 tPtr++;
1981 const Uint32 tAttrInfoLen = *tPtr;
1982 tPtr++;
1983 if (tOp && tOp->checkMagicNumber()) {
1984 tNoComp += tOp->execTCOPCONF(tAttrInfoLen);
1985 } else {
1986 return -1;
1987 }//if
1988 }//for
1989 Uint32 tNoSent = theNoOfOpSent;
1990 Uint32 tGCI = indxConf->gci;
1991 theNoOfOpCompleted = tNoComp;
1992 if (tCommitFlag == 1) {
1993 theCommitStatus = Committed;
1994 theGlobalCheckpointId = tGCI;
1995 if (tGCI) // Read(dirty) only transaction doesnt get GCI
1996 {
1997 *p_latest_trans_gci = tGCI;
1998 }
1999 } else if ((tNoComp >= tNoSent) &&
2000 (theLastExecOpInList->theCommitIndicator == 1)){
2001
2002 /**********************************************************************/
2003 // We sent the transaction with Commit flag set and received a CONF with
2004 // no Commit flag set. This is clearly an anomaly.
2005 /**********************************************************************/
2006 theError.code = 4011;
2007 theCompletionStatus = NdbTransaction::CompletedFailure;
2008 theCommitStatus = NdbTransaction::Aborted;
2009 theReturnStatus = NdbTransaction::ReturnFailure;
2010 return 0;
2011 }//if
2012 if (tNoComp >= tNoSent) {
2013 return 0; // No more operations to wait for
2014 }//if
2015 // Not completed the reception yet.
2016 } else {
2017 #ifdef NDB_NO_DROPPED_SIGNAL
2018 abort();
2019 #endif
2020 }
2021
2022 return -1;
2023 }//NdbTransaction::receiveTCINDXCONF()
2024
2025 /*******************************************************************************
2026 int OpCompletedFailure();
2027
2028 Return Value: Return 0 : OpCompleteSuccess was successful.
2029 Return -1: In all other case.
2030 Parameters: aErrorCode: The error code.
2031 Remark: An operation was completed with failure.
2032 *******************************************************************************/
2033 int
OpCompleteFailure(NdbOperation * op)2034 NdbTransaction::OpCompleteFailure(NdbOperation* op)
2035 {
2036 Uint32 tNoComp = theNoOfOpCompleted;
2037 Uint32 tNoSent = theNoOfOpSent;
2038
2039 tNoComp++;
2040 theNoOfOpCompleted = tNoComp;
2041
2042 return (tNoComp == tNoSent) ? 0 : -1;
2043 }//NdbTransaction::OpCompleteFailure()
2044
2045 /******************************************************************************
2046 int OpCompleteSuccess();
2047
2048 Return Value: Return 0 : OpCompleteSuccess was successful.
2049 Return -1: In all other case.
2050 Remark: An operation was completed with success.
2051 *******************************************************************************/
2052 int
OpCompleteSuccess()2053 NdbTransaction::OpCompleteSuccess()
2054 {
2055 Uint32 tNoComp = theNoOfOpCompleted;
2056 Uint32 tNoSent = theNoOfOpSent;
2057 tNoComp++;
2058 theNoOfOpCompleted = tNoComp;
2059 if (tNoComp == tNoSent) { // Last operation completed
2060 return 0;
2061 } else if (tNoComp < tNoSent) {
2062 return -1; // Continue waiting for more signals
2063 } else {
2064 setOperationErrorCodeAbort(4113); // Too many operations,
2065 // stop waiting for more
2066 theCompletionStatus = NdbTransaction::CompletedFailure;
2067 theReturnStatus = NdbTransaction::ReturnFailure;
2068 return 0;
2069 }//if
2070 }//NdbTransaction::OpCompleteSuccess()
2071
2072 /******************************************************************************
2073 int getGCI();
2074
2075 Remark: Get global checkpoint identity of the transaction
2076 *******************************************************************************/
2077 int
getGCI()2078 NdbTransaction::getGCI()
2079 {
2080 if (theCommitStatus == NdbTransaction::Committed) {
2081 return theGlobalCheckpointId;
2082 }//if
2083 return 0;
2084 }//NdbTransaction::getGCI()
2085
2086 /*******************************************************************************
2087 Uint64 getTransactionId(void);
2088
2089 Remark: Get the transaction identity.
2090 *******************************************************************************/
2091 Uint64
getTransactionId()2092 NdbTransaction::getTransactionId()
2093 {
2094 return theTransactionId;
2095 }//NdbTransaction::getTransactionId()
2096
2097 NdbTransaction::CommitStatusType
commitStatus()2098 NdbTransaction::commitStatus()
2099 {
2100 return theCommitStatus;
2101 }//NdbTransaction::commitStatus()
2102
2103 int
getNdbErrorLine()2104 NdbTransaction::getNdbErrorLine()
2105 {
2106 return theErrorLine;
2107 }
2108
2109 NdbOperation*
getNdbErrorOperation()2110 NdbTransaction::getNdbErrorOperation()
2111 {
2112 return theErrorOperation;
2113 }//NdbTransaction::getNdbErrorOperation()
2114
2115 const NdbOperation *
getNextCompletedOperation(const NdbOperation * current) const2116 NdbTransaction::getNextCompletedOperation(const NdbOperation * current) const {
2117 if(current == 0)
2118 return theCompletedFirstOp;
2119 return current->theNext;
2120 }
2121
2122 #ifdef VM_TRACE
2123 #define CASE(x) case x: ndbout << " " << #x; break
2124 void
printState()2125 NdbTransaction::printState()
2126 {
2127 ndbout << "con=" << hex << this << dec;
2128 ndbout << " node=" << getConnectedNodeId();
2129 switch (theStatus) {
2130 CASE(NotConnected);
2131 CASE(Connecting);
2132 CASE(Connected);
2133 CASE(DisConnecting);
2134 CASE(ConnectFailure);
2135 default: ndbout << (Uint32) theStatus;
2136 }
2137 switch (theListState) {
2138 CASE(NotInList);
2139 CASE(InPreparedList);
2140 CASE(InSendList);
2141 CASE(InCompletedList);
2142 default: ndbout << (Uint32) theListState;
2143 }
2144 switch (theSendStatus) {
2145 CASE(NotInit);
2146 CASE(InitState);
2147 CASE(sendOperations);
2148 CASE(sendCompleted);
2149 CASE(sendCOMMITstate);
2150 CASE(sendABORT);
2151 CASE(sendABORTfail);
2152 CASE(sendTC_ROLLBACK);
2153 CASE(sendTC_COMMIT);
2154 CASE(sendTC_OP);
2155 default: ndbout << (Uint32) theSendStatus;
2156 }
2157 switch (theCommitStatus) {
2158 CASE(NotStarted);
2159 CASE(Started);
2160 CASE(Committed);
2161 CASE(Aborted);
2162 CASE(NeedAbort);
2163 default: ndbout << (Uint32) theCommitStatus;
2164 }
2165 switch (theCompletionStatus) {
2166 CASE(NotCompleted);
2167 CASE(CompletedSuccess);
2168 CASE(CompletedFailure);
2169 CASE(DefinitionFailure);
2170 default: ndbout << (Uint32) theCompletionStatus;
2171 }
2172 ndbout << endl;
2173 }
2174 #undef CASE
2175 #endif
2176
2177 int
report_node_failure(Uint32 id)2178 NdbTransaction::report_node_failure(Uint32 id){
2179 NdbNodeBitmask::set(m_failed_db_nodes, id);
2180 if(!NdbNodeBitmask::get(m_db_nodes, id))
2181 {
2182 return 0;
2183 }
2184
2185 /**
2186 * Arrived
2187 * TCKEYCONF TRANSIDAI
2188 * 1) - -
2189 * 2) - X
2190 * 3) X -
2191 * 4) X X
2192 */
2193 NdbOperation* tmp = theFirstExecOpInList;
2194 const Uint32 len = TcKeyConf::DirtyReadBit | id;
2195 Uint32 tNoComp = theNoOfOpCompleted;
2196 Uint32 tNoSent = theNoOfOpSent;
2197 Uint32 count = 0;
2198 while(tmp != 0)
2199 {
2200 if(tmp->theReceiver.m_expected_result_length == len &&
2201 tmp->theReceiver.m_received_result_length == 0)
2202 {
2203 count++;
2204 tmp->theError.code = 4119;
2205 }
2206 tmp = tmp->next();
2207 }
2208 tNoComp += count;
2209 theNoOfOpCompleted = tNoComp;
2210 if(count)
2211 {
2212 theReturnStatus = NdbTransaction::ReturnFailure;
2213 if(tNoComp == tNoSent)
2214 {
2215 theError.code = 4119;
2216 theCompletionStatus = NdbTransaction::CompletedFailure;
2217 return 1;
2218 }
2219 }
2220 return 0;
2221 }
2222