Ndb.cpp 36.7 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
/* Copyright (C) 2003 MySQL AB

   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 2 of the License, or
   (at your option) any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */




/*****************************************************************************
Name:          Ndb.cpp
******************************************************************************/

24
#include <ndb_global.h>
unknown's avatar
unknown committed
25

26

27 28
#include "NdbApiSignal.hpp"
#include "NdbImpl.hpp"
29
#include <NdbOperation.hpp>
30
#include <NdbTransaction.hpp>
31 32
#include <NdbEventOperation.hpp>
#include <NdbRecAttr.hpp>
33 34 35 36 37 38 39 40 41 42 43 44 45
#include <md5_hash.hpp>
#include <NdbSleep.h>
#include <NdbOut.hpp>
#include <ndb_limits.h>
#include "API.hpp"
#include <NdbEnv.h>
#include <BaseString.hpp>

/****************************************************************************
void connect();

Connect to any node which has no connection at the moment.
****************************************************************************/
46
NdbTransaction* Ndb::doConnect(Uint32 tConNode) 
47 48 49
{
  Uint32        tNode;
  Uint32        tAnyAlive = 0;
unknown's avatar
unknown committed
50
  int TretCode= 0;
51

unknown's avatar
unknown committed
52 53
  DBUG_ENTER("Ndb::doConnect");

54 55 56 57 58 59
  if (tConNode != 0) {
    TretCode = NDB_connect(tConNode);
    if ((TretCode == 1) || (TretCode == 2)) {
//****************************************************************************
// We have connections now to the desired node. Return
//****************************************************************************
unknown's avatar
unknown committed
60
      DBUG_RETURN(getConnectedNdbTransaction(tConNode));
61 62 63 64 65 66 67 68
    } else if (TretCode != 0) {
      tAnyAlive = 1;
    }//if
  }//if
//****************************************************************************
// We will connect to any node. Make sure that we have connections to all
// nodes.
//****************************************************************************
69 70 71 72 73 74 75 76 77 78 79
  if (theImpl->m_optimized_node_selection)
  {
    Ndb_cluster_connection_node_iter &node_iter= 
      theImpl->m_node_iter;
    theImpl->m_ndb_cluster_connection.init_get_next_node(node_iter);
    while ((tNode= theImpl->m_ndb_cluster_connection.get_next_node(node_iter)))
    {
      TretCode= NDB_connect(tNode);
      if ((TretCode == 1) ||
	  (TretCode == 2))
      {
80 81 82
//****************************************************************************
// We have connections now to the desired node. Return
//****************************************************************************
unknown's avatar
unknown committed
83
	DBUG_RETURN(getConnectedNdbTransaction(tNode));
84 85
      } else if (TretCode != 0) {
	tAnyAlive= 1;
86
      }//if
87 88 89
      DBUG_PRINT("info",("tried node %d, TretCode %d, error code %d, %s",
			 tNode, TretCode, getNdbError().code,
			 getNdbError().message));
90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110
    }
  }
  else // just do a regular round robin
  {
    Uint32 tNoOfDbNodes= theImpl->theNoOfDBnodes;
    Uint32 &theCurrentConnectIndex= theImpl->theCurrentConnectIndex;
    UintR Tcount = 0;
    do {
      theCurrentConnectIndex++;
      if (theCurrentConnectIndex >= tNoOfDbNodes)
	theCurrentConnectIndex = 0;

      Tcount++;
      tNode= theImpl->theDBnodes[theCurrentConnectIndex];
      TretCode= NDB_connect(tNode);
      if ((TretCode == 1) ||
	  (TretCode == 2))
      {
//****************************************************************************
// We have connections now to the desired node. Return
//****************************************************************************
unknown's avatar
unknown committed
111
	DBUG_RETURN(getConnectedNdbTransaction(tNode));
112 113 114
      } else if (TretCode != 0) {
	tAnyAlive= 1;
      }//if
unknown's avatar
unknown committed
115
      DBUG_PRINT("info",("tried node %d TretCode %d", tNode, TretCode));
116 117
    } while (Tcount < tNoOfDbNodes);
  }
118 119 120 121 122 123 124 125 126 127 128 129
//****************************************************************************
// We were unable to find a free connection. If no node alive we will report
// error code for cluster failure otherwise connection failure.
//****************************************************************************
  if (tAnyAlive == 1) {
#ifdef VM_TRACE
    ndbout << "TretCode = " << TretCode << endl;
#endif
    theError.code = 4006;
  } else {
    theError.code = 4009;
  }//if
unknown's avatar
unknown committed
130
  DBUG_RETURN(NULL);
131 132 133 134 135 136 137 138 139 140 141 142
}

