📄 bank.cpp
字号:
/* Copyright (C) 2003 MySQL AB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */#include "Bank.hpp"#include <time.h>#include <NdbSleep.h>#include <UtilTransactions.hpp>Bank::Bank(Ndb_cluster_connection& con, bool _init): m_ndb(&con, "BANK"), m_maxAccount(-1), m_initialized(false){ if(_init) init();}int Bank::init(){ if (m_initialized == true) return NDBT_OK; myRandom48Init(NdbTick_CurrentMillisecond()); m_ndb.init(); if (m_ndb.waitUntilReady(30) != 0) { ndbout << "Ndb not ready" << endl; return NDBT_FAILED; } if (getNumAccounts() != NDBT_OK) return NDBT_FAILED; m_initialized = true; return NDBT_OK;}int Bank::performTransactions(int maxSleepBetweenTrans, int yield){ int transactions = 0; while(performTransaction() == NDBT_OK) { transactions++; if (maxSleepBetweenTrans > 0){ int val = myRandom48(maxSleepBetweenTrans); NdbSleep_MilliSleep(val); } if((transactions % 100) == 0) g_info << transactions << endl; if (yield != 0 && transactions >= yield) return NDBT_OK; } return NDBT_FAILED;}int Bank::performTransaction(){ int result = NDBT_OK; if (m_maxAccount <= 0){ g_err << "No accounts in bank" << endl; return NDBT_FAILED; } int fromAccount = myRandom48(m_maxAccount); int toAccount = myRandom48(m_maxAccount); if (fromAccount == toAccount){ // Increase toAccount with 1 toAccount = (toAccount+1)%m_maxAccount; } int maxAmount = getMaxAmount(); int amount = myRandom48(maxAmount);retry_transaction: int res = performTransaction(fromAccount, toAccount, amount); if (res != 0){ switch (res){ case NDBT_FAILED: g_err << "performTransaction returned NDBT_FAILED" << endl << " fromAccount = " << fromAccount << endl << " toAccount = " << toAccount << endl << " amount = " << amount << endl; result = NDBT_FAILED; break; case NOT_ENOUGH_FUNDS: // ndbout << "performTransaction returned NOT_ENOUGH_FUNDS" << endl; break; case NDBT_TEMPORARY: g_err << "TEMPORARY_ERRROR retrying" << endl; goto retry_transaction; break; default: g_info << "performTransaction returned "<<res << endl; break; } } return result;}/** * Perform a transaction in the bank. * Ie. transfer money from one account to another. * * @param * @return 0 if successful or an error code */int Bank::performTransaction(int fromAccountId, int toAccountId, int amount ){ /** * 1. Start transaction * 2. Check balance on from account, if there is * not enough funds abort transaction * 3. Update ACCOUNT set balance = balance - amount on * from account * 4. Insert withdrawal in TRANSACTION * 5. Insert deposit in transaction * 6. Update ACCOUNT set balance = balance + amount on * to account * 7. Commit transaction */ // g_info << "performTransaction " << fromAccountId // << ", "<<toAccountId<<", "<<amount << endl; // Call the first implementation of this trans // In the future we can have several different versions of this trans // and call them randomly return performTransactionImpl1(fromAccountId, toAccountId, amount); }int Bank::performTransactionImpl1(int fromAccountId, int toAccountId, int amount ){ int check; // Ok, all clear to do the transaction Uint64 transId; int result = NDBT_OK; if ((result= getNextTransactionId(transId)) != NDBT_OK){ return result; } NdbConnection* pTrans = m_ndb.startTransaction(); if( pTrans == NULL ) { const NdbError err = m_ndb.getNdbError(); if (err.status == NdbError::TemporaryError){ ERR(err); return NDBT_TEMPORARY; } ERR(err); return NDBT_FAILED; } Uint64 currTime; if (prepareGetCurrTimeOp(pTrans, currTime) != NDBT_OK){ ERR(pTrans->getNdbError()); m_ndb.closeTransaction(pTrans); return NDBT_FAILED; } /** * Check balance on from account */ NdbOperation* pOp = pTrans->getNdbOperation("ACCOUNT"); if (pOp == NULL) { ERR(pTrans->getNdbError()); m_ndb.closeTransaction(pTrans); return NDBT_FAILED; } check = pOp->readTupleExclusive(); if( check == -1 ) { ERR(pTrans->getNdbError()); m_ndb.closeTransaction(pTrans); return NDBT_FAILED; } check = pOp->equal("ACCOUNT_ID", fromAccountId); if( check == -1 ) { ERR(pTrans->getNdbError()); m_ndb.closeTransaction(pTrans); return NDBT_FAILED; } NdbRecAttr* balanceFromRec = pOp->getValue("BALANCE"); if( balanceFromRec ==NULL ) { ERR(pTrans->getNdbError()); m_ndb.closeTransaction(pTrans); return NDBT_FAILED; } NdbRecAttr* fromAccountTypeRec = pOp->getValue("ACCOUNT_TYPE"); if( fromAccountTypeRec == NULL ) { ERR(pTrans->getNdbError()); m_ndb.closeTransaction(pTrans); return NDBT_FAILED; } /** * Read balance on to account */ NdbOperation* pOp6 = pTrans->getNdbOperation("ACCOUNT"); if (pOp6 == NULL) { ERR(pTrans->getNdbError()); m_ndb.closeTransaction(pTrans); return NDBT_FAILED; } check = pOp6->readTupleExclusive(); if( check == -1 ) { ERR(pTrans->getNdbError()); m_ndb.closeTransaction(pTrans); return NDBT_FAILED; } check = pOp6->equal("ACCOUNT_ID", toAccountId); if( check == -1 ) { ERR(pTrans->getNdbError()); m_ndb.closeTransaction(pTrans); return NDBT_FAILED; } NdbRecAttr* balanceToRec = pOp6->getValue("BALANCE"); if( balanceToRec == NULL ) { ERR(pTrans->getNdbError()); m_ndb.closeTransaction(pTrans); return NDBT_FAILED; } NdbRecAttr* toAccountTypeRec = pOp6->getValue("ACCOUNT_TYPE"); if( toAccountTypeRec == NULL ) { ERR(pTrans->getNdbError()); m_ndb.closeTransaction(pTrans); return NDBT_FAILED; } check = pTrans->execute(NoCommit); if( check == -1 ) { const NdbError err = pTrans->getNdbError(); m_ndb.closeTransaction(pTrans); if (err.status == NdbError::TemporaryError){ ERR(err); return NDBT_TEMPORARY; } ERR(err); return NDBT_FAILED; } Uint32 balanceFrom = balanceFromRec->u_32_value(); // ndbout << "balanceFrom: " << balanceFrom << endl; if (((Int64)balanceFrom - amount) < 0){ m_ndb.closeTransaction(pTrans); //ndbout << "Not enough funds" << endl; return NOT_ENOUGH_FUNDS; } Uint32 fromAccountType = fromAccountTypeRec->u_32_value(); Uint32 balanceTo = balanceToRec->u_32_value(); // ndbout << "balanceTo: " << balanceTo << endl; Uint32 toAccountType = toAccountTypeRec->u_32_value(); /** * Update balance on from account */ NdbOperation* pOp2 = pTrans->getNdbOperation("ACCOUNT"); if (pOp2 == NULL) { ERR(pTrans->getNdbError()); m_ndb.closeTransaction(pTrans); return NDBT_FAILED; } check = pOp2->updateTuple(); if( check == -1 ) { ERR(pTrans->getNdbError()); m_ndb.closeTransaction(pTrans); return NDBT_FAILED; } check = pOp2->equal("ACCOUNT_ID", fromAccountId); if( check == -1 ) { ERR(pTrans->getNdbError()); m_ndb.closeTransaction(pTrans); return NDBT_FAILED; } check = pOp2->setValue("BALANCE", balanceFrom - amount); if( check == -1 ) { ERR(pTrans->getNdbError()); m_ndb.closeTransaction(pTrans); return NDBT_FAILED; } /** * Update balance on to account */ NdbOperation* pOp3 = pTrans->getNdbOperation("ACCOUNT"); if (pOp3 == NULL) { ERR(pTrans->getNdbError()); m_ndb.closeTransaction(pTrans); return NDBT_FAILED; } check = pOp3->updateTuple(); if( check == -1 ) { ERR(pTrans->getNdbError()); m_ndb.closeTransaction(pTrans); return NDBT_FAILED; } check = pOp3->equal("ACCOUNT_ID", toAccountId); if( check == -1 ) { ERR(pTrans->getNdbError()); m_ndb.closeTransaction(pTrans); return NDBT_FAILED; } check = pOp3->setValue("BALANCE", balanceTo + amount); if( check == -1 ) { ERR(pTrans->getNdbError()); m_ndb.closeTransaction(pTrans); return NDBT_FAILED; } /** * Insert withdrawal transaction */ NdbOperation* pOp4 = pTrans->getNdbOperation("TRANSACTION"); if (pOp4 == NULL) { ERR(pTrans->getNdbError()); m_ndb.closeTransaction(pTrans); return NDBT_FAILED; } check = pOp4->insertTuple(); if( check == -1 ) { ERR(pTrans->getNdbError()); m_ndb.closeTransaction(pTrans); return NDBT_FAILED; } check = pOp4->equal("TRANSACTION_ID", transId); if( check == -1 ) { ERR(pTrans->getNdbError()); m_ndb.closeTransaction(pTrans); return NDBT_FAILED; } check = pOp4->equal("ACCOUNT", fromAccountId); if( check == -1 ) { ERR(pTrans->getNdbError()); m_ndb.closeTransaction(pTrans); return NDBT_FAILED; } check = pOp4->setValue("ACCOUNT_TYPE", fromAccountType); if( check == -1 ) { ERR(pTrans->getNdbError()); m_ndb.closeTransaction(pTrans); return NDBT_FAILED; } check = pOp4->setValue("OTHER_ACCOUNT", toAccountId); if( check == -1 ) { ERR(pTrans->getNdbError()); m_ndb.closeTransaction(pTrans); return NDBT_FAILED; } check = pOp4->setValue("TRANSACTION_TYPE", WithDrawal); if( check == -1 ) { ERR(pTrans->getNdbError()); m_ndb.closeTransaction(pTrans); return NDBT_FAILED; } check = pOp4->setValue("TIME", currTime); if( check == -1 ) { ERR(pTrans->getNdbError()); m_ndb.closeTransaction(pTrans); return NDBT_FAILED; } check = pOp4->setValue("AMOUNT", amount); if( check == -1 ) { ERR(pTrans->getNdbError()); m_ndb.closeTransaction(pTrans); return NDBT_FAILED; } /** * Insert deposit transaction */ NdbOperation* pOp5 = pTrans->getNdbOperation("TRANSACTION"); if (pOp5 == NULL) { ERR(pTrans->getNdbError()); m_ndb.closeTransaction(pTrans); return NDBT_FAILED; } check = pOp5->insertTuple(); if( check == -1 ) { ERR(pTrans->getNdbError()); m_ndb.closeTransaction(pTrans); return NDBT_FAILED; } check = pOp5->equal("TRANSACTION_ID", transId); if( check == -1 ) { ERR(pTrans->getNdbError()); m_ndb.closeTransaction(pTrans); return NDBT_FAILED; } check = pOp5->equal("ACCOUNT", toAccountId); if( check == -1 ) { ERR(pTrans->getNdbError()); m_ndb.closeTransaction(pTrans); return NDBT_FAILED; } check = pOp5->setValue("ACCOUNT_TYPE", toAccountType); if( check == -1 ) { ERR(pTrans->getNdbError()); m_ndb.closeTransaction(pTrans); return NDBT_FAILED; } check = pOp5->setValue("OTHER_ACCOUNT", fromAccountId); if( check == -1 ) { ERR(pTrans->getNdbError()); m_ndb.closeTransaction(pTrans); return NDBT_FAILED; } check = pOp5->setValue("TRANSACTION_TYPE", Deposit); if( check == -1 ) { ERR(pTrans->getNdbError()); m_ndb.closeTransaction(pTrans); return NDBT_FAILED; } check = pOp5->setValue("TIME", currTime); if( check == -1 ) { ERR(pTrans->getNdbError()); m_ndb.closeTransaction(pTrans); return NDBT_FAILED; } check = pOp5->setValue("AMOUNT", amount); if( check == -1 ) { ERR(pTrans->getNdbError()); m_ndb.closeTransaction(pTrans); return NDBT_FAILED; } check = pTrans->execute(Commit); if( check == -1 ) { const NdbError err = pTrans->getNdbError(); m_ndb.closeTransaction(pTrans); if (err.status == NdbError::TemporaryError){ ERR(err); return NDBT_TEMPORARY; } ERR(err); return NDBT_FAILED; } m_ndb.closeTransaction(pTrans); return NDBT_OK; } int Bank::performMakeGLs(int yield){ int result; int counter, maxCounter; int yieldCounter = 0; while (1){ // Counters to keep tracck of how many // GLs should be made before performing a validation counter = 0; maxCounter = 50 + myRandom48(100); /** * Validate GLs and Transactions for previous days * */ result = performValidateGLs(); if (result != NDBT_OK){ if (result == VERIFICATION_FAILED){ g_err << "performValidateGLs verification failed" << endl; return NDBT_FAILED; } g_info << "performValidateGLs failed" << endl; return NDBT_FAILED; continue; } result = performValidatePurged(); if (result != NDBT_OK){ if (result == VERIFICATION_FAILED){ g_err << "performValidatePurged verification failed" << endl; return NDBT_FAILED; } g_info << "performValidatePurged failed" << endl; return NDBT_FAILED; } while (1){ yieldCounter++; if (yield != 0 && yieldCounter >= yield) return NDBT_OK; /** * Find last GL time. * ( GL record with highest time value) */ Uint64 lastGLTime; if (findLastGL(lastGLTime) != NDBT_OK){ g_info << "findLastGL failed" << endl; // Break out of inner while loop break; } lastGLTime++; /** * If last GL time + 1 is smaller than current time * perform a GL for that time */ Uint64 currTime; if (getCurrTime(currTime) != NDBT_OK){ g_info << "getCurrTime failed" << endl; // Break out of inner while loop break; } if (lastGLTime < currTime){ counter++; if (performMakeGL(lastGLTime) != NDBT_OK){ g_info << "performMakeGL failed" << endl; // Break out of inner while loop break; } if (counter > maxCounter){ // Break out of inner while loop and // validatePreviousGLs g_info << "counter("<<counter<<") > maxCounter("<<maxCounter<<")" << endl; break; } } else { ;//ndbout << "It's not time to make GL yet" << endl; // ndbout << "Sleeping 1 second" << endl; NdbSleep_SecSleep(1); } Uint32 age = 3; if (purgeOldGLTransactions(currTime, age) != NDBT_OK){ g_info << "purgeOldGLTransactions failed" << endl; // Break out of inner while loop break; } } } return NDBT_FAILED; }int Bank::performValidateAllGLs(){ int result; while (1){ /** * Validate GLs and Transactions for previous days * Set age so that ALL GL's are validated */ int age = 100000; result = performValidateGLs(age); if (result != NDBT_OK){ if (result == VERIFICATION_FAILED){
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -