flexHammer.cpp
上传用户:romrleung
上传日期:2022-05-23
资源大小:18897k
文件大小:24k
源码类别:

MySQL数据库

开发平台:

Visual C++

  1. /* Copyright (C) 2003 MySQL AB
  2.    This program is free software; you can redistribute it and/or modify
  3.    it under the terms of the GNU General Public License as published by
  4.    the Free Software Foundation; either version 2 of the License, or
  5.    (at your option) any later version.
  6.    This program is distributed in the hope that it will be useful,
  7.    but WITHOUT ANY WARRANTY; without even the implied warranty of
  8.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  9.    GNU General Public License for more details.
  10.    You should have received a copy of the GNU General Public License
  11.    along with this program; if not, write to the Free Software
  12.    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
  13. /* ***************************************************
  14.        FLEXHAMMER
  15.        Hammer ndb with read, insert, update and delete transactions. 
  16.        Arguments:
  17.         -t Number of threads to start, default 1
  18.         -o Number of operations per hammering-round, default 500
  19. -l Number of loops to run, default 1, 0=infinite
  20.         -a Number of attributes, default 25
  21.         -c Number of tables, default 1
  22. -s Size of each attribute, default 1
  23. -simple Use simple read to read from database
  24.         -dirty Use dirty read to read from database
  25. -write Use writeTuple to write to db
  26. -r Number of records to Hammer
  27.         -no_table_create Don't create tables in db
  28.         -regulate To be able to regulate the load flexHammer produces.
  29.         -stdtables Use standard table names
  30. -sleep Sleep a number of seconds before running the test, this 
  31.        can be used so that another flexProgram have tome to create tables
  32.        Returns:
  33.         0 - Test passed
  34.        -1 - Test failed
  35.         1 - Invalid arguments
  36. Revision history:
  37.   1.7  020208 epesson: Adapted to use NDBT
  38.   1.10 020222 epesson: Finalised handling of thread results
  39.   1.11 020222 epesson: Bug in checking results during delete fixed
  40.  * *************************************************** */
  41. #include <NdbApi.hpp>
  42. #include <NdbMain.h>
  43. #include <NdbThread.h>
  44. #include <NdbSleep.h>
  45. #include <NdbTick.h>
  46. #include <NdbOut.hpp>
  47. #include <NdbTimer.hpp>
  48. #include <NdbTick.h>
  49. #include <NdbTest.hpp>
  50. #include <NDBT_Error.hpp>
  51. #include <NdbSchemaCon.hpp>
  52. ErrorData * flexHammerErrorData;
  53. #if defined NDB_OSE || defined NDB_SOFTOSE
  54. #include <outfmt.h> 
  55. #endif
  56. #define MAXSTRLEN 16 
  57. #define MAXATTR 64
  58. #define MAXTABLES 64
  59. #define MAXTHREADS 256
  60. #define MAXATTRSIZE 100
  61. // Max number of retries if something fails
  62. #define MaxNoOfAttemptsC 10 
  63. enum StartType {
  64.   stIdle,
  65.   stHammer,
  66.   stStop,
  67.   stLast};
  68. enum MyOpType {
  69.   otInsert,
  70.   otRead,
  71.   otDelete,
  72.   otUpdate,
  73.   otLast};
  74. struct ThreadNdb {
  75.   int threadNo;
  76.   NdbThread* threadLife;
  77.   int threadReady;
  78.   StartType threadStart;
  79.   int threadResult;};
  80. extern "C" void* flexHammerThread(void*);
  81. static int setAttrNames(void);
  82. static int setTableNames(void);
  83. static int readArguments(int, const char**);
  84. static int createTables(Ndb*);
  85. static void sleepBeforeStartingTest(int seconds);
  86. static int checkThreadResults(ThreadNdb *threadArrayP, char* phase);
  87. //enum OperationType {
  88. //  otInsert,
  89. //  otRead,
  90. //  otUpdate,
  91. //  otDelete,
  92. //  otVerifyDelete,
  93. //  otLast };
  94. enum ReadyType {
  95. stReady, 
  96. stRunning
  97. } ;
  98. static int tNoOfThreads;
  99. static int tNoOfAttributes;
  100. static int tNoOfTables;
  101. static int tNoOfBackups;
  102. static int tAttributeSize;
  103. static int tNoOfOperations;
  104. static int tNoOfRecords;
  105. static int tNoOfLoops;
  106. static ReadyType ThreadReady[MAXTHREADS];
  107. static StartType ThreadStart[MAXTHREADS];
  108. static char tableName[MAXTABLES][MAXSTRLEN];
  109. static char attrName[MAXATTR][MAXSTRLEN];
  110. static int theSimpleFlag = 0;
  111. static int theWriteFlag = 0;
  112. static int theDirtyFlag = 0;
  113. static int theTableCreateFlag = 0;
  114. static int theStandardTableNameFlag = 0;
  115. static unsigned int tSleepTime = 0;
  116. #define START_TIMER { NdbTimer timer; timer.doStart();
  117. #define STOP_TIMER timer.doStop();
  118. #define PRINT_TIMER(text, trans, opertrans) timer.printTransactionStatistics(text, trans, opertrans); }; 
  119. // Initialise thread data
  120. void 
  121. resetThreads(ThreadNdb *threadArrayP) {
  122.   for (int i = 0; i < tNoOfThreads ; i++)
  123.     {
  124.       threadArrayP[i].threadReady = 0;
  125.       threadArrayP[i].threadResult = 0;
  126.       threadArrayP[i].threadStart = stIdle;
  127.     }
  128. } // resetThreads
  129. void 
  130. waitForThreads(ThreadNdb *threadArrayP)
  131. {
  132.   int cont = 1;
  133.   while (cont) {
  134.     NdbSleep_MilliSleep(100);
  135.     cont = 0;
  136.     for (int i = 0; i < tNoOfThreads ; i++) {
  137.       if (threadArrayP[i].threadReady == 0) {
  138. cont = 1;
  139.       } // if
  140.     } // for
  141.   } // while
  142. } // waitForThreads
  143. void 
  144. tellThreads(ThreadNdb* threadArrayP, const StartType what)
  145. {
  146.   for (int i = 0; i < tNoOfThreads ; i++) 
  147.     {
  148.     threadArrayP[i].threadStart = what;
  149.     } // for
  150. } // tellThreads
  151.  
  152. NDB_COMMAND(flexHammer, "flexHammer", "flexHammer", "flexHammer", 65535)
  153. //main(int argc, const char** argv)
  154. {
  155.   ndb_init();
  156.   ThreadNdb* pThreads = NULL; // Pointer to thread data array
  157.   Ndb* pMyNdb = NULL;       // Pointer to Ndb object
  158.   int tLoops = 0;
  159.   int returnValue = 0;
  160.   int check = 0;
  161.   
  162.   flexHammerErrorData = new ErrorData;
  163.   flexHammerErrorData->resetErrorCounters();
  164.   if (readArguments(argc, argv) != 0) {
  165.     ndbout << "Wrong arguments to flexHammer" << endl;
  166.     return NDBT_ProgramExit(NDBT_WRONGARGS);
  167.   } // if
  168.   /* print Setting */
  169.   flexHammerErrorData->printSettings(ndbout);
  170.   check = setAttrNames();
  171.   if (check == -1) {
  172.     ndbout << "Couldn't set attribute names" << endl;
  173.     return NDBT_ProgramExit(NDBT_FAILED);
  174.   } // if
  175.   check = setTableNames();
  176.   if (check == -1) {
  177.     ndbout << "Couldn't set table names" << endl;
  178.     return NDBT_ProgramExit(NDBT_FAILED);
  179.   } // if
  180.   // Create thread data array
  181.   pThreads = new ThreadNdb[tNoOfThreads];
  182.   // NdbThread_SetConcurrencyLevel(tNoOfThreads + 2);
  183.   // Create and init Ndb object
  184.   pMyNdb = new Ndb("TEST_DB");
  185.   pMyNdb->init();
  186.   // Wait for Ndb to become ready
  187.   if (pMyNdb->waitUntilReady(10000) != 0) {
  188.     ndbout << "NDB is not ready" << endl << "Benchmark failed" << endl;
  189.     returnValue = NDBT_FAILED;
  190.   }
  191.   else {
  192.     check = createTables(pMyNdb);
  193.     if (check != 0) {
  194.       returnValue = NDBT_FAILED;
  195.     } // if
  196.     else {
  197.       sleepBeforeStartingTest(tSleepTime);
  198.       
  199.       // Create threads.                                           *
  200.       resetThreads(pThreads);
  201.       for (int i = 0; i < tNoOfThreads ; i++) {  
  202. pThreads[i].threadNo = i;
  203. pThreads[i].threadLife = NdbThread_Create(flexHammerThread,
  204.   (void**)&pThreads[i],
  205.   65535,
  206.   "flexHammerThread",
  207.                                                   NDB_THREAD_PRIO_LOW);
  208.       } // for
  209.       
  210.       // And wait until they are ready
  211.       waitForThreads(pThreads);
  212.       if (checkThreadResults(pThreads, "init") != 0) {
  213.         returnValue = NDBT_FAILED;
  214.       } // if
  215.       
  216.       
  217.       if (returnValue == NDBT_OK) {
  218. ndbout << endl <<  "All threads started" << endl << endl;
  219. for(;;) {
  220.   
  221.   // Check if it's time to exit program
  222.   if((tNoOfLoops != 0) && (tNoOfLoops <= tLoops))
  223.     break;
  224.   
  225.   // Tell all threads to start hammer
  226.   ndbout << "Hammering..." << endl;
  227.   
  228.   resetThreads(pThreads);
  229.   
  230.   START_TIMER;
  231.   tellThreads(pThreads, stHammer);
  232.   
  233.   waitForThreads(pThreads);
  234.   ndbout << "Threads ready to continue..." << endl;
  235.   STOP_TIMER;
  236.   
  237.   // Check here if anything went wrong
  238.   if (checkThreadResults(pThreads, "hammer") != 0) {
  239.     ndbout << "Thread(s) failed." << endl;
  240.     returnValue = NDBT_FAILED;
  241.   } // if
  242.   
  243.   PRINT_TIMER("hammer", tNoOfOperations*tNoOfThreads, tNoOfTables*6);
  244.   
  245.   ndbout << endl;
  246.   
  247.   tLoops++;
  248.   
  249. } // for
  250.       } // if
  251.       // Signaling threads to stop 
  252.       resetThreads(pThreads);
  253.       tellThreads(pThreads, stStop);
  254.       
  255.       // Wait for threads to stop
  256.       waitForThreads(pThreads);
  257.       
  258.       ndbout << "----------------------------------------------" << endl << endl;
  259.       ndbout << "Benchmark completed" << endl;
  260.     } // else
  261.   } // else
  262.   // Clean up 
  263.   flexHammerErrorData->printErrorCounters(ndbout);
  264.   // Kill them all! 
  265.   void* tmp;
  266.   for(int i = 0; i < tNoOfThreads; i++){
  267.     NdbThread_WaitFor(pThreads[i].threadLife, &tmp);
  268.     NdbThread_Destroy(&pThreads[i].threadLife);
  269.   }
  270.   delete flexHammerErrorData;
  271.   delete [] pThreads;
  272.   delete pMyNdb;
  273.   // Exit via NDBT
  274.   return NDBT_ProgramExit(returnValue);
  275.   
  276. } //main
  277. extern "C"
  278. void*
  279. flexHammerThread(void* pArg)
  280. {
  281.   ThreadNdb* pThreadData = (ThreadNdb*)pArg;
  282.   unsigned int threadNo = pThreadData->threadNo;
  283.   Ndb* pMyNdb = NULL ;
  284.   NdbConnection *pMyTransaction = NULL ;
  285.   //  NdbOperation* pMyOperation[MAXTABLES] = {NULL};
  286.   NdbOperation* pMyOperation[MAXTABLES];
  287.   int check = 0;
  288.   int loop_count_ops = 0;
  289.   int loop_count_tables = 0;
  290.   int loop_count_attributes = 0;
  291.   int count_round = 0;
  292.   int count = 0;
  293.   int count_tables = 0;
  294.   int count_attributes = 0;
  295.   int i = 0;
  296.   int j = 0;
  297.   int tThreadResult = 0;
  298.   MyOpType tMyOpType = otLast;
  299.   int pkValue = 0;
  300.   int readValue[MAXATTR][MAXATTRSIZE] = {0};
  301.   int attrValue[MAXATTRSIZE];
  302.   NdbRecAttr* tTmp = NULL;
  303.   int tNoOfAttempts = 0;
  304.  
  305.   for (i = 0; i < MAXATTRSIZE; i++)
  306.     attrValue[i] = 0; 
  307.   // Ndb object for each thread
  308.   pMyNdb = new Ndb( "TEST_DB" );
  309.   pMyNdb->init();
  310.   if (pMyNdb->waitUntilReady(10000) != 0) {
  311.     // Error, NDB is not ready
  312.     tThreadResult = 99;
  313.     // Go to idle directly
  314.     pThreadData->threadStart = stIdle;
  315.   } // if
  316.   
  317.   for(;;) {
  318.     pThreadData->threadResult = tThreadResult;
  319.     pThreadData->threadReady = 1; // Signalling ready to main
  320.     
  321.     // If Idle just wait to be stopped from main
  322.     while (pThreadData->threadStart == stIdle) {
  323.       NdbSleep_MilliSleep(100);   
  324.     } // while
  325.     
  326.     // Check if signal to exit is received
  327.     if (pThreadData->threadStart == stStop) {
  328.       pThreadData->threadReady = 1;
  329.       // break out of eternal loop
  330.       break;
  331.     } // if
  332.     
  333.     // Set to Idle to prepare for possible error break
  334.     pThreadData->threadStart = stIdle;
  335.     
  336.     // Prepare transaction
  337.     loop_count_ops = tNoOfOperations;
  338.     loop_count_tables = tNoOfTables;
  339.     loop_count_attributes = tNoOfAttributes;
  340.     
  341.     for (count=0 ; count < loop_count_ops ; count++) {
  342.       
  343.       //pkValue = (int)(count + thread_base);
  344.       // This limits the number of records used in this test
  345.       pkValue = count % tNoOfRecords; 
  346.       
  347.       for (count_round = 0; count_round < 5; ) {
  348. switch (count_round) {
  349. case 0:       // Insert
  350.   tMyOpType = otInsert;
  351.   // Increase attrValues
  352.   for (i=0; i < MAXATTRSIZE; i ++) {
  353.     attrValue[i]++;
  354.   }
  355.   break;
  356. case 1: 
  357. case 3:       // Read and verify
  358.   tMyOpType = otRead;
  359.   break;
  360. case 2:       // Update
  361.   // Increase attrValues
  362.   for(i=0; i < MAXATTRSIZE; i ++) {
  363.     attrValue[i]++;
  364.   }
  365.   tMyOpType = otUpdate;
  366.   break;
  367. case 4:       // Delete
  368.   tMyOpType = otDelete;
  369.   break;
  370. default:
  371.   assert(false);
  372.   break;
  373. } // switch
  374.     
  375. // Get transaction object
  376. pMyTransaction = pMyNdb->startTransaction();
  377. if (pMyTransaction == NULL) {
  378.   // Fatal error
  379.   tThreadResult = 1;
  380.   // break out of for count_round loop waiting to be stopped by main
  381.   break;
  382. } // if
  383. for (count_tables = 0; count_tables < loop_count_tables; 
  384.      count_tables++) {
  385.   pMyOperation[count_tables] = 
  386.     pMyTransaction->getNdbOperation(tableName[count_tables]);
  387.   if (pMyOperation[count_tables] == NULL) {
  388.     //Fatal error
  389.     tThreadResult = 2;
  390.     // break out of inner for count_tables loop
  391.     break;
  392.   } // if
  393.   switch (tMyOpType) {
  394.   case otInsert: // Insert case
  395.     if (theWriteFlag == 1 && theDirtyFlag == 1) {
  396.       check = pMyOperation[count_tables]->dirtyWrite();
  397.     } else if (theWriteFlag == 1) {
  398.       check = pMyOperation[count_tables]->writeTuple();
  399.     } else {
  400.       check = pMyOperation[count_tables]->insertTuple();
  401.     } // if else
  402.     break;
  403.   case otRead: // Read Case
  404.     if (theSimpleFlag == 1) {
  405.       check = pMyOperation[count_tables]->simpleRead();
  406.     } else if (theDirtyFlag == 1) {
  407.       check = pMyOperation[count_tables]->dirtyRead();
  408.     } else {
  409.       check = pMyOperation[count_tables]->readTuple();
  410.     } // if else
  411.     break;
  412.   case otUpdate: // Update Case
  413.     if (theWriteFlag == 1 && theDirtyFlag == 1) {
  414.       check = pMyOperation[count_tables]->dirtyWrite();
  415.     } else if (theWriteFlag == 1) {
  416.       check = pMyOperation[count_tables]->writeTuple();
  417.     } else if (theDirtyFlag == 1) {
  418.       check = pMyOperation[count_tables]->dirtyUpdate();
  419.     } else {
  420.       check = pMyOperation[count_tables]->updateTuple();
  421.     } // if else
  422.     break;
  423.   case otDelete: // Delete Case
  424.     check = pMyOperation[count_tables]->deleteTuple();
  425.     break;
  426.   default:
  427.     assert(false);
  428.     break;
  429.   } // switch
  430.   if (check == -1) {
  431.     // Fatal error
  432.     tThreadResult = 3;
  433.     // break out of inner for count_tables loop
  434.     break;
  435.   } // if
  436.   check = pMyOperation[count_tables]->equal( (char*)attrName[0], 
  437.     (char*)&pkValue );
  438.   if (check == -1) {
  439.     // Fatal error
  440.     tThreadResult = 4;
  441.     ndbout << "pMyOperation equal failed" << endl;
  442.     // break out of inner for count_tables loop
  443.     break;
  444.   } // if
  445.   
  446.   check = -1;
  447.   tTmp = NULL;
  448.   switch (tMyOpType) {
  449.   case otInsert: // Insert case
  450.   case otUpdate: // Update Case
  451.     for (count_attributes = 1; count_attributes < loop_count_attributes;
  452.  count_attributes++) {
  453.       check = 
  454. pMyOperation[count_tables]->setValue((char*)attrName[count_attributes], (char*)&attrValue[0]);
  455.     } // for
  456.     break;
  457.   case otRead: // Read Case
  458.     for (count_attributes = 1; count_attributes < loop_count_attributes; 
  459.  count_attributes++) {
  460.       tTmp = pMyOperation[count_tables]->
  461. getValue( (char*)attrName[count_attributes], 
  462.   (char*)&readValue[count_attributes][0] );
  463.     } // for
  464.     break;
  465.   case otDelete: // Delete Case
  466.     break;
  467.   default:
  468.     assert(false);
  469.     break;
  470.   } // switch
  471.   if (check == -1 && tTmp == NULL && tMyOpType != otDelete) {
  472.     // Fatal error
  473.     tThreadResult = 5;
  474.     break;
  475.   } // if
  476. } // for count_tables
  477.     
  478. // Only execute if everything is OK
  479. if (tThreadResult != 0) {
  480.   // Close transaction (below)
  481.   // and continue with next count_round
  482.   count_round++;
  483.   tNoOfAttempts = 0;
  484. } // if
  485. else {
  486.   check = pMyTransaction->execute(Commit);
  487.   if (check == -1 ) {
  488.     const NdbError & err = pMyTransaction->getNdbError();
  489. // Add complete error handling here
  490.               int retCode = flexHammerErrorData->handleErrorCommon(pMyTransaction->getNdbError());
  491.               if (retCode == 1) {
  492. //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);
  493. if (pMyTransaction->getNdbError().code != 626 && pMyTransaction->getNdbError().code != 630){
  494.      ndbout_c("Error code = %d", pMyTransaction->getNdbError().code);
  495.      ndbout_c("execute: %s", pMyTransaction->getNdbError().message);}
  496.               } else if (retCode == 2) {
  497.                 ndbout << "4115 should not happen in flexHammer" << endl;
  498.               } else if (retCode == 3) {
  499. // --------------------------------------------------------------------
  500. // We are not certain if the transaction was successful or not.
  501. // We must reexecute but might very well find that the transaction
  502. // actually was updated. Updates and Reads are no problem here. Inserts
  503. // will not cause a problem if error code 630 arrives. Deletes will
  504. // not cause a problem if 626 arrives.
  505. // --------------------------------------------------------------------
  506. /* What can we do here? */
  507. ndbout_c("execute: %s", pMyTransaction->getNdbError().message);
  508.                  }//if(retCode == 3)
  509. // End of adding complete error handling
  510.     switch( err.classification) {
  511.     case NdbError::ConstraintViolation: // Tuple already existed
  512.       count_round++;
  513.       tNoOfAttempts = 0;
  514.       break;
  515.     case NdbError::TimeoutExpired:
  516.     case NdbError::NodeRecoveryError:
  517.     case NdbError::TemporaryResourceError:
  518.     case NdbError::OverloadError:
  519.       if (tNoOfAttempts <= MaxNoOfAttemptsC) {
  520. // Retry
  521. tNoOfAttempts++;
  522.       } else {
  523. // Too many retries, continue with next
  524. count_round++;
  525. tNoOfAttempts = 0;
  526.       } // else if
  527.       break;
  528.       // Fatal, just continue
  529.     default:
  530.       count_round++;
  531.       tNoOfAttempts = 0;
  532.       break;
  533.     } // switch
  534.   } // if
  535.   else {
  536.     // Execute commit was OK
  537.     // This is verifying read values
  538.     //switch (tMyOpType) {
  539.     //case otRead:  // Read case
  540.     //for (j = 0; j < tNoOfAttributes; j++) {
  541.     //for(i = 1; i < tAttributeSize; i++) {
  542.     //if ( readValue[j][i] != attrValue[i]) {
  543.     //ndbout << "pkValue = " << pkValue << endl;
  544.     //ndbout << "readValue != attrValue" << endl;
  545.     //ndbout << readValue[j][i] << " != " << attrValue[i] << endl;
  546.     //} // if
  547.     //  } // for
  548.     //} // for
  549.     //break;
  550.     //} // switch
  551.     count_round++;
  552.     tNoOfAttempts = 0;
  553.   } // else if
  554. } // else if
  555. pMyNdb->closeTransaction(pMyTransaction);
  556.       } // for count_round
  557.     } // for count
  558.   } // for (;;)
  559.   // Clean up
  560.   delete pMyNdb; 
  561.   pMyNdb = NULL;
  562.   flexHammerErrorData->resetErrorCounters();
  563.   return  NULL; // thread exits
  564.   
  565. } // flexHammerThread
  566. int
  567. readArguments (int argc, const char** argv)
  568. {
  569.   int i = 1;
  570.   
  571.   tNoOfThreads = 5; // Default Value
  572.   tNoOfOperations = 500; // Default Value
  573.   tNoOfRecords = 1;             // Default Value
  574.   tNoOfLoops = 1;         // Default Value
  575.   tNoOfAttributes = 25; // Default Value
  576.   tNoOfTables = 1; // Default Value
  577.   tNoOfBackups = 0; // Default Value
  578.   tAttributeSize = 1; // Default Value
  579.   theTableCreateFlag = 0;
  580.   
  581.   while (argc > 1) {
  582.     if (strcmp(argv[i], "-t") == 0) {
  583.       tNoOfThreads = atoi(argv[i+1]);
  584.       if ((tNoOfThreads < 1) || (tNoOfThreads > MAXTHREADS))
  585. return(1);
  586.     }
  587.     else if (strcmp(argv[i], "-o") == 0) {
  588.       tNoOfOperations = atoi(argv[i+1]);
  589.       if (tNoOfOperations < 1)
  590. return(1);
  591.     }
  592.     else if (strcmp(argv[i], "-r") == 0) {
  593.       tNoOfRecords = atoi(argv[i+1]);
  594.       if (tNoOfRecords < 1)
  595. return(1);
  596.     }
  597.     else if (strcmp(argv[i], "-a") == 0) {
  598.       tNoOfAttributes = atoi(argv[i+1]);
  599.       if ((tNoOfAttributes < 2) || (tNoOfAttributes > MAXATTR))
  600. return(1);
  601.     }
  602.     else if (strcmp(argv[i], "-c") == 0) {
  603.       tNoOfTables = atoi(argv[i+1]);
  604.       if ((tNoOfTables < 1) || (tNoOfTables > MAXTABLES))
  605. return(1);
  606.     }
  607.     else if (strcmp(argv[i], "-l") == 0) {
  608.       tNoOfLoops = atoi(argv[i+1]);
  609.       if ((tNoOfLoops < 0) || (tNoOfLoops > 100000))
  610. return(1);
  611.     }
  612.     else if (strcmp(argv[i], "-s") == 0) {
  613.       tAttributeSize = atoi(argv[i+1]);
  614.       if ((tAttributeSize < 1) || (tAttributeSize > MAXATTRSIZE))
  615. return(1);
  616.     }
  617.     else if (strcmp(argv[i], "-sleep") == 0) {
  618.       tSleepTime = atoi(argv[i+1]);
  619.       if ((tSleepTime < 1) || (tSleepTime > 3600))
  620. exit(-1);
  621.     }
  622.     else if (strcmp(argv[i], "-simple") == 0) {
  623.       theSimpleFlag = 1;
  624.       argc++;
  625.       i--;
  626.     }
  627.     else if (strcmp(argv[i], "-write") == 0) {
  628.       theWriteFlag = 1;
  629.       argc++;
  630.       i--;
  631.     }
  632.     else if (strcmp(argv[i], "-dirty") == 0) {
  633.       theDirtyFlag = 1;
  634.       argc++;
  635.       i--;
  636.     }
  637.     else if (strcmp(argv[i], "-no_table_create") == 0) {
  638.       theTableCreateFlag = 1;
  639.       argc++;
  640.       i--;
  641.     }
  642.     else if (strcmp(argv[i], "-stdtables") == 0) {
  643.       theStandardTableNameFlag = 1;
  644.       argc++;
  645.       i--;
  646.     } // if
  647.     else {
  648.       return(1);
  649.     }
  650.     
  651.     argc -= 2;
  652.     i = i + 2;
  653.   } // while
  654.   
  655.   ndbout << endl << "FLEXHAMMER - Starting normal mode" << endl;
  656.   ndbout << "Hammer ndb with read, insert, update and delete transactions"<< endl << endl;
  657.   
  658.   ndbout << "  " << tNoOfThreads << " thread(s) " << endl;
  659.   ndbout << "  " << tNoOfLoops << " iterations " << endl;
  660.   ndbout << "  " << tNoOfTables << " table(s) and " << 1 << " operation(s) per transaction " << endl;
  661.   ndbout << "  " << tNoOfRecords << " records to hammer(limit this with the -r option)" << endl;
  662.   ndbout << "  " << tNoOfAttributes << " attributes per table " << endl;
  663.   ndbout << "  " << tNoOfOperations << " transaction(s) per thread and round " << endl;
  664.   ndbout << "  " << tAttributeSize << " is the number of 32 bit words per attribute " << endl << endl;
  665.   return 0;
  666. } // readArguments
  667. void sleepBeforeStartingTest(int seconds)
  668. {
  669.   if (seconds > 0) {
  670.     ndbout << "Sleeping(" << seconds << ")...";
  671.     NdbSleep_SecSleep(seconds);
  672.     ndbout << " done!" << endl;
  673.   } // if
  674. } // sleepBeforeStartingTest
  675. static int
  676. createTables(Ndb* pMyNdb)
  677. {
  678.   int i = 0;
  679.   int j = 0;
  680.   int check = 0;
  681.   NdbSchemaCon *MySchemaTransaction = NULL;
  682.   NdbSchemaOp *MySchemaOp = NULL;
  683.   // Create Table and Attributes.                            
  684.   if (theTableCreateFlag == 0) {
  685.     for (i = 0; i < tNoOfTables; i++) {
  686.       ndbout << "Creating " << tableName[i] << "...";
  687.       // Check if table exists already
  688.       const void * p = pMyNdb->getDictionary()->getTable(tableName[i]);
  689.       if (p != 0) {
  690. ndbout << " already exists." << endl;
  691. // Continue with next table at once
  692. continue;
  693.       } // if
  694.       ndbout << endl;
  695.       
  696.       MySchemaTransaction = NdbSchemaCon::startSchemaTrans(pMyNdb);
  697.       if (MySchemaTransaction == NULL) {
  698. return(-1);
  699.       } // if
  700.       
  701.       MySchemaOp = MySchemaTransaction->getNdbSchemaOp();
  702.       if (MySchemaOp == NULL) {
  703. // Clean up opened schema transaction
  704. NdbSchemaCon::closeSchemaTrans(MySchemaTransaction);
  705. return(-1);
  706.       } // if
  707.       
  708.       // Create tables, rest of parameters are default right now
  709. #if defined NDB_OSE || defined NDB_SOFTOSE
  710.       check = MySchemaOp->createTable(tableName[i],
  711.       8, // Table Size
  712.       TupleKey, // Key Type
  713.       40, // Nr of Pages
  714.       All, 
  715.       6,
  716.       78,
  717.       80,
  718.       1,
  719.       false);
  720. #else
  721.       check = MySchemaOp->createTable(tableName[i],
  722.       8, // Table Size
  723.       TupleKey, // Key Type
  724.       40); // Nr of Pages
  725. #endif
  726.       if (check == -1) { 
  727. // Clean up opened schema transaction
  728. NdbSchemaCon::closeSchemaTrans(MySchemaTransaction);
  729. return(-1);
  730.       } // if
  731.       
  732.       // Primary key
  733.       //ndbout << "  pk " << (char*)&attrName[0] << "..." << endl;
  734.       check = MySchemaOp->createAttribute( (char*)attrName[0], TupleKey, 32,
  735.    1, UnSigned, MMBased,
  736.    NotNullAttribute );
  737.       if (check == -1) { 
  738. // Clean up opened schema transaction
  739. NdbSchemaCon::closeSchemaTrans(MySchemaTransaction);
  740. return(-1);
  741.       } // if
  742.       // Rest of attributes
  743.       for (j = 1; j < tNoOfAttributes ; j++) {
  744. //ndbout << "    " << (char*)attrName[j] << "..." << endl;
  745. check = MySchemaOp->createAttribute( (char*)attrName[j], NoKey, 32, 
  746.      tAttributeSize, UnSigned, MMBased, 
  747.      NotNullAttribute );
  748. if (check == -1) {
  749.   // Clean up opened schema transaction
  750.   NdbSchemaCon::closeSchemaTrans(MySchemaTransaction);
  751.   return(-1);
  752. } // if
  753.       } // for
  754.   
  755.       // Execute creation
  756.       check = MySchemaTransaction->execute();
  757.       if (check == -1) {
  758. // Clean up opened schema transaction
  759. NdbSchemaCon::closeSchemaTrans(MySchemaTransaction);
  760. return(-1);
  761.       } // if
  762.       
  763.       NdbSchemaCon::closeSchemaTrans(MySchemaTransaction);
  764.     } // for
  765.   } // if
  766.   return(0);
  767. } // createTables 
  768. static int setAttrNames()
  769. {
  770.   int i = 0;
  771.   int retVal = 0;
  772.   for (i = 0; i < MAXATTR ; i++) {
  773.     retVal = BaseString::snprintf(attrName[i], MAXSTRLEN, "COL%d", i);
  774.     if (retVal < 0) {
  775.       // Error in conversion
  776.       return(-1);
  777.     } // if
  778.   } // for
  779.   return (0);
  780. } // setAttrNames
  781. static int setTableNames()
  782. {
  783.   // Note! Uses only uppercase letters in table name's
  784.   // so that we can look at the tables wits SQL
  785.   int i = 0;
  786.   int retVal = 0;
  787.   for (i = 0; i < MAXTABLES ; i++) {
  788.     if (theStandardTableNameFlag == 0) {
  789.       retVal = BaseString::snprintf(tableName[i], MAXSTRLEN, "TAB%d_%d", i, 
  790.  NdbTick_CurrentMillisecond()/1000);
  791.     } // if 
  792.     else {
  793.       retVal = BaseString::snprintf(tableName[i], MAXSTRLEN, "TAB%d", i);
  794.     } // else
  795.     if (retVal < 0) {
  796.       // Error in conversion
  797.       return(-1);
  798.     } // if
  799.   } // for
  800.   return(0);
  801. } // setTableNames
  802. static int checkThreadResults(ThreadNdb *threadArrayP, char* phase)
  803. {
  804.   int i = 0;
  805.   for (i = 0; i < tNoOfThreads; i++) {
  806.     if (threadArrayP[i].threadResult != 0) {
  807.       ndbout << "Thread " << i << " reported fatal error " 
  808.      << threadArrayP[i].threadResult << " during " << phase << endl;
  809.       return(-1);
  810.     } // if
  811.   } // for
  812.   return(0);
  813. }