int 
Ndb::NDB_connect(Uint32 tNode) 
{
//****************************************************************************
// We will perform seize of a transaction record in DBTC in the specified node.
//***************************************************************************
  
  int	         tReturnCode;
  TransporterFacade *tp = TransporterFacade::instance();

unknown's avatar
unknown committed
143 144
  DBUG_ENTER("Ndb::NDB_connect");

145 146
  bool nodeAvail = tp->get_node_alive(tNode);
  if(nodeAvail == false){
unknown's avatar
unknown committed
147
    DBUG_RETURN(0);
148 149
  }
  
150
  NdbTransaction * tConArray = theConnectionArray[tNode];
151
  if (tConArray != NULL) {
unknown's avatar
unknown committed
152
    DBUG_RETURN(2);
153 154
  }
  
155
  NdbTransaction * tNdbCon = getNdbCon();	// Get free connection object.
156
  if (tNdbCon == NULL) {
unknown's avatar
unknown committed
157
    DBUG_RETURN(4);
158 159 160 161
  }//if
  NdbApiSignal*	tSignal = getSignal();		// Get signal object
  if (tSignal == NULL) {
    releaseNdbCon(tNdbCon);
unknown's avatar
unknown committed
162
    DBUG_RETURN(4);
163 164 165 166
  }//if
  if (tSignal->setSignal(GSN_TCSEIZEREQ) == -1) {
    releaseNdbCon(tNdbCon);
    releaseSignal(tSignal);
unknown's avatar
unknown committed
167
    DBUG_RETURN(4);
168 169 170
  }//if
  tSignal->setData(tNdbCon->ptr2int(), 1);
//************************************************
171
// Set connection pointer as NdbTransaction object
172 173
//************************************************
  tSignal->setData(theMyRef, 2);	// Set my block reference
174
  tNdbCon->Status(NdbTransaction::Connecting); // Set status to connecting
175 176
  Uint32 nodeSequence;
  { // send and receive signal
unknown's avatar
unknown committed
177
    Guard guard(tp->theMutexPtr);
178 179 180 181 182
    nodeSequence = tp->getNodeSequence(tNode);
    bool node_is_alive = tp->get_node_alive(tNode);
    if (node_is_alive) { 
      tReturnCode = tp->sendSignal(tSignal, tNode);  
      releaseSignal(tSignal); 
unknown's avatar
unknown committed
183
      if (tReturnCode != -1) {
184 185
        theImpl->theWaiter.m_node = tNode;  
        theImpl->theWaiter.m_state = WAIT_TC_SEIZE;  
186 187 188 189 190 191 192
        tReturnCode = receiveResponse(); 
      }//if
    } else {
      releaseSignal(tSignal);
      tReturnCode = -1;
    }//if
  }
193
  if ((tReturnCode == 0) && (tNdbCon->Status() == NdbTransaction::Connected)) {
194 195 196
    //************************************************
    // Send and receive was successful
    //************************************************
197
    NdbTransaction* tPrevFirst = theConnectionArray[tNode];
198 199 200 201 202
    tNdbCon->setConnectedNodeId(tNode, nodeSequence);
    
    tNdbCon->setMyBlockReference(theMyRef);
    theConnectionArray[tNode] = tNdbCon;
    tNdbCon->theNext = tPrevFirst;
unknown's avatar
unknown committed
203
    DBUG_RETURN(1);
204 205 206 207 208
  } else {
    releaseNdbCon(tNdbCon);
//****************************************************************************
// Unsuccessful connect is indicated by 3.
//****************************************************************************
unknown's avatar
unknown committed
209 210 211 212
    DBUG_PRINT("info",
	       ("unsuccessful connect tReturnCode %d, tNdbCon->Status() %d",
		tReturnCode, tNdbCon->Status()));
    DBUG_RETURN(3);
213 214 215
  }//if
}//Ndb::NDB_connect()

216 217 218
NdbTransaction *
Ndb::getConnectedNdbTransaction(Uint32 nodeId){
  NdbTransaction* next = theConnectionArray[nodeId];
219 220 221 222
  theConnectionArray[nodeId] = next->theNext;
  next->theNext = NULL;

  return next;
223
}//Ndb::getConnectedNdbTransaction()
224 225 226 227 228 229 230 231 232

/*****************************************************************************
disconnect();

Remark:        Disconnect all connections to the database. 
*****************************************************************************/
void 
Ndb::doDisconnect()
{
233
  NdbTransaction* tNdbCon;
234
  CHECK_STATUS_MACRO_VOID;
unknown's avatar
unknown committed
235 236
  /* DBUG_ENTER must be after CHECK_STATUS_MACRO_VOID because of 'return' */
  DBUG_ENTER("Ndb::doDisconnect");
237

238 239 240
  Uint32 tNoOfDbNodes = theImpl->theNoOfDBnodes;
  Uint8 *theDBnodes= theImpl->theDBnodes;
  DBUG_PRINT("info", ("theNoOfDBnodes=%d", tNoOfDbNodes));
241 242 243 244 245
  UintR i;
  for (i = 0; i < tNoOfDbNodes; i++) {
    Uint32 tNode = theDBnodes[i];
    tNdbCon = theConnectionArray[tNode];
    while (tNdbCon != NULL) {
246
      NdbTransaction* tmpNdbCon = tNdbCon;
247 248 249 250 251 252
      tNdbCon = tNdbCon->theNext;
      releaseConnectToNdb(tmpNdbCon);
    }//while
  }//for
  tNdbCon = theTransactionList;
  while (tNdbCon != NULL) {
253
    NdbTransaction* tmpNdbCon = tNdbCon;
254 255 256
    tNdbCon = tNdbCon->theNext;
    releaseConnectToNdb(tmpNdbCon);
  }//while
257
  DBUG_VOID_RETURN;
258 259 260 261 262 263 264 265 266 267 268 269
}//Ndb::disconnect()

/*****************************************************************************
int waitUntilReady(int timeout);

Return Value:   Returns 0 if the Ndb is ready within timeout seconds.
                Returns -1 otherwise.
Remark:         Waits until a node has status != 0
*****************************************************************************/ 
int
Ndb::waitUntilReady(int timeout)
{
270
  DBUG_ENTER("Ndb::waitUntilReady");
271 272 273
  int secondsCounter = 0;
  int milliCounter = 0;
  int noChecksSinceFirstAliveFound = 0;
274
  int id;
275 276 277 278

  if (theInitState != Initialised) {
    // Ndb::init is not called
    theError.code = 4256;
279
    DBUG_RETURN(-1);
280 281
  }

282
  while (theNode == 0) {
283
    if (secondsCounter >= timeout)
284 285 286 287
    {
      theError.code = 4269;
      DBUG_RETURN(-1);
    }
288 289 290 291 292 293
    NdbSleep_MilliSleep(100);
    milliCounter += 100;
    if (milliCounter >= 1000) {
      secondsCounter++;
      milliCounter = 0;
    }//if
294 295 296
  }

  if (theImpl->m_ndb_cluster_connection.wait_until_ready
297
      (timeout-secondsCounter,30) < 0)
298 299
  {
    theError.code = 4009;
300 301
    DBUG_RETURN(-1);
  }
302 303

  DBUG_RETURN(0);
304 305 306
}

/*****************************************************************************
307
NdbTransaction* startTransaction();
308 309 310 311 312

Return Value:   Returns a pointer to a connection object.
                Return NULL otherwise.
Remark:         Start transaction. Synchronous.
*****************************************************************************/ 
313
NdbTransaction* 
314 315
Ndb::startTransaction(const NdbDictionary::Table *table,
		      const char * keyData, Uint32 keyLen)
