summaryrefslogtreecommitdiff
path: root/ndb/test/ndbapi/flexHammer.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'ndb/test/ndbapi/flexHammer.cpp')
-rw-r--r--ndb/test/ndbapi/flexHammer.cpp890
1 files changed, 890 insertions, 0 deletions
diff --git a/ndb/test/ndbapi/flexHammer.cpp b/ndb/test/ndbapi/flexHammer.cpp
new file mode 100644
index 00000000000..c1c47923de9
--- /dev/null
+++ b/ndb/test/ndbapi/flexHammer.cpp
@@ -0,0 +1,890 @@
+/* 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)
+{
+ 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();
+
+ // And exit using NDBT
+ NdbThread_Exit(0);
+
+ return NULL;
+
+} // 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 = 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 = snprintf(tableName[i], MAXSTRLEN, "TAB%d_%d", i,
+ NdbTick_CurrentMillisecond()/1000);
+ } // if
+ else {
+ retVal = 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);
+}
+