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