316
{
317
  DBUG_ENTER("Ndb::startTransaction");
318 319 320 321

  if (theInitState == Initialised) {
    theError.code = 0;
    checkFailedNode();
unknown's avatar
unknown committed
322 323 324 325 326
    /**
     * If the user supplied key data
     * We will make a qualified quess to which node is the primary for the
     * the fragment and contact that node
     */
327
    Uint32 nodeId;
unknown's avatar
unknown committed
328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352
    NdbTableImpl* impl;
    if(table != 0 && keyData != 0 && (impl= &NdbTableImpl::getImpl(*table))) 
    {
      Uint32 hashValue;
      {
	Uint32 buf[4];
	if((UintPtr(keyData) & 7) == 0 && (keyLen & 3) == 0)
	{
	  md5_hash(buf, (const Uint64*)keyData, keyLen >> 2);
	}
	else
	{
	  Uint64 tmp[1000];
	  tmp[keyLen/8] = 0;
	  memcpy(tmp, keyData, keyLen);
	  md5_hash(buf, tmp, (keyLen+3) >> 2);	  
	}
	hashValue= buf[1];
      }
      const Uint16 *nodes;
      Uint32 cnt= impl->get_nodes(hashValue, &nodes);
      if(cnt)
	nodeId= nodes[0];
      else
	nodeId= 0;
353 354 355
    } else {
      nodeId = 0;
    }//if
unknown's avatar
unknown committed
356

357
    {
358
      NdbTransaction *trans= startTransactionLocal(0, nodeId);
unknown's avatar
unknown committed
359
      DBUG_PRINT("exit",("start trans: 0x%x transid: 0x%llx",
unknown's avatar
unknown committed
360
			 trans, trans ? trans->getTransactionId() : 0));
361 362
      DBUG_RETURN(trans);
    }
363
  } else {
364
    DBUG_RETURN(NULL);
365 366 367 368
  }//if
}//Ndb::startTransaction()

/*****************************************************************************
369
NdbTransaction* hupp(NdbTransaction* pBuddyTrans);
370 371 372 373 374 375

Return Value:   Returns a pointer to a connection object.
                Connected to the same node as pBuddyTrans
                and also using the same transction id
Remark:         Start transaction. Synchronous.
*****************************************************************************/ 
376 377
NdbTransaction* 
Ndb::hupp(NdbTransaction* pBuddyTrans)
378
{
379 380
  DBUG_ENTER("Ndb::hupp");

unknown's avatar
unknown committed
381 382
  DBUG_PRINT("enter", ("trans: 0x%x",pBuddyTrans));

383 384
  Uint32 aPriority = 0;
  if (pBuddyTrans == NULL){
385
    DBUG_RETURN(startTransaction());
386 387 388 389 390 391 392
  }

  if (theInitState == Initialised) {
    theError.code = 0;
    checkFailedNode();

    Uint32 nodeId = pBuddyTrans->getConnectedNodeId();
393
    NdbTransaction* pCon = startTransactionLocal(aPriority, nodeId);
394
    if(pCon == NULL)
395
      DBUG_RETURN(NULL);
396 397 398 399 400

    if (pCon->getConnectedNodeId() != nodeId){
      // We could not get a connection to the desired node
      // release the connection and return NULL
      closeTransaction(pCon);
401
      theError.code = 4006;
402
      DBUG_RETURN(NULL);
403 404 405
    }
    pCon->setTransactionId(pBuddyTrans->getTransactionId());
    pCon->setBuddyConPtr((Uint32)pBuddyTrans->getTC_ConnectPtr());
unknown's avatar
unknown committed
406 407
    DBUG_PRINT("exit", ("hupp trans: 0x%x transid: 0x%llx",
			pCon, pCon ? pCon->getTransactionId() : 0));
408
    DBUG_RETURN(pCon);
409
  } else {
410
    DBUG_RETURN(NULL);
411 412 413
  }//if
}//Ndb::hupp()

414
NdbTransaction* 
415 416 417 418 419 420 421 422 423 424
Ndb::startTransactionLocal(Uint32 aPriority, Uint32 nodeId)
{
#ifdef VM_TRACE
  char buf[255];
  const char* val = NdbEnv_GetEnv("NDB_TRANSACTION_NODE_ID", buf, 255);
  if(val != 0){
    nodeId = atoi(val);
  }
#endif

unknown's avatar
unknown committed
425 426 427
  DBUG_ENTER("Ndb::startTransactionLocal");
  DBUG_PRINT("enter", ("nodeid: %d", nodeId));

428
  NdbTransaction* tConnection;
429 430 431
  Uint64 tFirstTransId = theFirstTransId;
  tConnection = doConnect(nodeId);
  if (tConnection == NULL) {
unknown's avatar
unknown committed
432
    DBUG_RETURN(NULL);
433
  }//if
434
  NdbTransaction* tConNext = theTransactionList;
435 436 437 438 439 440 441 442 443 444 445 446 447 448 449
  tConnection->init();
  theTransactionList = tConnection;        // into a transaction list.
  tConnection->next(tConNext);   // Add the active connection object
  tConnection->setTransactionId(tFirstTransId);
  tConnection->thePriority = aPriority;
  if ((tFirstTransId & 0xFFFFFFFF) == 0xFFFFFFFF) {
    //---------------------------------------------------
// Transaction id rolling round. We will start from
// consecutive identity 0 again.
//---------------------------------------------------
    theFirstTransId = ((tFirstTransId >> 32) << 32);      
  } else {
    theFirstTransId = tFirstTransId + 1;
  }//if
#ifdef VM_TRACE
450
  if (tConnection->theListState != NdbTransaction::NotInList) {
451 452 453 454
    printState("startTransactionLocal %x", tConnection);
    abort();
  }
#endif
unknown's avatar
unknown committed
455
  DBUG_RETURN(tConnection);
456 457 458
}//Ndb::startTransactionLocal()

