mirror of
https://github.com/MariaDB/server.git
synced 2025-01-19 05:22:25 +01:00
888 lines
24 KiB
C++
888 lines
24 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 */
|
|
|
|
/* ***************************************************
|
|
FLEXHAMMER
|
|
Hammer ndb with read, insert, update and delete transactions.
|
|
|
|
Arguments:
|
|
-t Number of threads to start, default 1
|
|
-o Number of operations per hammering-round, default 500
|
|
-l Number of loops to run, default 1, 0=infinite
|
|
-a Number of attributes, default 25
|
|
-c Number of tables, default 1
|
|
-s Size of each attribute, default 1
|
|
-simple Use simple read to read from database
|
|
-dirty Use dirty read to read from database
|
|
-write Use writeTuple to write to db
|
|
-r Number of records to Hammer
|
|
-no_table_create Don't create tables in db
|
|
-regulate To be able to regulate the load flexHammer produces.
|
|
-stdtables Use standard table names
|
|
-sleep Sleep a number of seconds before running the test, this
|
|
can be used so that another flexProgram have tome to create tables
|
|
|
|
Returns:
|
|
0 - Test passed
|
|
-1 - Test failed
|
|
1 - Invalid arguments
|
|
|
|
Revision history:
|
|
1.7 020208 epesson: Adapted to use NDBT
|
|
1.10 020222 epesson: Finalised handling of thread results
|
|
1.11 020222 epesson: Bug in checking results during delete fixed
|
|
|
|
* *************************************************** */
|
|
|
|
#include <NdbApi.hpp>
|
|
|
|
#include <NdbMain.h>
|
|
#include <NdbThread.h>
|
|
#include <NdbSleep.h>
|
|
#include <NdbTick.h>
|
|
#include <NdbOut.hpp>
|
|
#include <NdbTimer.hpp>
|
|
#include <NdbTick.h>
|
|
#include <NdbTest.hpp>
|
|
#include <NDBT_Error.hpp>
|
|
#include <NdbSchemaCon.hpp>
|
|
|
|
ErrorData * flexHammerErrorData;
|
|
|
|
#if defined NDB_OSE || defined NDB_SOFTOSE
|
|
#include <outfmt.h>
|
|
#endif
|
|
|
|
#define MAXSTRLEN 16
|
|
#define MAXATTR 64
|
|
#define MAXTABLES 64
|
|
#define MAXTHREADS 256
|
|
#define MAXATTRSIZE 100
|
|
// Max number of retries if something fails
|
|
#define MaxNoOfAttemptsC 10
|
|
|
|
enum StartType {
|
|
stIdle,
|
|
stHammer,
|
|
stStop,
|
|
stLast};
|
|
|
|
enum MyOpType {
|
|
otInsert,
|
|
otRead,
|
|
otDelete,
|
|
otUpdate,
|
|
otLast};
|
|
|
|
struct ThreadNdb {
|
|
int threadNo;
|
|
NdbThread* threadLife;
|
|
int threadReady;
|
|
StartType threadStart;
|
|
int threadResult;};
|
|
|
|
extern "C" void* flexHammerThread(void*);
|
|
static int setAttrNames(void);
|
|
static int setTableNames(void);
|
|
static int readArguments(int, const char**);
|
|
static int createTables(Ndb*);
|
|
static void sleepBeforeStartingTest(int seconds);
|
|
static int checkThreadResults(ThreadNdb *threadArrayP, char* phase);
|
|
|
|
//enum OperationType {
|
|
// otInsert,
|
|
// otRead,
|
|
// otUpdate,
|
|
// otDelete,
|
|
// otVerifyDelete,
|
|
// otLast };
|
|
|
|
enum ReadyType {
|
|
stReady,
|
|
stRunning
|
|
} ;
|
|
static int tNoOfThreads;
|
|
static int tNoOfAttributes;
|
|
static int tNoOfTables;
|
|
static int tNoOfBackups;
|
|
static int tAttributeSize;
|
|
static int tNoOfOperations;
|
|
static int tNoOfRecords;
|
|
static int tNoOfLoops;
|
|
static ReadyType ThreadReady[MAXTHREADS];
|
|
static StartType ThreadStart[MAXTHREADS];
|
|
static char tableName[MAXTABLES][MAXSTRLEN];
|
|
static char attrName[MAXATTR][MAXSTRLEN];
|
|
static int theSimpleFlag = 0;
|
|
static int theWriteFlag = 0;
|
|
static int theDirtyFlag = 0;
|
|
static int theTableCreateFlag = 0;
|
|
static int theStandardTableNameFlag = 0;
|
|
static unsigned int tSleepTime = 0;
|
|
|
|
#define START_TIMER { NdbTimer timer; timer.doStart();
|
|
#define STOP_TIMER timer.doStop();
|
|
#define PRINT_TIMER(text, trans, opertrans) timer.printTransactionStatistics(text, trans, opertrans); };
|
|
|
|
|
|
// Initialise thread data
|
|
void
|
|
resetThreads(ThreadNdb *threadArrayP) {
|
|
|
|
for (int i = 0; i < tNoOfThreads ; i++)
|
|
{
|
|
threadArrayP[i].threadReady = 0;
|
|
threadArrayP[i].threadResult = 0;
|
|
threadArrayP[i].threadStart = stIdle;
|
|
}
|
|
} // resetThreads
|
|
|
|
void
|
|
waitForThreads(ThreadNdb *threadArrayP)
|
|
{
|
|
int cont = 1;
|
|
|
|
while (cont) {
|
|
NdbSleep_MilliSleep(100);
|
|
cont = 0;
|
|
for (int i = 0; i < tNoOfThreads ; i++) {
|
|
if (threadArrayP[i].threadReady == 0) {
|
|
cont = 1;
|
|
} // if
|
|
} // for
|
|
} // while
|
|
} // waitForThreads
|
|
|
|
void
|
|
tellThreads(ThreadNdb* threadArrayP, const StartType what)
|
|
{
|
|
for (int i = 0; i < tNoOfThreads ; i++)
|
|
{
|
|
threadArrayP[i].threadStart = what;
|
|
} // for
|
|
} // tellThreads
|
|
|
|
NDB_COMMAND(flexHammer, "flexHammer", "flexHammer", "flexHammer", 65535)
|
|
//main(int argc, const char** argv)
|
|
{
|
|
ndb_init();
|
|
ThreadNdb* pThreads = NULL; // Pointer to thread data array
|
|
Ndb* pMyNdb = NULL; // Pointer to Ndb object
|
|
int tLoops = 0;
|
|
int returnValue = 0;
|
|
int check = 0;
|
|
|
|
flexHammerErrorData = new ErrorData;
|
|
|
|
flexHammerErrorData->resetErrorCounters();
|
|
|
|
if (readArguments(argc, argv) != 0) {
|
|
ndbout << "Wrong arguments to flexHammer" << endl;
|
|
return NDBT_ProgramExit(NDBT_WRONGARGS);
|
|
} // if
|
|
|
|
/* print Setting */
|
|
flexHammerErrorData->printSettings(ndbout);
|
|
|
|
check = setAttrNames();
|
|
if (check == -1) {
|
|
ndbout << "Couldn't set attribute names" << endl;
|
|
return NDBT_ProgramExit(NDBT_FAILED);
|
|
} // if
|
|
check = setTableNames();
|
|
if (check == -1) {
|
|
ndbout << "Couldn't set table names" << endl;
|
|
return NDBT_ProgramExit(NDBT_FAILED);
|
|
} // if
|
|
|
|
// Create thread data array
|
|
pThreads = new ThreadNdb[tNoOfThreads];
|
|
// NdbThread_SetConcurrencyLevel(tNoOfThreads + 2);
|
|
|
|
// Create and init Ndb object
|
|
pMyNdb = new Ndb("TEST_DB");
|
|
pMyNdb->init();
|
|
|
|
// Wait for Ndb to become ready
|
|
if (pMyNdb->waitUntilReady(10000) != 0) {
|
|
ndbout << "NDB is not ready" << endl << "Benchmark failed" << endl;
|
|
returnValue = NDBT_FAILED;
|
|
}
|
|
|
|
else {
|
|
check = createTables(pMyNdb);
|
|
if (check != 0) {
|
|
returnValue = NDBT_FAILED;
|
|
} // if
|
|
else {
|
|
sleepBeforeStartingTest(tSleepTime);
|
|
|
|
// Create threads. *
|
|
resetThreads(pThreads);
|
|
for (int i = 0; i < tNoOfThreads ; i++) {
|
|
pThreads[i].threadNo = i;
|
|
pThreads[i].threadLife = NdbThread_Create(flexHammerThread,
|
|
(void**)&pThreads[i],
|
|
65535,
|
|
"flexHammerThread",
|
|
NDB_THREAD_PRIO_LOW);
|
|
} // for
|
|
|
|
// And wait until they are ready
|
|
waitForThreads(pThreads);
|
|
if (checkThreadResults(pThreads, "init") != 0) {
|
|
returnValue = NDBT_FAILED;
|
|
} // if
|
|
|
|
|
|
if (returnValue == NDBT_OK) {
|
|
ndbout << endl << "All threads started" << endl << endl;
|
|
|
|
for(;;) {
|
|
|
|
// Check if it's time to exit program
|
|
if((tNoOfLoops != 0) && (tNoOfLoops <= tLoops))
|
|
break;
|
|
|
|
// Tell all threads to start hammer
|
|
ndbout << "Hammering..." << endl;
|
|
|
|
resetThreads(pThreads);
|
|
|
|
START_TIMER;
|
|
tellThreads(pThreads, stHammer);
|
|
|
|
waitForThreads(pThreads);
|
|
ndbout << "Threads ready to continue..." << endl;
|
|
STOP_TIMER;
|
|
|
|
// Check here if anything went wrong
|
|
if (checkThreadResults(pThreads, "hammer") != 0) {
|
|
ndbout << "Thread(s) failed." << endl;
|
|
returnValue = NDBT_FAILED;
|
|
} // if
|
|
|
|
PRINT_TIMER("hammer", tNoOfOperations*tNoOfThreads, tNoOfTables*6);
|
|
|
|
ndbout << endl;
|
|
|
|
tLoops++;
|
|
|
|
} // for
|
|
} // if
|
|
|
|
// Signaling threads to stop
|
|
resetThreads(pThreads);
|
|
tellThreads(pThreads, stStop);
|
|
|
|
// Wait for threads to stop
|
|
waitForThreads(pThreads);
|
|
|
|
ndbout << "----------------------------------------------" << endl << endl;
|
|
ndbout << "Benchmark completed" << endl;
|
|
} // else
|
|
} // else
|
|
// Clean up
|
|
|
|
flexHammerErrorData->printErrorCounters(ndbout);
|
|
|
|
// Kill them all!
|
|
void* tmp;
|
|
for(int i = 0; i < tNoOfThreads; i++){
|
|
NdbThread_WaitFor(pThreads[i].threadLife, &tmp);
|
|
NdbThread_Destroy(&pThreads[i].threadLife);
|
|
}
|
|
delete flexHammerErrorData;
|
|
delete [] pThreads;
|
|
delete pMyNdb;
|
|
|
|
// Exit via NDBT
|
|
return NDBT_ProgramExit(returnValue);
|
|
|
|
} //main
|
|
|
|
extern "C"
|
|
void*
|
|
flexHammerThread(void* pArg)
|
|
{
|
|
ThreadNdb* pThreadData = (ThreadNdb*)pArg;
|
|
unsigned int threadNo = pThreadData->threadNo;
|
|
Ndb* pMyNdb = NULL ;
|
|
NdbConnection *pMyTransaction = NULL ;
|
|
// NdbOperation* pMyOperation[MAXTABLES] = {NULL};
|
|
NdbOperation* pMyOperation[MAXTABLES];
|
|
int check = 0;
|
|
int loop_count_ops = 0;
|
|
int loop_count_tables = 0;
|
|
int loop_count_attributes = 0;
|
|
int count_round = 0;
|
|
int count = 0;
|
|
int count_tables = 0;
|
|
int count_attributes = 0;
|
|
int i = 0;
|
|
int j = 0;
|
|
int tThreadResult = 0;
|
|
MyOpType tMyOpType = otLast;
|
|
int pkValue = 0;
|
|
int readValue[MAXATTR][MAXATTRSIZE] = {0};
|
|
int attrValue[MAXATTRSIZE];
|
|
NdbRecAttr* tTmp = NULL;
|
|
int tNoOfAttempts = 0;
|
|
|
|
for (i = 0; i < MAXATTRSIZE; i++)
|
|
attrValue[i] = 0;
|
|
// Ndb object for each thread
|
|
pMyNdb = new Ndb( "TEST_DB" );
|
|
pMyNdb->init();
|
|
if (pMyNdb->waitUntilReady(10000) != 0) {
|
|
// Error, NDB is not ready
|
|
tThreadResult = 99;
|
|
// Go to idle directly
|
|
pThreadData->threadStart = stIdle;
|
|
} // if
|
|
|
|
for(;;) {
|
|
pThreadData->threadResult = tThreadResult;
|
|
pThreadData->threadReady = 1; // Signalling ready to main
|
|
|
|
// If Idle just wait to be stopped from main
|
|
while (pThreadData->threadStart == stIdle) {
|
|
NdbSleep_MilliSleep(100);
|
|
} // while
|
|
|
|
// Check if signal to exit is received
|
|
if (pThreadData->threadStart == stStop) {
|
|
pThreadData->threadReady = 1;
|
|
// break out of eternal loop
|
|
break;
|
|
} // if
|
|
|
|
// Set to Idle to prepare for possible error break
|
|
pThreadData->threadStart = stIdle;
|
|
|
|
// Prepare transaction
|
|
loop_count_ops = tNoOfOperations;
|
|
loop_count_tables = tNoOfTables;
|
|
loop_count_attributes = tNoOfAttributes;
|
|
|
|
for (count=0 ; count < loop_count_ops ; count++) {
|
|
|
|
//pkValue = (int)(count + thread_base);
|
|
// This limits the number of records used in this test
|
|
pkValue = count % tNoOfRecords;
|
|
|
|
for (count_round = 0; count_round < 5; ) {
|
|
switch (count_round) {
|
|
case 0: // Insert
|
|
tMyOpType = otInsert;
|
|
// Increase attrValues
|
|
for (i=0; i < MAXATTRSIZE; i ++) {
|
|
attrValue[i]++;
|
|
}
|
|
break;
|
|
case 1:
|
|
case 3: // Read and verify
|
|
tMyOpType = otRead;
|
|
break;
|
|
case 2: // Update
|
|
// Increase attrValues
|
|
for(i=0; i < MAXATTRSIZE; i ++) {
|
|
attrValue[i]++;
|
|
}
|
|
tMyOpType = otUpdate;
|
|
break;
|
|
case 4: // Delete
|
|
tMyOpType = otDelete;
|
|
break;
|
|
default:
|
|
assert(false);
|
|
break;
|
|
} // switch
|
|
|
|
// Get transaction object
|
|
pMyTransaction = pMyNdb->startTransaction();
|
|
if (pMyTransaction == NULL) {
|
|
// Fatal error
|
|
tThreadResult = 1;
|
|
// break out of for count_round loop waiting to be stopped by main
|
|
break;
|
|
} // if
|
|
|
|
for (count_tables = 0; count_tables < loop_count_tables;
|
|
count_tables++) {
|
|
pMyOperation[count_tables] =
|
|
pMyTransaction->getNdbOperation(tableName[count_tables]);
|
|
if (pMyOperation[count_tables] == NULL) {
|
|
//Fatal error
|
|
tThreadResult = 2;
|
|
// break out of inner for count_tables loop
|
|
break;
|
|
} // if
|
|
|
|
switch (tMyOpType) {
|
|
case otInsert: // Insert case
|
|
if (theWriteFlag == 1 && theDirtyFlag == 1) {
|
|
check = pMyOperation[count_tables]->dirtyWrite();
|
|
} else if (theWriteFlag == 1) {
|
|
check = pMyOperation[count_tables]->writeTuple();
|
|
} else {
|
|
check = pMyOperation[count_tables]->insertTuple();
|
|
} // if else
|
|
break;
|
|
case otRead: // Read Case
|
|
if (theSimpleFlag == 1) {
|
|
check = pMyOperation[count_tables]->simpleRead();
|
|
} else if (theDirtyFlag == 1) {
|
|
check = pMyOperation[count_tables]->dirtyRead();
|
|
} else {
|
|
check = pMyOperation[count_tables]->readTuple();
|
|
} // if else
|
|
break;
|
|
case otUpdate: // Update Case
|
|
if (theWriteFlag == 1 && theDirtyFlag == 1) {
|
|
check = pMyOperation[count_tables]->dirtyWrite();
|
|
} else if (theWriteFlag == 1) {
|
|
check = pMyOperation[count_tables]->writeTuple();
|
|
} else if (theDirtyFlag == 1) {
|
|
check = pMyOperation[count_tables]->dirtyUpdate();
|
|
} else {
|
|
check = pMyOperation[count_tables]->updateTuple();
|
|
} // if else
|
|
break;
|
|
case otDelete: // Delete Case
|
|
check = pMyOperation[count_tables]->deleteTuple();
|
|
break;
|
|
default:
|
|
assert(false);
|
|
break;
|
|
} // switch
|
|
if (check == -1) {
|
|
// Fatal error
|
|
tThreadResult = 3;
|
|
// break out of inner for count_tables loop
|
|
break;
|
|
} // if
|
|
|
|
check = pMyOperation[count_tables]->equal( (char*)attrName[0],
|
|
(char*)&pkValue );
|
|
|
|
if (check == -1) {
|
|
// Fatal error
|
|
tThreadResult = 4;
|
|
ndbout << "pMyOperation equal failed" << endl;
|
|
// break out of inner for count_tables loop
|
|
break;
|
|
} // if
|
|
|
|
check = -1;
|
|
tTmp = NULL;
|
|
switch (tMyOpType) {
|
|
case otInsert: // Insert case
|
|
case otUpdate: // Update Case
|
|
for (count_attributes = 1; count_attributes < loop_count_attributes;
|
|
count_attributes++) {
|
|
check =
|
|
pMyOperation[count_tables]->setValue((char*)attrName[count_attributes], (char*)&attrValue[0]);
|
|
} // for
|
|
break;
|
|
case otRead: // Read Case
|
|
for (count_attributes = 1; count_attributes < loop_count_attributes;
|
|
count_attributes++) {
|
|
tTmp = pMyOperation[count_tables]->
|
|
getValue( (char*)attrName[count_attributes],
|
|
(char*)&readValue[count_attributes][0] );
|
|
} // for
|
|
break;
|
|
case otDelete: // Delete Case
|
|
break;
|
|
default:
|
|
assert(false);
|
|
break;
|
|
} // switch
|
|
if (check == -1 && tTmp == NULL && tMyOpType != otDelete) {
|
|
// Fatal error
|
|
tThreadResult = 5;
|
|
break;
|
|
} // if
|
|
} // for count_tables
|
|
|
|
// Only execute if everything is OK
|
|
if (tThreadResult != 0) {
|
|
// Close transaction (below)
|
|
// and continue with next count_round
|
|
count_round++;
|
|
tNoOfAttempts = 0;
|
|
} // if
|
|
else {
|
|
check = pMyTransaction->execute(Commit);
|
|
if (check == -1 ) {
|
|
const NdbError & err = pMyTransaction->getNdbError();
|
|
|
|
// Add complete error handling here
|
|
|
|
int retCode = flexHammerErrorData->handleErrorCommon(pMyTransaction->getNdbError());
|
|
if (retCode == 1) {
|
|
//if (strcmp(pMyTransaction->getNdbError().message, "Tuple did not exist") != 0 && strcmp(pMyTransaction->getNdbError().message,"Tuple already existed when attempting to insert") != 0) ndbout_c("execute: %s", pMyTransaction->getNdbError().message);
|
|
|
|
if (pMyTransaction->getNdbError().code != 626 && pMyTransaction->getNdbError().code != 630){
|
|
ndbout_c("Error code = %d", pMyTransaction->getNdbError().code);
|
|
ndbout_c("execute: %s", pMyTransaction->getNdbError().message);}
|
|
|
|
} else if (retCode == 2) {
|
|
ndbout << "4115 should not happen in flexHammer" << endl;
|
|
} else if (retCode == 3) {
|
|
// --------------------------------------------------------------------
|
|
// We are not certain if the transaction was successful or not.
|
|
// We must reexecute but might very well find that the transaction
|
|
// actually was updated. Updates and Reads are no problem here. Inserts
|
|
// will not cause a problem if error code 630 arrives. Deletes will
|
|
// not cause a problem if 626 arrives.
|
|
// --------------------------------------------------------------------
|
|
/* What can we do here? */
|
|
ndbout_c("execute: %s", pMyTransaction->getNdbError().message);
|
|
}//if(retCode == 3)
|
|
// End of adding complete error handling
|
|
|
|
switch( err.classification) {
|
|
case NdbError::ConstraintViolation: // Tuple already existed
|
|
count_round++;
|
|
tNoOfAttempts = 0;
|
|
break;
|
|
case NdbError::TimeoutExpired:
|
|
case NdbError::NodeRecoveryError:
|
|
case NdbError::TemporaryResourceError:
|
|
case NdbError::OverloadError:
|
|
if (tNoOfAttempts <= MaxNoOfAttemptsC) {
|
|
// Retry
|
|
tNoOfAttempts++;
|
|
} else {
|
|
// Too many retries, continue with next
|
|
count_round++;
|
|
tNoOfAttempts = 0;
|
|
} // else if
|
|
break;
|
|
// Fatal, just continue
|
|
default:
|
|
count_round++;
|
|
tNoOfAttempts = 0;
|
|
break;
|
|
} // switch
|
|
} // if
|
|
else {
|
|
// Execute commit was OK
|
|
// This is verifying read values
|
|
//switch (tMyOpType) {
|
|
//case otRead: // Read case
|
|
//for (j = 0; j < tNoOfAttributes; j++) {
|
|
//for(i = 1; i < tAttributeSize; i++) {
|
|
//if ( readValue[j][i] != attrValue[i]) {
|
|
//ndbout << "pkValue = " << pkValue << endl;
|
|
//ndbout << "readValue != attrValue" << endl;
|
|
//ndbout << readValue[j][i] << " != " << attrValue[i] << endl;
|
|
//} // if
|
|
// } // for
|
|
//} // for
|
|
//break;
|
|
//} // switch
|
|
count_round++;
|
|
tNoOfAttempts = 0;
|
|
} // else if
|
|
} // else if
|
|
pMyNdb->closeTransaction(pMyTransaction);
|
|
} // for count_round
|
|
} // for count
|
|
} // for (;;)
|
|
|
|
// Clean up
|
|
delete pMyNdb;
|
|
pMyNdb = NULL;
|
|
|
|
flexHammerErrorData->resetErrorCounters();
|
|
|
|
return NULL; // thread exits
|
|
|
|
} // flexHammerThread
|
|
|
|
|
|
int
|
|
readArguments (int argc, const char** argv)
|
|
{
|
|
int i = 1;
|
|
|
|
tNoOfThreads = 5; // Default Value
|
|
tNoOfOperations = 500; // Default Value
|
|
tNoOfRecords = 1; // Default Value
|
|
tNoOfLoops = 1; // Default Value
|
|
tNoOfAttributes = 25; // Default Value
|
|
tNoOfTables = 1; // Default Value
|
|
tNoOfBackups = 0; // Default Value
|
|
tAttributeSize = 1; // Default Value
|
|
theTableCreateFlag = 0;
|
|
|
|
while (argc > 1) {
|
|
if (strcmp(argv[i], "-t") == 0) {
|
|
tNoOfThreads = atoi(argv[i+1]);
|
|
if ((tNoOfThreads < 1) || (tNoOfThreads > MAXTHREADS))
|
|
return(1);
|
|
}
|
|
else if (strcmp(argv[i], "-o") == 0) {
|
|
tNoOfOperations = atoi(argv[i+1]);
|
|
if (tNoOfOperations < 1)
|
|
return(1);
|
|
}
|
|
else if (strcmp(argv[i], "-r") == 0) {
|
|
tNoOfRecords = atoi(argv[i+1]);
|
|
if (tNoOfRecords < 1)
|
|
return(1);
|
|
}
|
|
else if (strcmp(argv[i], "-a") == 0) {
|
|
tNoOfAttributes = atoi(argv[i+1]);
|
|
if ((tNoOfAttributes < 2) || (tNoOfAttributes > MAXATTR))
|
|
return(1);
|
|
}
|
|
else if (strcmp(argv[i], "-c") == 0) {
|
|
tNoOfTables = atoi(argv[i+1]);
|
|
if ((tNoOfTables < 1) || (tNoOfTables > MAXTABLES))
|
|
return(1);
|
|
}
|
|
else if (strcmp(argv[i], "-l") == 0) {
|
|
tNoOfLoops = atoi(argv[i+1]);
|
|
if ((tNoOfLoops < 0) || (tNoOfLoops > 100000))
|
|
return(1);
|
|
}
|
|
else if (strcmp(argv[i], "-s") == 0) {
|
|
tAttributeSize = atoi(argv[i+1]);
|
|
if ((tAttributeSize < 1) || (tAttributeSize > MAXATTRSIZE))
|
|
return(1);
|
|
}
|
|
else if (strcmp(argv[i], "-sleep") == 0) {
|
|
tSleepTime = atoi(argv[i+1]);
|
|
if ((tSleepTime < 1) || (tSleepTime > 3600))
|
|
exit(-1);
|
|
}
|
|
else if (strcmp(argv[i], "-simple") == 0) {
|
|
theSimpleFlag = 1;
|
|
argc++;
|
|
i--;
|
|
}
|
|
else if (strcmp(argv[i], "-write") == 0) {
|
|
theWriteFlag = 1;
|
|
argc++;
|
|
i--;
|
|
}
|
|
else if (strcmp(argv[i], "-dirty") == 0) {
|
|
theDirtyFlag = 1;
|
|
argc++;
|
|
i--;
|
|
}
|
|
else if (strcmp(argv[i], "-no_table_create") == 0) {
|
|
theTableCreateFlag = 1;
|
|
argc++;
|
|
i--;
|
|
}
|
|
else if (strcmp(argv[i], "-stdtables") == 0) {
|
|
theStandardTableNameFlag = 1;
|
|
argc++;
|
|
i--;
|
|
} // if
|
|
else {
|
|
return(1);
|
|
}
|
|
|
|
argc -= 2;
|
|
i = i + 2;
|
|
} // while
|
|
|
|
ndbout << endl << "FLEXHAMMER - Starting normal mode" << endl;
|
|
ndbout << "Hammer ndb with read, insert, update and delete transactions"<< endl << endl;
|
|
|
|
ndbout << " " << tNoOfThreads << " thread(s) " << endl;
|
|
ndbout << " " << tNoOfLoops << " iterations " << endl;
|
|
ndbout << " " << tNoOfTables << " table(s) and " << 1 << " operation(s) per transaction " << endl;
|
|
ndbout << " " << tNoOfRecords << " records to hammer(limit this with the -r option)" << endl;
|
|
ndbout << " " << tNoOfAttributes << " attributes per table " << endl;
|
|
ndbout << " " << tNoOfOperations << " transaction(s) per thread and round " << endl;
|
|
ndbout << " " << tAttributeSize << " is the number of 32 bit words per attribute " << endl << endl;
|
|
return 0;
|
|
} // readArguments
|
|
|
|
|
|
void sleepBeforeStartingTest(int seconds)
|
|
{
|
|
if (seconds > 0) {
|
|
ndbout << "Sleeping(" << seconds << ")...";
|
|
NdbSleep_SecSleep(seconds);
|
|
ndbout << " done!" << endl;
|
|
} // if
|
|
} // sleepBeforeStartingTest
|
|
|
|
static int
|
|
createTables(Ndb* pMyNdb)
|
|
{
|
|
int i = 0;
|
|
int j = 0;
|
|
int check = 0;
|
|
NdbSchemaCon *MySchemaTransaction = NULL;
|
|
NdbSchemaOp *MySchemaOp = NULL;
|
|
|
|
// Create Table and Attributes.
|
|
if (theTableCreateFlag == 0) {
|
|
|
|
for (i = 0; i < tNoOfTables; i++) {
|
|
|
|
ndbout << "Creating " << tableName[i] << "...";
|
|
// Check if table exists already
|
|
const void * p = pMyNdb->getDictionary()->getTable(tableName[i]);
|
|
if (p != 0) {
|
|
ndbout << " already exists." << endl;
|
|
// Continue with next table at once
|
|
continue;
|
|
} // if
|
|
ndbout << endl;
|
|
|
|
MySchemaTransaction = NdbSchemaCon::startSchemaTrans(pMyNdb);
|
|
if (MySchemaTransaction == NULL) {
|
|
return(-1);
|
|
} // if
|
|
|
|
MySchemaOp = MySchemaTransaction->getNdbSchemaOp();
|
|
if (MySchemaOp == NULL) {
|
|
// Clean up opened schema transaction
|
|
NdbSchemaCon::closeSchemaTrans(MySchemaTransaction);
|
|
return(-1);
|
|
} // if
|
|
|
|
// Create tables, rest of parameters are default right now
|
|
#if defined NDB_OSE || defined NDB_SOFTOSE
|
|
check = MySchemaOp->createTable(tableName[i],
|
|
8, // Table Size
|
|
TupleKey, // Key Type
|
|
40, // Nr of Pages
|
|
All,
|
|
6,
|
|
78,
|
|
80,
|
|
1,
|
|
false);
|
|
|
|
#else
|
|
check = MySchemaOp->createTable(tableName[i],
|
|
8, // Table Size
|
|
TupleKey, // Key Type
|
|
40); // Nr of Pages
|
|
#endif
|
|
if (check == -1) {
|
|
// Clean up opened schema transaction
|
|
NdbSchemaCon::closeSchemaTrans(MySchemaTransaction);
|
|
return(-1);
|
|
} // if
|
|
|
|
// Primary key
|
|
//ndbout << " pk " << (char*)&attrName[0] << "..." << endl;
|
|
check = MySchemaOp->createAttribute( (char*)attrName[0], TupleKey, 32,
|
|
1, UnSigned, MMBased,
|
|
NotNullAttribute );
|
|
if (check == -1) {
|
|
// Clean up opened schema transaction
|
|
NdbSchemaCon::closeSchemaTrans(MySchemaTransaction);
|
|
return(-1);
|
|
} // if
|
|
|
|
// Rest of attributes
|
|
for (j = 1; j < tNoOfAttributes ; j++) {
|
|
//ndbout << " " << (char*)attrName[j] << "..." << endl;
|
|
check = MySchemaOp->createAttribute( (char*)attrName[j], NoKey, 32,
|
|
tAttributeSize, UnSigned, MMBased,
|
|
NotNullAttribute );
|
|
if (check == -1) {
|
|
// Clean up opened schema transaction
|
|
NdbSchemaCon::closeSchemaTrans(MySchemaTransaction);
|
|
return(-1);
|
|
} // if
|
|
} // for
|
|
|
|
// Execute creation
|
|
check = MySchemaTransaction->execute();
|
|
if (check == -1) {
|
|
// Clean up opened schema transaction
|
|
NdbSchemaCon::closeSchemaTrans(MySchemaTransaction);
|
|
return(-1);
|
|
} // if
|
|
|
|
NdbSchemaCon::closeSchemaTrans(MySchemaTransaction);
|
|
} // for
|
|
} // if
|
|
|
|
return(0);
|
|
|
|
} // createTables
|
|
|
|
|
|
static int setAttrNames()
|
|
{
|
|
int i = 0;
|
|
int retVal = 0;
|
|
|
|
for (i = 0; i < MAXATTR ; i++) {
|
|
retVal = BaseString::snprintf(attrName[i], MAXSTRLEN, "COL%d", i);
|
|
if (retVal < 0) {
|
|
// Error in conversion
|
|
return(-1);
|
|
} // if
|
|
} // for
|
|
|
|
return (0);
|
|
} // setAttrNames
|
|
|
|
static int setTableNames()
|
|
{
|
|
// Note! Uses only uppercase letters in table name's
|
|
// so that we can look at the tables wits SQL
|
|
int i = 0;
|
|
int retVal = 0;
|
|
|
|
for (i = 0; i < MAXTABLES ; i++) {
|
|
if (theStandardTableNameFlag == 0) {
|
|
retVal = BaseString::snprintf(tableName[i], MAXSTRLEN, "TAB%d_%d", i,
|
|
NdbTick_CurrentMillisecond()/1000);
|
|
} // if
|
|
else {
|
|
retVal = BaseString::snprintf(tableName[i], MAXSTRLEN, "TAB%d", i);
|
|
} // else
|
|
if (retVal < 0) {
|
|
// Error in conversion
|
|
return(-1);
|
|
} // if
|
|
} // for
|
|
|
|
return(0);
|
|
} // setTableNames
|
|
|
|
static int checkThreadResults(ThreadNdb *threadArrayP, char* phase)
|
|
{
|
|
int i = 0;
|
|
|
|
for (i = 0; i < tNoOfThreads; i++) {
|
|
if (threadArrayP[i].threadResult != 0) {
|
|
ndbout << "Thread " << i << " reported fatal error "
|
|
<< threadArrayP[i].threadResult << " during " << phase << endl;
|
|
return(-1);
|
|
} // if
|
|
} // for
|
|
|
|
return(0);
|
|
}
|
|
|