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