/*****************************************************************************
459
void closeTransaction(NdbTransaction* aConnection);
460 461 462 463 464

Parameters:     aConnection: the connection used in the transaction.
Remark:         Close transaction by releasing the connection and all operations.
*****************************************************************************/
void
465
Ndb::closeTransaction(NdbTransaction* aConnection)
466
{
467
  DBUG_ENTER("Ndb::closeTransaction");
468 469
  NdbTransaction* tCon;
  NdbTransaction* tPreviousCon;
470 471 472 473 474 475 476 477 478

  if (aConnection == NULL) {
//-----------------------------------------------------
// closeTransaction called on NULL pointer, destructive
// application behaviour.
//-----------------------------------------------------
#ifdef VM_TRACE
    printf("NULL into closeTransaction\n");
#endif
479
    DBUG_VOID_RETURN;
480 481 482 483
  }//if
  CHECK_STATUS_MACRO_VOID;
  
  tCon = theTransactionList;
unknown's avatar
unknown committed
484
  
unknown's avatar
unknown committed
485 486 487 488 489 490
  DBUG_PRINT("info",("close trans: 0x%x transid: 0x%llx",
		     aConnection, aConnection->getTransactionId()));
  DBUG_PRINT("info",("magic number: 0x%x TCConPtr: 0x%x theMyRef: 0x%x 0x%x",
		     aConnection->theMagicNumber, aConnection->theTCConPtr,
		     aConnection->theMyRef, getReference()));

491
  if (aConnection == tCon) {		// Remove the active connection object
unknown's avatar
unknown committed
492
    theTransactionList = tCon->next();	// from the transaction list.
493 494 495 496 497 498
  } else { 
    while (aConnection != tCon) {
      if (tCon == NULL) {
//-----------------------------------------------------
// closeTransaction called on non-existing transaction
//-----------------------------------------------------
499

unknown's avatar
unknown committed
500 501
	if(aConnection->theError.code == 4008){
	  /**
502
	   * When a SCAN timed-out, returning the NdbTransaction leads
unknown's avatar
unknown committed
503 504 505
	   * to reuse. And TC crashes when the API tries to reuse it to
	   * something else...
	   */
506
#ifdef VM_TRACE
507
	  printf("Scan timeout:ed NdbTransaction-> "
unknown's avatar
unknown committed
508
		 "not returning it-> memory leak\n");
509
#endif
510
	  DBUG_VOID_RETURN;
unknown's avatar
unknown committed
511
	}
512

513
#ifdef VM_TRACE
unknown's avatar
unknown committed
514
	printf("Non-existing transaction into closeTransaction\n");
515 516
	abort();
#endif
517
	DBUG_VOID_RETURN;
518 519 520 521 522 523
      }//if
      tPreviousCon = tCon;
      tCon = tCon->next();
    }//while
    tPreviousCon->next(tCon->next());
  }//if
unknown's avatar
unknown committed
524
  
525
  aConnection->release();
unknown's avatar
unknown committed
526
  
527 528
  if(aConnection->theError.code == 4008){
    /**
529
     * Something timed-out, returning the NdbTransaction leads
530 531 532 533
     * to reuse. And TC crashes when the API tries to reuse it to
     * something else...
     */
#ifdef VM_TRACE
534
    printf("Con timeout:ed NdbTransaction-> not returning it-> memory leak\n");
535
#endif
536
    DBUG_VOID_RETURN;
537
  }
unknown's avatar
unknown committed
538
  
539 540 541 542 543 544 545
  if (aConnection->theReleaseOnClose == false) {
    /**
     * Put it back in idle list for that node
     */
    Uint32 nodeId = aConnection->getConnectedNodeId();
    aConnection->theNext = theConnectionArray[nodeId];
    theConnectionArray[nodeId] = aConnection;
546
    DBUG_VOID_RETURN;
547 548 549 550
  } else {
    aConnection->theReleaseOnClose = false;
    releaseNdbCon(aConnection);
  }//if
551
  DBUG_VOID_RETURN;
552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572
}//Ndb::closeTransaction()

/*****************************************************************************
int* NdbTamper(int aAction, int aNode);

Parameters: aAction     Specifies what action to be taken
            1: Lock global checkpointing    Can only be sent to master DIH, Parameter aNode ignored.
            2: UnLock global checkpointing    Can only be sent to master DIH, Parameter aNode ignored.
	    3: Crash node

           aNode        Specifies which node the action will be taken
     	  -1: Master DIH 
       	0-16: Nodnumber

Return Value: -1 Error  .
                
Remark:         Sends a signal to DIH.
*****************************************************************************/ 
int 
Ndb::NdbTamper(TamperType aAction, int aNode)
{
573
  NdbTransaction*	tNdbConn;
574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614
  NdbApiSignal		tSignal(theMyRef);
  int			tNode;
  int                   tAction;
  int			ret_code;

#ifdef CUSTOMER_RELEASE
  return -1;
#else
  CHECK_STATUS_MACRO;
  checkFailedNode();

  theRestartGCI = 0;
  switch (aAction) {
// Translate enum to integer. This is done because the SCI layer
// expects integers. 
     case LockGlbChp:
        tAction = 1;
        break;
     case UnlockGlbChp:
        tAction = 2;
	break;
     case CrashNode:
        tAction = 3;
        break;
     case ReadRestartGCI:
	tAction = 4;
	break;
     default:
        theError.code = 4102;
        return -1;
  }

  tNdbConn = getNdbCon();	// Get free connection object
  if (tNdbConn == NULL) {
    theError.code = 4000;
    return -1;
  }
  tSignal.setSignal(GSN_DIHNDBTAMPER);
  tSignal.setData (tAction, 1);
  tSignal.setData(tNdbConn->ptr2int(),2);
  tSignal.setData(theMyRef,3);		// Set return block reference
615
  tNdbConn->Status(NdbTransaction::Connecting); // Set status to connecting
616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647
  TransporterFacade *tp = TransporterFacade::instance();
  if (tAction == 3) {
    tp->lock_mutex();
    tp->sendSignal(&tSignal, aNode);
    tp->unlock_mutex();
    releaseNdbCon(tNdbConn);
  } else if ( (tAction == 2) || (tAction == 1) ) {
    tp->lock_mutex();
    tNode = tp->get_an_alive_node();
    if (tNode == 0) {
      theError.code = 4002;
      releaseNdbCon(tNdbConn);
      return -1;
    }//if
    ret_code = tp->sendSignal(&tSignal,aNode);
    tp->unlock_mutex();
    releaseNdbCon(tNdbConn);
    return ret_code;
  } else {
    do {
      tp->lock_mutex();
      // Start protected area
      tNode = tp->get_an_alive_node();
      tp->unlock_mutex();
      // End protected area
      if (tNode == 0) {
        theError.code = 4009;
        releaseNdbCon(tNdbConn);
        return -1;
      }//if
      ret_code = sendRecSignal(tNode, WAIT_NDB_TAMPER, &tSignal, 0);
      if (ret_code == 0) {  
648
        if (tNdbConn->Status() != NdbTransaction::Connected) {
649 650 651 652 653 654 655 656 657 658 659 660 661 662
          theRestartGCI = 0;
        }//if
        releaseNdbCon(tNdbConn);
        return theRestartGCI;
      } else if ((ret_code == -5) || (ret_code == -2)) {
        TRACE_DEBUG("Continue DIHNDBTAMPER when node failed/stopping");
      } else {
        return -1;
      }//if
    } while (1);
  }
  return 0;
#endif
}
663
#if 0
664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704
/****************************************************************************
NdbSchemaCon* startSchemaTransaction();

Return Value:   Returns a pointer to a schema connection object.
                Return NULL otherwise.
Remark:         Start schema transaction. Synchronous.
****************************************************************************/ 
NdbSchemaCon* 
Ndb::startSchemaTransaction()
{
  NdbSchemaCon* tSchemaCon;
  if (theSchemaConToNdbList != NULL) {
    theError.code = 4321;
    return NULL;
  }//if
  tSchemaCon = new NdbSchemaCon(this);
  if (tSchemaCon == NULL) {
    theError.code = 4000;
    return NULL;
  }//if 
  theSchemaConToNdbList = tSchemaCon;
  return tSchemaCon;  
}
/*****************************************************************************
void closeSchemaTransaction(NdbSchemaCon* aSchemaCon);

Parameters:     aSchemaCon: the schemacon used in the transaction.
Remark:         Close transaction by releasing the schemacon and all schemaop.
*****************************************************************************/
void
Ndb::closeSchemaTransaction(NdbSchemaCon* aSchemaCon)
{
  if (theSchemaConToNdbList != aSchemaCon) {
    abort();
    return;
  }//if
  aSchemaCon->release();
  delete aSchemaCon;
  theSchemaConToNdbList = NULL;
  return;
}//Ndb::closeSchemaTransaction()
705
#endif
706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745

