1 /* Copyright (c) 2003-2006 MySQL AB
3 This program is free software; you can redistribute it and/or modify
4 it under the terms of the GNU General Public License as published by
5 the Free Software Foundation; version 2 of the License.
7 This program is distributed in the hope that it will be useful,
8 but WITHOUT ANY WARRANTY; without even the implied warranty of
9 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 GNU General Public License for more details.
12 You should have received a copy of the GNU General Public License
13 along with this program; if not, write to the Free Software
14 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */
19 #include <UtilTransactions.hpp>
21 Bank::Bank(Ndb_cluster_connection
& con
, bool _init
, const char * dbase
):
32 if (m_initialized
== true)
35 myRandom48Init(NdbTick_CurrentMillisecond());
38 if (m_ndb
.waitUntilReady(30) != 0)
40 ndbout
<< "Ndb not ready" << endl
;
44 if (getNumAccounts() != NDBT_OK
)
51 int Bank::performTransactions(int maxSleepBetweenTrans
, int yield
){
55 while(performTransaction() == NDBT_OK
)
59 if (maxSleepBetweenTrans
> 0){
60 int val
= myRandom48(maxSleepBetweenTrans
);
61 NdbSleep_MilliSleep(val
);
64 if((transactions
% 100) == 0)
65 g_info
<< transactions
<< endl
;
67 if (yield
!= 0 && transactions
>= yield
)
75 int Bank::performTransaction(){
78 if (m_maxAccount
<= 0){
79 g_err
<< "No accounts in bank" << endl
;
83 int fromAccount
= myRandom48(m_maxAccount
);
84 int toAccount
= myRandom48(m_maxAccount
);
86 if (fromAccount
== toAccount
){
87 // Increase toAccount with 1
88 toAccount
= (toAccount
+1)%m_maxAccount
;
91 int maxAmount
= getMaxAmount();
93 int amount
= myRandom48(maxAmount
);
96 int res
= performTransaction(fromAccount
, toAccount
, amount
);
100 g_err
<< "performTransaction returned NDBT_FAILED" << endl
101 << " fromAccount = " << fromAccount
<< endl
102 << " toAccount = " << toAccount
<< endl
103 << " amount = " << amount
<< endl
;
104 result
= NDBT_FAILED
;
106 case NOT_ENOUGH_FUNDS
:
107 // ndbout << "performTransaction returned NOT_ENOUGH_FUNDS" << endl;
110 g_err
<< "TEMPORARY_ERRROR retrying" << endl
;
111 NdbSleep_MilliSleep(50);
112 goto retry_transaction
;
115 g_info
<< "performTransaction returned "<<res
<< endl
;
123 * Perform a transaction in the bank.
124 * Ie. transfer money from one account to another.
127 * @return 0 if successful or an error code
129 int Bank::performTransaction(int fromAccountId
,
133 * 1. Start transaction
134 * 2. Check balance on from account, if there is
135 * not enough funds abort transaction
136 * 3. Update ACCOUNT set balance = balance - amount on
138 * 4. Insert withdrawal in TRANSACTION
139 * 5. Insert deposit in transaction
140 * 6. Update ACCOUNT set balance = balance + amount on
142 * 7. Commit transaction
144 // g_info << "performTransaction " << fromAccountId
145 // << ", "<<toAccountId<<", "<<amount << endl;
147 // Call the first implementation of this trans
148 // In the future we can have several different versions of this trans
149 // and call them randomly
150 return performTransactionImpl1(fromAccountId
, toAccountId
, amount
);
154 int Bank::performTransactionImpl1(int fromAccountId
,
160 // Ok, all clear to do the transaction
162 int result
= NDBT_OK
;
163 if ((result
= getNextTransactionId(transId
)) != NDBT_OK
){
167 NdbConnection
* pTrans
= m_ndb
.startTransaction();
169 if( pTrans
== NULL
) {
170 const NdbError err
= m_ndb
.getNdbError();
171 if (err
.status
== NdbError::TemporaryError
){
173 return NDBT_TEMPORARY
;
180 if (prepareGetCurrTimeOp(pTrans
, currTime
) != NDBT_OK
){
181 ERR(pTrans
->getNdbError());
182 m_ndb
.closeTransaction(pTrans
);
187 * Check balance on from account
189 NdbOperation
* pOp
= pTrans
->getNdbOperation("ACCOUNT");
191 ERR(pTrans
->getNdbError());
192 m_ndb
.closeTransaction(pTrans
);
196 check
= pOp
->readTupleExclusive();
198 ERR(pTrans
->getNdbError());
199 m_ndb
.closeTransaction(pTrans
);
203 check
= pOp
->equal("ACCOUNT_ID", fromAccountId
);
205 ERR(pTrans
->getNdbError());
206 m_ndb
.closeTransaction(pTrans
);
210 NdbRecAttr
* balanceFromRec
= pOp
->getValue("BALANCE");
211 if( balanceFromRec
==NULL
) {
212 ERR(pTrans
->getNdbError());
213 m_ndb
.closeTransaction(pTrans
);
217 NdbRecAttr
* fromAccountTypeRec
= pOp
->getValue("ACCOUNT_TYPE");
218 if( fromAccountTypeRec
== NULL
) {
219 ERR(pTrans
->getNdbError());
220 m_ndb
.closeTransaction(pTrans
);
225 * Read balance on to account
227 NdbOperation
* pOp6
= pTrans
->getNdbOperation("ACCOUNT");
229 ERR(pTrans
->getNdbError());
230 m_ndb
.closeTransaction(pTrans
);
234 check
= pOp6
->readTupleExclusive();
236 ERR(pTrans
->getNdbError());
237 m_ndb
.closeTransaction(pTrans
);
241 check
= pOp6
->equal("ACCOUNT_ID", toAccountId
);
243 ERR(pTrans
->getNdbError());
244 m_ndb
.closeTransaction(pTrans
);
248 NdbRecAttr
* balanceToRec
= pOp6
->getValue("BALANCE");
249 if( balanceToRec
== NULL
) {
250 ERR(pTrans
->getNdbError());
251 m_ndb
.closeTransaction(pTrans
);
255 NdbRecAttr
* toAccountTypeRec
= pOp6
->getValue("ACCOUNT_TYPE");
256 if( toAccountTypeRec
== NULL
) {
257 ERR(pTrans
->getNdbError());
258 m_ndb
.closeTransaction(pTrans
);
262 check
= pTrans
->execute(NoCommit
);
264 const NdbError err
= pTrans
->getNdbError();
265 m_ndb
.closeTransaction(pTrans
);
266 if (err
.status
== NdbError::TemporaryError
){
268 return NDBT_TEMPORARY
;
275 Uint32 balanceFrom
= balanceFromRec
->u_32_value();
276 // ndbout << "balanceFrom: " << balanceFrom << endl;
278 if (((Int64
)balanceFrom
- amount
) < 0){
279 m_ndb
.closeTransaction(pTrans
);
280 //ndbout << "Not enough funds" << endl;
281 return NOT_ENOUGH_FUNDS
;
284 Uint32 fromAccountType
= fromAccountTypeRec
->u_32_value();
286 Uint32 balanceTo
= balanceToRec
->u_32_value();
287 // ndbout << "balanceTo: " << balanceTo << endl;
288 Uint32 toAccountType
= toAccountTypeRec
->u_32_value();
291 * Update balance on from account
293 NdbOperation
* pOp2
= pTrans
->getNdbOperation("ACCOUNT");
295 ERR(pTrans
->getNdbError());
296 m_ndb
.closeTransaction(pTrans
);
300 check
= pOp2
->updateTuple();
302 ERR(pTrans
->getNdbError());
303 m_ndb
.closeTransaction(pTrans
);
307 check
= pOp2
->equal("ACCOUNT_ID", fromAccountId
);
309 ERR(pTrans
->getNdbError());
310 m_ndb
.closeTransaction(pTrans
);
314 check
= pOp2
->setValue("BALANCE", balanceFrom
- amount
);
316 ERR(pTrans
->getNdbError());
317 m_ndb
.closeTransaction(pTrans
);
322 * Update balance on to account
324 NdbOperation
* pOp3
= pTrans
->getNdbOperation("ACCOUNT");
326 ERR(pTrans
->getNdbError());
327 m_ndb
.closeTransaction(pTrans
);
331 check
= pOp3
->updateTuple();
333 ERR(pTrans
->getNdbError());
334 m_ndb
.closeTransaction(pTrans
);
338 check
= pOp3
->equal("ACCOUNT_ID", toAccountId
);
340 ERR(pTrans
->getNdbError());
341 m_ndb
.closeTransaction(pTrans
);
345 check
= pOp3
->setValue("BALANCE", balanceTo
+ amount
);
347 ERR(pTrans
->getNdbError());
348 m_ndb
.closeTransaction(pTrans
);
353 * Insert withdrawal transaction
355 NdbOperation
* pOp4
= pTrans
->getNdbOperation("TRANSACTION");
357 ERR(pTrans
->getNdbError());
358 m_ndb
.closeTransaction(pTrans
);
362 check
= pOp4
->insertTuple();
364 ERR(pTrans
->getNdbError());
365 m_ndb
.closeTransaction(pTrans
);
369 check
= pOp4
->equal("TRANSACTION_ID", transId
);
371 ERR(pTrans
->getNdbError());
372 m_ndb
.closeTransaction(pTrans
);
376 check
= pOp4
->equal("ACCOUNT", fromAccountId
);
378 ERR(pTrans
->getNdbError());
379 m_ndb
.closeTransaction(pTrans
);
383 check
= pOp4
->setValue("ACCOUNT_TYPE", fromAccountType
);
385 ERR(pTrans
->getNdbError());
386 m_ndb
.closeTransaction(pTrans
);
390 check
= pOp4
->setValue("OTHER_ACCOUNT", toAccountId
);
392 ERR(pTrans
->getNdbError());
393 m_ndb
.closeTransaction(pTrans
);
397 check
= pOp4
->setValue("TRANSACTION_TYPE", WithDrawal
);
399 ERR(pTrans
->getNdbError());
400 m_ndb
.closeTransaction(pTrans
);
404 check
= pOp4
->setValue("TIME", currTime
);
406 ERR(pTrans
->getNdbError());
407 m_ndb
.closeTransaction(pTrans
);
411 check
= pOp4
->setValue("AMOUNT", amount
);
413 ERR(pTrans
->getNdbError());
414 m_ndb
.closeTransaction(pTrans
);
419 * Insert deposit transaction
421 NdbOperation
* pOp5
= pTrans
->getNdbOperation("TRANSACTION");
423 ERR(pTrans
->getNdbError());
424 m_ndb
.closeTransaction(pTrans
);
428 check
= pOp5
->insertTuple();
430 ERR(pTrans
->getNdbError());
431 m_ndb
.closeTransaction(pTrans
);
435 check
= pOp5
->equal("TRANSACTION_ID", transId
);
437 ERR(pTrans
->getNdbError());
438 m_ndb
.closeTransaction(pTrans
);
442 check
= pOp5
->equal("ACCOUNT", toAccountId
);
444 ERR(pTrans
->getNdbError());
445 m_ndb
.closeTransaction(pTrans
);
449 check
= pOp5
->setValue("ACCOUNT_TYPE", toAccountType
);
451 ERR(pTrans
->getNdbError());
452 m_ndb
.closeTransaction(pTrans
);
456 check
= pOp5
->setValue("OTHER_ACCOUNT", fromAccountId
);
458 ERR(pTrans
->getNdbError());
459 m_ndb
.closeTransaction(pTrans
);
463 check
= pOp5
->setValue("TRANSACTION_TYPE", Deposit
);
465 ERR(pTrans
->getNdbError());
466 m_ndb
.closeTransaction(pTrans
);
470 check
= pOp5
->setValue("TIME", currTime
);
472 ERR(pTrans
->getNdbError());
473 m_ndb
.closeTransaction(pTrans
);
477 check
= pOp5
->setValue("AMOUNT", amount
);
479 ERR(pTrans
->getNdbError());
480 m_ndb
.closeTransaction(pTrans
);
484 check
= pTrans
->execute(Commit
);
486 const NdbError err
= pTrans
->getNdbError();
487 m_ndb
.closeTransaction(pTrans
);
488 if (err
.status
== NdbError::TemporaryError
){
490 return NDBT_TEMPORARY
;
496 m_ndb
.closeTransaction(pTrans
);
503 int Bank::performMakeGLs(int yield
){
506 int counter
, maxCounter
;
507 int yieldCounter
= 0;
510 // Counters to keep tracck of how many
511 // GLs should be made before performing a validation
513 maxCounter
= 50 + myRandom48(100);
516 * Validate GLs and Transactions for previous days
519 result
= performValidateGLs();
520 if (result
!= NDBT_OK
){
521 if (result
== VERIFICATION_FAILED
){
522 g_err
<< "performValidateGLs verification failed" << endl
;
525 g_info
<< "performValidateGLs failed" << endl
;
530 result
= performValidatePurged();
531 if (result
!= NDBT_OK
){
532 if (result
== VERIFICATION_FAILED
){
533 g_err
<< "performValidatePurged verification failed" << endl
;
536 g_info
<< "performValidatePurged failed" << endl
;
543 if (yield
!= 0 && yieldCounter
>= yield
)
548 * ( GL record with highest time value)
551 if (findLastGL(lastGLTime
) != NDBT_OK
){
552 g_info
<< "findLastGL failed" << endl
;
553 // Break out of inner while loop
560 * If last GL time + 1 is smaller than current time
561 * perform a GL for that time
564 if (getCurrTime(currTime
) != NDBT_OK
){
565 g_info
<< "getCurrTime failed" << endl
;
566 // Break out of inner while loop
569 if (lastGLTime
< currTime
){
571 if (performMakeGL(lastGLTime
) != NDBT_OK
){
572 g_info
<< "performMakeGL failed" << endl
;
573 // Break out of inner while loop
577 if (counter
> maxCounter
){
578 // Break out of inner while loop and
579 // validatePreviousGLs
580 g_info
<< "counter("<<counter
<<") > maxCounter("<<maxCounter
<<")" << endl
;
585 ;//ndbout << "It's not time to make GL yet" << endl;
587 // ndbout << "Sleeping 1 second" << endl;
588 NdbSleep_SecSleep(1);
593 if (purgeOldGLTransactions(currTime
, age
) != NDBT_OK
){
594 g_info
<< "purgeOldGLTransactions failed" << endl
;
595 // Break out of inner while loop
606 int Bank::performValidateAllGLs(){
612 * Validate GLs and Transactions for previous days
613 * Set age so that ALL GL's are validated
616 result
= performValidateGLs(age
);
617 if (result
!= NDBT_OK
){
618 if (result
== VERIFICATION_FAILED
){
619 g_err
<< "performValidateGLs verification failed" << endl
;
622 g_err
<< "performValidateGLs failed" << endl
;
630 result
= performValidatePurged();
631 if (result
!= NDBT_OK
){
632 if (result
== VERIFICATION_FAILED
){
633 g_err
<< "performValidatePurged verification failed" << endl
;
636 g_err
<< "performValidatePurged failed" << endl
;
646 int Bank::findLastGL(Uint64
&lastTime
){
650 * SELECT MAX(time) FROM GL
652 NdbConnection
* pScanTrans
= m_ndb
.startTransaction();
653 if (pScanTrans
== NULL
) {
654 ERR(m_ndb
.getNdbError());
658 NdbScanOperation
* pOp
= pScanTrans
->getNdbScanOperation("GL");
660 ERR(pScanTrans
->getNdbError());
661 m_ndb
.closeTransaction(pScanTrans
);
665 if( pOp
->readTuples() ) {
666 ERR(pScanTrans
->getNdbError());
667 m_ndb
.closeTransaction(pScanTrans
);
671 check
= pOp
->interpret_exit_ok();
673 ERR(pScanTrans
->getNdbError());
674 m_ndb
.closeTransaction(pScanTrans
);
678 NdbRecAttr
* timeRec
= pOp
->getValue("TIME");
679 if( timeRec
==NULL
) {
680 ERR(pScanTrans
->getNdbError());
681 m_ndb
.closeTransaction(pScanTrans
);
685 check
= pScanTrans
->execute(NoCommit
);
687 ERR(pScanTrans
->getNdbError());
688 m_ndb
.closeTransaction(pScanTrans
);
694 eof
= pOp
->nextResult();
699 Uint64 t
= timeRec
->u_32_value();
704 eof
= pOp
->nextResult();
707 ERR(pScanTrans
->getNdbError());
708 m_ndb
.closeTransaction(pScanTrans
);
712 m_ndb
.closeTransaction(pScanTrans
);
718 int Bank::performMakeGL(int time
){
719 g_info
<< "performMakeGL: " << time
<< endl
;
721 * Create one GL record for each account type.
722 * All in the same transaction
725 NdbConnection
* pTrans
= m_ndb
.startTransaction();
727 ERR(m_ndb
.getNdbError());
730 for (int i
= 0; i
< getNumAccountTypes(); i
++){
732 if (performMakeGLForAccountType(pTrans
, time
, i
) != NDBT_OK
){
733 g_err
<< "performMakeGLForAccountType returned NDBT_FAILED"<<endl
;
734 m_ndb
.closeTransaction(pTrans
);
738 // Execute transaction
739 if( pTrans
->execute(Commit
) == -1 ) {
740 ERR(pTrans
->getNdbError());
741 m_ndb
.closeTransaction(pTrans
);
744 m_ndb
.closeTransaction(pTrans
);
749 int Bank::performMakeGLForAccountType(NdbConnection
* pTrans
,
751 Uint32 accountTypeId
){
755 Uint32 withdrawalCount
= 0;
756 Uint32 withdrawalSum
= 0;
757 Uint32 depositSum
= 0;
758 Uint32 depositCount
= 0;
759 Uint32 countTransactions
= 0;
762 // Insert record in GL so that we know
763 // that no one else is performing the same task
764 // Set purged = 0 to indicate that TRANSACTION
765 // records still exist
766 NdbOperation
* pOp
= pTrans
->getNdbOperation("GL");
768 ERR(pTrans
->getNdbError());
772 check
= pOp
->insertTuple();
774 ERR(pTrans
->getNdbError());
778 check
= pOp
->equal("TIME", glTime
);
780 ERR(pTrans
->getNdbError());
784 check
= pOp
->equal("ACCOUNT_TYPE", accountTypeId
);
786 ERR(pTrans
->getNdbError());
790 check
= pOp
->setValue("BALANCE", balance
);
792 ERR(pTrans
->getNdbError());
796 check
= pOp
->setValue("DEPOSIT_COUNT", depositCount
);
798 ERR(pTrans
->getNdbError());
802 check
= pOp
->setValue("DEPOSIT_SUM", depositSum
);
804 ERR(pTrans
->getNdbError());
808 check
= pOp
->setValue("WITHDRAWAL_COUNT", withdrawalCount
);
810 ERR(pTrans
->getNdbError());
814 check
= pOp
->setValue("WITHDRAWAL_SUM", withdrawalSum
);
816 ERR(pTrans
->getNdbError());
820 check
= pOp
->setValue("PURGED", purged
);
822 ERR(pTrans
->getNdbError());
826 check
= pTrans
->execute(NoCommit
);
828 ERR(pOp
->getNdbError());
832 // Read previous GL record to get old balance
833 NdbOperation
* pOp2
= pTrans
->getNdbOperation("GL");
835 ERR(pTrans
->getNdbError());
839 check
= pOp2
->readTuple();
841 ERR(pTrans
->getNdbError());
845 check
= pOp2
->equal("TIME", glTime
-1);
847 ERR(pTrans
->getNdbError());
851 check
= pOp2
->equal("ACCOUNT_TYPE", accountTypeId
);
853 ERR(pTrans
->getNdbError());
857 NdbRecAttr
* oldBalanceRec
= pOp2
->getValue("BALANCE");
858 if( oldBalanceRec
== NULL
) {
859 ERR(pTrans
->getNdbError());
863 check
= pTrans
->execute(NoCommit
);
865 ERR(pOp2
->getNdbError());
869 Uint32 oldBalance
= oldBalanceRec
->u_32_value();
870 // ndbout << "oldBalance = "<<oldBalance<<endl;
871 balance
= oldBalance
;
872 // Start a scan transaction to search
873 // for TRANSACTION records with TIME = time
874 // and ACCOUNT_TYPE = accountTypeId
875 // Build sum of all found transactions
877 if (sumTransactionsForGL(glTime
,
888 // ndbout << "sumTransactionsForGL completed" << endl;
889 // ndbout << "balance="<<balance<<endl
890 // << "withdrawalCount="<<withdrawalCount<<endl
891 // << "withdrawalSum="<<withdrawalSum<<endl
892 // << "depositCount="<<depositCount<<endl
893 // << "depositSum="<<depositSum<<endl;
897 NdbOperation
* pOp3
= pTrans
->getNdbOperation("GL");
899 ERR(pTrans
->getNdbError());
903 check
= pOp3
->updateTuple();
905 ERR(pTrans
->getNdbError());
909 check
= pOp3
->equal("TIME", glTime
);
911 ERR(pTrans
->getNdbError());
915 check
= pOp3
->equal("ACCOUNT_TYPE", accountTypeId
);
917 ERR(pTrans
->getNdbError());
921 check
= pOp3
->setValue("BALANCE", balance
);
923 ERR(pTrans
->getNdbError());
927 check
= pOp3
->setValue("DEPOSIT_COUNT", depositCount
);
929 ERR(pTrans
->getNdbError());
933 check
= pOp3
->setValue("DEPOSIT_SUM", depositSum
);
935 ERR(pTrans
->getNdbError());
939 check
= pOp3
->setValue("WITHDRAWAL_COUNT", withdrawalCount
);
941 ERR(pTrans
->getNdbError());
945 check
= pOp3
->setValue("WITHDRAWAL_SUM", withdrawalSum
);
947 ERR(pTrans
->getNdbError());
951 check
= pOp3
->setValue("PURGED", purged
);
953 ERR(pTrans
->getNdbError());
957 // Execute transaction
958 check
= pTrans
->execute(NoCommit
);
960 ERR(pTrans
->getNdbError());
970 int Bank::sumTransactionsForGL(const Uint64 glTime
,
971 const Uint32 accountType
,
973 Uint32
& withdrawalCount
,
974 Uint32
& withdrawalSum
,
976 Uint32
& depositCount
,
977 Uint32
& transactionsCount
,
978 NdbConnection
* pTrans
){
981 // g_info << "sumTransactionsForGL: " << glTime << ", " << accountType << endl;
983 NdbConnection
* pScanTrans
= m_ndb
.startTransaction();
984 if (pScanTrans
== NULL
) {
985 ERR(m_ndb
.getNdbError());
989 NdbScanOperation
* pOp
= pScanTrans
->getNdbScanOperation("TRANSACTION");
991 ERR(pScanTrans
->getNdbError());
992 m_ndb
.closeTransaction(pScanTrans
);
996 if( pOp
->readTuplesExclusive()) {
997 ERR(pScanTrans
->getNdbError());
998 m_ndb
.closeTransaction(pScanTrans
);
1002 check
= pOp
->interpret_exit_ok();
1004 ERR(pScanTrans
->getNdbError());
1005 m_ndb
.closeTransaction(pScanTrans
);
1009 NdbRecAttr
* accountTypeRec
= pOp
->getValue("ACCOUNT_TYPE");
1010 if( accountTypeRec
==NULL
) {
1011 ERR(pScanTrans
->getNdbError());
1012 m_ndb
.closeTransaction(pScanTrans
);
1016 NdbRecAttr
* timeRec
= pOp
->getValue("TIME");
1017 if( timeRec
==NULL
) {
1018 ERR(pScanTrans
->getNdbError());
1019 m_ndb
.closeTransaction(pScanTrans
);
1023 NdbRecAttr
* transTypeRec
= pOp
->getValue("TRANSACTION_TYPE");
1024 if( transTypeRec
==NULL
) {
1025 ERR(pScanTrans
->getNdbError());
1026 m_ndb
.closeTransaction(pScanTrans
);
1030 NdbRecAttr
* amountRec
= pOp
->getValue("AMOUNT");
1031 if( amountRec
==NULL
) {
1032 ERR(pScanTrans
->getNdbError());
1033 m_ndb
.closeTransaction(pScanTrans
);
1037 check
= pScanTrans
->execute(NoCommit
);
1039 ERR(pScanTrans
->getNdbError());
1040 m_ndb
.closeTransaction(pScanTrans
);
1047 eof
= pOp
->nextResult();
1051 Uint32 a
= accountTypeRec
->u_32_value();
1052 Uint64 t
= timeRec
->u_64_value();
1054 if (a
== accountType
&& t
== glTime
){
1057 int transType
= transTypeRec
->u_32_value();
1058 int amount
= amountRec
->u_32_value();
1059 if (transType
== WithDrawal
){
1061 withdrawalSum
+= amount
;
1064 assert(transType
== Deposit
);
1066 depositSum
+= amount
;
1071 eof
= pOp
->nextResult();
1073 if ((rows
% 100) == 0){
1074 // "refresh" ownner transaction every 100th row
1075 if (pTrans
->refresh() == -1) {
1076 ERR(pTrans
->getNdbError());
1083 ERR(pScanTrans
->getNdbError());
1084 m_ndb
.closeTransaction(pScanTrans
);
1088 m_ndb
.closeTransaction(pScanTrans
);
1089 // ndbout << rows << " TRANSACTIONS have been read" << endl;
1090 transactionsCount
= rowsFound
;
1096 int Bank::performValidateGLs(Uint64 age
){
1099 if (getCurrTime(currTime
) != NDBT_OK
){
1102 Uint64 glTime
= currTime
- 1;
1103 while((glTime
> 0) && ((glTime
+ age
) >= currTime
)){
1105 int result
= performValidateGL(glTime
);
1106 if (result
!= NDBT_OK
){
1107 g_err
<< "performValidateGL failed" << endl
;
1117 int Bank::performValidateGL(Uint64 glTime
){
1119 ndbout
<< "performValidateGL: " << glTime
<< endl
;
1122 * - There should be zero or NoAccountTypes GL records for each glTime
1123 * - If purged == 0, then the TRANSACTION table should be checked
1124 * to see that there are:
1125 * + DEPOSIT_COUNT deposit transactions with account_type == ACCOUNT_TYPE
1126 * and TIME == glTime. The sum of these transactions should be
1128 * + WITHDRAWAL_COUNT withdrawal transactions with account_type ==
1129 * ACCOUNT_TYPE and TIME == glTime. The sum of these transactions
1130 * should be WITHDRAWAL_SUM
1131 * + BALANCE should be equal to the sum of all transactions plus
1132 * the balance of the previous GL record
1133 * - If purged == 1 then there should be NO transactions with TIME == glTime
1134 * and ACCOUNT_TYPE == account_type
1140 * SELECT * FROM GL WHERE account_type = @accountType and time = @time
1142 NdbConnection
* pScanTrans
= m_ndb
.startTransaction();
1143 if (pScanTrans
== NULL
) {
1144 ERR(m_ndb
.getNdbError());
1148 NdbScanOperation
* pOp
= pScanTrans
->getNdbScanOperation("GL");
1150 ERR(pScanTrans
->getNdbError());
1151 m_ndb
.closeTransaction(pScanTrans
);
1155 if( pOp
->readTuples() ) {
1156 ERR(pScanTrans
->getNdbError());
1157 m_ndb
.closeTransaction(pScanTrans
);
1161 check
= pOp
->interpret_exit_ok();
1163 ERR(pScanTrans
->getNdbError());
1164 m_ndb
.closeTransaction(pScanTrans
);
1168 NdbRecAttr
* accountTypeRec
= pOp
->getValue("ACCOUNT_TYPE");
1169 if( accountTypeRec
==NULL
) {
1170 ERR(pScanTrans
->getNdbError());
1171 m_ndb
.closeTransaction(pScanTrans
);
1175 NdbRecAttr
* timeRec
= pOp
->getValue("TIME");
1176 if( timeRec
==NULL
) {
1177 ERR(pScanTrans
->getNdbError());
1178 m_ndb
.closeTransaction(pScanTrans
);
1182 NdbRecAttr
* purgedRec
= pOp
->getValue("PURGED");
1183 if( purgedRec
==NULL
) {
1184 ERR(pScanTrans
->getNdbError());
1185 m_ndb
.closeTransaction(pScanTrans
);
1189 NdbRecAttr
* balanceRec
= pOp
->getValue("BALANCE");
1190 if( balanceRec
==NULL
) {
1191 ERR(pScanTrans
->getNdbError());
1192 m_ndb
.closeTransaction(pScanTrans
);
1196 NdbRecAttr
* depositSumRec
= pOp
->getValue("DEPOSIT_SUM");
1197 if( depositSumRec
==NULL
) {
1198 ERR(pScanTrans
->getNdbError());
1199 m_ndb
.closeTransaction(pScanTrans
);
1203 NdbRecAttr
* depositCountRec
= pOp
->getValue("DEPOSIT_COUNT");
1204 if( depositCountRec
==NULL
) {
1205 ERR(pScanTrans
->getNdbError());
1206 m_ndb
.closeTransaction(pScanTrans
);
1210 NdbRecAttr
* withdrawalSumRec
= pOp
->getValue("WITHDRAWAL_SUM");
1211 if( withdrawalSumRec
==NULL
) {
1212 ERR(pScanTrans
->getNdbError());
1213 m_ndb
.closeTransaction(pScanTrans
);
1216 NdbRecAttr
* withdrawalCountRec
= pOp
->getValue("WITHDRAWAL_COUNT");
1217 if( withdrawalCountRec
==NULL
) {
1218 ERR(pScanTrans
->getNdbError());
1219 m_ndb
.closeTransaction(pScanTrans
);
1223 check
= pScanTrans
->execute(NoCommit
);
1225 ERR(pScanTrans
->getNdbError());
1226 m_ndb
.closeTransaction(pScanTrans
);
1232 int countGlRecords
= 0;
1233 int result
= NDBT_OK
;
1234 eof
= pOp
->nextResult();
1238 Uint64 t
= timeRec
->u_64_value();
1242 Uint32 a
= accountTypeRec
->u_32_value();
1243 Uint32 purged
= purgedRec
->u_32_value();
1244 Uint32 wsum
= withdrawalSumRec
->u_32_value();
1245 Uint32 wcount
= withdrawalCountRec
->u_32_value();
1246 Uint32 dsum
= depositSumRec
->u_32_value();
1247 Uint32 dcount
= depositCountRec
->u_32_value();
1248 Uint32 b
= balanceRec
->u_32_value();
1251 Uint32 withdrawalSum
= 0;
1252 Uint32 withdrawalCount
= 0;
1253 Uint32 depositSum
= 0;
1254 Uint32 depositCount
= 0;
1255 Uint32 countTransactions
= 0;
1257 // If purged == 0, then the TRANSACTION table should be checked
1258 // to see that there are:
1259 // + DEPOSIT_COUNT deposit transactions with account_type == ACCOUNT_TYPE
1260 // and TIME == glTime. The sum of these transactions should be
1262 // + WITHDRAWAL_COUNT withdrawal transactions with account_type ==
1263 // ACCOUNT_TYPE and TIME == glTime. The sum of these transactions
1264 // should be WITHDRAWAL_SUM
1265 // + BALANCE should be equal to the sum of all transactions plus
1266 // the balance of the previous GL record
1267 if (sumTransactionsForGL(t
,
1275 pScanTrans
) != NDBT_OK
){
1276 result
= NDBT_FAILED
;
1278 Uint32 prevBalance
= 0;
1279 if (getBalanceForGL(t
-1, a
, prevBalance
) != NDBT_OK
){
1280 result
= NDBT_FAILED
;
1282 if (((prevBalance
+ balance
) != b
) ||
1283 (wsum
!= withdrawalSum
) ||
1284 (wcount
!= withdrawalCount
) ||
1285 (dsum
!= depositSum
) ||
1286 (dcount
!= depositCount
)){
1287 g_err
<< "performValidateGL, sums and counts failed" << endl
1288 << "balance : " << balance
+prevBalance
<< "!="<<b
<<endl
1289 << "with sum : " << withdrawalSum
<< "!="<<wsum
<<endl
1290 << "with count: " << withdrawalCount
<< "!="<<wcount
<<endl
1291 << "dep sum : " << depositSum
<< "!="<<dsum
<<endl
1292 << "dep count : " << depositCount
<< "!="<<dcount
<<endl
;
1293 result
= VERIFICATION_FAILED
;
1298 assert(purged
== 1);
1299 // If purged == 1 then there should be NO transactions with
1300 // TIME == glTime and ACCOUNT_TYPE == account_type
1302 if (sumTransactionsForGL(t
,
1310 pScanTrans
) != NDBT_OK
){
1311 result
= NDBT_FAILED
;
1313 if (countTransactions
!= 0){
1314 g_err
<< "performValidateGL, countTransactions("<<countTransactions
<<") != 0" << endl
;
1315 result
= VERIFICATION_FAILED
;
1321 eof
= pOp
->nextResult();
1324 ERR(pScanTrans
->getNdbError());
1325 m_ndb
.closeTransaction(pScanTrans
);
1329 m_ndb
.closeTransaction(pScanTrans
);
1331 // - There should be zero or NoAccountTypes GL records for each glTime
1332 if ((countGlRecords
!= 0) && (countGlRecords
!= getNumAccountTypes())){
1333 g_err
<< "performValidateGL: " << endl
1334 << "countGlRecords = " << countGlRecords
<< endl
;
1335 result
= VERIFICATION_FAILED
;
1343 int Bank::getBalanceForGL(const Uint64 glTime
,
1344 const Uint32 accountTypeId
,
1348 NdbConnection
* pTrans
= m_ndb
.startTransaction();
1349 if (pTrans
== NULL
) {
1350 ERR(m_ndb
.getNdbError());
1354 NdbOperation
* pOp
= pTrans
->getNdbOperation("GL");
1356 ERR(pTrans
->getNdbError());
1360 check
= pOp
->readTuple();
1362 ERR(pTrans
->getNdbError());
1366 check
= pOp
->equal("TIME", glTime
);
1368 ERR(pTrans
->getNdbError());
1372 check
= pOp
->equal("ACCOUNT_TYPE", accountTypeId
);
1374 ERR(pTrans
->getNdbError());
1378 NdbRecAttr
* balanceRec
= pOp
->getValue("BALANCE");
1379 if( balanceRec
== NULL
) {
1380 ERR(pTrans
->getNdbError());
1384 check
= pTrans
->execute(Commit
);
1386 ERR(pTrans
->getNdbError());
1390 m_ndb
.closeTransaction(pTrans
);
1392 balance
= balanceRec
->u_32_value();
1399 int Bank::getOldestPurgedGL(const Uint32 accountType
,
1403 * SELECT MAX(time) FROM GL WHERE account_type = @accountType and purged=1
1405 NdbConnection
* pScanTrans
= 0;
1408 pScanTrans
= m_ndb
.startTransaction();
1409 if (pScanTrans
== NULL
) {
1410 ERR(m_ndb
.getNdbError());
1414 NdbScanOperation
* pOp
= pScanTrans
->getNdbScanOperation("GL");
1416 ERR(pScanTrans
->getNdbError());
1417 m_ndb
.closeTransaction(pScanTrans
);
1421 if( pOp
->readTuples() ) {
1422 ERR(pScanTrans
->getNdbError());
1423 m_ndb
.closeTransaction(pScanTrans
);
1427 check
= pOp
->interpret_exit_ok();
1429 ERR(pScanTrans
->getNdbError());
1430 m_ndb
.closeTransaction(pScanTrans
);
1434 NdbRecAttr
* accountTypeRec
= pOp
->getValue("ACCOUNT_TYPE");
1435 if( accountTypeRec
==NULL
) {
1436 ERR(pScanTrans
->getNdbError());
1437 m_ndb
.closeTransaction(pScanTrans
);
1441 NdbRecAttr
* timeRec
= pOp
->getValue("TIME");
1442 if( timeRec
==NULL
) {
1443 ERR(pScanTrans
->getNdbError());
1444 m_ndb
.closeTransaction(pScanTrans
);
1448 NdbRecAttr
* purgedRec
= pOp
->getValue("PURGED");
1449 if( purgedRec
==NULL
) {
1450 ERR(pScanTrans
->getNdbError());
1451 m_ndb
.closeTransaction(pScanTrans
);
1455 check
= pScanTrans
->execute(NoCommit
);
1457 NdbError err
= pScanTrans
->getNdbError();
1459 m_ndb
.closeTransaction(pScanTrans
);
1460 if (err
.status
== NdbError::TemporaryError
)
1462 NdbSleep_MilliSleep(50);
1470 eof
= pOp
->nextResult();
1475 Uint32 a
= accountTypeRec
->u_32_value();
1476 Uint32 p
= purgedRec
->u_32_value();
1478 if (a
== accountType
&& p
== 1){
1480 Uint64 t
= timeRec
->u_64_value();
1484 eof
= pOp
->nextResult();
1488 NdbError err
= pScanTrans
->getNdbError();
1490 m_ndb
.closeTransaction(pScanTrans
);
1492 if (err
.status
== NdbError::TemporaryError
)
1494 NdbSleep_MilliSleep(50);
1502 m_ndb
.closeTransaction(pScanTrans
);
1507 int Bank::getOldestNotPurgedGL(Uint64
&oldest
,
1508 Uint32
&accountTypeId
,
1512 * SELECT time, accountTypeId FROM GL
1513 * WHERE purged=0 order by time asc
1515 NdbConnection
* pScanTrans
= m_ndb
.startTransaction();
1516 if (pScanTrans
== NULL
) {
1517 ERR(m_ndb
.getNdbError());
1521 NdbScanOperation
* pOp
= pScanTrans
->getNdbScanOperation("GL");
1523 ERR(pScanTrans
->getNdbError());
1524 m_ndb
.closeTransaction(pScanTrans
);
1528 if( pOp
->readTuples() ) {
1529 ERR(pScanTrans
->getNdbError());
1530 m_ndb
.closeTransaction(pScanTrans
);
1534 check
= pOp
->interpret_exit_ok();
1536 ERR(pScanTrans
->getNdbError());
1537 m_ndb
.closeTransaction(pScanTrans
);
1541 NdbRecAttr
* accountTypeRec
= pOp
->getValue("ACCOUNT_TYPE");
1542 if( accountTypeRec
==NULL
) {
1543 ERR(pScanTrans
->getNdbError());
1544 m_ndb
.closeTransaction(pScanTrans
);
1548 NdbRecAttr
* timeRec
= pOp
->getValue("TIME");
1549 if( timeRec
==NULL
) {
1550 ERR(pScanTrans
->getNdbError());
1551 m_ndb
.closeTransaction(pScanTrans
);
1555 NdbRecAttr
* purgedRec
= pOp
->getValue("PURGED");
1556 if( purgedRec
==NULL
) {
1557 ERR(pScanTrans
->getNdbError());
1558 m_ndb
.closeTransaction(pScanTrans
);
1562 check
= pScanTrans
->execute(NoCommit
);
1564 ERR(pScanTrans
->getNdbError());
1565 m_ndb
.closeTransaction(pScanTrans
);
1571 eof
= pOp
->nextResult();
1572 oldest
= (Uint64
)-1;
1577 Uint32 p
= purgedRec
->u_32_value();
1581 Uint32 a
= accountTypeRec
->u_32_value();
1582 Uint64 t
= timeRec
->u_64_value();
1588 eof
= pOp
->nextResult();
1591 ERR(pScanTrans
->getNdbError());
1592 m_ndb
.closeTransaction(pScanTrans
);
1596 m_ndb
.closeTransaction(pScanTrans
);
1602 int Bank::checkNoTransactionsOlderThan(const Uint32 accountType
,
1603 const Uint64 oldest
){
1605 * SELECT COUNT(transaction_id) FROM TRANSACTION
1606 * WHERE account_type = @accountType and time <= @oldest
1612 NdbConnection
* pScanTrans
= 0;
1616 pScanTrans
= m_ndb
.startTransaction();
1617 if (pScanTrans
== NULL
) {
1618 ERR(m_ndb
.getNdbError());
1622 NdbScanOperation
* pOp
= pScanTrans
->getNdbScanOperation("TRANSACTION");
1624 ERR(pScanTrans
->getNdbError());
1625 m_ndb
.closeTransaction(pScanTrans
);
1629 if( pOp
->readTuples() ) {
1630 ERR(pScanTrans
->getNdbError());
1631 m_ndb
.closeTransaction(pScanTrans
);
1635 check
= pOp
->interpret_exit_ok();
1637 ERR(pScanTrans
->getNdbError());
1638 m_ndb
.closeTransaction(pScanTrans
);
1642 NdbRecAttr
* accountTypeRec
= pOp
->getValue("ACCOUNT_TYPE");
1643 if( accountTypeRec
==NULL
) {
1644 ERR(pScanTrans
->getNdbError());
1645 m_ndb
.closeTransaction(pScanTrans
);
1649 NdbRecAttr
* timeRec
= pOp
->getValue("TIME");
1650 if( timeRec
==NULL
) {
1651 ERR(pScanTrans
->getNdbError());
1652 m_ndb
.closeTransaction(pScanTrans
);
1656 NdbRecAttr
* transactionIdRec
= pOp
->getValue("TRANSACTION_ID");
1657 if( transactionIdRec
==NULL
) {
1658 ERR(pScanTrans
->getNdbError());
1659 m_ndb
.closeTransaction(pScanTrans
);
1663 check
= pScanTrans
->execute(NoCommit
);
1665 NdbError err
= pScanTrans
->getNdbError();
1667 m_ndb
.closeTransaction(pScanTrans
);
1669 if (err
.status
== NdbError::TemporaryError
)
1671 NdbSleep_MilliSleep(50);
1680 eof
= pOp
->nextResult();
1684 Uint32 a
= accountTypeRec
->u_32_value();
1685 Uint32 t
= timeRec
->u_32_value();
1687 if (a
== accountType
&& t
<= oldest
){
1689 Uint64 ti
= transactionIdRec
->u_64_value();
1690 g_err
<< "checkNoTransactionsOlderThan found one record" << endl
1691 << " t = " << t
<< endl
1692 << " a = " << a
<< endl
1693 << " ti = " << ti
<< endl
;
1696 eof
= pOp
->nextResult();
1699 NdbError err
= pScanTrans
->getNdbError();
1701 m_ndb
.closeTransaction(pScanTrans
);
1703 if (err
.status
== NdbError::TemporaryError
)
1705 NdbSleep_MilliSleep(50);
1715 m_ndb
.closeTransaction(pScanTrans
);
1720 return VERIFICATION_FAILED
;
1724 int Bank::performValidatePurged(){
1726 * Make sure there are no TRANSACTIONS older than the oldest
1731 for (int i
= 0; i
< getNumAccountTypes(); i
++){
1732 ndbout
<< "performValidatePurged: " << i
<< endl
;
1733 Uint64 oldestGlTime
;
1734 if (getOldestPurgedGL(i
, oldestGlTime
) != NDBT_OK
){
1735 g_err
<< "getOldestPurgedGL failed" << endl
;
1738 int result
= checkNoTransactionsOlderThan(i
, oldestGlTime
);
1739 if (result
!= NDBT_OK
){
1740 g_err
<< "checkNoTransactionsOlderThan failed" << endl
;
1749 int Bank::purgeOldGLTransactions(Uint64 currTime
, Uint32 age
){
1751 * For each GL record that are older than age and have purged == 0
1752 * - delete all TRANSACTIONS belonging to the GL and set purged = 1
1764 // Search for the oldest GL record with purged == 0
1765 Uint64 oldestGlTime
;
1766 Uint32 accountTypeId
;
1767 if (getOldestNotPurgedGL(oldestGlTime
, accountTypeId
, found
) != NDBT_OK
){
1768 g_err
<< "getOldestNotPurgedGL failed" << endl
;
1773 if (found
== false){
1774 // ndbout << "not found" << endl;
1779 // ndbout << "purgeOldGLTransactions" << endl
1780 // << " oldestGlTime = " << oldestGlTime << endl
1781 // << " currTime = " << currTime << endl
1782 // << " age = " << age << endl;
1783 // Check if this GL is old enough to be purged
1784 if ((currTime
< age
) || (oldestGlTime
> (currTime
-age
))){
1785 // ndbout << "is not old enough" << endl;
1789 if (purgeTransactions(oldestGlTime
, accountTypeId
) != NDBT_OK
){
1790 g_err
<< "purgeTransactions failed" << endl
;
1794 g_err
<< "abnormal return" << endl
;
1799 int Bank::purgeTransactions(const Uint64 glTime
,
1800 const Uint32 accountTypeId
)
1803 g_info
<< "purgeTransactions: " << glTime
<< ", "<<accountTypeId
<<endl
;
1804 NdbConnection
* pTrans
= m_ndb
.startTransaction();
1805 if (pTrans
== NULL
){
1806 ERR(m_ndb
.getNdbError());
1810 // Start by updating the GL record with purged = 1, use NoCommit
1811 NdbOperation
* pOp
= pTrans
->getNdbOperation("GL");
1813 ERR(pTrans
->getNdbError());
1817 check
= pOp
->updateTuple();
1819 ERR(pTrans
->getNdbError());
1823 check
= pOp
->equal("TIME", glTime
);
1825 ERR(pTrans
->getNdbError());
1829 check
= pOp
->equal("ACCOUNT_TYPE", accountTypeId
);
1831 ERR(pTrans
->getNdbError());
1836 check
= pOp
->setValue("PURGED", purged
);
1838 ERR(pTrans
->getNdbError());
1842 // Execute transaction
1843 check
= pTrans
->execute(NoCommit
);
1845 ERR(pTrans
->getNdbError());
1849 // Find all transactions and take over them for delete
1851 if(findTransactionsToPurge(glTime
,
1853 pTrans
) != NDBT_OK
){
1854 g_err
<< "findTransactionToPurge failed" << endl
;
1855 m_ndb
.closeTransaction(pTrans
);
1861 check
= pTrans
->execute(Commit
);
1863 ERR(pTrans
->getNdbError());
1867 m_ndb
.closeTransaction(pTrans
);
1872 int Bank::findTransactionsToPurge(const Uint64 glTime
,
1873 const Uint32 accountType
,
1874 NdbConnection
* pTrans
){
1877 NdbConnection
* pScanTrans
= m_ndb
.startTransaction();
1878 if (pScanTrans
== NULL
) {
1879 ERR(m_ndb
.getNdbError());
1883 NdbScanOperation
* pOp
= pScanTrans
->getNdbScanOperation("TRANSACTION");
1885 ERR(pScanTrans
->getNdbError());
1886 m_ndb
.closeTransaction(pScanTrans
);
1890 if( pOp
->readTuplesExclusive() ) {
1891 ERR(pScanTrans
->getNdbError());
1892 m_ndb
.closeTransaction(pScanTrans
);
1896 check
= pOp
->interpret_exit_ok();
1898 ERR(pScanTrans
->getNdbError());
1899 m_ndb
.closeTransaction(pScanTrans
);
1903 NdbRecAttr
* timeRec
= pOp
->getValue("TIME");
1904 if( timeRec
==NULL
) {
1905 ERR(pScanTrans
->getNdbError());
1906 m_ndb
.closeTransaction(pScanTrans
);
1910 NdbRecAttr
* accountTypeRec
= pOp
->getValue("ACCOUNT_TYPE");
1911 if( accountTypeRec
==NULL
) {
1912 ERR(pScanTrans
->getNdbError());
1913 m_ndb
.closeTransaction(pScanTrans
);
1917 check
= pScanTrans
->execute(NoCommit
);
1919 ERR(pScanTrans
->getNdbError());
1920 m_ndb
.closeTransaction(pScanTrans
);
1927 eof
= pOp
->nextResult();
1931 Uint64 t
= timeRec
->u_64_value();
1932 Uint32 a
= accountTypeRec
->u_32_value();
1934 if (a
== accountType
&& t
== glTime
){
1937 check
= pOp
->deleteCurrentTuple(pTrans
);
1939 ERR(m_ndb
.getNdbError());
1940 m_ndb
.closeTransaction(pScanTrans
);
1944 // Execute transaction
1945 check
= pTrans
->execute(NoCommit
);
1947 ERR(pTrans
->getNdbError());
1948 m_ndb
.closeTransaction(pScanTrans
);
1952 eof
= pOp
->nextResult();
1955 ERR(pScanTrans
->getNdbError());
1956 m_ndb
.closeTransaction(pScanTrans
);
1960 m_ndb
.closeTransaction(pScanTrans
);
1961 // ndbout << rowsFound << " TRANSACTIONS have been deleted" << endl;
1968 int Bank::performIncreaseTime(int maxSleepBetweenDays
, int yield
)
1970 int yieldCounter
= 0;
1975 if (incCurrTime(currTime
) != NDBT_OK
)
1978 g_info
<< "Current time is " << currTime
<< endl
;
1979 if (maxSleepBetweenDays
> 0){
1980 int val
= myRandom48(maxSleepBetweenDays
);
1981 NdbSleep_SecSleep(val
);
1985 if (yield
!= 0 && yieldCounter
>= yield
)
1992 int Bank::readSystemValue(SystemValueId sysValId
, Uint64
& value
){
1995 NdbConnection
* pTrans
= 0;
1998 pTrans
= m_ndb
.startTransaction();
2001 ERR(m_ndb
.getNdbError());
2002 if(m_ndb
.getNdbError().status
== NdbError::TemporaryError
)
2004 NdbSleep_MilliSleep(50);
2011 if ((result
= prepareReadSystemValueOp(pTrans
, sysValId
, value
)) != NDBT_OK
)
2013 ERR(pTrans
->getNdbError());
2014 m_ndb
.closeTransaction(pTrans
);
2018 check
= pTrans
->execute(Commit
);
2020 NdbError err
= pTrans
->getNdbError();
2021 m_ndb
.closeTransaction(pTrans
);
2023 if(err
.status
== NdbError::TemporaryError
)
2025 NdbSleep_MilliSleep(50);
2034 m_ndb
.closeTransaction(pTrans
);
2039 int Bank::prepareReadSystemValueOp(NdbConnection
* pTrans
, SystemValueId sysValId
, Uint64
& value
){
2043 NdbOperation
* pOp
= pTrans
->getNdbOperation("SYSTEM_VALUES");
2048 check
= pOp
->readTuple();
2053 check
= pOp
->equal("SYSTEM_VALUES_ID", sysValId
);
2058 NdbRecAttr
* valueRec
= pOp
->getValue("VALUE", (char *)&value
);
2059 if( valueRec
== NULL
) {
2066 int Bank::writeSystemValue(SystemValueId sysValId
, Uint64 value
){
2070 NdbConnection
* pTrans
= m_ndb
.startTransaction();
2071 if (pTrans
== NULL
){
2072 ERR(m_ndb
.getNdbError());
2076 NdbOperation
* pOp
= pTrans
->getNdbOperation("SYSTEM_VALUES");
2078 ERR(pTrans
->getNdbError());
2079 m_ndb
.closeTransaction(pTrans
);
2083 check
= pOp
->insertTuple();
2085 ERR(pTrans
->getNdbError());
2086 m_ndb
.closeTransaction(pTrans
);
2090 check
= pOp
->equal("SYSTEM_VALUES_ID", sysValId
);
2092 ERR(pTrans
->getNdbError());
2093 m_ndb
.closeTransaction(pTrans
);
2097 check
= pOp
->setValue("VALUE", value
);
2099 ERR(pTrans
->getNdbError());
2100 m_ndb
.closeTransaction(pTrans
);
2104 check
= pTrans
->execute(Commit
);
2106 ERR(pTrans
->getNdbError());
2107 m_ndb
.closeTransaction(pTrans
);
2111 m_ndb
.closeTransaction(pTrans
);
2116 int Bank::getNextTransactionId(Uint64
&value
){
2117 return increaseSystemValue2(LastTransactionId
, value
);
2120 int Bank::incCurrTime(Uint64
&value
){
2121 return increaseSystemValue(CurrentTime
, value
);
2125 int Bank::increaseSystemValue(SystemValueId sysValId
, Uint64
&value
){
2127 * Increase value with one and return
2132 DBUG_ENTER("Bank::increaseSystemValue");
2136 NdbConnection
* pTrans
= m_ndb
.startTransaction();
2137 if (pTrans
== NULL
){
2138 ERR(m_ndb
.getNdbError());
2139 if (m_ndb
.getNdbError().status
== NdbError::TemporaryError
)
2140 DBUG_RETURN(NDBT_TEMPORARY
);
2141 DBUG_RETURN(NDBT_FAILED
);
2144 NdbOperation
* pOp
= pTrans
->getNdbOperation("SYSTEM_VALUES");
2146 ERR(pTrans
->getNdbError());
2147 m_ndb
.closeTransaction(pTrans
);
2148 DBUG_RETURN(NDBT_FAILED
);
2151 check
= pOp
->readTupleExclusive();
2152 // check = pOp->readTuple();
2154 ERR(pTrans
->getNdbError());
2155 m_ndb
.closeTransaction(pTrans
);
2156 DBUG_RETURN(NDBT_FAILED
);
2159 check
= pOp
->equal("SYSTEM_VALUES_ID", sysValId
);
2161 ERR(pTrans
->getNdbError());
2162 m_ndb
.closeTransaction(pTrans
);
2163 DBUG_RETURN(NDBT_FAILED
);
2166 NdbRecAttr
* valueRec
= pOp
->getValue("VALUE");
2167 if( valueRec
==NULL
) {
2168 ERR(pTrans
->getNdbError());
2169 m_ndb
.closeTransaction(pTrans
);
2170 DBUG_RETURN(NDBT_FAILED
);
2173 check
= pTrans
->execute(NoCommit
);
2175 ERR(pTrans
->getNdbError());
2176 if (pTrans
->getNdbError().status
== NdbError::TemporaryError
)
2178 m_ndb
.closeTransaction(pTrans
);
2179 DBUG_RETURN(NDBT_TEMPORARY
);
2181 m_ndb
.closeTransaction(pTrans
);
2182 DBUG_RETURN(NDBT_FAILED
);
2185 value
= valueRec
->u_64_value();
2188 NdbOperation
* pOp2
= pTrans
->getNdbOperation("SYSTEM_VALUES");
2190 ERR(pTrans
->getNdbError());
2191 m_ndb
.closeTransaction(pTrans
);
2192 DBUG_RETURN(NDBT_FAILED
);
2195 check
= pOp2
->updateTuple();
2197 ERR(pTrans
->getNdbError());
2198 m_ndb
.closeTransaction(pTrans
);
2199 DBUG_RETURN(NDBT_FAILED
);
2202 check
= pOp2
->equal("SYSTEM_VALUES_ID", sysValId
);
2204 ERR(pTrans
->getNdbError());
2205 m_ndb
.closeTransaction(pTrans
);
2206 DBUG_RETURN(NDBT_FAILED
);
2209 check
= pOp2
->setValue("VALUE", value
);
2211 ERR(pTrans
->getNdbError());
2212 m_ndb
.closeTransaction(pTrans
);
2213 DBUG_RETURN(NDBT_FAILED
);
2216 check
= pTrans
->execute(NoCommit
);
2218 ERR(pTrans
->getNdbError());
2219 m_ndb
.closeTransaction(pTrans
);
2220 DBUG_RETURN(NDBT_FAILED
);
2223 NdbOperation
* pOp3
= pTrans
->getNdbOperation("SYSTEM_VALUES");
2225 ERR(pTrans
->getNdbError());
2226 m_ndb
.closeTransaction(pTrans
);
2227 DBUG_RETURN(NDBT_FAILED
);
2230 check
= pOp3
->readTuple();
2232 ERR(pTrans
->getNdbError());
2233 m_ndb
.closeTransaction(pTrans
);
2234 DBUG_RETURN(NDBT_FAILED
);
2237 check
= pOp3
->equal("SYSTEM_VALUES_ID", sysValId
);
2239 ERR(pTrans
->getNdbError());
2240 m_ndb
.closeTransaction(pTrans
);
2241 DBUG_RETURN(NDBT_FAILED
);
2245 NdbRecAttr
* valueNewRec
= pOp3
->getValue("VALUE");
2246 if( valueNewRec
==NULL
) {
2247 ERR(pTrans
->getNdbError());
2248 m_ndb
.closeTransaction(pTrans
);
2249 DBUG_RETURN(NDBT_FAILED
);
2252 check
= pTrans
->execute(Commit
);
2254 ERR(pTrans
->getNdbError());
2255 if (pTrans
->getNdbError().status
== NdbError::TemporaryError
)
2257 m_ndb
.closeTransaction(pTrans
);
2258 DBUG_RETURN(NDBT_TEMPORARY
);
2260 m_ndb
.closeTransaction(pTrans
);
2261 DBUG_RETURN(NDBT_FAILED
);
2264 // Check that value updated equals the value we read after the update
2265 if (valueNewRec
->u_64_value() != value
){
2267 printf("value actual=%lld\n", valueNewRec
->u_64_value());
2268 printf("value expected=%lld actual=%lld\n", value
, valueNewRec
->u_64_value());
2270 DBUG_PRINT("info", ("value expected=%ld actual=%ld", value
, valueNewRec
->u_64_value()));
2271 g_err
<< "getNextTransactionId: value was not updated" << endl
;
2272 m_ndb
.closeTransaction(pTrans
);
2273 DBUG_RETURN(NDBT_FAILED
);
2276 m_ndb
.closeTransaction(pTrans
);
2281 int Bank::increaseSystemValue2(SystemValueId sysValId
, Uint64
&value
){
2283 * Increase value with one and return
2285 * A more optimized version using interpreted update!
2291 NdbConnection
* pTrans
= m_ndb
.startTransaction();
2292 if (pTrans
== NULL
){
2293 ERR(m_ndb
.getNdbError());
2294 if(m_ndb
.getNdbError().status
== NdbError::TemporaryError
)
2295 return NDBT_TEMPORARY
;
2299 NdbOperation
* pOp
= pTrans
->getNdbOperation("SYSTEM_VALUES");
2301 ERR(pTrans
->getNdbError());
2302 m_ndb
.closeTransaction(pTrans
);
2306 check
= pOp
->interpretedUpdateTuple();
2308 ERR(pTrans
->getNdbError());
2309 m_ndb
.closeTransaction(pTrans
);
2313 check
= pOp
->equal("SYSTEM_VALUES_ID", sysValId
);
2315 ERR(pTrans
->getNdbError());
2316 m_ndb
.closeTransaction(pTrans
);
2320 Uint32 valToIncWith
= 1;
2321 check
= pOp
->incValue("VALUE", valToIncWith
);
2323 ERR(pTrans
->getNdbError());
2324 m_ndb
.closeTransaction(pTrans
);
2328 NdbRecAttr
* valueRec
= pOp
->getValue("VALUE");
2329 if( valueRec
== NULL
) {
2330 ERR(pTrans
->getNdbError());
2331 m_ndb
.closeTransaction(pTrans
);
2335 check
= pTrans
->execute(Commit
);
2337 ERR(pTrans
->getNdbError());
2338 if(pTrans
->getNdbError().status
== NdbError::TemporaryError
)
2340 m_ndb
.closeTransaction(pTrans
);
2341 return NDBT_TEMPORARY
;
2343 m_ndb
.closeTransaction(pTrans
);
2347 value
= valueRec
->u_64_value();
2349 m_ndb
.closeTransaction(pTrans
);
2357 int Bank::getCurrTime(Uint64
&time
){
2358 return readSystemValue(CurrentTime
, time
);
2361 int Bank::prepareGetCurrTimeOp(NdbConnection
*pTrans
, Uint64
&time
){
2362 return prepareReadSystemValueOp(pTrans
, CurrentTime
, time
);
2366 int Bank::performSumAccounts(int maxSleepBetweenSums
, int yield
){
2368 int yieldCounter
= 0;
2372 Uint32 sumAccounts
= 0;
2373 Uint32 numAccounts
= 0;
2374 if (getSumAccounts(sumAccounts
, numAccounts
) != NDBT_OK
){
2375 g_err
<< "getSumAccounts FAILED" << endl
;
2378 g_info
<< "num="<<numAccounts
<<", sum=" << sumAccounts
<< endl
;
2380 if (sumAccounts
!= (10000000 + (10000*(numAccounts
-1)))){
2381 g_err
<< "performSumAccounts FAILED" << endl
2382 << " sumAccounts="<<sumAccounts
<<endl
2383 << " expected ="<<(10000000 + (10000*(numAccounts
-1)))<<endl
2384 << " numAccounts="<<numAccounts
<<endl
;
2388 if (maxSleepBetweenSums
> 0){
2389 int val
= myRandom48(maxSleepBetweenSums
);
2390 NdbSleep_MilliSleep(val
);
2395 if (yield
!= 0 && yieldCounter
>= yield
)
2402 int Bank::getSumAccounts(Uint32
&sumAccounts
,
2403 Uint32
&numAccounts
){
2405 // SELECT SUM(balance) FROM ACCOUNT
2408 NdbConnection
* pScanTrans
= m_ndb
.startTransaction();
2409 if (pScanTrans
== NULL
) {
2410 ERR(m_ndb
.getNdbError());
2414 NdbScanOperation
* pOp
= pScanTrans
->getNdbScanOperation("ACCOUNT");
2416 ERR(pScanTrans
->getNdbError());
2417 m_ndb
.closeTransaction(pScanTrans
);
2421 if( pOp
->readTuplesExclusive() ) {
2422 ERR(pScanTrans
->getNdbError());
2423 m_ndb
.closeTransaction(pScanTrans
);
2427 check
= pOp
->interpret_exit_ok();
2429 ERR(pScanTrans
->getNdbError());
2430 m_ndb
.closeTransaction(pScanTrans
);
2434 NdbRecAttr
* balanceRec
= pOp
->getValue("BALANCE");
2435 if( balanceRec
==NULL
) {
2436 ERR(pScanTrans
->getNdbError());
2437 m_ndb
.closeTransaction(pScanTrans
);
2441 check
= pScanTrans
->execute(NoCommit
);
2443 ERR(pScanTrans
->getNdbError());
2444 m_ndb
.closeTransaction(pScanTrans
);
2448 NdbConnection
* pTrans
= m_ndb
.startTransaction();
2449 if (pTrans
== NULL
) {
2450 ERR(m_ndb
.getNdbError());
2451 m_ndb
.closeTransaction(pScanTrans
);
2456 eof
= pOp
->nextResult();
2459 Uint32 b
= balanceRec
->u_32_value();
2464 // ndbout << numAccounts << ": balance =" << b
2465 // << ", sum="<< sumAccounts << endl;
2467 // Take over the operation so that the lock is kept in db
2468 NdbOperation
* pLockOp
= pOp
->updateCurrentTuple(pTrans
);
2469 if (pLockOp
== NULL
){
2470 ERR(m_ndb
.getNdbError());
2471 m_ndb
.closeTransaction(pScanTrans
);
2472 m_ndb
.closeTransaction(pTrans
);
2476 Uint32 illegalBalance
= 99;
2477 check
= pLockOp
->setValue("BALANCE", illegalBalance
);
2479 ERR(pTrans
->getNdbError());
2480 m_ndb
.closeTransaction(pTrans
);
2481 m_ndb
.closeTransaction(pScanTrans
);
2485 // Execute transaction
2486 check
= pTrans
->execute(NoCommit
);
2488 ERR(pTrans
->getNdbError());
2489 m_ndb
.closeTransaction(pScanTrans
);
2490 m_ndb
.closeTransaction(pTrans
);
2494 eof
= pOp
->nextResult();
2497 ERR(pScanTrans
->getNdbError());
2498 m_ndb
.closeTransaction(pScanTrans
);
2499 m_ndb
.closeTransaction(pTrans
);
2503 // TODO Forget about rolling back, just close pTrans!!
2505 // Rollback transaction
2506 check
= pTrans
->execute(Rollback
);
2508 ERR(pTrans
->getNdbError());
2509 m_ndb
.closeTransaction(pScanTrans
);
2510 m_ndb
.closeTransaction(pTrans
);
2514 m_ndb
.closeTransaction(pScanTrans
);
2515 m_ndb
.closeTransaction(pTrans
);