Bank.cpp
上传用户:romrleung
上传日期:2022-05-23
资源大小:18897k
文件大小:59k
源码类别:

MySQL数据库

开发平台:

Visual C++

  1. /* Copyright (C) 2003 MySQL AB
  2.    This program is free software; you can redistribute it and/or modify
  3.    it under the terms of the GNU General Public License as published by
  4.    the Free Software Foundation; either version 2 of the License, or
  5.    (at your option) any later version.
  6.    This program is distributed in the hope that it will be useful,
  7.    but WITHOUT ANY WARRANTY; without even the implied warranty of
  8.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  9.    GNU General Public License for more details.
  10.    You should have received a copy of the GNU General Public License
  11.    along with this program; if not, write to the Free Software
  12.    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
  13. #include "Bank.hpp"
  14. #include <time.h>
  15. #include <NdbSleep.h>
  16. #include <UtilTransactions.hpp>
  17. Bank::Bank(bool _init):
  18.   m_ndb("BANK"),
  19.   m_maxAccount(-1),
  20.   m_initialized(false)
  21. {
  22.   if(_init)
  23.     init();
  24. }
  25. int Bank::init(){
  26.   if (m_initialized == true)
  27.     return NDBT_OK;
  28.   myRandom48Init(NdbTick_CurrentMillisecond());
  29.   m_ndb.init();   
  30.   if (m_ndb.waitUntilReady(30) != 0)
  31.   {
  32.     ndbout << "Ndb not ready" << endl;
  33.     return NDBT_FAILED;
  34.   }
  35.   
  36.   if (getNumAccounts() != NDBT_OK)
  37.     return NDBT_FAILED;
  38.   m_initialized = true;
  39.   return NDBT_OK;
  40. }
  41. int Bank::performTransactions(int maxSleepBetweenTrans, int yield){
  42.   int transactions = 0;
  43.   while(performTransaction() == NDBT_OK)
  44.   {
  45.     transactions++;
  46.     
  47.     if (maxSleepBetweenTrans > 0){
  48.       int val = myRandom48(maxSleepBetweenTrans);
  49.       NdbSleep_MilliSleep(val);      
  50.     }
  51.     
  52.     if((transactions % 100) == 0)
  53.       g_info << transactions  << endl;
  54.     
  55.     if (yield != 0 && transactions >= yield)
  56.       return NDBT_OK;
  57.   }
  58.   return NDBT_FAILED;
  59. }
  60. int Bank::performTransaction(){
  61.   int result = NDBT_OK;
  62.   if (m_maxAccount <= 0){
  63.     g_err << "No accounts in bank" << endl;
  64.     return NDBT_FAILED;
  65.   }
  66.   int fromAccount = myRandom48(m_maxAccount);
  67.   int toAccount = myRandom48(m_maxAccount);
  68.     
  69.   if (fromAccount == toAccount){
  70.     // Increase toAccount with 1
  71.     toAccount = (toAccount+1)%m_maxAccount;
  72.   }
  73.     
  74.   int maxAmount = getMaxAmount();
  75.     
  76.   int amount = myRandom48(maxAmount);
  77. retry_transaction:
  78.   int res = performTransaction(fromAccount, toAccount, amount);
  79.   if (res != 0){
  80.     switch (res){
  81.     case NDBT_FAILED:
  82.       g_err << "performTransaction returned NDBT_FAILED" << endl
  83.     << "  fromAccount = " << fromAccount << endl
  84.     << "  toAccount = " << toAccount << endl
  85.     << "  amount = " << amount << endl;
  86.       result = NDBT_FAILED;
  87.       break;
  88.     case NOT_ENOUGH_FUNDS:
  89.       //   ndbout << "performTransaction returned NOT_ENOUGH_FUNDS" << endl;
  90.       break;
  91.     case NDBT_TEMPORARY:
  92.       g_err << "TEMPORARY_ERRROR retrying" << endl;
  93.       goto retry_transaction;
  94.       break;
  95.     default:
  96.       g_info << "performTransaction returned "<<res << endl;
  97.       break;
  98.     }
  99.   }
  100.   return result;
  101. }
  102. /**
  103.  * Perform a transaction in the bank. 
  104.  * Ie. transfer money from one account to another.
  105.  *
  106.  * @param 
  107.  * @return 0 if successful or an error code
  108.  */
  109. int Bank::performTransaction(int fromAccountId,
  110.      int toAccountId,
  111.      int amount ){
  112.   /**
  113.    * 1. Start transaction
  114.    * 2. Check balance on from account, if there is
  115.    *    not enough funds abort transaction
  116.    * 3. Update ACCOUNT set balance = balance - amount on
  117.    *    from account 
  118.    * 4. Insert withdrawal in TRANSACTION
  119.    * 5. Insert deposit in transaction
  120.    * 6. Update ACCOUNT set balance = balance + amount on 
  121.    *    to account
  122.    * 7. Commit transaction
  123.    */ 
  124.   //  g_info << "performTransaction " << fromAccountId 
  125.   //  << ", "<<toAccountId<<", "<<amount << endl;
  126.   // Call the first implementation of this trans
  127.   // In the future we can have several different versions of this trans
  128.   // and call them randomly 
  129.   return performTransactionImpl1(fromAccountId, toAccountId, amount); 
  130. }
  131. int Bank::performTransactionImpl1(int fromAccountId,
  132.   int toAccountId,
  133.   int amount ){
  134.   int check;
  135.     
  136.   // Ok, all clear to do the transaction
  137.   Uint64 transId;
  138.   int result = NDBT_OK;
  139.   if ((result= getNextTransactionId(transId)) != NDBT_OK){
  140.     return result;
  141.   }
  142.   NdbConnection* pTrans = m_ndb.startTransaction();
  143.   if( pTrans == NULL ) {
  144.     const NdbError err = m_ndb.getNdbError();
  145.     if (err.status == NdbError::TemporaryError){
  146.       ERR(err);
  147.       return NDBT_TEMPORARY;
  148.     }
  149.     ERR(err);
  150.     return NDBT_FAILED;
  151.   }
  152.     
  153.   Uint64 currTime;
  154.   if (prepareGetCurrTimeOp(pTrans, currTime) != NDBT_OK){
  155.     ERR(pTrans->getNdbError());
  156.     m_ndb.closeTransaction(pTrans);
  157.     return NDBT_FAILED;
  158.   }
  159.   /** 
  160.    * Check balance on from account
  161.    */
  162.   NdbOperation* pOp = pTrans->getNdbOperation("ACCOUNT");
  163.   if (pOp == NULL) {
  164.     ERR(pTrans->getNdbError());
  165.     m_ndb.closeTransaction(pTrans);
  166.     return NDBT_FAILED;
  167.   }
  168.     
  169.   check = pOp->readTupleExclusive();
  170.   if( check == -1 ) {
  171.     ERR(pTrans->getNdbError());
  172.     m_ndb.closeTransaction(pTrans);
  173.     return NDBT_FAILED;
  174.   }
  175.     
  176.   check = pOp->equal("ACCOUNT_ID", fromAccountId);
  177.   if( check == -1 ) {
  178.     ERR(pTrans->getNdbError());
  179.     m_ndb.closeTransaction(pTrans);
  180.     return NDBT_FAILED;
  181.   }
  182.     
  183.   NdbRecAttr* balanceFromRec = pOp->getValue("BALANCE");
  184.   if( balanceFromRec ==NULL ) {
  185.     ERR(pTrans->getNdbError());
  186.     m_ndb.closeTransaction(pTrans);
  187.     return NDBT_FAILED;
  188.   }
  189.     
  190.   NdbRecAttr* fromAccountTypeRec = pOp->getValue("ACCOUNT_TYPE");
  191.   if( fromAccountTypeRec == NULL ) {
  192.     ERR(pTrans->getNdbError());
  193.     m_ndb.closeTransaction(pTrans);
  194.     return NDBT_FAILED;
  195.   }
  196.   /** 
  197.    * Read balance on to account
  198.    */
  199.   NdbOperation* pOp6 = pTrans->getNdbOperation("ACCOUNT");
  200.   if (pOp6 == NULL) {
  201.     ERR(pTrans->getNdbError());
  202.     m_ndb.closeTransaction(pTrans);
  203.     return NDBT_FAILED;
  204.   }
  205.     
  206.   check = pOp6->readTupleExclusive();
  207.   if( check == -1 ) {
  208.     ERR(pTrans->getNdbError());
  209.     m_ndb.closeTransaction(pTrans);
  210.     return NDBT_FAILED;
  211.   }
  212.     
  213.   check = pOp6->equal("ACCOUNT_ID", toAccountId);
  214.   if( check == -1 ) {
  215.     ERR(pTrans->getNdbError());
  216.     m_ndb.closeTransaction(pTrans);
  217.     return NDBT_FAILED;
  218.   }
  219.     
  220.   NdbRecAttr* balanceToRec = pOp6->getValue("BALANCE");
  221.   if( balanceToRec == NULL ) {
  222.     ERR(pTrans->getNdbError());
  223.     m_ndb.closeTransaction(pTrans);
  224.     return NDBT_FAILED;
  225.   }
  226.   NdbRecAttr* toAccountTypeRec = pOp6->getValue("ACCOUNT_TYPE");
  227.   if( toAccountTypeRec == NULL ) {
  228.     ERR(pTrans->getNdbError());
  229.     m_ndb.closeTransaction(pTrans);
  230.     return NDBT_FAILED;
  231.   }
  232.     
  233.   check = pTrans->execute(NoCommit);
  234.   if( check == -1 ) {
  235.     const NdbError err = pTrans->getNdbError();
  236.     m_ndb.closeTransaction(pTrans);    
  237.     if (err.status == NdbError::TemporaryError){
  238.       ERR(err);
  239.       return NDBT_TEMPORARY;
  240.     }
  241.     ERR(err);
  242.     return NDBT_FAILED;
  243.   }
  244.     
  245.   Uint32  balanceFrom = balanceFromRec->u_32_value();
  246.   //  ndbout << "balanceFrom: " << balanceFrom << endl;
  247.   if (((Int64)balanceFrom - amount) < 0){
  248.     m_ndb.closeTransaction(pTrans);      
  249.     //ndbout << "Not enough funds" << endl;      
  250.     return NOT_ENOUGH_FUNDS;
  251.   }
  252.   Uint32 fromAccountType = fromAccountTypeRec->u_32_value();
  253.   Uint32  balanceTo = balanceToRec->u_32_value();
  254.   //  ndbout << "balanceTo: " << balanceTo << endl;
  255.   Uint32 toAccountType = toAccountTypeRec->u_32_value();
  256.   /**
  257.    * Update balance on from account
  258.    */
  259.   NdbOperation* pOp2 = pTrans->getNdbOperation("ACCOUNT");
  260.   if (pOp2 == NULL) {
  261.     ERR(pTrans->getNdbError());
  262.     m_ndb.closeTransaction(pTrans);
  263.     return NDBT_FAILED;
  264.   }
  265.     
  266.   check = pOp2->updateTuple();
  267.   if( check == -1 ) {
  268.     ERR(pTrans->getNdbError());
  269.     m_ndb.closeTransaction(pTrans);
  270.     return NDBT_FAILED;
  271.   }
  272.     
  273.   check = pOp2->equal("ACCOUNT_ID", fromAccountId);
  274.   if( check == -1 ) {
  275.     ERR(pTrans->getNdbError());
  276.     m_ndb.closeTransaction(pTrans);
  277.     return NDBT_FAILED;
  278.   }
  279.   check = pOp2->setValue("BALANCE", balanceFrom - amount);
  280.   if( check == -1 ) {
  281.     ERR(pTrans->getNdbError());
  282.     m_ndb.closeTransaction(pTrans);
  283.     return NDBT_FAILED;
  284.   }
  285.   /**
  286.    * Update balance on to account
  287.    */
  288.   NdbOperation* pOp3 = pTrans->getNdbOperation("ACCOUNT");
  289.   if (pOp3 == NULL) {
  290.     ERR(pTrans->getNdbError());
  291.     m_ndb.closeTransaction(pTrans);
  292.     return NDBT_FAILED;
  293.   }
  294.     
  295.   check = pOp3->updateTuple();
  296.   if( check == -1 ) {
  297.     ERR(pTrans->getNdbError());
  298.     m_ndb.closeTransaction(pTrans);
  299.     return NDBT_FAILED;
  300.   }
  301.     
  302.   check = pOp3->equal("ACCOUNT_ID", toAccountId);
  303.   if( check == -1 ) {
  304.     ERR(pTrans->getNdbError());
  305.     m_ndb.closeTransaction(pTrans);
  306.     return NDBT_FAILED;
  307.   }
  308.   check = pOp3->setValue("BALANCE", balanceTo + amount);
  309.   if( check == -1 ) {
  310.     ERR(pTrans->getNdbError());
  311.     m_ndb.closeTransaction(pTrans);
  312.     return NDBT_FAILED;
  313.   }
  314.   /**
  315.    * Insert withdrawal transaction
  316.    */
  317.   NdbOperation* pOp4 = pTrans->getNdbOperation("TRANSACTION");
  318.   if (pOp4 == NULL) {
  319.     ERR(pTrans->getNdbError());
  320.     m_ndb.closeTransaction(pTrans);
  321.     return NDBT_FAILED;
  322.   }
  323.     
  324.   check = pOp4->insertTuple();
  325.   if( check == -1 ) {
  326.     ERR(pTrans->getNdbError());
  327.     m_ndb.closeTransaction(pTrans);
  328.     return NDBT_FAILED;
  329.   }
  330.     
  331.   check = pOp4->equal("TRANSACTION_ID", transId);
  332.   if( check == -1 ) {
  333.     ERR(pTrans->getNdbError());
  334.     m_ndb.closeTransaction(pTrans);
  335.     return NDBT_FAILED;
  336.   }
  337.   check = pOp4->equal("ACCOUNT", fromAccountId);
  338.   if( check == -1 ) {
  339.     ERR(pTrans->getNdbError());
  340.     m_ndb.closeTransaction(pTrans);
  341.     return NDBT_FAILED;
  342.   }
  343.   check = pOp4->setValue("ACCOUNT_TYPE", fromAccountType);
  344.   if( check == -1 ) {
  345.     ERR(pTrans->getNdbError());
  346.     m_ndb.closeTransaction(pTrans);
  347.     return NDBT_FAILED;
  348.   }
  349.   check = pOp4->setValue("OTHER_ACCOUNT", toAccountId);
  350.   if( check == -1 ) {
  351.     ERR(pTrans->getNdbError());
  352.     m_ndb.closeTransaction(pTrans);
  353.     return NDBT_FAILED;
  354.   }
  355.   check = pOp4->setValue("TRANSACTION_TYPE", WithDrawal);
  356.   if( check == -1 ) {
  357.     ERR(pTrans->getNdbError());
  358.     m_ndb.closeTransaction(pTrans);
  359.     return NDBT_FAILED;
  360.   }
  361.     
  362.   check = pOp4->setValue("TIME", currTime);
  363.   if( check == -1 ) {
  364.     ERR(pTrans->getNdbError());
  365.     m_ndb.closeTransaction(pTrans);
  366.     return NDBT_FAILED;
  367.   }
  368.   check = pOp4->setValue("AMOUNT", amount);
  369.   if( check == -1 ) {
  370.     ERR(pTrans->getNdbError());
  371.     m_ndb.closeTransaction(pTrans);
  372.     return NDBT_FAILED;
  373.   }
  374.   /**
  375.    * Insert deposit transaction
  376.    */
  377.   NdbOperation* pOp5 = pTrans->getNdbOperation("TRANSACTION");
  378.   if (pOp5 == NULL) {
  379.     ERR(pTrans->getNdbError());
  380.     m_ndb.closeTransaction(pTrans);
  381.     return NDBT_FAILED;
  382.   }
  383.     
  384.   check = pOp5->insertTuple();
  385.   if( check == -1 ) {
  386.     ERR(pTrans->getNdbError());
  387.     m_ndb.closeTransaction(pTrans);
  388.     return NDBT_FAILED;
  389.   }
  390.     
  391.   check = pOp5->equal("TRANSACTION_ID", transId);
  392.   if( check == -1 ) {
  393.     ERR(pTrans->getNdbError());
  394.     m_ndb.closeTransaction(pTrans);
  395.     return NDBT_FAILED;
  396.   }
  397.   check = pOp5->equal("ACCOUNT", toAccountId);
  398.   if( check == -1 ) {
  399.     ERR(pTrans->getNdbError());
  400.     m_ndb.closeTransaction(pTrans);
  401.     return NDBT_FAILED;
  402.   }
  403.   check = pOp5->setValue("ACCOUNT_TYPE", toAccountType);
  404.   if( check == -1 ) {
  405.     ERR(pTrans->getNdbError());
  406.     m_ndb.closeTransaction(pTrans);
  407.     return NDBT_FAILED;
  408.   }
  409.   check = pOp5->setValue("OTHER_ACCOUNT", fromAccountId);
  410.   if( check == -1 ) {
  411.     ERR(pTrans->getNdbError());
  412.     m_ndb.closeTransaction(pTrans);
  413.     return NDBT_FAILED;
  414.   }
  415.   check = pOp5->setValue("TRANSACTION_TYPE", Deposit);
  416.   if( check == -1 ) {
  417.     ERR(pTrans->getNdbError());
  418.     m_ndb.closeTransaction(pTrans);
  419.     return NDBT_FAILED;
  420.   }
  421.   check = pOp5->setValue("TIME", currTime);
  422.   if( check == -1 ) {
  423.     ERR(pTrans->getNdbError());
  424.     m_ndb.closeTransaction(pTrans);
  425.     return NDBT_FAILED;
  426.   }
  427.   check = pOp5->setValue("AMOUNT", amount);
  428.   if( check == -1 ) {
  429.     ERR(pTrans->getNdbError());
  430.     m_ndb.closeTransaction(pTrans);
  431.     return NDBT_FAILED;
  432.   }
  433.   check = pTrans->execute(Commit);
  434.   if( check == -1 ) {
  435.     const NdbError err = pTrans->getNdbError();
  436.     m_ndb.closeTransaction(pTrans);    
  437.     if (err.status == NdbError::TemporaryError){
  438.       ERR(err);
  439.       return NDBT_TEMPORARY;
  440.     }
  441.     ERR(err);
  442.     return NDBT_FAILED;
  443.   }
  444.     
  445.   m_ndb.closeTransaction(pTrans);      
  446.   return NDBT_OK;  
  447. }
  448.     
  449. int Bank::performMakeGLs(int yield){
  450.   int result;
  451.   
  452.   int counter, maxCounter;
  453.   int yieldCounter = 0;
  454.   while (1){
  455.     // Counters to keep tracck of how many
  456.     // GLs should be made before performing a validation
  457.     counter = 0;
  458.     maxCounter = 50 + myRandom48(100);
  459.     
  460.     /** 
  461.      * Validate GLs and Transactions for previous days
  462.      *
  463.      */
  464.     result = performValidateGLs();
  465.     if (result != NDBT_OK){
  466.       if (result == VERIFICATION_FAILED){
  467. g_err << "performValidateGLs verification failed" << endl;
  468. return NDBT_FAILED;
  469.       }
  470.       g_info << "performValidateGLs failed" << endl;
  471.       return NDBT_FAILED;
  472.       continue;
  473.     }
  474.     result = performValidatePurged();
  475.     if (result != NDBT_OK){
  476.       if (result == VERIFICATION_FAILED){
  477. g_err << "performValidatePurged verification failed" << endl;
  478. return NDBT_FAILED;
  479.       }
  480.       g_info << "performValidatePurged failed" << endl;
  481.       return NDBT_FAILED;
  482.     }
  483.     while (1){
  484.       yieldCounter++;
  485.       if (yield != 0 && yieldCounter >= yield)
  486. return NDBT_OK;
  487.       /**
  488.        * Find last GL time.  
  489.        * ( GL record with highest time value)
  490.        */
  491.       Uint64 lastGLTime;
  492.       if (findLastGL(lastGLTime) != NDBT_OK){
  493. g_info << "findLastGL failed" << endl;
  494. // Break out of inner while loop
  495. break;
  496.       }
  497.       
  498.       lastGLTime++;
  499.       
  500.       /** 
  501.        * If last GL time + 1 is smaller than current time
  502.        * perform a GL for that time
  503.        */
  504.       Uint64 currTime;
  505.       if (getCurrTime(currTime) != NDBT_OK){
  506. g_info << "getCurrTime failed" << endl;
  507. // Break out of inner while loop
  508. break;
  509.       }      
  510.       if (lastGLTime < currTime){
  511. counter++;
  512. if (performMakeGL(lastGLTime) != NDBT_OK){
  513.   g_info << "performMakeGL failed" << endl;
  514. // Break out of inner while loop
  515.   break;
  516. }
  517. if (counter > maxCounter){
  518.   // Break out of inner while loop and 
  519.   // validatePreviousGLs
  520.   g_info << "counter("<<counter<<") > maxCounter("<<maxCounter<<")" << endl;
  521.   break;
  522. }
  523.       } else {
  524. ;//ndbout << "It's not time to make GL yet" << endl;
  525. // ndbout << "Sleeping 1 second" << endl;
  526. NdbSleep_SecSleep(1);      
  527.       }
  528.       
  529.       Uint32 age = 3;
  530.       if (purgeOldGLTransactions(currTime, age) != NDBT_OK){
  531.         g_info << "purgeOldGLTransactions failed" << endl;
  532. // Break out of inner while loop
  533. break;
  534.       }     
  535.             
  536.     }
  537.   }
  538.     
  539.   return NDBT_FAILED;
  540.   
  541. }
  542. int Bank::performValidateAllGLs(){
  543.   int result;
  544.   
  545.   while (1){
  546.     
  547.     /** 
  548.      * Validate GLs and Transactions for previous days
  549.      * Set age so that ALL GL's are validated
  550.      */
  551.     int age = 100000;
  552.     result = performValidateGLs(age);
  553.     if (result != NDBT_OK){
  554.       if (result == VERIFICATION_FAILED){
  555. g_err << "performValidateGLs verification failed" << endl;
  556. return NDBT_FAILED;
  557.       }
  558.       g_err << "performValidateGLs failed" << endl;
  559.       return NDBT_FAILED;
  560.     }
  561.     /**
  562.      * 
  563.      *
  564.      */
  565.     result = performValidatePurged();
  566.     if (result != NDBT_OK){
  567.       if (result == VERIFICATION_FAILED){
  568. g_err << "performValidatePurged verification failed" << endl;
  569. return NDBT_FAILED;
  570.       }
  571.       g_err << "performValidatePurged failed" << endl;
  572.       return NDBT_FAILED;
  573.     }
  574.     return NDBT_OK;
  575.   }
  576.     
  577.   return NDBT_FAILED;
  578.   
  579. }
  580. int Bank::findLastGL(Uint64 &lastTime){
  581.  int check;  
  582.   /**
  583.    * SELECT MAX(time) FROM GL
  584.    */
  585.   NdbConnection* pScanTrans = m_ndb.startTransaction();
  586.   if (pScanTrans == NULL) {
  587.     ERR(m_ndb.getNdbError());
  588.     return NDBT_FAILED;
  589.   }
  590.       
  591.   NdbScanOperation* pOp = pScanTrans->getNdbScanOperation("GL");
  592.   if (pOp == NULL) {
  593.     ERR(pScanTrans->getNdbError());
  594.     m_ndb.closeTransaction(pScanTrans);
  595.     return NDBT_FAILED;
  596.   }
  597.   NdbResultSet * rs = pOp->readTuples();
  598.   if( rs == 0 ) {
  599.     ERR(pScanTrans->getNdbError());
  600.     m_ndb.closeTransaction(pScanTrans);
  601.     return NDBT_FAILED;
  602.   }
  603.   check = pOp->interpret_exit_ok();
  604.   if( check == -1 ) {
  605.     ERR(pScanTrans->getNdbError());
  606.     m_ndb.closeTransaction(pScanTrans);
  607.     return NDBT_FAILED;
  608.   }
  609.   NdbRecAttr* timeRec = pOp->getValue("TIME");
  610.   if( timeRec ==NULL ) {
  611.     ERR(pScanTrans->getNdbError());
  612.     m_ndb.closeTransaction(pScanTrans);
  613.     return NDBT_FAILED;
  614.   }
  615.   check = pScanTrans->execute(NoCommit);
  616.   if( check == -1 ) {
  617.     ERR(pScanTrans->getNdbError());
  618.     m_ndb.closeTransaction(pScanTrans);
  619.     return NDBT_FAILED;
  620.   }
  621.     
  622.   int eof;
  623.   int rows = 0;
  624.   eof = rs->nextResult();
  625.   lastTime = 0;
  626.     
  627.   while(eof == 0){
  628.     rows++;
  629.     Uint64 t = timeRec->u_32_value();
  630.     if (t > lastTime)
  631.       lastTime = t;
  632.     
  633.     eof = rs->nextResult();
  634.   }
  635.   if (eof == -1) {
  636.     ERR(pScanTrans->getNdbError());
  637.     m_ndb.closeTransaction(pScanTrans);
  638.     return NDBT_FAILED;
  639.   }
  640.     
  641.   m_ndb.closeTransaction(pScanTrans);
  642.   
  643.   return NDBT_OK;
  644. }
  645. int Bank::performMakeGL(int time){
  646.   g_info << "performMakeGL: " << time << endl;
  647.   /**
  648.    *  Create one GL record for each account type.
  649.    *  All in the same transaction
  650.    */
  651.   // Start transaction    
  652.   NdbConnection* pTrans = m_ndb.startTransaction();
  653.   if (pTrans == NULL){
  654.     ERR(m_ndb.getNdbError());
  655.     return NDBT_FAILED;
  656.   }
  657.   for (int i = 0; i < getNumAccountTypes(); i++){
  658.   
  659.     if (performMakeGLForAccountType(pTrans, time, i) != NDBT_OK){
  660.       g_err << "performMakeGLForAccountType returned NDBT_FAILED"<<endl;
  661.       m_ndb.closeTransaction(pTrans);      
  662.       return NDBT_FAILED;
  663.     }
  664.   }
  665.   // Execute transaction    
  666.   if( pTrans->execute(Commit) == -1 ) {
  667.     ERR(pTrans->getNdbError());
  668.     m_ndb.closeTransaction(pTrans);
  669.     return NDBT_FAILED;
  670.   }    
  671.   m_ndb.closeTransaction(pTrans);      
  672.   
  673.   return NDBT_OK;
  674. }
  675. int Bank::performMakeGLForAccountType(NdbConnection* pTrans, 
  676.       Uint64 glTime,
  677.       Uint32 accountTypeId){
  678.   int check;
  679.   Uint32 balance = 0;
  680.   Uint32 withdrawalCount = 0;
  681.   Uint32 withdrawalSum = 0;
  682.   Uint32 depositSum = 0;
  683.   Uint32 depositCount = 0;
  684.   Uint32 countTransactions = 0;
  685.   Uint32 purged = 0;
  686.   // Insert record in GL so that we know
  687.   // that no one else is performing the same task
  688.   // Set purged = 0 to indicate that TRANSACTION
  689.   // records still exist
  690.   NdbOperation* pOp = pTrans->getNdbOperation("GL");
  691.   if (pOp == NULL) {
  692.     ERR(pTrans->getNdbError());
  693.     return NDBT_FAILED;
  694.   }
  695.     
  696.   check = pOp->insertTuple();
  697.   if( check == -1 ) {
  698.     ERR(pTrans->getNdbError());
  699.     return NDBT_FAILED;
  700.   }
  701.       
  702.   check = pOp->equal("TIME", glTime);
  703.   if( check == -1 ) {
  704.     ERR(pTrans->getNdbError());
  705.     return NDBT_FAILED;
  706.   }
  707.   check = pOp->equal("ACCOUNT_TYPE", accountTypeId);
  708.   if( check == -1 ) {
  709.     ERR(pTrans->getNdbError());
  710.     return NDBT_FAILED;
  711.   }
  712.   check = pOp->setValue("BALANCE", balance);
  713.   if( check == -1 ) {
  714.     ERR(pTrans->getNdbError());
  715.     return NDBT_FAILED;
  716.   }
  717.   check = pOp->setValue("DEPOSIT_COUNT", depositCount);
  718.   if( check == -1 ) {
  719.     ERR(pTrans->getNdbError());
  720.     return NDBT_FAILED;
  721.   }
  722.   check = pOp->setValue("DEPOSIT_SUM", depositSum);
  723.   if( check == -1 ) {
  724.     ERR(pTrans->getNdbError());
  725.     return NDBT_FAILED;
  726.   }
  727.   check = pOp->setValue("WITHDRAWAL_COUNT", withdrawalCount);
  728.   if( check == -1 ) {
  729.     ERR(pTrans->getNdbError());
  730.     return NDBT_FAILED;
  731.   }
  732.   check = pOp->setValue("WITHDRAWAL_SUM", withdrawalSum);
  733.   if( check == -1 ) {
  734.     ERR(pTrans->getNdbError());
  735.     return NDBT_FAILED;
  736.   }
  737.   check = pOp->setValue("PURGED", purged);
  738.   if( check == -1 ) {
  739.     ERR(pTrans->getNdbError());
  740.     return NDBT_FAILED;
  741.   }
  742.       
  743.   check = pTrans->execute(NoCommit);
  744.   if( check == -1 ) {
  745.     ERR(pOp->getNdbError());
  746.     return NDBT_FAILED;
  747.   }
  748.   // Read previous GL record to get old balance
  749.   NdbOperation* pOp2 = pTrans->getNdbOperation("GL");
  750.   if (pOp2 == NULL) {
  751.     ERR(pTrans->getNdbError());
  752.     return NDBT_FAILED;
  753.   }
  754.     
  755.   check = pOp2->readTuple();
  756.   if( check == -1 ) {
  757.     ERR(pTrans->getNdbError());
  758.     return NDBT_FAILED;
  759.   }
  760.       
  761.   check = pOp2->equal("TIME", glTime-1);
  762.   if( check == -1 ) {
  763.     ERR(pTrans->getNdbError());
  764.     return NDBT_FAILED;
  765.   }
  766.   check = pOp2->equal("ACCOUNT_TYPE", accountTypeId);
  767.   if( check == -1 ) {
  768.     ERR(pTrans->getNdbError());
  769.     return NDBT_FAILED;
  770.   }
  771.   NdbRecAttr* oldBalanceRec = pOp2->getValue("BALANCE");
  772.   if( oldBalanceRec == NULL ) {
  773.     ERR(pTrans->getNdbError());
  774.     return NDBT_FAILED;
  775.   }
  776.   check = pTrans->execute(NoCommit);
  777.   if( check == -1 ) {
  778.     ERR(pOp2->getNdbError());
  779.     return NDBT_FAILED;
  780.   }    
  781.   Uint32 oldBalance = oldBalanceRec->u_32_value();
  782.   //  ndbout << "oldBalance = "<<oldBalance<<endl;
  783.   balance = oldBalance;
  784.   // Start a scan transaction to search
  785.   // for TRANSACTION records with TIME = time 
  786.   // and ACCOUNT_TYPE = accountTypeId
  787.   // Build sum of all found transactions
  788.     
  789.   if (sumTransactionsForGL(glTime, 
  790.    accountTypeId,
  791.    balance,
  792.    withdrawalCount,
  793.    withdrawalSum,
  794.    depositSum,
  795.    depositCount,
  796.    countTransactions,
  797.    pTrans) != NDBT_OK){
  798.     return NDBT_FAILED;
  799.   }
  800.   //  ndbout << "sumTransactionsForGL completed" << endl;
  801.   //  ndbout << "balance="<<balance<<endl
  802.   //  << "withdrawalCount="<<withdrawalCount<<endl
  803.   //  << "withdrawalSum="<<withdrawalSum<<endl
  804.   //  << "depositCount="<<depositCount<<endl
  805.   //  << "depositSum="<<depositSum<<endl;
  806.       
  807.   NdbOperation* pOp3 = pTrans->getNdbOperation("GL");
  808.   if (pOp3 == NULL) {
  809.     ERR(pTrans->getNdbError());
  810.     return NDBT_FAILED;
  811.   }
  812.     
  813.   check = pOp3->updateTuple();
  814.   if( check == -1 ) {
  815.     ERR(pTrans->getNdbError());
  816.     return NDBT_FAILED;
  817.   }
  818.       
  819.   check = pOp3->equal("TIME", glTime);
  820.   if( check == -1 ) {
  821.     ERR(pTrans->getNdbError());
  822.     return NDBT_FAILED;
  823.   }
  824.   check = pOp3->equal("ACCOUNT_TYPE", accountTypeId);
  825.   if( check == -1 ) {
  826.     ERR(pTrans->getNdbError());
  827.     return NDBT_FAILED;
  828.   }
  829.   check = pOp3->setValue("BALANCE", balance);
  830.   if( check == -1 ) {
  831.     ERR(pTrans->getNdbError());
  832.     return NDBT_FAILED;
  833.   }
  834.   check = pOp3->setValue("DEPOSIT_COUNT", depositCount);
  835.   if( check == -1 ) {
  836.     ERR(pTrans->getNdbError());
  837.     return NDBT_FAILED;
  838.   }
  839.   check = pOp3->setValue("DEPOSIT_SUM", depositSum);
  840.   if( check == -1 ) {
  841.     ERR(pTrans->getNdbError());
  842.     return NDBT_FAILED;
  843.   }
  844.   check = pOp3->setValue("WITHDRAWAL_COUNT", withdrawalCount);
  845.   if( check == -1 ) {
  846.     ERR(pTrans->getNdbError());
  847.     return NDBT_FAILED;
  848.   }
  849.   check = pOp3->setValue("WITHDRAWAL_SUM", withdrawalSum);
  850.   if( check == -1 ) {
  851.     ERR(pTrans->getNdbError());
  852.     return NDBT_FAILED;
  853.   }
  854.   check = pOp3->setValue("PURGED", purged);
  855.   if( check == -1 ) {
  856.     ERR(pTrans->getNdbError());
  857.     return NDBT_FAILED;
  858.   }
  859.   // Execute transaction    
  860.   check = pTrans->execute(NoCommit);
  861.   if( check == -1 ) {
  862.     ERR(pTrans->getNdbError());
  863.     return NDBT_FAILED;
  864.   }    
  865.   return NDBT_OK;
  866. }
  867. int Bank::sumTransactionsForGL(const Uint64 glTime, 
  868.        const Uint32 accountType,
  869.        Uint32& balance,
  870.        Uint32& withdrawalCount,
  871.        Uint32& withdrawalSum,
  872.        Uint32& depositSum,
  873.        Uint32& depositCount,
  874.        Uint32& transactionsCount,
  875.        NdbConnection* pTrans){
  876.   int check;
  877.   //  g_info << "sumTransactionsForGL: " << glTime << ", " << accountType << endl;
  878.     
  879.   NdbConnection* pScanTrans = m_ndb.startTransaction();
  880.   if (pScanTrans == NULL) {
  881.     ERR(m_ndb.getNdbError());
  882.     return NDBT_FAILED;
  883.   }
  884.       
  885.   NdbScanOperation* pOp = pScanTrans->getNdbScanOperation("TRANSACTION");
  886.   if (pOp == NULL) {
  887.     ERR(pScanTrans->getNdbError());
  888.     m_ndb.closeTransaction(pScanTrans);
  889.     return NDBT_FAILED;
  890.   }
  891.   NdbResultSet * rs = pOp->readTuplesExclusive();
  892.   if( rs == 0 ) {
  893.     ERR(pScanTrans->getNdbError());
  894.     m_ndb.closeTransaction(pScanTrans);
  895.     return NDBT_FAILED;
  896.   }
  897.   check = pOp->interpret_exit_ok();
  898.   if( check == -1 ) {
  899.     ERR(pScanTrans->getNdbError());
  900.     m_ndb.closeTransaction(pScanTrans);
  901.     return NDBT_FAILED;
  902.   }
  903.   NdbRecAttr* accountTypeRec = pOp->getValue("ACCOUNT_TYPE");
  904.   if( accountTypeRec ==NULL ) {
  905.     ERR(pScanTrans->getNdbError());
  906.     m_ndb.closeTransaction(pScanTrans);
  907.     return NDBT_FAILED;
  908.   }
  909.   NdbRecAttr* timeRec = pOp->getValue("TIME");
  910.   if( timeRec ==NULL ) {
  911.     ERR(pScanTrans->getNdbError());
  912.     m_ndb.closeTransaction(pScanTrans);
  913.     return NDBT_FAILED;
  914.   }
  915.   NdbRecAttr* transTypeRec = pOp->getValue("TRANSACTION_TYPE");
  916.   if( transTypeRec ==NULL ) {
  917.     ERR(pScanTrans->getNdbError());
  918.     m_ndb.closeTransaction(pScanTrans);
  919.     return NDBT_FAILED;
  920.   }
  921.   NdbRecAttr* amountRec = pOp->getValue("AMOUNT");
  922.   if( amountRec ==NULL ) {
  923.     ERR(pScanTrans->getNdbError());
  924.     m_ndb.closeTransaction(pScanTrans);
  925.     return NDBT_FAILED;
  926.   }
  927.   check = pScanTrans->execute(NoCommit);
  928.   if( check == -1 ) {
  929.     ERR(pScanTrans->getNdbError());
  930.     m_ndb.closeTransaction(pScanTrans);
  931.     return NDBT_FAILED;
  932.   }
  933.     
  934.   int eof;
  935.   int rows = 0;
  936.   int rowsFound = 0;
  937.   eof = rs->nextResult();
  938.     
  939.   while(eof == 0){
  940.     rows++;
  941.     Uint32 a = accountTypeRec->u_32_value();
  942.     Uint64 t = timeRec->u_64_value();
  943.     if (a == accountType && t == glTime){
  944.       rowsFound++;
  945.       // One record found
  946.       int transType = transTypeRec->u_32_value();
  947.       int amount = amountRec->u_32_value();
  948.       if (transType == WithDrawal){
  949. withdrawalCount++;
  950. withdrawalSum += amount;
  951. balance -= amount;
  952.       } else {   
  953. assert(transType == Deposit);
  954. depositCount++;
  955. depositSum += amount;
  956. balance += amount;
  957.       }
  958.     }
  959.     eof = rs->nextResult();
  960.     if ((rows % 100) == 0){
  961.       // "refresh" ownner transaction every 100th row
  962.       if (pTrans->refresh() == -1) {
  963. ERR(pTrans->getNdbError());
  964. return NDBT_FAILED;
  965.       }
  966.     }
  967.   }
  968.   if (eof == -1) {
  969.     ERR(pScanTrans->getNdbError());
  970.     m_ndb.closeTransaction(pScanTrans);
  971.     return NDBT_FAILED;
  972.   }
  973.     
  974.   m_ndb.closeTransaction(pScanTrans);
  975.   //  ndbout << rows << " TRANSACTIONS have been read" << endl;
  976.   transactionsCount = rowsFound;
  977.   return NDBT_OK;
  978. }
  979.  int Bank::performValidateGLs(Uint64 age){
  980.   Uint64 currTime;
  981.   if (getCurrTime(currTime) != NDBT_OK){
  982.     return NDBT_FAILED;
  983.   }
  984.   Uint64 glTime = currTime - 1;
  985.   while((glTime > 0) && ((glTime + age) >= currTime)){
  986.     
  987.     int result = performValidateGL(glTime);
  988.     if (result != NDBT_OK){
  989.       g_err << "performValidateGL failed" << endl;
  990.       return result;
  991.     }
  992.     
  993.     glTime--;
  994.   }
  995.   
  996.   return NDBT_OK;
  997.  }
  998. int Bank::performValidateGL(Uint64 glTime){
  999.    
  1000.    ndbout << "performValidateGL: " << glTime << endl;
  1001.    /**
  1002.     * Rules: 
  1003.     * - There should be zero or NoAccountTypes GL records for each glTime
  1004.     * - If purged == 0, then the TRANSACTION table should be checked
  1005.     *   to see that there are:
  1006.     *   + DEPOSIT_COUNT deposit transactions with account_type == ACCOUNT_TYPE
  1007.     *     and TIME == glTime. The sum of these transactions should be 
  1008.     *     DEPOSIT_SUM
  1009.     *   + WITHDRAWAL_COUNT withdrawal transactions with account_type == 
  1010.     *     ACCOUNT_TYPE and TIME == glTime. The sum of these transactions 
  1011.     *     should be WITHDRAWAL_SUM
  1012.     *   + BALANCE should be equal to the sum of all transactions plus
  1013.     *     the balance of the previous GL record
  1014.     * - If purged == 1 then there should be NO transactions with TIME == glTime
  1015.     *   and ACCOUNT_TYPE == account_type
  1016.     *  
  1017.     */ 
  1018.    int check;  
  1019.    /**
  1020.     * SELECT * FROM GL WHERE account_type = @accountType and time = @time
  1021.     */
  1022.    NdbConnection* pScanTrans = m_ndb.startTransaction();
  1023.    if (pScanTrans == NULL) {
  1024.      ERR(m_ndb.getNdbError());
  1025.      return NDBT_FAILED;
  1026.    }
  1027.    
  1028.    NdbScanOperation* pOp = pScanTrans->getNdbScanOperation("GL");
  1029.    if (pOp == NULL) {
  1030.      ERR(pScanTrans->getNdbError());
  1031.      m_ndb.closeTransaction(pScanTrans);
  1032.      return NDBT_FAILED;
  1033.    }
  1034.    
  1035.    NdbResultSet * rs = pOp->readTuples();
  1036.    if( rs == 0 ) {
  1037.      ERR(pScanTrans->getNdbError());
  1038.      m_ndb.closeTransaction(pScanTrans);
  1039.      return NDBT_FAILED;
  1040.    }
  1041.    
  1042.    check = pOp->interpret_exit_ok();
  1043.    if( check == -1 ) {
  1044.      ERR(pScanTrans->getNdbError());
  1045.      m_ndb.closeTransaction(pScanTrans);
  1046.      return NDBT_FAILED;
  1047.    }
  1048.    
  1049.    NdbRecAttr* accountTypeRec = pOp->getValue("ACCOUNT_TYPE");
  1050.    if( accountTypeRec ==NULL ) {
  1051.      ERR(pScanTrans->getNdbError());
  1052.      m_ndb.closeTransaction(pScanTrans);
  1053.      return NDBT_FAILED;
  1054.    }
  1055.   NdbRecAttr* timeRec = pOp->getValue("TIME");
  1056.   if( timeRec ==NULL ) {
  1057.     ERR(pScanTrans->getNdbError());
  1058.     m_ndb.closeTransaction(pScanTrans);
  1059.     return NDBT_FAILED;
  1060.   }
  1061.   NdbRecAttr* purgedRec = pOp->getValue("PURGED");
  1062.   if( purgedRec ==NULL ) {
  1063.     ERR(pScanTrans->getNdbError());
  1064.     m_ndb.closeTransaction(pScanTrans);
  1065.     return NDBT_FAILED;
  1066.   }
  1067.   NdbRecAttr* balanceRec = pOp->getValue("BALANCE");
  1068.   if( balanceRec ==NULL ) {
  1069.     ERR(pScanTrans->getNdbError());
  1070.     m_ndb.closeTransaction(pScanTrans);
  1071.     return NDBT_FAILED;
  1072.   }
  1073.   NdbRecAttr* depositSumRec = pOp->getValue("DEPOSIT_SUM");
  1074.   if( depositSumRec ==NULL ) {
  1075.     ERR(pScanTrans->getNdbError());
  1076.     m_ndb.closeTransaction(pScanTrans);
  1077.     return NDBT_FAILED;
  1078.   }
  1079.   NdbRecAttr* depositCountRec = pOp->getValue("DEPOSIT_COUNT");
  1080.   if( depositCountRec ==NULL ) {
  1081.     ERR(pScanTrans->getNdbError());
  1082.     m_ndb.closeTransaction(pScanTrans);
  1083.     return NDBT_FAILED;
  1084.   }
  1085.   NdbRecAttr* withdrawalSumRec = pOp->getValue("WITHDRAWAL_SUM");
  1086.   if( withdrawalSumRec ==NULL ) {
  1087.     ERR(pScanTrans->getNdbError());
  1088.     m_ndb.closeTransaction(pScanTrans);
  1089.     return NDBT_FAILED;
  1090.   }
  1091.   NdbRecAttr* withdrawalCountRec = pOp->getValue("WITHDRAWAL_COUNT");
  1092.   if( withdrawalCountRec ==NULL ) {
  1093.     ERR(pScanTrans->getNdbError());
  1094.     m_ndb.closeTransaction(pScanTrans);
  1095.     return NDBT_FAILED;
  1096.   }
  1097.   check = pScanTrans->execute(NoCommit);
  1098.   if( check == -1 ) {
  1099.     ERR(pScanTrans->getNdbError());
  1100.     m_ndb.closeTransaction(pScanTrans);
  1101.     return NDBT_FAILED;
  1102.   }
  1103.   int eof;
  1104.   int rows = 0;
  1105.   int countGlRecords = 0;
  1106.   int result = NDBT_OK;
  1107.   eof = rs->nextResult();
  1108.     
  1109.   while(eof == 0){
  1110.     rows++;
  1111.     Uint64 t = timeRec->u_64_value();
  1112.     if (t == glTime){
  1113.       countGlRecords++;
  1114.       Uint32 a = accountTypeRec->u_32_value();
  1115.       Uint32 purged = purgedRec->u_32_value();
  1116.       Uint32 wsum = withdrawalSumRec->u_32_value();
  1117.       Uint32 wcount = withdrawalCountRec->u_32_value();
  1118.       Uint32 dsum = depositSumRec->u_32_value();
  1119.       Uint32 dcount = depositCountRec->u_32_value();
  1120.       Uint32 b = balanceRec->u_32_value();
  1121.       Uint32 balance = 0; 
  1122.       Uint32 withdrawalSum = 0;
  1123.       Uint32 withdrawalCount = 0;
  1124.       Uint32 depositSum = 0;
  1125.       Uint32 depositCount = 0;
  1126.       Uint32 countTransactions = 0;
  1127.       if (purged == 0){
  1128. // If purged == 0, then the TRANSACTION table should be checked
  1129. // to see that there are:
  1130. // + DEPOSIT_COUNT deposit transactions with account_type == ACCOUNT_TYPE
  1131. //   and TIME == glTime. The sum of these transactions should be 
  1132. //   DEPOSIT_SUM
  1133. // + WITHDRAWAL_COUNT withdrawal transactions with account_type == 
  1134. //   ACCOUNT_TYPE and TIME == glTime. The sum of these transactions 
  1135. //   should be WITHDRAWAL_SUM
  1136. // + BALANCE should be equal to the sum of all transactions plus
  1137. //   the balance of the previous GL record
  1138. if (sumTransactionsForGL(t, 
  1139.  a,
  1140.  balance,
  1141.  withdrawalCount,
  1142.  withdrawalSum,
  1143.  depositSum,
  1144.  depositCount,
  1145.  countTransactions,
  1146.  pScanTrans) != NDBT_OK){
  1147.   result = NDBT_FAILED;   
  1148. } else {
  1149.   Uint32 prevBalance = 0;
  1150.   if (getBalanceForGL(t-1, a, prevBalance) != NDBT_OK){
  1151.     result = NDBT_FAILED;
  1152.   } else
  1153.   if (((prevBalance + balance) != b) ||
  1154.       (wsum != withdrawalSum) ||
  1155.       (wcount != withdrawalCount) ||
  1156.       (dsum != depositSum) ||
  1157.       (dcount != depositCount)){
  1158.     g_err << "performValidateGL, sums and counts failed" << endl
  1159.   << "balance   :   " << balance+prevBalance << "!="<<b<<endl
  1160.   << "with sum  :   " << withdrawalSum << "!="<<wsum<<endl
  1161.   << "with count:   " << withdrawalCount << "!="<<wcount<<endl
  1162.   << "dep sum   :   " << depositSum << "!="<<dsum<<endl
  1163.   << "dep count :   " << depositCount << "!="<<dcount<<endl;
  1164.     result = VERIFICATION_FAILED;
  1165.   }
  1166.     }   
  1167.       } else {
  1168. assert(purged == 1);
  1169. // If purged == 1 then there should be NO transactions with 
  1170. // TIME == glTime and ACCOUNT_TYPE == account_type
  1171. if (sumTransactionsForGL(t, 
  1172.  a,
  1173.  balance,
  1174.  withdrawalCount,
  1175.  withdrawalSum,
  1176.  depositSum,
  1177.  depositCount,
  1178.  countTransactions,
  1179.  pScanTrans) != NDBT_OK){
  1180.   result = NDBT_FAILED;   
  1181. } else {
  1182.   if (countTransactions != 0){
  1183.     g_err << "performValidateGL, countTransactions("<<countTransactions<<") != 0" << endl;
  1184.     result = VERIFICATION_FAILED;
  1185.   }
  1186. }  
  1187.       }
  1188.     }
  1189.     eof = rs->nextResult();
  1190.   }
  1191.   if (eof == -1) {
  1192.     ERR(pScanTrans->getNdbError());
  1193.     m_ndb.closeTransaction(pScanTrans);
  1194.     return NDBT_FAILED;
  1195.   }
  1196.     
  1197.   m_ndb.closeTransaction(pScanTrans);
  1198.   // - There should be zero or NoAccountTypes GL records for each glTime
  1199.   if ((countGlRecords != 0) && (countGlRecords != getNumAccountTypes())){
  1200.     g_err << "performValidateGL: " << endl
  1201.    << "countGlRecords = " << countGlRecords << endl;
  1202.     result = VERIFICATION_FAILED;
  1203.   }
  1204.   return result;
  1205.    
  1206.  }
  1207. int Bank::getBalanceForGL(const Uint64 glTime,
  1208.   const Uint32 accountTypeId,
  1209.   Uint32 &balance){
  1210.   int check;
  1211.   NdbConnection* pTrans = m_ndb.startTransaction();
  1212.   if (pTrans == NULL) {
  1213.     ERR(m_ndb.getNdbError());
  1214.     return NDBT_FAILED;
  1215.   }
  1216.   
  1217.   NdbOperation* pOp = pTrans->getNdbOperation("GL");
  1218.   if (pOp == NULL) {
  1219.     ERR(pTrans->getNdbError());
  1220.     return NDBT_FAILED;
  1221.   }
  1222.     
  1223.   check = pOp->readTuple();
  1224.   if( check == -1 ) {
  1225.     ERR(pTrans->getNdbError());
  1226.     return NDBT_FAILED;
  1227.   }
  1228.       
  1229.   check = pOp->equal("TIME", glTime);
  1230.   if( check == -1 ) {
  1231.     ERR(pTrans->getNdbError());
  1232.     return NDBT_FAILED;
  1233.   }
  1234.   check = pOp->equal("ACCOUNT_TYPE", accountTypeId);
  1235.   if( check == -1 ) {
  1236.     ERR(pTrans->getNdbError());
  1237.     return NDBT_FAILED;
  1238.   }
  1239.   NdbRecAttr* balanceRec = pOp->getValue("BALANCE");
  1240.   if( balanceRec == NULL ) {
  1241.     ERR(pTrans->getNdbError());
  1242.     return NDBT_FAILED;
  1243.   }
  1244.   check = pTrans->execute(Commit);
  1245.   if( check == -1 ) {
  1246.     ERR(pTrans->getNdbError());
  1247.     return NDBT_FAILED;
  1248.   } 
  1249.   m_ndb.closeTransaction(pTrans);
  1250.   balance = balanceRec->u_32_value();
  1251.   return NDBT_OK;
  1252. }
  1253. int Bank::getOldestPurgedGL(const Uint32 accountType,
  1254.     Uint64 &oldest){
  1255.   int check;  
  1256.   /**
  1257.    * SELECT MAX(time) FROM GL WHERE account_type = @accountType and purged=1
  1258.    */
  1259.   NdbConnection* pScanTrans = m_ndb.startTransaction();
  1260.   if (pScanTrans == NULL) {
  1261.     ERR(m_ndb.getNdbError());
  1262.     return NDBT_FAILED;
  1263.   }
  1264.       
  1265.   NdbScanOperation* pOp = pScanTrans->getNdbScanOperation("GL");
  1266.   if (pOp == NULL) {
  1267.     ERR(pScanTrans->getNdbError());
  1268.     m_ndb.closeTransaction(pScanTrans);
  1269.     return NDBT_FAILED;
  1270.   }
  1271.   NdbResultSet * rs = pOp->readTuples();
  1272.   if( rs == 0 ) {
  1273.     ERR(pScanTrans->getNdbError());
  1274.     m_ndb.closeTransaction(pScanTrans);
  1275.     return NDBT_FAILED;
  1276.   }
  1277.   check = pOp->interpret_exit_ok();
  1278.   if( check == -1 ) {
  1279.     ERR(pScanTrans->getNdbError());
  1280.     m_ndb.closeTransaction(pScanTrans);
  1281.     return NDBT_FAILED;
  1282.   }
  1283.   NdbRecAttr* accountTypeRec = pOp->getValue("ACCOUNT_TYPE");
  1284.   if( accountTypeRec ==NULL ) {
  1285.     ERR(pScanTrans->getNdbError());
  1286.     m_ndb.closeTransaction(pScanTrans);
  1287.     return NDBT_FAILED;
  1288.   }
  1289.   NdbRecAttr* timeRec = pOp->getValue("TIME");
  1290.   if( timeRec ==NULL ) {
  1291.     ERR(pScanTrans->getNdbError());
  1292.     m_ndb.closeTransaction(pScanTrans);
  1293.     return NDBT_FAILED;
  1294.   }
  1295.   NdbRecAttr* purgedRec = pOp->getValue("PURGED");
  1296.   if( purgedRec ==NULL ) {
  1297.     ERR(pScanTrans->getNdbError());
  1298.     m_ndb.closeTransaction(pScanTrans);
  1299.     return NDBT_FAILED;
  1300.   }
  1301.   check = pScanTrans->execute(NoCommit);
  1302.   if( check == -1 ) {
  1303.     ERR(pScanTrans->getNdbError());
  1304.     m_ndb.closeTransaction(pScanTrans);
  1305.     return NDBT_FAILED;
  1306.   }
  1307.     
  1308.   int eof;
  1309.   int rows = 0;
  1310.   eof = rs->nextResult();
  1311.   oldest = 0;
  1312.     
  1313.   while(eof == 0){
  1314.     rows++;
  1315.     Uint32 a = accountTypeRec->u_32_value();
  1316.     Uint32 p = purgedRec->u_32_value();
  1317.     if (a == accountType && p == 1){
  1318.       // One record found
  1319.       Uint64 t = timeRec->u_64_value();
  1320.       if (t > oldest)
  1321. oldest = t;
  1322.     }
  1323.     eof = rs->nextResult();
  1324.   }
  1325.   if (eof == -1) {
  1326.     ERR(pScanTrans->getNdbError());
  1327.     m_ndb.closeTransaction(pScanTrans);
  1328.     return NDBT_FAILED;
  1329.   }
  1330.     
  1331.   m_ndb.closeTransaction(pScanTrans);
  1332.   
  1333.   return NDBT_OK;
  1334. }
  1335. int Bank::getOldestNotPurgedGL(Uint64 &oldest,
  1336.        Uint32 &accountTypeId,
  1337.        bool &found){
  1338.   int check;  
  1339.   /**
  1340.    * SELECT time, accountTypeId FROM GL 
  1341.    * WHERE purged=0 order by time asc
  1342.    */
  1343.   NdbConnection* pScanTrans = m_ndb.startTransaction();
  1344.   if (pScanTrans == NULL) {
  1345.     ERR(m_ndb.getNdbError());
  1346.     return NDBT_FAILED;
  1347.   }
  1348.       
  1349.   NdbScanOperation* pOp = pScanTrans->getNdbScanOperation("GL");
  1350.   if (pOp == NULL) {
  1351.     ERR(pScanTrans->getNdbError());
  1352.     m_ndb.closeTransaction(pScanTrans);
  1353.     return NDBT_FAILED;
  1354.   }
  1355.   NdbResultSet * rs = pOp->readTuples();
  1356.   if( rs == 0 ) {
  1357.     ERR(pScanTrans->getNdbError());
  1358.     m_ndb.closeTransaction(pScanTrans);
  1359.     return NDBT_FAILED;
  1360.   }
  1361.   check = pOp->interpret_exit_ok();
  1362.   if( check == -1 ) {
  1363.     ERR(pScanTrans->getNdbError());
  1364.     m_ndb.closeTransaction(pScanTrans);
  1365.     return NDBT_FAILED;
  1366.   }
  1367.   NdbRecAttr* accountTypeRec = pOp->getValue("ACCOUNT_TYPE");
  1368.   if( accountTypeRec ==NULL ) {
  1369.     ERR(pScanTrans->getNdbError());
  1370.     m_ndb.closeTransaction(pScanTrans);
  1371.     return NDBT_FAILED;
  1372.   }
  1373.   NdbRecAttr* timeRec = pOp->getValue("TIME");
  1374.   if( timeRec ==NULL ) {
  1375.     ERR(pScanTrans->getNdbError());
  1376.     m_ndb.closeTransaction(pScanTrans);
  1377.     return NDBT_FAILED;
  1378.   }
  1379.   NdbRecAttr* purgedRec = pOp->getValue("PURGED");
  1380.   if( purgedRec ==NULL ) {
  1381.     ERR(pScanTrans->getNdbError());
  1382.     m_ndb.closeTransaction(pScanTrans);
  1383.     return NDBT_FAILED;
  1384.   }
  1385.   check = pScanTrans->execute(NoCommit);
  1386.   if( check == -1 ) {
  1387.     ERR(pScanTrans->getNdbError());
  1388.     m_ndb.closeTransaction(pScanTrans);
  1389.     return NDBT_FAILED;
  1390.   }
  1391.     
  1392.   int eof;
  1393.   int rows = 0;
  1394.   eof = rs->nextResult();
  1395.   oldest = (Uint64)-1;
  1396.   found = false;
  1397.     
  1398.   while(eof == 0){
  1399.     rows++;
  1400.     Uint32 p = purgedRec->u_32_value();
  1401.     if (p == 0){
  1402.       found = true;
  1403.       // One record found
  1404.       Uint32 a = accountTypeRec->u_32_value();      
  1405.       Uint64 t = timeRec->u_64_value();
  1406.       if (t < oldest){
  1407. oldest = t;
  1408. accountTypeId = a;
  1409.       }
  1410.     }
  1411.     eof = rs->nextResult();
  1412.   }
  1413.   if (eof == -1) {
  1414.     ERR(pScanTrans->getNdbError());
  1415.     m_ndb.closeTransaction(pScanTrans);
  1416.     return NDBT_FAILED;
  1417.   }
  1418.     
  1419.   m_ndb.closeTransaction(pScanTrans);
  1420.   return NDBT_OK;
  1421. }
  1422. int Bank::checkNoTransactionsOlderThan(const Uint32 accountType,
  1423.        const Uint64 oldest){
  1424.   /**
  1425.    * SELECT COUNT(transaction_id) FROM TRANSACTION 
  1426.    * WHERE account_type = @accountType and time <= @oldest
  1427.    *
  1428.    */
  1429.   int check;  
  1430.   NdbConnection* pScanTrans = m_ndb.startTransaction();
  1431.   if (pScanTrans == NULL) {
  1432.     ERR(m_ndb.getNdbError());
  1433.     return NDBT_FAILED;
  1434.   }
  1435.       
  1436.   NdbScanOperation* pOp = pScanTrans->getNdbScanOperation("TRANSACTION");
  1437.   if (pOp == NULL) {
  1438.     ERR(pScanTrans->getNdbError());
  1439.     m_ndb.closeTransaction(pScanTrans);
  1440.     return NDBT_FAILED;
  1441.   }
  1442.   NdbResultSet * rs = pOp->readTuples();
  1443.   if( rs == 0 ) {
  1444.     ERR(pScanTrans->getNdbError());
  1445.     m_ndb.closeTransaction(pScanTrans);
  1446.     return NDBT_FAILED;
  1447.   }
  1448.   check = pOp->interpret_exit_ok();
  1449.   if( check == -1 ) {
  1450.     ERR(pScanTrans->getNdbError());
  1451.     m_ndb.closeTransaction(pScanTrans);
  1452.     return NDBT_FAILED;
  1453.   }
  1454.   NdbRecAttr* accountTypeRec = pOp->getValue("ACCOUNT_TYPE");
  1455.   if( accountTypeRec ==NULL ) {
  1456.     ERR(pScanTrans->getNdbError());
  1457.     m_ndb.closeTransaction(pScanTrans);
  1458.     return NDBT_FAILED;
  1459.   }
  1460.   NdbRecAttr* timeRec = pOp->getValue("TIME");
  1461.   if( timeRec ==NULL ) {
  1462.     ERR(pScanTrans->getNdbError());
  1463.     m_ndb.closeTransaction(pScanTrans);
  1464.     return NDBT_FAILED;
  1465.   }
  1466.   NdbRecAttr* transactionIdRec = pOp->getValue("TRANSACTION_ID");
  1467.   if( transactionIdRec ==NULL ) {
  1468.     ERR(pScanTrans->getNdbError());
  1469.     m_ndb.closeTransaction(pScanTrans);
  1470.     return NDBT_FAILED;
  1471.   }
  1472.   check = pScanTrans->execute(NoCommit);   
  1473.   if( check == -1 ) {
  1474.     ERR(pScanTrans->getNdbError());
  1475.     m_ndb.closeTransaction(pScanTrans);
  1476.     return NDBT_FAILED;
  1477.   }
  1478.     
  1479.   int eof;
  1480.   int rows = 0;
  1481.   int found = 0;
  1482.   eof = rs->nextResult();
  1483.     
  1484.   while(eof == 0){
  1485.     rows++;
  1486.     Uint32 a = accountTypeRec->u_32_value();
  1487.     Uint32 t = timeRec->u_32_value();
  1488.     if (a == accountType && t <= oldest){
  1489.       // One record found
  1490.       Uint64 ti = transactionIdRec->u_64_value();
  1491.       g_err << "checkNoTransactionsOlderThan found one record" << endl
  1492.     << "  t = " << t << endl
  1493.     << "  a = " << a << endl
  1494.     << "  ti = " << ti << endl;
  1495.       found++;
  1496.     }
  1497.     eof = rs->nextResult();
  1498.   }
  1499.   if (eof == -1) {
  1500.     ERR(pScanTrans->getNdbError());
  1501.     m_ndb.closeTransaction(pScanTrans);
  1502.     return NDBT_FAILED;
  1503.   }
  1504.     
  1505.   m_ndb.closeTransaction(pScanTrans);
  1506.   
  1507.   if (found == 0)
  1508.     return NDBT_OK;
  1509.   else
  1510.     return VERIFICATION_FAILED;
  1511. }
  1512.  int Bank::performValidatePurged(){
  1513.    /**
  1514.     * Make sure there are no TRANSACTIONS older than the oldest 
  1515.     * purged GL record
  1516.     * 
  1517.     */
  1518.    for (int i = 0; i < getNumAccountTypes(); i++){
  1519.      ndbout << "performValidatePurged: " << i << endl;
  1520.      Uint64 oldestGlTime; 
  1521.      if (getOldestPurgedGL(i, oldestGlTime) != NDBT_OK){
  1522.        g_err << "getOldestPurgedGL failed" << endl;
  1523.        return NDBT_FAILED;    
  1524.      }
  1525.      int result = checkNoTransactionsOlderThan(i, oldestGlTime);
  1526.      if (result != NDBT_OK){
  1527.        g_err << "checkNoTransactionsOlderThan failed" << endl;
  1528.        return result;
  1529.      }
  1530.      
  1531.    }
  1532.    
  1533.    return NDBT_OK;
  1534.  }
  1535.  int Bank::purgeOldGLTransactions(Uint64 currTime, Uint32 age){
  1536.    /** 
  1537.     * For each GL record that are older than age and have purged == 0
  1538.     *  - delete all TRANSACTIONS belonging to the GL and set purged = 1
  1539.     *
  1540.     * 
  1541.     */
  1542.    bool found;
  1543.    int count = 0;
  1544.    while(1){
  1545.      count++;
  1546.      if (count > 100)
  1547.        return NDBT_OK;
  1548.      
  1549.      // Search for the oldest GL record with purged == 0
  1550.      Uint64 oldestGlTime;
  1551.      Uint32 accountTypeId;
  1552.      if (getOldestNotPurgedGL(oldestGlTime, accountTypeId, found) != NDBT_OK){
  1553.        g_err << "getOldestNotPurgedGL failed" << endl;
  1554.        return NDBT_FAILED;
  1555.      }
  1556.      if (found == false){
  1557.        // ndbout << "not found" << endl;
  1558.        return NDBT_OK;
  1559.      }
  1560.      
  1561. //      ndbout << "purgeOldGLTransactions" << endl
  1562. //           << "  oldestGlTime = " << oldestGlTime << endl
  1563. //           << "  currTime = " << currTime << endl
  1564. //      << "  age = " << age << endl;
  1565.      // Check if this GL is old enough to be purged
  1566.      if ((currTime < age) || (oldestGlTime > (currTime-age))){
  1567.        //       ndbout << "is not old enough" << endl;
  1568.        return NDBT_OK;
  1569.      }
  1570.      if (purgeTransactions(oldestGlTime, accountTypeId) != NDBT_OK){
  1571.        g_err << "purgeTransactions failed" << endl;
  1572.        return NDBT_FAILED;
  1573.      }
  1574.    }
  1575.    g_err << "abnormal return" << endl; 
  1576.    return NDBT_FAILED;
  1577.  }
  1578.  
  1579. int Bank::purgeTransactions(const Uint64 glTime, 
  1580.     const Uint32 accountTypeId)
  1581. {
  1582.   int check;
  1583.   g_info << "purgeTransactions: " << glTime << ", "<<accountTypeId<<endl;
  1584.   NdbConnection* pTrans = m_ndb.startTransaction();
  1585.   if (pTrans == NULL){
  1586.     ERR(m_ndb.getNdbError());
  1587.     return NDBT_FAILED;
  1588.   }
  1589.   // Start by updating the GL record with purged = 1, use NoCommit
  1590.   NdbOperation* pOp = pTrans->getNdbOperation("GL");
  1591.   if (pOp == NULL) {
  1592.     ERR(pTrans->getNdbError());
  1593.     return NDBT_FAILED;
  1594.   }
  1595.     
  1596.   check = pOp->updateTuple();
  1597.   if( check == -1 ) {
  1598.     ERR(pTrans->getNdbError());
  1599.     return NDBT_FAILED;
  1600.   }
  1601.       
  1602.   check = pOp->equal("TIME", glTime);
  1603.   if( check == -1 ) {
  1604.     ERR(pTrans->getNdbError());
  1605.     return NDBT_FAILED;
  1606.   }
  1607.   check = pOp->equal("ACCOUNT_TYPE", accountTypeId);
  1608.   if( check == -1 ) {
  1609.     ERR(pTrans->getNdbError());
  1610.     return NDBT_FAILED;
  1611.   }
  1612.   Uint32 purged = 1;
  1613.   check = pOp->setValue("PURGED", purged);
  1614.   if( check == -1 ) {
  1615.     ERR(pTrans->getNdbError());
  1616.     return NDBT_FAILED;
  1617.   }
  1618.   // Execute transaction    
  1619.   check = pTrans->execute(NoCommit);
  1620.   if( check == -1 ) {
  1621.     ERR(pTrans->getNdbError());
  1622.     return NDBT_FAILED;
  1623.   }    
  1624.   // Find all transactions and take over them for delete
  1625.   if(findTransactionsToPurge(glTime,
  1626.     accountTypeId,
  1627.     pTrans) != NDBT_OK){
  1628.     g_err << "findTransactionToPurge failed" << endl;
  1629.     m_ndb.closeTransaction(pTrans);
  1630.     return NDBT_FAILED;
  1631.   }
  1632.   check = pTrans->execute(Commit);
  1633.   if( check == -1 ) {
  1634.     ERR(pTrans->getNdbError());
  1635.     return NDBT_FAILED;
  1636.   } 
  1637.   m_ndb.closeTransaction(pTrans);
  1638.   return NDBT_OK;
  1639. }
  1640. int Bank::findTransactionsToPurge(const Uint64 glTime, 
  1641.   const Uint32 accountType,
  1642.   NdbConnection* pTrans){
  1643.   int check;
  1644.   
  1645.   NdbConnection* pScanTrans = m_ndb.startTransaction();
  1646.   if (pScanTrans == NULL) {
  1647.     ERR(m_ndb.getNdbError());
  1648.     return NDBT_FAILED;
  1649.   }
  1650.       
  1651.   NdbScanOperation* pOp = pScanTrans->getNdbScanOperation("TRANSACTION");
  1652.   if (pOp == NULL) {
  1653.     ERR(pScanTrans->getNdbError());
  1654.     m_ndb.closeTransaction(pScanTrans);
  1655.     return NDBT_FAILED;
  1656.   }
  1657.   NdbResultSet * rs = pOp->readTuplesExclusive();
  1658.   if( rs == 0 ) {
  1659.     ERR(pScanTrans->getNdbError());
  1660.     m_ndb.closeTransaction(pScanTrans);
  1661.     return NDBT_FAILED;
  1662.   }
  1663.   check = pOp->interpret_exit_ok();
  1664.   if( check == -1 ) {
  1665.     ERR(pScanTrans->getNdbError());
  1666.     m_ndb.closeTransaction(pScanTrans);
  1667.     return NDBT_FAILED;
  1668.   }
  1669.   NdbRecAttr* timeRec = pOp->getValue("TIME");
  1670.   if( timeRec ==NULL ) {
  1671.     ERR(pScanTrans->getNdbError());
  1672.     m_ndb.closeTransaction(pScanTrans);
  1673.     return NDBT_FAILED;
  1674.   }
  1675.   NdbRecAttr* accountTypeRec = pOp->getValue("ACCOUNT_TYPE");
  1676.   if( accountTypeRec ==NULL ) {
  1677.     ERR(pScanTrans->getNdbError());
  1678.     m_ndb.closeTransaction(pScanTrans);
  1679.     return NDBT_FAILED;
  1680.   }
  1681.   check = pScanTrans->execute(NoCommit);   
  1682.   if( check == -1 ) {
  1683.     ERR(pScanTrans->getNdbError());
  1684.     m_ndb.closeTransaction(pScanTrans);
  1685.     return NDBT_FAILED;
  1686.   }
  1687.     
  1688.   int eof;
  1689.   int rows = 0;
  1690.   int rowsFound = 0;
  1691.   eof = rs->nextResult();
  1692.     
  1693.   while(eof == 0){
  1694.     rows++;
  1695.     Uint64 t = timeRec->u_64_value();
  1696.     Uint32 a = accountTypeRec->u_32_value();
  1697.     if (a == accountType && t == glTime){
  1698.       rowsFound++;
  1699.       // One record found
  1700.       check = rs->deleteTuple(pTrans);
  1701.       if (check == -1){
  1702. ERR(m_ndb.getNdbError());
  1703. m_ndb.closeTransaction(pScanTrans);
  1704. return NDBT_FAILED;
  1705.       }
  1706.       
  1707.       // Execute transaction    
  1708.       check = pTrans->execute(NoCommit);
  1709.       if( check == -1 ) {
  1710. ERR(pTrans->getNdbError());
  1711. m_ndb.closeTransaction(pScanTrans);
  1712. return NDBT_FAILED;
  1713.       }       
  1714.     }
  1715.     eof = rs->nextResult();
  1716.   }
  1717.   if (eof == -1) {
  1718.     ERR(pScanTrans->getNdbError());
  1719.     m_ndb.closeTransaction(pScanTrans);
  1720.     return NDBT_FAILED;
  1721.   }
  1722.     
  1723.   m_ndb.closeTransaction(pScanTrans);
  1724.   //  ndbout << rowsFound << " TRANSACTIONS have been deleted" << endl;
  1725.   return NDBT_OK;
  1726. }
  1727.  
  1728.  
  1729. int Bank::performIncreaseTime(int maxSleepBetweenDays, int yield)
  1730. {
  1731.   int yieldCounter = 0;
  1732.   
  1733.   while(1){
  1734.     
  1735.     Uint64 currTime;
  1736.     if (incCurrTime(currTime) != NDBT_OK)
  1737.       break;
  1738.     
  1739.     g_info << "Current time is " << currTime << endl;
  1740.     if (maxSleepBetweenDays > 0){
  1741.       int val = myRandom48(maxSleepBetweenDays);
  1742.       NdbSleep_SecSleep(val);
  1743.     }
  1744.     
  1745.     yieldCounter++;
  1746.     if (yield != 0 && yieldCounter >= yield)
  1747.       return NDBT_OK;
  1748.     
  1749.   }
  1750.   return NDBT_FAILED;
  1751. }
  1752. int Bank::readSystemValue(SystemValueId sysValId, Uint64 & value){
  1753.   int check;
  1754.     
  1755.   NdbConnection* pTrans = m_ndb.startTransaction();
  1756.   if (pTrans == NULL){
  1757.     ERR(m_ndb.getNdbError());
  1758.     if(m_ndb.getNdbError().status == NdbError::TemporaryError)
  1759.       return NDBT_TEMPORARY;
  1760.     return NDBT_FAILED;
  1761.   }
  1762.   int result;
  1763.   if ((result= prepareReadSystemValueOp(pTrans, sysValId, value)) != NDBT_OK) {
  1764.     ERR(pTrans->getNdbError());
  1765.     m_ndb.closeTransaction(pTrans);
  1766.     return result;
  1767.   }
  1768.   check = pTrans->execute(Commit);
  1769.   if( check == -1 ) {
  1770.     ERR(pTrans->getNdbError());
  1771.     if(pTrans->getNdbError().status == NdbError::TemporaryError)
  1772.     {
  1773.       m_ndb.closeTransaction(pTrans);
  1774.       return NDBT_TEMPORARY;
  1775.     }
  1776.     m_ndb.closeTransaction(pTrans);
  1777.     return NDBT_FAILED;
  1778.   }
  1779.   
  1780.   m_ndb.closeTransaction(pTrans);      
  1781.   return NDBT_OK;
  1782. }
  1783. int Bank::prepareReadSystemValueOp(NdbConnection* pTrans, SystemValueId sysValId, Uint64 & value){
  1784.   int check;
  1785.     
  1786.   NdbOperation* pOp = pTrans->getNdbOperation("SYSTEM_VALUES");
  1787.   if (pOp == NULL) {
  1788.     return NDBT_FAILED;
  1789.   }
  1790.     
  1791.   check = pOp->readTuple();
  1792.   if( check == -1 ) {
  1793.     return NDBT_FAILED;
  1794.   }
  1795.     
  1796.   check = pOp->equal("SYSTEM_VALUES_ID", sysValId);
  1797.   if( check == -1 ) {
  1798.     return NDBT_FAILED;
  1799.   }
  1800.     
  1801.   NdbRecAttr* valueRec = pOp->getValue("VALUE", (char *)&value);
  1802.   if( valueRec == NULL ) {
  1803.     return NDBT_FAILED;
  1804.   }
  1805.     
  1806.   return NDBT_OK;
  1807. }
  1808. int Bank::writeSystemValue(SystemValueId sysValId, Uint64 value){
  1809.   int check;
  1810.     
  1811.   NdbConnection* pTrans = m_ndb.startTransaction();
  1812.   if (pTrans == NULL){
  1813.     ERR(m_ndb.getNdbError());
  1814.     return NDBT_FAILED;
  1815.   }
  1816.     
  1817.   NdbOperation* pOp = pTrans->getNdbOperation("SYSTEM_VALUES");
  1818.   if (pOp == NULL) {
  1819.     ERR(pTrans->getNdbError());
  1820.     m_ndb.closeTransaction(pTrans);
  1821.     return NDBT_FAILED;
  1822.   }
  1823.     
  1824.   check = pOp->insertTuple();
  1825.   if( check == -1 ) {
  1826.     ERR(pTrans->getNdbError());
  1827.     m_ndb.closeTransaction(pTrans);
  1828.     return NDBT_FAILED;
  1829.   }
  1830.       
  1831.   check = pOp->equal("SYSTEM_VALUES_ID", sysValId);
  1832.   if( check == -1 ) {
  1833.     ERR(pTrans->getNdbError());
  1834.     m_ndb.closeTransaction(pTrans);
  1835.     return NDBT_FAILED;
  1836.   }
  1837.   check = pOp->setValue("VALUE", value);
  1838.   if( check == -1 ) {
  1839.     ERR(pTrans->getNdbError());
  1840.     m_ndb.closeTransaction(pTrans);
  1841.     return NDBT_FAILED;
  1842.   }
  1843.   check = pTrans->execute(Commit);
  1844.   if( check == -1 ) {
  1845.     ERR(pTrans->getNdbError());
  1846.     m_ndb.closeTransaction(pTrans);
  1847.     return NDBT_FAILED;
  1848.   }
  1849.     
  1850.   m_ndb.closeTransaction(pTrans);      
  1851.   return NDBT_OK;
  1852. }
  1853. int Bank::getNextTransactionId(Uint64 &value){
  1854.   return increaseSystemValue2(LastTransactionId, value);
  1855. }
  1856. int Bank::incCurrTime(Uint64 &value){
  1857.   return increaseSystemValue(CurrentTime, value);
  1858. }
  1859.   
  1860. int Bank::increaseSystemValue(SystemValueId sysValId, Uint64 &value){
  1861.   /**
  1862.    * Increase value with one and return
  1863.    * updated value
  1864.    *
  1865.    */
  1866.   DBUG_ENTER("Bank::increaseSystemValue");
  1867.   int check;
  1868.     
  1869.   NdbConnection* pTrans = m_ndb.startTransaction();
  1870.   if (pTrans == NULL){
  1871.     ERR(m_ndb.getNdbError());
  1872.     if (m_ndb.getNdbError().status == NdbError::TemporaryError)
  1873.       DBUG_RETURN(NDBT_TEMPORARY);
  1874.     DBUG_RETURN(NDBT_FAILED);
  1875.   }
  1876.     
  1877.   NdbOperation* pOp = pTrans->getNdbOperation("SYSTEM_VALUES");
  1878.   if (pOp == NULL) {
  1879.     ERR(pTrans->getNdbError());
  1880.     m_ndb.closeTransaction(pTrans);
  1881.     DBUG_RETURN(NDBT_FAILED);
  1882.   }
  1883.     
  1884.   check = pOp->readTupleExclusive();
  1885.   //  check = pOp->readTuple();
  1886.   if( check == -1 ) {
  1887.     ERR(pTrans->getNdbError());
  1888.     m_ndb.closeTransaction(pTrans);
  1889.     DBUG_RETURN(NDBT_FAILED);
  1890.   }
  1891.     
  1892.   check = pOp->equal("SYSTEM_VALUES_ID", sysValId);
  1893.   if( check == -1 ) {
  1894.     ERR(pTrans->getNdbError());
  1895.     m_ndb.closeTransaction(pTrans);
  1896.     DBUG_RETURN(NDBT_FAILED);
  1897.   }
  1898.     
  1899.   NdbRecAttr* valueRec = pOp->getValue("VALUE");
  1900.   if( valueRec ==NULL ) {
  1901.     ERR(pTrans->getNdbError());
  1902.     m_ndb.closeTransaction(pTrans);
  1903.     DBUG_RETURN(NDBT_FAILED);
  1904.   }
  1905.     
  1906.   check = pTrans->execute(NoCommit);
  1907.   if( check == -1 ) {
  1908.     ERR(pTrans->getNdbError());
  1909.     if (pTrans->getNdbError().status == NdbError::TemporaryError)
  1910.     {
  1911.       m_ndb.closeTransaction(pTrans);
  1912.       DBUG_RETURN(NDBT_TEMPORARY);
  1913.     }
  1914.     m_ndb.closeTransaction(pTrans);
  1915.     DBUG_RETURN(NDBT_FAILED);
  1916.   }
  1917.     
  1918.   value = valueRec->u_64_value();
  1919.   value++;
  1920.     
  1921.   NdbOperation* pOp2 = pTrans->getNdbOperation("SYSTEM_VALUES");
  1922.   if (pOp2 == NULL) {
  1923.     ERR(pTrans->getNdbError());
  1924.     m_ndb.closeTransaction(pTrans);
  1925.     DBUG_RETURN(NDBT_FAILED);
  1926.   }
  1927.     
  1928.   check = pOp2->updateTuple();
  1929.   if( check == -1 ) {
  1930.     ERR(pTrans->getNdbError());
  1931.     m_ndb.closeTransaction(pTrans);
  1932.     DBUG_RETURN(NDBT_FAILED);
  1933.   }
  1934.     
  1935.   check = pOp2->equal("SYSTEM_VALUES_ID", sysValId);
  1936.   if( check == -1 ) {
  1937.     ERR(pTrans->getNdbError());
  1938.     m_ndb.closeTransaction(pTrans);
  1939.     DBUG_RETURN(NDBT_FAILED);
  1940.   }
  1941.     
  1942.   check = pOp2->setValue("VALUE", value);
  1943.   if( check == -1 ) {
  1944.     ERR(pTrans->getNdbError());
  1945.     m_ndb.closeTransaction(pTrans);
  1946.     DBUG_RETURN(NDBT_FAILED);
  1947.   }
  1948.   check = pTrans->execute(NoCommit);
  1949.   if( check == -1 ) {
  1950.     ERR(pTrans->getNdbError());
  1951.     m_ndb.closeTransaction(pTrans);
  1952.     DBUG_RETURN(NDBT_FAILED);
  1953.   }
  1954.   NdbOperation* pOp3 = pTrans->getNdbOperation("SYSTEM_VALUES");
  1955.   if (pOp3 == NULL) {
  1956.     ERR(pTrans->getNdbError());
  1957.     m_ndb.closeTransaction(pTrans);
  1958.     DBUG_RETURN(NDBT_FAILED);
  1959.   }
  1960.   check = pOp3->readTuple();
  1961.   if( check == -1 ) {
  1962.     ERR(pTrans->getNdbError());
  1963.     m_ndb.closeTransaction(pTrans);
  1964.     DBUG_RETURN(NDBT_FAILED);
  1965.   }
  1966.     
  1967.   check = pOp3->equal("SYSTEM_VALUES_ID", sysValId);
  1968.   if( check == -1 ) {
  1969.     ERR(pTrans->getNdbError());
  1970.     m_ndb.closeTransaction(pTrans);
  1971.     DBUG_RETURN(NDBT_FAILED);
  1972.   }
  1973.   // Read new value
  1974.   NdbRecAttr* valueNewRec = pOp3->getValue("VALUE");
  1975.   if( valueNewRec ==NULL ) {
  1976.     ERR(pTrans->getNdbError());
  1977.     m_ndb.closeTransaction(pTrans);
  1978.     DBUG_RETURN(NDBT_FAILED);
  1979.   }
  1980.   check = pTrans->execute(Commit);
  1981.   if( check == -1 ) {
  1982.     ERR(pTrans->getNdbError());
  1983.     if (pTrans->getNdbError().status == NdbError::TemporaryError)
  1984.     {
  1985.       m_ndb.closeTransaction(pTrans);
  1986.       DBUG_RETURN(NDBT_TEMPORARY);
  1987.     }
  1988.     m_ndb.closeTransaction(pTrans);
  1989.     DBUG_RETURN(NDBT_FAILED);
  1990.   }
  1991.   // Check that value updated equals the value we read after the update
  1992.   if (valueNewRec->u_64_value() != value){
  1993.     
  1994.     printf("value actual=%lldn", valueNewRec->u_64_value());
  1995.     printf("value expected=%lld actual=%lldn", value, valueNewRec->u_64_value());
  1996.     
  1997.     DBUG_PRINT("info", ("value expected=%ld actual=%ld", value, valueNewRec->u_64_value()));
  1998.     g_err << "getNextTransactionId: value was not updated" << endl;
  1999.     m_ndb.closeTransaction(pTrans);
  2000.     DBUG_RETURN(NDBT_FAILED);
  2001.   }
  2002.   m_ndb.closeTransaction(pTrans);
  2003.   
  2004.   DBUG_RETURN(0);
  2005. }
  2006. int Bank::increaseSystemValue2(SystemValueId sysValId, Uint64 &value){
  2007.   /**
  2008.    * Increase value with one and return
  2009.    * updated value
  2010.    * A more optimized version using interpreted update!
  2011.    *
  2012.    */
  2013.   int check;
  2014.     
  2015.   NdbConnection* pTrans = m_ndb.startTransaction();
  2016.   if (pTrans == NULL){
  2017.     ERR(m_ndb.getNdbError());
  2018.     if(m_ndb.getNdbError().status == NdbError::TemporaryError)
  2019.       return NDBT_TEMPORARY;
  2020.     return NDBT_FAILED;
  2021.   }
  2022.     
  2023.   NdbOperation* pOp = pTrans->getNdbOperation("SYSTEM_VALUES");
  2024.   if (pOp == NULL) {
  2025.     ERR(pTrans->getNdbError());
  2026.     m_ndb.closeTransaction(pTrans);
  2027.     return NDBT_FAILED;
  2028.   }
  2029.   check = pOp->interpretedUpdateTuple();
  2030.   if( check == -1 ) {
  2031.     ERR(pTrans->getNdbError());
  2032.     m_ndb.closeTransaction(pTrans);
  2033.     return NDBT_FAILED;
  2034.   }
  2035.   check = pOp->equal("SYSTEM_VALUES_ID", sysValId );
  2036.   if( check == -1 ) {
  2037.     ERR(pTrans->getNdbError());
  2038.     m_ndb.closeTransaction(pTrans);
  2039.     return NDBT_FAILED;
  2040.   }
  2041.   Uint32 valToIncWith = 1;
  2042.   check = pOp->incValue("VALUE", valToIncWith);
  2043.   if( check == -1 ) {
  2044.     ERR(pTrans->getNdbError());
  2045.     m_ndb.closeTransaction(pTrans);
  2046.     return NDBT_FAILED;
  2047.   }
  2048.   NdbRecAttr* valueRec = pOp->getValue("VALUE");
  2049.   if( valueRec == NULL ) {
  2050.     ERR(pTrans->getNdbError());
  2051.     m_ndb.closeTransaction(pTrans);
  2052.     return NDBT_FAILED;
  2053.   }
  2054.   
  2055.   check = pTrans->execute(Commit);
  2056.   if( check == -1 ) {
  2057.     ERR(pTrans->getNdbError());
  2058.     if(pTrans->getNdbError().status == NdbError::TemporaryError)
  2059.     {
  2060.       m_ndb.closeTransaction(pTrans);
  2061.       return NDBT_TEMPORARY;
  2062.     }
  2063.     m_ndb.closeTransaction(pTrans);
  2064.     return NDBT_FAILED;
  2065.   }
  2066.   value = valueRec->u_64_value();
  2067.     
  2068.   m_ndb.closeTransaction(pTrans);
  2069.   return 0;
  2070. }
  2071. int Bank::getCurrTime(Uint64 &time){
  2072.   return readSystemValue(CurrentTime, time);
  2073. }
  2074. int Bank::prepareGetCurrTimeOp(NdbConnection *pTrans, Uint64 &time){
  2075.   return prepareReadSystemValueOp(pTrans, CurrentTime, time);
  2076. }
  2077. int Bank::performSumAccounts(int maxSleepBetweenSums, int yield){
  2078.   
  2079.   int yieldCounter = 0;
  2080.   while (1){
  2081.     Uint32 sumAccounts = 0;
  2082.     Uint32 numAccounts = 0;
  2083.     if (getSumAccounts(sumAccounts, numAccounts) != NDBT_OK){
  2084.       g_err << "getSumAccounts FAILED" << endl;
  2085.     } else {
  2086.     
  2087.       g_info << "num="<<numAccounts<<", sum=" << sumAccounts << endl;
  2088.       
  2089.       if (sumAccounts != (10000000 + (10000*(numAccounts-1)))){
  2090. g_err << "performSumAccounts  FAILED" << endl
  2091.       << "   sumAccounts="<<sumAccounts<<endl
  2092.       << "   expected   ="<<(10000000 + (10000*(numAccounts-1)))<<endl
  2093.       << "   numAccounts="<<numAccounts<<endl;
  2094. return NDBT_FAILED;
  2095.       } 
  2096.     
  2097.       if (maxSleepBetweenSums > 0){
  2098. int val = myRandom48(maxSleepBetweenSums);
  2099. NdbSleep_MilliSleep(val);      
  2100.       }
  2101.     }
  2102.     yieldCounter++;
  2103.     if (yield != 0 && yieldCounter >= yield)
  2104.       return NDBT_OK;
  2105.   }
  2106.   return NDBT_FAILED;
  2107. }
  2108. int Bank::getSumAccounts(Uint32 &sumAccounts, 
  2109.  Uint32 &numAccounts){
  2110.   // SELECT SUM(balance) FROM ACCOUNT
  2111.   int check;    
  2112.   NdbConnection* pScanTrans = m_ndb.startTransaction();
  2113.   if (pScanTrans == NULL) {
  2114.     ERR(m_ndb.getNdbError());
  2115.     return NDBT_FAILED;
  2116.   }
  2117.   NdbScanOperation* pOp = pScanTrans->getNdbScanOperation("ACCOUNT");
  2118.   if (pOp == NULL) {
  2119.     ERR(pScanTrans->getNdbError());
  2120.     m_ndb.closeTransaction(pScanTrans);
  2121.     return NDBT_FAILED;
  2122.   }
  2123.   NdbResultSet * rs = pOp->readTuplesExclusive();
  2124.   if( rs == 0 ) {
  2125.     ERR(pScanTrans->getNdbError());
  2126.     m_ndb.closeTransaction(pScanTrans);
  2127.     return NDBT_FAILED;
  2128.   }
  2129.   check = pOp->interpret_exit_ok();
  2130.   if( check == -1 ) {
  2131.     ERR(pScanTrans->getNdbError());
  2132.     m_ndb.closeTransaction(pScanTrans);
  2133.     return NDBT_FAILED;
  2134.   }
  2135.   NdbRecAttr* balanceRec = pOp->getValue("BALANCE");
  2136.   if( balanceRec ==NULL ) {
  2137.     ERR(pScanTrans->getNdbError());
  2138.     m_ndb.closeTransaction(pScanTrans);
  2139.     return NDBT_FAILED;
  2140.   }
  2141.   check = pScanTrans->execute(NoCommit);   
  2142.   if( check == -1 ) {
  2143.     ERR(pScanTrans->getNdbError());
  2144.     m_ndb.closeTransaction(pScanTrans);
  2145.     return NDBT_FAILED;
  2146.   }
  2147.   NdbConnection* pTrans = m_ndb.startTransaction();
  2148.   if (pTrans == NULL) {
  2149.     ERR(m_ndb.getNdbError());
  2150.     m_ndb.closeTransaction(pScanTrans);
  2151.     return NDBT_FAILED;
  2152.   }   
  2153.   int eof;
  2154.   eof = rs->nextResult();
  2155.     
  2156.   while(eof == 0){
  2157.     Uint32 b = balanceRec->u_32_value();
  2158.     
  2159.     sumAccounts += b;
  2160.     numAccounts++;
  2161.     //    ndbout << numAccounts << ": balance =" << b 
  2162.     //    << ", sum="<< sumAccounts << endl;
  2163.     // Take over the operation so that the lock is kept in db
  2164.     NdbOperation* pLockOp = rs->updateTuple(pTrans);
  2165.     if (pLockOp == NULL){
  2166.       ERR(m_ndb.getNdbError());
  2167.       m_ndb.closeTransaction(pScanTrans);
  2168.       m_ndb.closeTransaction(pTrans);
  2169.       return NDBT_FAILED;
  2170.     }
  2171.     
  2172.     Uint32 illegalBalance = 99;
  2173.     check = pLockOp->setValue("BALANCE", illegalBalance);
  2174.     if( check == -1 ) {
  2175.       ERR(pTrans->getNdbError());
  2176.       m_ndb.closeTransaction(pTrans);
  2177.       m_ndb.closeTransaction(pScanTrans);
  2178.       return NDBT_FAILED;
  2179.     }
  2180.     
  2181.     // Execute transaction    
  2182.     check = pTrans->execute(NoCommit);
  2183.     if( check == -1 ) {
  2184.       ERR(pTrans->getNdbError());
  2185.       m_ndb.closeTransaction(pScanTrans);
  2186.       m_ndb.closeTransaction(pTrans);
  2187.       return NDBT_FAILED;
  2188.     }       
  2189.     eof = rs->nextResult();
  2190.   }
  2191.   if (eof == -1) {
  2192.     ERR(pScanTrans->getNdbError());
  2193.     m_ndb.closeTransaction(pScanTrans);
  2194.     m_ndb.closeTransaction(pTrans);
  2195.     return NDBT_FAILED;
  2196.   }
  2197.   // TODO Forget about rolling back, just close pTrans!!
  2198.   // Rollback transaction    
  2199.   check = pTrans->execute(Rollback);
  2200.   if( check == -1 ) {
  2201.     ERR(pTrans->getNdbError());
  2202.     m_ndb.closeTransaction(pScanTrans);
  2203.     m_ndb.closeTransaction(pTrans);
  2204.     return NDBT_FAILED;
  2205.   }       
  2206.     
  2207.   m_ndb.closeTransaction(pScanTrans);
  2208.   m_ndb.closeTransaction(pTrans);
  2209.   return NDBT_OK;
  2210. }