/*****************************************************************************
void RestartGCI(int aRestartGCI);

Remark:		Set theRestartGCI on the NDB object
*****************************************************************************/
void
Ndb::RestartGCI(int aRestartGCI)
{
  theRestartGCI = aRestartGCI;
}

/****************************************************************************
int getBlockNumber(void);

Remark:		
****************************************************************************/
int
Ndb::getBlockNumber()
{
  return theNdbBlockNumber;
}

NdbDictionary::Dictionary *
Ndb::getDictionary() const {
  return theDictionary;
}

/****************************************************************************
int getNodeId();

Remark:		
****************************************************************************/
int
Ndb::getNodeId()
{
  return theNode;
}

/****************************************************************************
unknown's avatar
unknown committed
746
Uint64 getTupleIdFromNdb( Uint32 aTableId, Uint32 cacheSize );
747 748

Parameters:     aTableId : The TableId.
unknown's avatar
unknown committed
749
                cacheSize: Prefetch this many values
750 751 752 753 754 755 756 757 758 759
Remark:		Returns a new TupleId to the application.
                The TupleId comes from SYSTAB_0 where SYSKEY_0 = TableId.
                It is initialized to (TableId << 48) + 1 in NdbcntrMain.cpp.
****************************************************************************/
#define DEBUG_TRACE(msg) \
//  ndbout << __FILE__ << " line: " << __LINE__ << " msg: " << msg << endl

Uint64
Ndb::getAutoIncrementValue(const char* aTableName, Uint32 cacheSize)
{
760
  DBUG_ENTER("getAutoIncrementValue");
761
  const char * internalTableName = internalizeTableName(aTableName);
762 763
  Ndb_local_table_info *info=
    theDictionary->get_local_table_info(internalTableName, false);
764
  if (info == 0)
765
    DBUG_RETURN(~(Uint64)0);
766
  const NdbTableImpl *table= info->m_table_impl;
767
  Uint64 tupleId = getTupleIdFromNdb(table->m_tableId, cacheSize);
unknown's avatar
unknown committed
768
  DBUG_PRINT("info", ("value %ul", (ulong) tupleId));
769
  DBUG_RETURN(tupleId);
770 771
}

772
Uint64
unknown's avatar
unknown committed
773
Ndb::getAutoIncrementValue(const NdbDictionary::Table * aTable, Uint32 cacheSize)
774
{
775
  DBUG_ENTER("getAutoIncrementValue");
776
  if (aTable == 0)
777
    DBUG_RETURN(~(Uint64)0);
778 779
  const NdbTableImpl* table = & NdbTableImpl::getImpl(*aTable);
  Uint64 tupleId = getTupleIdFromNdb(table->m_tableId, cacheSize);
unknown's avatar
unknown committed
780
  DBUG_PRINT("info", ("value %ul", (ulong) tupleId));
781
  DBUG_RETURN(tupleId);
782 783
}

784
Uint64 
unknown's avatar
unknown committed
785
Ndb::getTupleIdFromNdb(const char* aTableName, Uint32 cacheSize)
786 787 788
{
  const NdbTableImpl* table = theDictionary->getTable(aTableName);
  if (table == 0)
789
    return ~(Uint64)0;
790 791 792 793
  return getTupleIdFromNdb(table->m_tableId, cacheSize);
}

Uint64
unknown's avatar
unknown committed
794
Ndb::getTupleIdFromNdb(Uint32 aTableId, Uint32 cacheSize)
795
{
796
  DBUG_ENTER("getTupleIdFromNdb");
797 798 799
  if ( theFirstTupleId[aTableId] != theLastTupleId[aTableId] )
  {
    theFirstTupleId[aTableId]++;
unknown's avatar
unknown committed
800 801
    DBUG_PRINT("info", ("next cached value %ul", 
                        (ulong) theFirstTupleId[aTableId]));
802
    DBUG_RETURN(theFirstTupleId[aTableId]);
803 804 805
  }
  else // theFirstTupleId == theLastTupleId
  {
806 807 808
    DBUG_PRINT("info",("reading %u values from database", 
                       (cacheSize == 0) ? 1 : cacheSize));
    DBUG_RETURN(opTupleIdOnNdb(aTableId, (cacheSize == 0) ? 1 : cacheSize, 0));
809 810 811
  }
}

