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