mirror of
https://github.com/MariaDB/server.git
synced 2025-01-19 05:22:25 +01:00
47c877bdf8
ndb/examples/ndbapi_async_example/ndbapi_async.cpp: ndb_init() ndb/examples/ndbapi_example1/ndbapi_example1.cpp: ndb_init() ndb/examples/ndbapi_example2/ndbapi_example2.cpp: ndb_init() ndb/examples/ndbapi_example3/ndbapi_example3.cpp: ndb_init() ndb/examples/ndbapi_example4/ndbapi_example4.cpp: ndb_init() ndb/examples/ndbapi_example5/ndbapi_example5.cpp: ndb_init() ndb/examples/ndbapi_scan_example/ndbapi_scan.cpp: ndb_init() ndb/examples/select_all/select_all.cpp: ndb_init() ndb/include/ndb_global.h: ndb_init() ndb/src/common/util/Makefile.am: ndb_init() ndb/src/kernel/blocks/backup/read.cpp: ndb_init() ndb/src/kernel/blocks/backup/restore/main.cpp: ndb_init() ndb/src/kernel/main.cpp: ndb_init() ndb/src/kernel/vm/Configuration.cpp: ndb_init() ndb/src/mgmclient/main.cpp: ndb_init() ndb/src/mgmsrv/main.cpp: ndb_init() ndb/src/mgmsrv/mkconfig/mkconfig.cpp: ndb_init() ndb/src/ndbapi/Ndbinit.cpp: ndb_init() ndb/test/ndbapi/acid.cpp: ndb_init() ndb/test/ndbapi/acid2.cpp: ndb_init() ndb/test/ndbapi/benchronja.cpp: ndb_init() ndb/test/ndbapi/bulk_copy.cpp: ndb_init() ndb/test/ndbapi/cdrserver.cpp: ndb_init() ndb/test/ndbapi/celloDb.cpp: ndb_init() ndb/test/ndbapi/create_all_tabs.cpp: ndb_init() ndb/test/ndbapi/create_tab.cpp: ndb_init() ndb/test/ndbapi/drop_all_tabs.cpp: ndb_init() ndb/test/ndbapi/flexAsynch.cpp: ndb_init() ndb/test/ndbapi/flexBench.cpp: ndb_init() ndb/test/ndbapi/flexHammer.cpp: ndb_init() ndb/test/ndbapi/flexScan.cpp: ndb_init() ndb/test/ndbapi/flexTT.cpp: ndb_init() ndb/test/ndbapi/flexTimedAsynch.cpp: ndb_init() ndb/test/ndbapi/flex_bench_mysql.cpp: ndb_init() ndb/test/ndbapi/index.cpp: ndb_init() ndb/test/ndbapi/index2.cpp: ndb_init() ndb/test/ndbapi/initronja.cpp: ndb_init() ndb/test/ndbapi/interpreterInTup.cpp: ndb_init() ndb/test/ndbapi/mainAsyncGenerator.cpp: ndb_init() ndb/test/ndbapi/msa.cpp: ndb_init() ndb/test/ndbapi/restarter.cpp: ndb_init() ndb/test/ndbapi/restarter2.cpp: ndb_init() ndb/test/ndbapi/restarts.cpp: ndb_init() ndb/test/ndbapi/size.cpp: ndb_init() ndb/test/ndbapi/slow_select.cpp: ndb_init() ndb/test/ndbapi/testBackup.cpp: ndb_init() ndb/test/ndbapi/testBasic.cpp: ndb_init() ndb/test/ndbapi/testBasicAsynch.cpp: ndb_init() ndb/test/ndbapi/testBlobs.cpp: ndb_init() ndb/test/ndbapi/testDataBuffers.cpp: ndb_init() ndb/test/ndbapi/testDeadlock.cpp: ndb_init() ndb/test/ndbapi/testDict.cpp: ndb_init() ndb/test/ndbapi/testGrep.cpp: ndb_init() ndb/test/ndbapi/testGrepVerify.cpp: ndb_init() ndb/test/ndbapi/testIndex.cpp: ndb_init() ndb/test/ndbapi/testInterpreter.cpp: ndb_init() ndb/test/ndbapi/testMgm.cpp: ndb_init() ndb/test/ndbapi/bank/bankCreator.cpp: ndb_init() ndb/test/ndbapi/bank/bankMakeGL.cpp: ndb_init() ndb/test/ndbapi/bank/bankSumAccounts.cpp: ndb_init() ndb/test/ndbapi/bank/bankTimer.cpp: ndb_init() ndb/test/ndbapi/bank/bankTransactionMaker.cpp: ndb_init() ndb/test/ndbapi/bank/bankValidateAllGLs.cpp: ndb_init() ndb/test/ndbapi/bank/testBank.cpp: ndb_init() ndb/test/ndbapi/testNdbApi.cpp: ndb_init() ndb/test/ndbapi/testNodeRestart.cpp: ndb_init() ndb/test/ndbapi/testOIBasic.cpp: ndb_init() ndb/test/ndbapi/testOperations.cpp: ndb_init() ndb/test/ndbapi/testOrderedIndex.cpp: ndb_init() ndb/test/ndbapi/testReadPerf.cpp: ndb_init() ndb/test/ndbapi/testRestartGci.cpp: ndb_init() ndb/test/ndbapi/testScan.cpp: ndb_init() ndb/test/ndbapi/testScanInterpreter.cpp: ndb_init() ndb/test/ndbapi/testScanPerf.cpp: ndb_init() ndb/test/ndbapi/testSystemRestart.cpp: ndb_init() ndb/test/ndbapi/testTimeout.cpp: ndb_init() ndb/test/ndbapi/testTransactions.cpp: ndb_init() ndb/test/ndbapi/test_event.cpp: ndb_init() ndb/test/run-test/main.cpp: ndb_init() ndb/test/src/NDBT_Test.cpp: ndb_init() ndb/test/tools/copy_tab.cpp: ndb_init() ndb/test/tools/cpcc.cpp: ndb_init() ndb/test/tools/create_index.cpp: ndb_init() ndb/test/tools/hugoCalculator.cpp: ndb_init() ndb/test/tools/hugoFill.cpp: ndb_init() ndb/test/tools/hugoLoad.cpp: ndb_init() ndb/test/tools/hugoLockRecords.cpp: ndb_init() ndb/test/tools/hugoPkDelete.cpp: ndb_init() ndb/test/tools/hugoPkRead.cpp: ndb_init() ndb/test/tools/hugoPkReadRecord.cpp: ndb_init() ndb/test/tools/hugoPkUpdate.cpp: ndb_init() ndb/test/tools/hugoScanRead.cpp: ndb_init() ndb/test/tools/hugoScanUpdate.cpp: ndb_init() ndb/test/tools/restart.cpp: ndb_init() ndb/test/tools/transproxy.cpp: ndb_init() ndb/test/tools/verify_index.cpp: ndb_init() ndb/tools/delete_all.cpp: ndb_init() ndb/tools/desc.cpp: ndb_init() ndb/tools/drop_index.cpp: ndb_init() ndb/tools/drop_tab.cpp: ndb_init() ndb/tools/listTables.cpp: ndb_init() ndb/tools/ndbsql.cpp: ndb_init() ndb/tools/select_all.cpp: ndb_init() ndb/tools/select_count.cpp: ndb_init() ndb/tools/waiter.cpp: ndb_init()
1206 lines
36 KiB
C++
1206 lines
36 KiB
C++
/* 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 <ndb_global.h>
|
|
|
|
#include <NdbApi.hpp>
|
|
#include <NdbSchemaCon.hpp>
|
|
#include <NdbCondition.h>
|
|
#include <NdbMutex.h>
|
|
#include <NdbSleep.h>
|
|
#include <NdbThread.h>
|
|
#include <NdbTick.h>
|
|
|
|
const char* const c_szDatabaseName = "TEST_DB";
|
|
|
|
const char* const c_szTableNameStored = "CCStored";
|
|
const char* const c_szTableNameTemp = "CCTemp";
|
|
|
|
const char* const c_szContextId = "ContextId";
|
|
const char* const c_szVersion = "Version";
|
|
const char* const c_szLockFlag = "LockFlag";
|
|
const char* const c_szLockTime = "LockTime";
|
|
const char* const c_szLockTimeUSec = "LockTimeUSec";
|
|
const char* const c_szContextData = "ContextData";
|
|
|
|
const char* g_szTableName = c_szTableNameStored;
|
|
|
|
|
|
#ifdef NDB_WIN32
|
|
HANDLE hShutdownEvent = 0;
|
|
#else
|
|
#include <signal.h>
|
|
bool bShutdownEvent = false;
|
|
#endif
|
|
long g_nMaxContextIdPerThread = 5000;
|
|
long g_nNumThreads = 0;
|
|
long g_nMaxCallsPerSecond = 0;
|
|
long g_nMaxRetry = 50;
|
|
bool g_bWriteTuple = false;
|
|
bool g_bInsertInitial = false;
|
|
bool g_bVerifyInitial = false;
|
|
|
|
NdbMutex* g_pNdbMutexPrintf = 0;
|
|
NdbMutex* g_pNdbMutexIncrement = 0;
|
|
long g_nNumCallsProcessed = 0;
|
|
NDB_TICKS g_tStartTime = 0;
|
|
NDB_TICKS g_tEndTime = 0;
|
|
|
|
long g_nNumberOfInitialInsert = 0;
|
|
long g_nNumberOfInitialVerify = 0;
|
|
|
|
const long c_nMaxMillisecForAllCall = 5000;
|
|
long* g_plCountMillisecForCall = 0;
|
|
const long c_nMaxMillisecForAllTrans = 5000;
|
|
long* g_plCountMillisecForTrans = 0;
|
|
bool g_bReport = false;
|
|
bool g_bReportPlus = false;
|
|
|
|
|
|
// data for CALL_CONTEXT and GROUP_RESOURCE
|
|
static char STATUS_DATA[]=
|
|
"000102030405060708090A0B0C0D0E0F000102030405060708090A0B0C0D0E0F"
|
|
"101112131415161718191A1B1C1D1E1F000102030405060708090A0B0C0D0E0F"
|
|
"202122232425262728292A2B2C2D2E2F000102030405060708090A0B0C0D0E0F"
|
|
"303132333435363738393A3B3C3D3E3F000102030405060708090A0B0C0D0E0F"
|
|
"404142434445464748494A4B4C4D4E4F000102030405060708090A0B0C0D0E0F"
|
|
"505152535455565758595A5B5C5D5E5F000102030405060708090A0B0C0D0E0F"
|
|
"606162636465666768696A6B6C6D6E6F000102030405060708090A0B0C0D0E0F"
|
|
"707172737475767778797A7B7C7D7E7F000102030405060708090A0B0C0D0E0F"
|
|
"808182838485868788898A8B8C8D8E8F000102030405060708090A0B0C0D0E0F"
|
|
"909192939495969798999A9B9C9D9E9F000102030405060708090A0B0C0D0E0F"
|
|
"10010110210310410510610710810910A000102030405060708090A0B0C0D0EF"
|
|
"10B10C10D10E10F110111112113114115000102030405060708090A0B0C0D0EF"
|
|
"11611711811911A11B11C11D11E11F120000102030405060708090A0B0C0D0EF"
|
|
"12112212312412512612712812912A12B000102030405060708090A0B0C0D0EF"
|
|
"12C12D12E12F130131132134135136137000102030405060708090A0B0C0D0EF"
|
|
"13813913A13B13C13D13E13F140141142000102030405060708090A0B0C0D0EF"
|
|
"14314414514614714814914A14B14C14D000102030405060708090A0B0C0D0EF"
|
|
"14E14F150151152153154155156157158000102030405060708090A0B0C0D0EF"
|
|
"15915A15B15C15D15E15F160161162163000102030405060708090A0B0C0D0EF"
|
|
"16416516616716816916A16B16C16D16E000102030405060708090A0B0C0D0EF"
|
|
"16F170171172173174175176177178179000102030405060708090A0B0C0D0EF"
|
|
"17A17B17C17D17E17F180181182183184000102030405060708090A0B0C0D0EF"
|
|
"18518618718818918A18B18C18D18E18F000102030405060708090A0B0C0D0EF"
|
|
"19019119219319419519619719819919A000102030405060708090A0B0C0D0EF"
|
|
"19B19C19D19E19F200201202203204205000102030405060708090A0B0C0D0EF"
|
|
"20620720820920A20B20C20D20F210211000102030405060708090A0B0C0D0EF"
|
|
"21221321421521621721821921A21B21C000102030405060708090A0B0C0D0EF"
|
|
"21D21E21F220221222223224225226227000102030405060708090A0B0C0D0EF"
|
|
"22822922A22B22C22D22E22F230231232000102030405060708090A0B0C0D0EF"
|
|
"23323423523623723823923A23B23C23D000102030405060708090A0B0C0D0EF"
|
|
"23E23F240241242243244245246247248000102030405060708090A0B0C0D0EF"
|
|
"24924A24B24C24D24E24F250251252253000102030405060708090A0B0C0D0EF"
|
|
"101112131415161718191A1B1C1D1E1F000102030405060708090A0B0C0D0E0F"
|
|
"202122232425262728292A2B2C2D2E2F000102030405060708090A0B0C0D0E0F"
|
|
"303132333435363738393A3B3C3D3E3F000102030405060708090A0B0C0D0E0F"
|
|
"404142434445464748494A4B4C4D4E4F000102030405060708090A0B0C0D0E0F"
|
|
"505152535455565758595A5B5C5D5E5F000102030405060708090A0B0C0D0E0F"
|
|
"606162636465666768696A6B6C6D6E6F000102030405060708090A0B0C0D0E0F"
|
|
"707172737475767778797A7B7C7D7E7F000102030405060708090A0B0C0D0E0F"
|
|
"808182838485868788898A8B8C8D8E8F000102030405060708090A0B0C0D0E0F"
|
|
"909192939495969798999A9B9C9D9E9F000102030405060708090A0B0C0D0E0F"
|
|
"10010110210310410510610710810910A000102030405060708090A0B0C0D0EF"
|
|
"10B10C10D10E10F110111112113114115000102030405060708090A0B0C0D0EF"
|
|
"11611711811911A11B11C11D11E11F120000102030405060708090A0B0C0D0EF"
|
|
"12112212312412512612712812912A12B000102030405060708090A0B0C0D0EF"
|
|
"12C12D12E12F130131132134135136137000102030405060708090A0B0C0D0EF"
|
|
"13813913A13B13C13D13E13F140141142000102030405060708090A0B0C0D0EF"
|
|
"14314414514614714814914A14B14C14D000102030405060708090A0B0C0D0EF"
|
|
"14E14F150151152153154155156157158000102030405060708090A0B0C0D0EF"
|
|
"15915A15B15C15D15E15F160161162163000102030405060708090A0B0C0D0EF"
|
|
"16416516616716816916A16B16C16D16E000102030405060708090A0B0C0D0EF"
|
|
"16F170171172173174175176177178179000102030405060708090A0B0C0D0EF"
|
|
"17A17B17C17D17E17F180181182183184000102030405060708090A0B0C0D0EF"
|
|
"18518618718818918A18B18C18D18E18F000102030405060708090A0B0C0D0EF"
|
|
"19019119219319419519619719819919A000102030405060708090A0B0C0D0EF"
|
|
"19B19C19D19E19F200201202203204205000102030405060708090A0B0C0D0EF"
|
|
"20620720820920A20B20C20D20F210211000102030405060708090A0B0C0D0EF"
|
|
"21221321421521621721821921A21B21C000102030405060708090A0B0C0D0EF"
|
|
"21D21E21F220221222223224225226227000102030405060708090A0B0C0D0EF"
|
|
"22822922A22B22C22D22E22F230231232000102030405060708090A0B0C0D0EF"
|
|
"23323423523623723823923A23B23C23D000102030405060708090A0B0C0D0EF"
|
|
"2366890FE1438751097E7F6325DC0E6326F"
|
|
"25425525625725825925A25B25C25D25E25F000102030405060708090A0B0C0F";
|
|
|
|
long g_nStatusDataSize = sizeof(STATUS_DATA);
|
|
|
|
|
|
// Thread function for Call Context Inserts
|
|
|
|
|
|
#ifdef NDB_WIN32
|
|
|
|
BOOL WINAPI ConsoleCtrlHandler(DWORD dwCtrlType)
|
|
{
|
|
if(CTRL_C_EVENT == dwCtrlType)
|
|
{
|
|
SetEvent(hShutdownEvent);
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
#else
|
|
|
|
void CtrlCHandler(int)
|
|
{
|
|
bShutdownEvent = true;
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
void ReportNdbError(const char* szMsg, const NdbError& err)
|
|
{
|
|
NdbMutex_Lock(g_pNdbMutexPrintf);
|
|
printf("%s: %d: %s\n", szMsg, err.code, (err.message ? err.message : ""));
|
|
NdbMutex_Unlock(g_pNdbMutexPrintf);
|
|
}
|
|
|
|
|
|
void
|
|
ReportCallsPerSecond(long nNumCallsProcessed,
|
|
NDB_TICKS tStartTime,
|
|
NDB_TICKS tEndTime)
|
|
{
|
|
NDB_TICKS tElapsed = tEndTime - tStartTime;
|
|
long lCallsPerSec;
|
|
if(tElapsed>0)
|
|
lCallsPerSec = (long)((1000*nNumCallsProcessed)/tElapsed);
|
|
else
|
|
lCallsPerSec = 0;
|
|
|
|
NdbMutex_Lock(g_pNdbMutexPrintf);
|
|
printf("Time Taken for %ld Calls is %ld msec (= %ld calls/sec)\n",
|
|
nNumCallsProcessed, (long)tElapsed, lCallsPerSec);
|
|
NdbMutex_Unlock(g_pNdbMutexPrintf);
|
|
}
|
|
|
|
|
|
#ifndef NDB_WIN32
|
|
void InterlockedIncrement(long* lp) // expensive
|
|
{
|
|
NdbMutex_Lock(g_pNdbMutexIncrement);
|
|
(*lp)++;
|
|
NdbMutex_Unlock(g_pNdbMutexIncrement);
|
|
}
|
|
#endif
|
|
|
|
|
|
void InterlockedIncrementAndReport(void)
|
|
{
|
|
NdbMutex_Lock(g_pNdbMutexIncrement);
|
|
++g_nNumCallsProcessed;
|
|
if((g_nNumCallsProcessed%1000)==0)
|
|
{
|
|
g_tEndTime = NdbTick_CurrentMillisecond();
|
|
if(g_tStartTime)
|
|
ReportCallsPerSecond(1000, g_tStartTime, g_tEndTime);
|
|
|
|
g_tStartTime = g_tEndTime;
|
|
}
|
|
NdbMutex_Unlock(g_pNdbMutexIncrement);
|
|
}
|
|
|
|
|
|
void SleepOneCall(void)
|
|
{
|
|
int iMillisecToSleep;
|
|
if(g_nMaxCallsPerSecond>0)
|
|
iMillisecToSleep = (1000*g_nNumThreads)/g_nMaxCallsPerSecond;
|
|
else
|
|
iMillisecToSleep = 50;
|
|
|
|
if(iMillisecToSleep>0)
|
|
NdbSleep_MilliSleep(iMillisecToSleep);
|
|
|
|
}
|
|
|
|
|
|
|
|
int QueryTransaction(Ndb* pNdb,
|
|
long iContextId,
|
|
long* piVersion,
|
|
long* piLockFlag,
|
|
long* piLockTime,
|
|
long* piLockTimeUSec,
|
|
char* pchContextData,
|
|
NdbError& err)
|
|
{
|
|
int iRes = -1;
|
|
NdbConnection* pNdbConnection = pNdb->startTransaction(0, (const char*)&iContextId, 4);
|
|
if(pNdbConnection)
|
|
{
|
|
NdbOperation* pNdbOperation = pNdbConnection->getNdbOperation(g_szTableName);
|
|
if(pNdbOperation)
|
|
{
|
|
NdbRecAttr* pNdbRecAttrVersion;
|
|
NdbRecAttr* pNdbRecAttrLockFlag;
|
|
NdbRecAttr* pNdbRecAttrLockTime;
|
|
NdbRecAttr* pNdbRecAttrLockTimeUSec;
|
|
NdbRecAttr* pNdbRecAttrContextData;
|
|
if(!pNdbOperation->readTuple()
|
|
&& !pNdbOperation->equal(c_szContextId, (Int32)iContextId)
|
|
&& (pNdbRecAttrVersion=pNdbOperation->getValue(c_szVersion, (char*)piVersion))
|
|
&& (pNdbRecAttrLockFlag=pNdbOperation->getValue(c_szLockFlag, (char*)piLockFlag))
|
|
&& (pNdbRecAttrLockTime=pNdbOperation->getValue(c_szLockTime, (char*)piLockTime))
|
|
&& (pNdbRecAttrLockTimeUSec=pNdbOperation->getValue(c_szLockTimeUSec, (char*)piLockTimeUSec))
|
|
&& (pNdbRecAttrContextData=pNdbOperation->getValue(c_szContextData, pchContextData)))
|
|
{
|
|
if(!pNdbConnection->execute(Commit))
|
|
iRes = 0;
|
|
else
|
|
err = pNdbConnection->getNdbError();
|
|
}
|
|
else
|
|
err = pNdbOperation->getNdbError();
|
|
}
|
|
else
|
|
err = pNdbConnection->getNdbError();
|
|
|
|
pNdb->closeTransaction(pNdbConnection);
|
|
}
|
|
else
|
|
err = pNdb->getNdbError();
|
|
|
|
return iRes;
|
|
}
|
|
|
|
|
|
int RetryQueryTransaction(Ndb* pNdb,
|
|
long iContextId,
|
|
long* piVersion,
|
|
long* piLockFlag,
|
|
long* piLockTime,
|
|
long* piLockTimeUSec,
|
|
char* pchContextData,
|
|
NdbError& err,
|
|
int& nRetry)
|
|
{
|
|
int iRes = -1;
|
|
nRetry = 0;
|
|
bool bRetry = true;
|
|
while(bRetry && nRetry<g_nMaxRetry)
|
|
{
|
|
if(!QueryTransaction(pNdb, iContextId, piVersion, piLockFlag,
|
|
piLockTime, piLockTimeUSec, pchContextData, err))
|
|
{
|
|
iRes = 0;
|
|
bRetry = false;
|
|
}
|
|
else
|
|
{
|
|
switch(err.status)
|
|
{
|
|
case NdbError::TemporaryError:
|
|
case NdbError::UnknownResult:
|
|
SleepOneCall();
|
|
++nRetry;
|
|
break;
|
|
|
|
case NdbError::PermanentError:
|
|
default:
|
|
bRetry = false;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
return iRes;
|
|
}
|
|
|
|
|
|
int DeleteTransaction(Ndb* pNdb, long iContextId, NdbError& err)
|
|
{
|
|
int iRes = -1;
|
|
NdbConnection* pNdbConnection = pNdb->startTransaction(0, (const char*)&iContextId, 4);
|
|
if(pNdbConnection)
|
|
{
|
|
NdbOperation* pNdbOperation = pNdbConnection->getNdbOperation(g_szTableName);
|
|
if(pNdbOperation)
|
|
{
|
|
if(!pNdbOperation->deleteTuple()
|
|
&& !pNdbOperation->equal(c_szContextId, (Int32)iContextId))
|
|
{
|
|
if(pNdbConnection->execute(Commit) == 0)
|
|
iRes = 0;
|
|
else
|
|
err = pNdbConnection->getNdbError();
|
|
}
|
|
else
|
|
err = pNdbOperation->getNdbError();
|
|
}
|
|
else
|
|
err = pNdbConnection->getNdbError();
|
|
|
|
pNdb->closeTransaction(pNdbConnection);
|
|
}
|
|
else
|
|
err = pNdb->getNdbError();
|
|
|
|
return iRes;
|
|
}
|
|
|
|
|
|
|
|
int RetryDeleteTransaction(Ndb* pNdb, long iContextId, NdbError& err, int& nRetry)
|
|
{
|
|
int iRes = -1;
|
|
nRetry = 0;
|
|
bool bRetry = true;
|
|
bool bUnknown = false;
|
|
while(bRetry && nRetry<g_nMaxRetry)
|
|
{
|
|
if(!DeleteTransaction(pNdb, iContextId, err))
|
|
{
|
|
iRes = 0;
|
|
bRetry = false;
|
|
}
|
|
else
|
|
{
|
|
switch(err.status)
|
|
{
|
|
case NdbError::UnknownResult:
|
|
bUnknown = true;
|
|
++nRetry;
|
|
break;
|
|
|
|
case NdbError::TemporaryError:
|
|
bUnknown = false;
|
|
SleepOneCall();
|
|
++nRetry;
|
|
break;
|
|
|
|
case NdbError::PermanentError:
|
|
if(err.code==626 && bUnknown)
|
|
iRes = 0;
|
|
bRetry = false;
|
|
break;
|
|
|
|
default:
|
|
bRetry = false;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
return iRes;
|
|
}
|
|
|
|
|
|
|
|
int InsertTransaction(Ndb* pNdb,
|
|
long iContextID,
|
|
long iVersion,
|
|
long iLockFlag,
|
|
long iLockTime,
|
|
long iLockTimeUSec,
|
|
const char* pchContextData,
|
|
NdbError& err)
|
|
{
|
|
int iRes = -1;
|
|
NdbConnection* pNdbConnection = pNdb->startTransaction(0, (const char*)&iContextID, 4);
|
|
if(pNdbConnection)
|
|
{
|
|
NdbOperation* pNdbOperation = pNdbConnection->getNdbOperation(g_szTableName);
|
|
if(pNdbOperation)
|
|
{
|
|
if(!(g_bWriteTuple ? pNdbOperation->writeTuple() : pNdbOperation->insertTuple())
|
|
&& !pNdbOperation->equal(c_szContextId, (Int32)iContextID)
|
|
&& !pNdbOperation->setValue(c_szVersion, (Int32)iVersion)
|
|
&& !pNdbOperation->setValue(c_szLockFlag, (Int32)iLockFlag)
|
|
&& !pNdbOperation->setValue(c_szLockTime, (Int32)iLockTime)
|
|
&& !pNdbOperation->setValue(c_szLockTimeUSec, (Int32)iLockTimeUSec)
|
|
&& !pNdbOperation->setValue(c_szContextData, pchContextData, g_nStatusDataSize))
|
|
{
|
|
if(!pNdbConnection->execute(Commit))
|
|
iRes = 0;
|
|
else
|
|
err = pNdbConnection->getNdbError();
|
|
}
|
|
else
|
|
err = pNdbOperation->getNdbError();
|
|
}
|
|
else
|
|
err = pNdbConnection->getNdbError();
|
|
|
|
pNdb->closeTransaction(pNdbConnection);
|
|
}
|
|
else
|
|
err = pNdb->getNdbError();
|
|
|
|
return iRes;
|
|
}
|
|
|
|
|
|
|
|
int RetryInsertTransaction(Ndb* pNdb,
|
|
long iContextId,
|
|
long iVersion,
|
|
long iLockFlag,
|
|
long iLockTime,
|
|
long iLockTimeUSec,
|
|
const char* pchContextData,
|
|
NdbError& err, int& nRetry)
|
|
{
|
|
int iRes = -1;
|
|
nRetry = 0;
|
|
bool bRetry = true;
|
|
bool bUnknown = false;
|
|
while(bRetry && nRetry<g_nMaxRetry)
|
|
{
|
|
if(!InsertTransaction(pNdb, iContextId, iVersion, iLockFlag,
|
|
iLockTime, iLockTimeUSec, pchContextData, err))
|
|
{
|
|
iRes = 0;
|
|
bRetry = false;
|
|
}
|
|
else
|
|
{
|
|
switch(err.status)
|
|
{
|
|
case NdbError::UnknownResult:
|
|
bUnknown = true;
|
|
++nRetry;
|
|
break;
|
|
|
|
case NdbError::TemporaryError:
|
|
bUnknown = false;
|
|
SleepOneCall();
|
|
++nRetry;
|
|
break;
|
|
|
|
case NdbError::PermanentError:
|
|
if(err.code==630 && bUnknown)
|
|
iRes = 0;
|
|
bRetry = false;
|
|
break;
|
|
|
|
default:
|
|
bRetry = false;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
return iRes;
|
|
}
|
|
|
|
|
|
int UpdateTransaction(Ndb* pNdb, long iContextId, NdbError& err)
|
|
{
|
|
int iRes = -1;
|
|
NdbConnection* pNdbConnection = pNdb->startTransaction(0, (const char*)&iContextId, 4);
|
|
if(pNdbConnection)
|
|
{
|
|
NdbOperation* pNdbOperation = pNdbConnection->getNdbOperation(g_szTableName);
|
|
if(pNdbOperation)
|
|
{
|
|
if(!pNdbOperation->updateTuple()
|
|
&& !pNdbOperation->equal(c_szContextId, (Int32)iContextId)
|
|
&& !pNdbOperation->setValue(c_szContextData, STATUS_DATA, g_nStatusDataSize))
|
|
{
|
|
if(!pNdbConnection->execute(Commit))
|
|
iRes = 0;
|
|
else
|
|
err = pNdbConnection->getNdbError();
|
|
}
|
|
else
|
|
err = pNdbOperation->getNdbError();
|
|
}
|
|
else
|
|
err = pNdbConnection->getNdbError();
|
|
|
|
pNdb->closeTransaction(pNdbConnection);
|
|
}
|
|
else
|
|
err = pNdb->getNdbError();
|
|
|
|
return iRes;
|
|
}
|
|
|
|
|
|
int RetryUpdateTransaction(Ndb* pNdb, long iContextId, NdbError& err, int& nRetry)
|
|
{
|
|
int iRes = -1;
|
|
nRetry = 0;
|
|
bool bRetry = true;
|
|
while(bRetry && nRetry<g_nMaxRetry)
|
|
{
|
|
if(!UpdateTransaction(pNdb, iContextId, err))
|
|
{
|
|
iRes = 0;
|
|
bRetry = false;
|
|
}
|
|
else
|
|
{
|
|
switch(err.status)
|
|
{
|
|
case NdbError::TemporaryError:
|
|
case NdbError::UnknownResult:
|
|
SleepOneCall();
|
|
++nRetry;
|
|
break;
|
|
|
|
case NdbError::PermanentError:
|
|
default:
|
|
bRetry = false;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
return iRes;
|
|
}
|
|
|
|
|
|
|
|
int InsertInitialRecords(Ndb* pNdb, long nInsert, long nSeed)
|
|
{
|
|
int iRes = -1;
|
|
char szMsg[100];
|
|
for(long i=0; i<nInsert; ++i)
|
|
{
|
|
int iContextID = i+nSeed;
|
|
int nRetry = 0;
|
|
NdbError err;
|
|
memset(&err, 0, sizeof(err));
|
|
NDB_TICKS tStartTrans = NdbTick_CurrentMillisecond();
|
|
iRes = RetryInsertTransaction(pNdb, iContextID, nSeed, iContextID,
|
|
(long)(tStartTrans/1000), (long)((tStartTrans%1000)*1000),
|
|
STATUS_DATA, err, nRetry);
|
|
NDB_TICKS tEndTrans = NdbTick_CurrentMillisecond();
|
|
long lMillisecForThisTrans = (long)(tEndTrans-tStartTrans);
|
|
if(nRetry>0)
|
|
{
|
|
sprintf(szMsg, "insert retried %d times, time %ld msec.",
|
|
nRetry, lMillisecForThisTrans);
|
|
ReportNdbError(szMsg, err);
|
|
}
|
|
if(iRes)
|
|
{
|
|
ReportNdbError("Insert initial record failed", err);
|
|
return iRes;
|
|
}
|
|
InterlockedIncrement(&g_nNumberOfInitialInsert);
|
|
}
|
|
return iRes;
|
|
}
|
|
|
|
|
|
|
|
int VerifyInitialRecords(Ndb* pNdb, long nVerify, long nSeed)
|
|
{
|
|
int iRes = -1;
|
|
char* pchContextData = new char[g_nStatusDataSize];
|
|
char szMsg[100];
|
|
long iPrevLockTime = -1;
|
|
long iPrevLockTimeUSec = -1;
|
|
for(long i=0; i<nVerify; ++i)
|
|
{
|
|
int iContextID = i+nSeed;
|
|
long iVersion = 0;
|
|
long iLockFlag = 0;
|
|
long iLockTime = 0;
|
|
long iLockTimeUSec = 0;
|
|
int nRetry = 0;
|
|
NdbError err;
|
|
memset(&err, 0, sizeof(err));
|
|
NDB_TICKS tStartTrans = NdbTick_CurrentMillisecond();
|
|
iRes = RetryQueryTransaction(pNdb, iContextID, &iVersion, &iLockFlag,
|
|
&iLockTime, &iLockTimeUSec, pchContextData, err, nRetry);
|
|
NDB_TICKS tEndTrans = NdbTick_CurrentMillisecond();
|
|
long lMillisecForThisTrans = (long)(tEndTrans-tStartTrans);
|
|
if(nRetry>0)
|
|
{
|
|
sprintf(szMsg, "verify retried %d times, time %ld msec.",
|
|
nRetry, lMillisecForThisTrans);
|
|
ReportNdbError(szMsg, err);
|
|
}
|
|
if(iRes)
|
|
{
|
|
ReportNdbError("Read initial record failed", err);
|
|
delete[] pchContextData;
|
|
return iRes;
|
|
}
|
|
if(memcmp(pchContextData, STATUS_DATA, g_nStatusDataSize))
|
|
{
|
|
sprintf(szMsg, "wrong context data in tuple %d", iContextID);
|
|
ReportNdbError(szMsg, err);
|
|
delete[] pchContextData;
|
|
return -1;
|
|
}
|
|
if(iVersion!=nSeed
|
|
|| iLockFlag!=iContextID
|
|
|| iLockTime<iPrevLockTime
|
|
|| (iLockTime==iPrevLockTime && iLockTimeUSec<iPrevLockTimeUSec))
|
|
{
|
|
sprintf(szMsg, "wrong call data in tuple %d", iContextID);
|
|
ReportNdbError(szMsg, err);
|
|
delete[] pchContextData;
|
|
return -1;
|
|
}
|
|
iPrevLockTime = iLockTime;
|
|
iPrevLockTimeUSec = iLockTimeUSec;
|
|
InterlockedIncrement(&g_nNumberOfInitialVerify);
|
|
}
|
|
delete[] pchContextData;
|
|
return iRes;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void* RuntimeCallContext(void* lpParam)
|
|
{
|
|
long nNumCallsProcessed = 0;
|
|
int nStartingRecordID = *(int*)lpParam;
|
|
|
|
Ndb* pNdb;
|
|
char* pchContextData = new char[g_nStatusDataSize];
|
|
char szMsg[100];
|
|
|
|
int iRes;
|
|
const char* szOp;
|
|
long iVersion;
|
|
long iLockFlag;
|
|
long iLockTime;
|
|
long iLockTimeUSec;
|
|
|
|
pNdb = new Ndb("TEST_DB");
|
|
if(!pNdb)
|
|
{
|
|
NdbMutex_Lock(g_pNdbMutexPrintf);
|
|
printf("new Ndb failed\n");
|
|
NdbMutex_Unlock(g_pNdbMutexPrintf);
|
|
delete[] pchContextData;
|
|
return 0;
|
|
}
|
|
|
|
if(pNdb->init(1) || pNdb->waitUntilReady())
|
|
{
|
|
ReportNdbError("init of Ndb failed", pNdb->getNdbError());
|
|
delete pNdb;
|
|
delete[] pchContextData;
|
|
return 0;
|
|
}
|
|
|
|
if(g_bInsertInitial)
|
|
{
|
|
if(InsertInitialRecords(pNdb, g_nMaxContextIdPerThread, -nStartingRecordID-g_nMaxContextIdPerThread))
|
|
{
|
|
delete pNdb;
|
|
delete[] pchContextData;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
if(g_bVerifyInitial)
|
|
{
|
|
NdbError err;
|
|
memset(&err, 0, sizeof(err));
|
|
if(VerifyInitialRecords(pNdb, g_nMaxContextIdPerThread, -nStartingRecordID-g_nMaxContextIdPerThread))
|
|
{
|
|
delete pNdb;
|
|
delete[] pchContextData;
|
|
return 0;
|
|
}
|
|
}
|
|
if(g_bInsertInitial || g_bVerifyInitial)
|
|
{
|
|
delete[] pchContextData;
|
|
return 0;
|
|
}
|
|
|
|
long nContextID = nStartingRecordID;
|
|
#ifdef NDB_WIN32
|
|
while(WaitForSingleObject(hShutdownEvent,0) != WAIT_OBJECT_0)
|
|
#else
|
|
while(!bShutdownEvent)
|
|
#endif
|
|
{
|
|
++nContextID;
|
|
nContextID %= g_nMaxContextIdPerThread;
|
|
nContextID += nStartingRecordID;
|
|
|
|
bool bTimeLatency = (nContextID==100);
|
|
|
|
NDB_TICKS tStartCall = NdbTick_CurrentMillisecond();
|
|
for (int i=0; i < 20; i++)
|
|
{
|
|
int nRetry = 0;
|
|
NdbError err;
|
|
memset(&err, 0, sizeof(err));
|
|
NDB_TICKS tStartTrans = NdbTick_CurrentMillisecond();
|
|
switch(i)
|
|
{
|
|
case 3:
|
|
case 6:
|
|
case 9:
|
|
case 11:
|
|
case 12:
|
|
case 15:
|
|
case 18: // Query Record
|
|
szOp = "Read";
|
|
iRes = RetryQueryTransaction(pNdb, nContextID, &iVersion, &iLockFlag,
|
|
&iLockTime, &iLockTimeUSec, pchContextData, err, nRetry);
|
|
break;
|
|
|
|
case 19: // Delete Record
|
|
szOp = "Delete";
|
|
iRes = RetryDeleteTransaction(pNdb, nContextID, err, nRetry);
|
|
break;
|
|
|
|
case 0: // Insert Record
|
|
szOp = "Insert";
|
|
iRes = RetryInsertTransaction(pNdb, nContextID, 1, 1, 1, 1, STATUS_DATA, err, nRetry);
|
|
break;
|
|
|
|
default: // Update Record
|
|
szOp = "Update";
|
|
iRes = RetryUpdateTransaction(pNdb, nContextID, err, nRetry);
|
|
break;
|
|
}
|
|
NDB_TICKS tEndTrans = NdbTick_CurrentMillisecond();
|
|
long lMillisecForThisTrans = (long)(tEndTrans-tStartTrans);
|
|
|
|
if(g_bReport)
|
|
{
|
|
assert(lMillisecForThisTrans>=0 && lMillisecForThisTrans<c_nMaxMillisecForAllTrans);
|
|
InterlockedIncrement(g_plCountMillisecForTrans+lMillisecForThisTrans);
|
|
}
|
|
|
|
if(nRetry>0)
|
|
{
|
|
sprintf(szMsg, "%s retried %d times, time %ld msec.",
|
|
szOp, nRetry, lMillisecForThisTrans);
|
|
ReportNdbError(szMsg, err);
|
|
}
|
|
else if(bTimeLatency)
|
|
{
|
|
NdbMutex_Lock(g_pNdbMutexPrintf);
|
|
printf("%s = %ld msec.\n", szOp, lMillisecForThisTrans);
|
|
NdbMutex_Unlock(g_pNdbMutexPrintf);
|
|
}
|
|
|
|
if(iRes)
|
|
{
|
|
sprintf(szMsg, "%s failed after %ld calls, terminating thread",
|
|
szOp, nNumCallsProcessed);
|
|
ReportNdbError(szMsg, err);
|
|
delete pNdb;
|
|
delete[] pchContextData;
|
|
return 0;
|
|
}
|
|
}
|
|
NDB_TICKS tEndCall = NdbTick_CurrentMillisecond();
|
|
long lMillisecForThisCall = (long)(tEndCall-tStartCall);
|
|
|
|
if(g_bReport)
|
|
{
|
|
assert(lMillisecForThisCall>=0 && lMillisecForThisCall<c_nMaxMillisecForAllCall);
|
|
InterlockedIncrement(g_plCountMillisecForCall+lMillisecForThisCall);
|
|
}
|
|
|
|
if(bTimeLatency)
|
|
{
|
|
NdbMutex_Lock(g_pNdbMutexPrintf);
|
|
printf("Total time for call is %ld msec.\n", (long)lMillisecForThisCall);
|
|
NdbMutex_Unlock(g_pNdbMutexPrintf);
|
|
}
|
|
|
|
nNumCallsProcessed++;
|
|
InterlockedIncrementAndReport();
|
|
if(g_nMaxCallsPerSecond>0)
|
|
{
|
|
int iMillisecToSleep = (1000*g_nNumThreads)/g_nMaxCallsPerSecond;
|
|
iMillisecToSleep -= lMillisecForThisCall;
|
|
if(iMillisecToSleep>0)
|
|
{
|
|
NdbSleep_MilliSleep(iMillisecToSleep);
|
|
}
|
|
}
|
|
}
|
|
|
|
NdbMutex_Lock(g_pNdbMutexPrintf);
|
|
printf("Terminating thread after %ld calls\n", nNumCallsProcessed);
|
|
NdbMutex_Unlock(g_pNdbMutexPrintf);
|
|
|
|
delete pNdb;
|
|
delete[] pchContextData;
|
|
return 0;
|
|
}
|
|
|
|
|
|
int CreateCallContextTable(Ndb* pNdb, const char* szTableName, bool bStored)
|
|
{
|
|
int iRes = -1;
|
|
NdbError err;
|
|
memset(&err, 0, sizeof(err));
|
|
|
|
NdbSchemaCon* pNdbSchemaCon = NdbSchemaCon::startSchemaTrans(pNdb);
|
|
if(pNdbSchemaCon)
|
|
{
|
|
NdbSchemaOp* pNdbSchemaOp = pNdbSchemaCon->getNdbSchemaOp();
|
|
if(pNdbSchemaOp)
|
|
{
|
|
if(!pNdbSchemaOp->createTable(szTableName, 8, TupleKey, 2,
|
|
All, 6, 78, 80, 1, bStored)
|
|
&& !pNdbSchemaOp->createAttribute(c_szContextId, TupleKey, 32, 1, Signed)
|
|
&& !pNdbSchemaOp->createAttribute(c_szVersion, NoKey, 32, 1, Signed)
|
|
&& !pNdbSchemaOp->createAttribute(c_szLockFlag, NoKey, 32, 1, Signed)
|
|
&& !pNdbSchemaOp->createAttribute(c_szLockTime, NoKey, 32, 1, Signed)
|
|
&& !pNdbSchemaOp->createAttribute(c_szLockTimeUSec, NoKey, 32, 1, Signed)
|
|
&& !pNdbSchemaOp->createAttribute(c_szContextData, NoKey, 8, g_nStatusDataSize, String))
|
|
{
|
|
if(!pNdbSchemaCon->execute())
|
|
iRes = 0;
|
|
else
|
|
err = pNdbSchemaCon->getNdbError();
|
|
}
|
|
else
|
|
err = pNdbSchemaOp->getNdbError();
|
|
}
|
|
else
|
|
err = pNdbSchemaCon->getNdbError();
|
|
|
|
NdbSchemaCon::closeSchemaTrans(pNdbSchemaCon);
|
|
}
|
|
else
|
|
err = pNdb->getNdbError();
|
|
|
|
if(iRes)
|
|
{
|
|
ReportNdbError("create call context table failed", err);
|
|
}
|
|
return iRes;
|
|
}
|
|
|
|
|
|
|
|
void ReportResponseTimeStatistics(const char* szStat, long* plCount, const long lSize)
|
|
{
|
|
long lCount = 0;
|
|
Int64 llSum = 0;
|
|
Int64 llSum2 = 0;
|
|
long lMin = -1;
|
|
long lMax = -1;
|
|
|
|
for(long l=0; l<lSize; ++l)
|
|
{
|
|
if(plCount[l]>0)
|
|
{
|
|
lCount += plCount[l];
|
|
llSum += (Int64)l*(Int64)plCount[l];
|
|
llSum2 += (Int64)l*(Int64)l*(Int64)plCount[l];
|
|
if(lMin==-1 || l<lMin)
|
|
{
|
|
lMin = l;
|
|
}
|
|
if(lMax==-1 || l>lMax)
|
|
{
|
|
lMax = l;
|
|
}
|
|
}
|
|
}
|
|
|
|
long lAvg = long(llSum/lCount);
|
|
double dblVar = ((double)lCount*(double)llSum2 - (double)llSum*(double)llSum)/((double)lCount*(double)(lCount-1));
|
|
long lStd = long(sqrt(dblVar));
|
|
|
|
long lMed = -1;
|
|
long l95 = -1;
|
|
long lSel = -1;
|
|
for(long l=lMin; l<=lMax; ++l)
|
|
{
|
|
if(plCount[l]>0)
|
|
{
|
|
lSel += plCount[l];
|
|
if(lMed==-1 && lSel>=(lCount/2))
|
|
{
|
|
lMed = l;
|
|
}
|
|
if(l95==-1 && lSel>=((lCount*95)/100))
|
|
{
|
|
l95 = l;
|
|
}
|
|
if(g_bReportPlus)
|
|
{
|
|
printf("%ld\t%ld\n", l, plCount[l]);
|
|
}
|
|
}
|
|
}
|
|
|
|
printf("%s: Count=%ld, Min=%ld, Max=%ld, Avg=%ld, Std=%ld, Med=%ld, 95%%=%ld\n",
|
|
szStat, lCount, lMin, lMax, lAvg, lStd, lMed, l95);
|
|
}
|
|
|
|
|
|
|
|
void ShowHelp(const char* szCmd)
|
|
{
|
|
printf("%s -t<threads> [-s<seed>] [-b<batch>] [-c<maxcps>] [-m<size>] [-d] [-i] [-v] [-f] [-w] [-r[+]]\n", szCmd);
|
|
printf("%s -?\n", szCmd);
|
|
puts("-d\t\tcreate the table");
|
|
puts("-i\t\tinsert initial records");
|
|
puts("-v\t\tverify initial records");
|
|
puts("-t<threads>\tnumber of threads making calls");
|
|
puts("-s<seed>\toffset for primary key");
|
|
puts("-b<batch>\tbatch size per thread");
|
|
puts("-c<maxcps>\tmax number of calls per second for this process");
|
|
puts("-m<size>\tsize of context data");
|
|
puts("-f\t\tno checkpointing and no logging");
|
|
puts("-w\t\tuse writeTuple instead of insertTuple");
|
|
puts("-r\t\treport response time statistics");
|
|
puts("-r+\t\treport response time distribution");
|
|
puts("-?\t\thelp");
|
|
}
|
|
|
|
|
|
int main(int argc, char* argv[])
|
|
{
|
|
ndb_init();
|
|
int iRes = -1;
|
|
g_nNumThreads = 0;
|
|
g_nMaxCallsPerSecond = 0;
|
|
long nSeed = 0;
|
|
bool bStoredTable = true;
|
|
bool bCreateTable = false;
|
|
g_bWriteTuple = false;
|
|
g_bReport = false;
|
|
g_bReportPlus = false;
|
|
|
|
for(int i=1; i<argc; ++i)
|
|
{
|
|
if(argv[i][0]=='-' || argv[i][0]=='/')
|
|
{
|
|
switch(argv[i][1])
|
|
{
|
|
case 't':
|
|
g_nNumThreads = atol(argv[i]+2);
|
|
break;
|
|
case 's':
|
|
nSeed = atol(argv[i]+2);
|
|
break;
|
|
case 'b':
|
|
g_nMaxContextIdPerThread = atol(argv[i]+2);
|
|
break;
|
|
case 'm':
|
|
g_nStatusDataSize = atol(argv[i]+2);
|
|
if(g_nStatusDataSize>sizeof(STATUS_DATA))
|
|
{
|
|
g_nStatusDataSize = sizeof(STATUS_DATA);
|
|
}
|
|
break;
|
|
case 'i':
|
|
g_bInsertInitial = true;
|
|
break;
|
|
case 'v':
|
|
g_bVerifyInitial = true;
|
|
break;
|
|
case 'd':
|
|
bCreateTable = true;
|
|
break;
|
|
case 'f':
|
|
bStoredTable = false;
|
|
break;
|
|
case 'w':
|
|
g_bWriteTuple = true;
|
|
break;
|
|
case 'r':
|
|
g_bReport = true;
|
|
if(argv[i][2]=='+')
|
|
{
|
|
g_bReportPlus = true;
|
|
}
|
|
break;
|
|
case 'c':
|
|
g_nMaxCallsPerSecond = atol(argv[i]+2);
|
|
break;
|
|
case '?':
|
|
default:
|
|
ShowHelp(argv[0]);
|
|
return -1;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ShowHelp(argv[0]);
|
|
return -1;
|
|
}
|
|
}
|
|
if(bCreateTable)
|
|
puts("-d\tcreate the table");
|
|
if(g_bInsertInitial)
|
|
printf("-i\tinsert initial records\n");
|
|
if(g_bVerifyInitial)
|
|
printf("-v\tverify initial records\n");
|
|
if(g_nNumThreads>0)
|
|
printf("-t%ld\tnumber of threads making calls\n", g_nNumThreads);
|
|
if(g_nNumThreads>0)
|
|
{
|
|
printf("-s%ld\toffset for primary key\n", nSeed);
|
|
printf("-b%ld\tbatch size per thread\n", g_nMaxContextIdPerThread);
|
|
}
|
|
if(g_nMaxCallsPerSecond>0)
|
|
printf("-c%ld\tmax number of calls per second for this process\n", g_nMaxCallsPerSecond);
|
|
if(!bStoredTable)
|
|
puts("-f\tno checkpointing and no logging to disk");
|
|
if(g_bWriteTuple)
|
|
puts("-w\tuse writeTuple instead of insertTuple");
|
|
if(g_bReport)
|
|
puts("-r\treport response time statistics");
|
|
if(g_bReportPlus)
|
|
puts("-r+\treport response time distribution");
|
|
|
|
if(!bCreateTable && g_nNumThreads<=0)
|
|
{
|
|
ShowHelp(argv[0]);
|
|
return -1;
|
|
}
|
|
printf("-m%ld\tsize of context data\n", g_nStatusDataSize);
|
|
|
|
g_szTableName = (bStoredTable ? c_szTableNameStored : c_szTableNameTemp);
|
|
|
|
#ifdef NDB_WIN32
|
|
SetConsoleCtrlHandler(ConsoleCtrlHandler, true);
|
|
#else
|
|
signal(SIGINT, CtrlCHandler);
|
|
#endif
|
|
|
|
if(g_bReport)
|
|
{
|
|
g_plCountMillisecForCall = new long[c_nMaxMillisecForAllCall];
|
|
memset(g_plCountMillisecForCall, 0, c_nMaxMillisecForAllCall*sizeof(long));
|
|
g_plCountMillisecForTrans = new long[c_nMaxMillisecForAllTrans];
|
|
memset(g_plCountMillisecForTrans, 0, c_nMaxMillisecForAllTrans*sizeof(long));
|
|
}
|
|
|
|
g_pNdbMutexIncrement = NdbMutex_Create();
|
|
g_pNdbMutexPrintf = NdbMutex_Create();
|
|
#ifdef NDB_WIN32
|
|
hShutdownEvent = CreateEvent(NULL,TRUE,FALSE,NULL);
|
|
#endif
|
|
|
|
Ndb* pNdb = new Ndb(c_szDatabaseName);
|
|
if(!pNdb)
|
|
{
|
|
printf("could not construct ndb\n");
|
|
return 1;
|
|
}
|
|
|
|
if(pNdb->init(1) || pNdb->waitUntilReady())
|
|
{
|
|
ReportNdbError("could not initialize ndb\n", pNdb->getNdbError());
|
|
delete pNdb;
|
|
return 2;
|
|
}
|
|
|
|
if(bCreateTable)
|
|
{
|
|
printf("Create CallContext table\n");
|
|
if (bStoredTable)
|
|
{
|
|
if (CreateCallContextTable(pNdb, c_szTableNameStored, true))
|
|
{
|
|
printf("Create table failed\n");
|
|
delete pNdb;
|
|
return 3;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (CreateCallContextTable(pNdb, c_szTableNameTemp, false))
|
|
{
|
|
printf("Create table failed\n");
|
|
delete pNdb;
|
|
return 3;
|
|
}
|
|
}
|
|
}
|
|
|
|
if(g_nNumThreads>0)
|
|
{
|
|
printf("creating %d threads\n", (int)g_nNumThreads);
|
|
if(g_bInsertInitial)
|
|
{
|
|
printf("each thread will insert %ld initial records, total %ld inserts\n",
|
|
g_nMaxContextIdPerThread, g_nNumThreads*g_nMaxContextIdPerThread);
|
|
}
|
|
if(g_bVerifyInitial)
|
|
{
|
|
printf("each thread will verify %ld initial records, total %ld reads\n",
|
|
g_nMaxContextIdPerThread, g_nNumThreads*g_nMaxContextIdPerThread);
|
|
}
|
|
|
|
g_nNumberOfInitialInsert = 0;
|
|
g_nNumberOfInitialVerify = 0;
|
|
|
|
NDB_TICKS tStartTime = NdbTick_CurrentMillisecond();
|
|
NdbThread* pThreads[256];
|
|
int pnStartingRecordNum[256];
|
|
int ij;
|
|
for(ij=0;ij<g_nNumThreads;ij++)
|
|
{
|
|
pnStartingRecordNum[ij] = (ij*g_nMaxContextIdPerThread) + nSeed;
|
|
}
|
|
|
|
for(ij=0;ij<g_nNumThreads;ij++)
|
|
{
|
|
pThreads[ij] = NdbThread_Create(RuntimeCallContext,
|
|
(void**)(pnStartingRecordNum+ij),
|
|
0, "RuntimeCallContext", NDB_THREAD_PRIO_LOW);
|
|
}
|
|
|
|
//Wait for the threads to finish
|
|
for(ij=0;ij<g_nNumThreads;ij++)
|
|
{
|
|
void* status;
|
|
NdbThread_WaitFor(pThreads[ij], &status);
|
|
}
|
|
NDB_TICKS tEndTime = NdbTick_CurrentMillisecond();
|
|
|
|
//Print time taken
|
|
printf("Time Taken for %ld Calls is %ld msec (= %ld calls/sec)\n",
|
|
g_nNumCallsProcessed,
|
|
(long)(tEndTime-tStartTime),
|
|
(long)((1000*g_nNumCallsProcessed)/(tEndTime-tStartTime)));
|
|
|
|
if(g_bInsertInitial)
|
|
printf("successfully inserted %ld tuples\n", g_nNumberOfInitialInsert);
|
|
if(g_bVerifyInitial)
|
|
printf("successfully verified %ld tuples\n", g_nNumberOfInitialVerify);
|
|
}
|
|
|
|
delete pNdb;
|
|
|
|
#ifdef NDB_WIN32
|
|
CloseHandle(hShutdownEvent);
|
|
#endif
|
|
NdbMutex_Destroy(g_pNdbMutexIncrement);
|
|
NdbMutex_Destroy(g_pNdbMutexPrintf);
|
|
|
|
if(g_bReport)
|
|
{
|
|
ReportResponseTimeStatistics("Calls", g_plCountMillisecForCall, c_nMaxMillisecForAllCall);
|
|
ReportResponseTimeStatistics("Transactions", g_plCountMillisecForTrans, c_nMaxMillisecForAllTrans);
|
|
|
|
delete[] g_plCountMillisecForCall;
|
|
delete[] g_plCountMillisecForTrans;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|