unknown's avatar
unknown committed
812 813 814
Uint64
Ndb::readAutoIncrementValue(const char* aTableName)
{
815
  DBUG_ENTER("readtAutoIncrementValue");
unknown's avatar
unknown committed
816
  const NdbTableImpl* table = theDictionary->getTable(aTableName);
817 818
  if (table == 0) {
    theError= theDictionary->getNdbError();
819
    DBUG_RETURN(~(Uint64)0);
820
  }
unknown's avatar
unknown committed
821
  Uint64 tupleId = readTupleIdFromNdb(table->m_tableId);
unknown's avatar
unknown committed
822
  DBUG_PRINT("info", ("value %ul", (ulong) tupleId));
823
  DBUG_RETURN(tupleId);
unknown's avatar
unknown committed
824 825
}

826
Uint64
unknown's avatar
unknown committed
827
Ndb::readAutoIncrementValue(const NdbDictionary::Table * aTable)
828
{
829
  DBUG_ENTER("readtAutoIncrementValue");
830
  if (aTable == 0)
831
    DBUG_RETURN(~(Uint64)0);
832 833
  const NdbTableImpl* table = & NdbTableImpl::getImpl(*aTable);
  Uint64 tupleId = readTupleIdFromNdb(table->m_tableId);
unknown's avatar
unknown committed
834
  DBUG_PRINT("info", ("value %ul", (ulong) tupleId));
835
  DBUG_RETURN(tupleId);
836 837
}

unknown's avatar
unknown committed
838 839 840 841 842 843 844 845 846 847
Uint64
Ndb::readTupleIdFromNdb(Uint32 aTableId)
{
  if ( theFirstTupleId[aTableId] == theLastTupleId[aTableId] )
    // Cache is empty, check next in database
    return opTupleIdOnNdb(aTableId, 0, 3);

  return theFirstTupleId[aTableId] + 1;
}

848
bool
849
Ndb::setAutoIncrementValue(const char* aTableName, Uint64 val, bool increase)
850 851
{
  DEBUG_TRACE("setAutoIncrementValue " << val);
852
  const char * internalTableName= internalizeTableName(aTableName);
853 854
  Ndb_local_table_info *info=
    theDictionary->get_local_table_info(internalTableName, false);
855
  if (info == 0) {
856
    theError= theDictionary->getNdbError();
857
    return false;
858
  }
859
  const NdbTableImpl* table= info->m_table_impl;
860
  return setTupleIdInNdb(table->m_tableId, val, increase);
861 862 863
}

bool
unknown's avatar
unknown committed
864
Ndb::setAutoIncrementValue(const NdbDictionary::Table * aTable, Uint64 val, bool increase)
865 866 867
{
  DEBUG_TRACE("setAutoIncrementValue " << val);
  if (aTable == 0)
868
    return ~(Uint64)0;
869 870
  const NdbTableImpl* table = & NdbTableImpl::getImpl(*aTable);
  return setTupleIdInNdb(table->m_tableId, val, increase);
871 872 873
}

bool 
874
Ndb::setTupleIdInNdb(const char* aTableName, Uint64 val, bool increase )
875 876 877
{
  DEBUG_TRACE("setTupleIdInNdb");
  const NdbTableImpl* table = theDictionary->getTable(aTableName);
878 879
  if (table == 0) {
    theError= theDictionary->getNdbError();
880
    return false;
881
  }
882
  return setTupleIdInNdb(table->m_tableId, val, increase);
883 884 885
}

bool
886
Ndb::setTupleIdInNdb(Uint32 aTableId, Uint64 val, bool increase )
887 888
{
  DEBUG_TRACE("setTupleIdInNdb");
889 890 891 892 893 894
  if (increase)
  {
    if (theFirstTupleId[aTableId] != theLastTupleId[aTableId])
    {
      // We have a cache sequence
      if (val <= theFirstTupleId[aTableId]+1)
unknown's avatar
unknown committed
895
	return false;
896 897 898 899 900 901 902 903 904 905 906
      if (val <= theLastTupleId[aTableId])
      {
	theFirstTupleId[aTableId] = val - 1;
	return true;
      }
      // else continue;
    }    
    return (opTupleIdOnNdb(aTableId, val, 2) == val);
  }
  else
    return (opTupleIdOnNdb(aTableId, val, 1) == val);
907 908 909 910 911
}

