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