Uint64
Ndb::opTupleIdOnNdb(Uint32 aTableId, Uint64 opValue, Uint32 op)
{
912 913
  DBUG_ENTER("Ndb::opTupleIdOnNdb");
  DBUG_PRINT("enter", ("table=%u value=%llu op=%u", aTableId, opValue, op));
914

915
  NdbTransaction*     tConnection;
unknown's avatar
unknown committed
916
  NdbOperation*      tOperation= 0; // Compiler warning if not initialized
917 918
  Uint64             tValue;
  NdbRecAttr*        tRecAttrResult;
unknown's avatar
unknown committed
919
  int                result;
920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944
  Uint64 ret;

  CHECK_STATUS_MACRO_ZERO;

  BaseString currentDb(getDatabaseName());
  BaseString currentSchema(getDatabaseSchemaName());

  setDatabaseName("sys");
  setDatabaseSchemaName("def");
  tConnection = this->startTransaction();
  if (tConnection == NULL)
    goto error_return;

  if (usingFullyQualifiedNames())
    tOperation = tConnection->getNdbOperation("SYSTAB_0");
  else
    tOperation = tConnection->getNdbOperation("sys/def/SYSTAB_0");
  if (tOperation == NULL)
    goto error_handler;

  switch (op)
    {
    case 0:
      tOperation->interpretedUpdateTuple();
      tOperation->equal("SYSKEY_0", aTableId );
unknown's avatar
unknown committed
945
      tOperation->incValue("NEXTID", opValue);
946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961
      tRecAttrResult = tOperation->getValue("NEXTID");

      if (tConnection->execute( Commit ) == -1 )
        goto error_handler;

      tValue = tRecAttrResult->u_64_value();

      theFirstTupleId[aTableId] = tValue - opValue;
      theLastTupleId[aTableId]  = tValue - 1;
      ret = theFirstTupleId[aTableId];
      break;
    case 1:
      tOperation->updateTuple();
      tOperation->equal("SYSKEY_0", aTableId );
      tOperation->setValue("NEXTID", opValue);

962 963 964
      if (tConnection->execute( Commit ) == -1 )
        goto error_handler;

unknown's avatar
unknown committed
965 966
      theFirstTupleId[aTableId] = ~(Uint64)0;
      theLastTupleId[aTableId]  = ~(Uint64)0;
967 968 969 970 971 972 973 974 975 976
      ret = opValue;
      break;
    case 2:
      tOperation->interpretedUpdateTuple();
      tOperation->equal("SYSKEY_0", aTableId );
      tOperation->load_const_u64(1, opValue);
      tOperation->read_attr("NEXTID", 2);
      tOperation->branch_le(2, 1, 0);
      tOperation->write_attr("NEXTID", 1);
      tOperation->interpret_exit_ok();
unknown's avatar
unknown committed
977 978
      tOperation->def_label(0);
      tOperation->interpret_exit_nok(9999);
979
      
980
      if ( (result = tConnection->execute( Commit )) == -1 )
981
        goto error_handler;
unknown's avatar
unknown committed
982 983 984 985 986 987 988 989
      
      if (result == 9999)
        ret = ~(Uint64)0;
      else
      {
        theFirstTupleId[aTableId] = theLastTupleId[aTableId] = opValue - 1;
	ret = opValue;
      }
990
      break;
unknown's avatar
unknown committed
991 992 993 994 995 996 997 998
    case 3:
      tOperation->readTuple();
      tOperation->equal("SYSKEY_0", aTableId );
      tRecAttrResult = tOperation->getValue("NEXTID");
      if (tConnection->execute( Commit ) == -1 )
        goto error_handler;
      ret = tRecAttrResult->u_64_value();
      break;
999 1000 1001 1002 1003 1004 1005 1006 1007 1008
    default:
      goto error_handler;
    }

  this->closeTransaction(tConnection);

  // Restore current name space
  setDatabaseName(currentDb.c_str());
  setDatabaseSchemaName(currentSchema.c_str());

1009
  DBUG_RETURN(ret);
1010 1011 1012 1013 1014 1015 1016 1017 1018

  error_handler:
    theError.code = tConnection->theError.code;
    this->closeTransaction(tConnection);
  error_return:
    // Restore current name space
    setDatabaseName(currentDb.c_str());
    setDatabaseSchemaName(currentSchema.c_str());

1019 1020 1021 1022
  DBUG_PRINT("error", ("ndb=%d con=%d op=%d",
             theError.code,
             tConnection ? tConnection->theError.code : -1,
             tOperation ? tOperation->theError.code : -1));
unknown's avatar
Merge  
unknown committed
1023
  DBUG_RETURN(~(Uint64)0);
1024 1025 1026 1027 1028
}

Uint32
convertEndian(Uint32 Data)
{
1029
#ifdef WORDS_BIGENDIAN
1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044
  Uint32 t1, t2, t3, t4;
  t4 = (Data >> 24) & 255;
  t3 = (Data >> 16) & 255;
  t4 = t4 + (t3 << 8);
  t2 = (Data >> 8) & 255;
  t4 = t4 + (t2 << 16);
  t1 = Data & 255;
  t4 = t4 + (t1 << 24);
  return t4;
#else
  return Data;
#endif
}
const char * Ndb::getCatalogName() const
{
unknown's avatar
unknown committed
1045
  return theImpl->m_dbname.c_str();
1046
}
unknown's avatar
unknown committed
1047 1048


1049 1050
void Ndb::setCatalogName(const char * a_catalog_name)
{
unknown's avatar
unknown committed
1051 1052 1053 1054
  if (a_catalog_name)
  {
    theImpl->m_dbname.assign(a_catalog_name);
    theImpl->update_prefix();
1055 1056
  }
}
unknown's avatar
unknown committed
1057 1058


1059 1060
const char * Ndb::getSchemaName() const
{
unknown's avatar
unknown committed
1061
  return theImpl->m_schemaname.c_str();
1062
}
unknown's avatar
unknown committed
1063 1064


1065 1066 1067
void Ndb::setSchemaName(const char * a_schema_name)
{
  if (a_schema_name) {
unknown's avatar
unknown committed
1068 1069
    theImpl->m_schemaname.assign(a_schema_name);
    theImpl->update_prefix();
1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101
  }
}
 
/*
Deprecated functions
*/
const char * Ndb::getDatabaseName() const
{
  return getCatalogName();
}
 
void Ndb::setDatabaseName(const char * a_catalog_name)
{
  setCatalogName(a_catalog_name);
}
 
const char * Ndb::getDatabaseSchemaName() const
{
  return getSchemaName();
}
 
void Ndb::setDatabaseSchemaName(const char * a_schema_name)
{
  setSchemaName(a_schema_name);
}
 
bool Ndb::usingFullyQualifiedNames()
{
  return fullyQualifiedNames;
}
 
const char *
1102
Ndb::externalizeTableName(const char * internalTableName, bool fullyQualifiedNames)
1103 1104 1105 1106 1107
{
  if (fullyQualifiedNames) {
    register const char *ptr = internalTableName;
   
    // Skip database name
1108
    while (*ptr && *ptr++ != table_name_separator);
1109
    // Skip schema name
1110
    while (*ptr && *ptr++ != table_name_separator);
1111 1112 1113 1114 1115 1116 1117
    return ptr;
  }
  else
    return internalTableName;
}

const char *
1118
Ndb::externalizeTableName(const char * internalTableName)
1119
{
1120
  return externalizeTableName(internalTableName, usingFullyQualifiedNames());
1121
}
1122

1123
const char *
1124
Ndb::externalizeIndexName(const char * internalIndexName, bool fullyQualifiedNames)
1125 1126 1127 1128 1129 1130
{
  if (fullyQualifiedNames) {
    register const char *ptr = internalIndexName;
   
    // Scan name from the end
    while (*ptr++); ptr--; // strend
1131
    while (ptr >= internalIndexName && *ptr != table_name_separator)
1132 1133 1134 1135 1136 1137 1138
      ptr--;
     
    return ptr + 1;
  }
  else
    return internalIndexName;
}
1139 1140 1141 1142 1143 1144 1145 1146 1147 1148

const char *
Ndb::externalizeIndexName(const char * internalIndexName)
{
  return externalizeIndexName(internalIndexName, usingFullyQualifiedNames());
}

const char *
Ndb::internalizeTableName(const char * externalTableName)
{
unknown's avatar
unknown committed
1149 1150
  if (fullyQualifiedNames)
    return theImpl->internalize_table_name(externalTableName);
1151 1152 1153
  else
    return externalTableName;
}
1154 1155 1156 1157 1158
 
const char *
Ndb::internalizeIndexName(const NdbTableImpl * table,
                          const char * externalIndexName)
{
unknown's avatar
unknown committed
1159 1160
  if (fullyQualifiedNames)
    return theImpl->internalize_index_name(table, externalIndexName);
1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171
  else
    return externalIndexName;
}

const BaseString
Ndb::getDatabaseFromInternalName(const char * internalName)
{
  char * databaseName = new char[strlen(internalName) + 1];
  strcpy(databaseName, internalName);
  register char *ptr = databaseName;
   
1172 1173
  /* Scan name for the first table_name_separator */
  while (*ptr && *ptr != table_name_separator)
1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186
    ptr++;
  *ptr = '\0';
  BaseString ret = BaseString(databaseName);
  delete [] databaseName;
  return ret;
}
 
const BaseString
Ndb::getSchemaFromInternalName(const char * internalName)
{
  char * schemaName = new char[strlen(internalName)];
  register const char *ptr1 = internalName;
   
1187 1188
  /* Scan name for the second table_name_separator */
  while (*ptr1 && *ptr1 != table_name_separator)
1189 1190 1191
    ptr1++;
  strcpy(schemaName, ptr1 + 1);
  register char *ptr = schemaName;
1192
  while (*ptr && *ptr != table_name_separator)
1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206
    ptr++;
  *ptr = '\0';
  BaseString ret = BaseString(schemaName);
  delete [] schemaName;
  return ret;
}

NdbEventOperation* Ndb::createEventOperation(const char* eventName,
					     const int bufferLength)
{
  NdbEventOperation* tOp;

  tOp = new NdbEventOperation(this, eventName, bufferLength);

unknown's avatar
unknown committed
1207 1208 1209 1210 1211 1212 1213 1214
  if (tOp == 0)
  {
    theError.code= 4000;
    return NULL;
  }

  if (tOp->getState() != NdbEventOperation::EO_CREATED) {
    theError.code= tOp->getNdbError().code;
1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246
    delete tOp;
    tOp = NULL;
  }

  //now we have to look up this event in dict

  return tOp;
}

int Ndb::dropEventOperation(NdbEventOperation* op) {
  delete op;
  return 0;
}

NdbGlobalEventBufferHandle* Ndb::getGlobalEventBufferHandle()
{
  return theGlobalEventBufferHandle;
}

//void Ndb::monitorEvent(NdbEventOperation *op, NdbEventCallback cb, void* rs)
//{
//}

int
Ndb::pollEvents(int aMillisecondNumber)
{
  return NdbEventOperation::wait(theGlobalEventBufferHandle,
				 aMillisecondNumber);
}

#ifdef VM_TRACE
#include <NdbMutex.h>
1247 1248
extern NdbMutex *ndb_print_state_mutex;

1249
static bool
1250
checkdups(NdbTransaction** list, unsigned no)
1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265
{
  for (unsigned i = 0; i < no; i++)
    for (unsigned j = i + 1; j < no; j++)
      if (list[i] == list[j])
        return true;
  return false;
}
void
Ndb::printState(const char* fmt, ...)
{
  char buf[200];
  va_list ap;
  va_start(ap, fmt);
  vsprintf(buf, fmt, ap);
  va_end(ap);
1266
  NdbMutex_Lock(ndb_print_state_mutex);
1267
  bool dups = false;
1268
  unsigned i;
1269
  ndbout << buf << " ndb=" << hex << this << dec;
unknown's avatar
unknown committed
1270
#ifndef NDB_WIN32
1271 1272 1273 1274
  ndbout << " thread=" << (int)pthread_self();
#endif
  ndbout << endl;
  for (unsigned n = 0; n < MAX_NDB_NODES; n++) {
1275
    NdbTransaction* con = theConnectionArray[n];
1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288
    if (con != 0) {
      ndbout << "conn " << n << ":" << endl;
      while (con != 0) {
        con->printState();
        con = con->theNext;
      }
    }
  }
  ndbout << "prepared: " << theNoOfPreparedTransactions<< endl;
  if (checkdups(thePreparedTransactionsArray, theNoOfPreparedTransactions)) {
    ndbout << "!! DUPS !!" << endl;
    dups = true;
  }
1289
  for (i = 0; i < theNoOfPreparedTransactions; i++)
1290 1291 1292 1293 1294 1295
    thePreparedTransactionsArray[i]->printState();
  ndbout << "sent: " << theNoOfSentTransactions<< endl;
  if (checkdups(theSentTransactionsArray, theNoOfSentTransactions)) {
    ndbout << "!! DUPS !!" << endl;
    dups = true;
  }
1296
  for (i = 0; i < theNoOfSentTransactions; i++)
1297 1298 1299 1300 1301 1302
    theSentTransactionsArray[i]->printState();
  ndbout << "completed: " << theNoOfCompletedTransactions<< endl;
  if (checkdups(theCompletedTransactionsArray, theNoOfCompletedTransactions)) {
    ndbout << "!! DUPS !!" << endl;
    dups = true;
  }
1303
  for (i = 0; i < theNoOfCompletedTransactions; i++)
1304
    theCompletedTransactionsArray[i]->printState();
1305
  NdbMutex_Unlock(ndb_print_state_mutex);
1306 1307 1308 1309
}
#endif