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

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.        FLEXSCAN
  15.        Perform benchmark of:
  16.          insert
  17.  read
  18.  scan read
  19.  update
  20.  scan update
  21.  read
  22.  scan delete
  23.  verify delete
  24.        Arguments:
  25.         -f Location of Ndb.cfg file, default Ndb.cfg
  26.         -t Number of threads to start, default 1
  27.         -o Number of operations per loop, default 500 -l Number of loops to run, default 1, 0=infinite
  28.         -a Number of attributes, default 25
  29.         -c Number of tables, default 1
  30. -s Size of each attribute, default 1
  31. -stdtables Use standard table names
  32.         -no_table_create Don't create tables in db
  33. -sleep Sleep a number of seconds before running the test, this 
  34.        can be used so that another flexBench hav etome to create tables
  35. -p Parallellism to use 1-32, default:1
  36. -abort <number> Test scan abort after a number of tuples
  37. -h Print help text
  38. -no_scan_update Don't do scan updates
  39. -no_scan_delete Don't do scan deletes
  40.        Returns:
  41.         NDBT_OK - Test passed
  42.         NDBT_FAILED - Test failed
  43.   Revision history:
  44.     1.12 020222 epesson: Rewritten to use NDBT. Major bugs fixed
  45.  * *************************************************** */
  46. #include "NdbApi.hpp"
  47. #include <NdbThread.h>
  48. #include <NdbSleep.h>
  49. #include <NdbTick.h>
  50. #include <NdbOut.hpp>
  51. #include <NdbTimer.hpp>
  52. #include <NdbMain.h>
  53. #include <NdbTest.hpp>
  54. #include <NDBT_Error.hpp>
  55. #include <NdbSchemaCon.hpp>
  56. #define PKSIZE 1
  57. #define FOREVER 1
  58. #define MAXSTRLEN 16 
  59. #define MAXATTR 64
  60. #define MAXTABLES 64
  61. #define MAXTHREADS 256
  62. #define MAXATTRSIZE 64
  63. enum StartType { 
  64.   stIdle, 
  65.   stInsert,
  66.   stRead, 
  67.   stScanRead,
  68.   stUpdate,
  69.   stScanUpdate,
  70.   stDelete,
  71.   stVerifyDelete, 
  72.   stScanDelete,
  73.   stStop,
  74.   stLast} ;
  75. struct ThreadNdb
  76. {
  77.   int ThreadNo;
  78.   NdbThread* threadLife;
  79.   StartType threadStart;
  80.   int threadResult;
  81.   int threadReady;
  82. };
  83. extern "C" void* flexScanThread(void*);
  84. static int setAttrNames(void);
  85. static int setTableNames(void);
  86. static int createTables(Ndb* pMyNdb);
  87. static void sleepBeforeStartingTest(int seconds);
  88. static int readArguments(int argc, const char** argv);
  89. static void setAttrValues(int* attrValue, 
  90.   int* readValue, 
  91.   int Offset);
  92. static int insertRows(Ndb* pNdb, int* pkValue, int* attrValue, StartType tType);
  93. static int readRows(Ndb* pNdb, int* pkValue, int* readValue);
  94. static int deleteRows(Ndb* pNdb, int* pkValue);
  95. static int scanReadRows(Ndb* pNdb, int* readValue);
  96. static int scanUpdateRows(Ndb* pNdb, int* readValue, int* attrValue);
  97. static int scanDeleteRows(Ndb* pNdb, int* readValue);
  98. static int verifyDeleteRows(Ndb* pNdb, int* pkValue, int* readValue);
  99. static void Compare(int* attrValue, int* readValue);
  100. static void UpdateArray(int *attrValue);
  101. static int tNoOfThreads = 1;
  102. static int tNoOfAttributes = 25;
  103. static int tNoOfTables = 1;
  104. static int tAttributeSize = 1;
  105. static int tNodeId = 0;
  106. static int tNoOfOperations = 500;
  107. static int tNoOfLoops = 1;
  108. static int tAbortAfter = 0;
  109. static int tParallellism = 1;
  110. static char tableName[MAXTABLES][MAXSTRLEN];
  111. static char attrName[MAXATTR][MAXSTRLEN];
  112. static unsigned int tSleepTime = 0;
  113. static int theStdTableNameFlag = 0;
  114. static int theTableCreateFlag = 0;
  115. static int theScanAbortTestFlag = 0;
  116. static int theNoScanUpdateFlag = 0;
  117. static int theNoScanDeleteFlag = 0;
  118. //flexScanErrorData = new ErrorData;
  119. ErrorData * flexScanErrorData;
  120. NdbError  * anerror;
  121. //static errorData            theErrorData; 
  122. //static unsigned int         tErrorCounter[6000]; 
  123. #define START_TIMER { NdbTimer timer; timer.doStart();
  124. #define STOP_TIMER timer.doStop();
  125. #define PRINT_TIMER(text, trans, opertrans) timer.printTransactionStatistics(text, trans, opertrans); }; 
  126. static void UpdateArray(int *attrValue)
  127. {
  128.   int tableCount = 0;
  129.   int attrCount = 0;
  130.   int opCount = 0;
  131.   int sizeCount = 0;
  132.   int* pValue = attrValue;
  133.   for (tableCount = 0; tableCount < tNoOfTables; tableCount++) {
  134.     for (attrCount = 0; attrCount < tNoOfAttributes-1; attrCount++) {
  135.       for (opCount = 0; opCount < tNoOfOperations; opCount++) {
  136. for (sizeCount = 0; sizeCount < tAttributeSize; sizeCount++) {
  137.   // Update value in array
  138.   (*pValue)++;
  139.   //ndbout << "attrValue[" << tableCount*tNoOfAttributes*tNoOfOperations*tAttributeSize +
  140.   //attrCount*tNoOfOperations*tAttributeSize + opCount*tAttributeSize + sizeCount <<
  141.   //"] = " << attrValue[tableCount*tNoOfAttributes*tNoOfOperations*tAttributeSize +
  142.   //attrCount*tNoOfOperations*tAttributeSize + opCount*tAttributeSize + sizeCount] << endl;
  143.   // Increment pointer
  144.   pValue++;
  145. } // sizeCount
  146.       } // for opCount
  147.     } // for attrCount
  148.   } // for tableCount
  149. } // Update
  150. static void Compare(int* attrValue, int* readValue)
  151. {
  152.   int tableCount = 0;
  153.   int attrCount = 0;
  154.   int OpCount = 0;
  155.   int first = 0;
  156.   for (tableCount = 0; tableCount < tNoOfTables; tableCount++) {
  157.     for (attrCount = 0; attrCount < tNoOfAttributes-1; attrCount++) {
  158.       for (OpCount = 0; OpCount < tNoOfOperations; OpCount++) {
  159. if (memcmp(&(attrValue[tableCount*(tNoOfAttributes-1)*tNoOfOperations + 
  160.       attrCount*tNoOfOperations + OpCount]),
  161.    &(readValue[tableCount*(tNoOfAttributes-1)*tNoOfOperations + 
  162.       attrCount*tNoOfOperations + OpCount]), 
  163.    tAttributeSize) != 0) {
  164.   // Values mismatch
  165.   if (first == 0) {
  166.     //ndbout << "Read and set values differ for:" << endl;
  167.     first = 1;
  168.     ndbout << "Mismatch found.";
  169.   } // if
  170.   // Comparision of values after scan update is meaningless right now
  171.   //ndbout << "  table " << tableName[tableCount] << 
  172.   //" - attr " << attrName[attrCount+1];
  173.   //for (sizeCount = 0; sizeCount < tAttributeSize; sizeCount++) {
  174.   //ndbout << ": set " << 
  175.   //attrValue[tableCount*(tNoOfAttributes-1)*tNoOfOperations*tAttributeSize + 
  176.   //attrCount*tNoOfOperations*tAttributeSize + 
  177.   //tNoOfOperations*tAttributeSize + sizeCount] << " read " << 
  178.   //readValue[tableCount*(tNoOfAttributes-1)*tNoOfOperations*tAttributeSize + 
  179.   //attrCount*tNoOfOperations*tAttributeSize + 
  180.   //tNoOfOperations*tAttributeSize + sizeCount] << endl;
  181.   //} // for
  182. } // if
  183.       } // for OpCount
  184.     } // for attrCount
  185.   } // for tableCount
  186.   // A final pretty-print
  187.   if (first == 1) {
  188.     ndbout << endl;
  189.   } // if
  190. } // Compare
  191. static void printInfo()
  192. {
  193.   ndbout << endl << "FLEXSCAN - Starting normal mode" << endl;
  194.   ndbout << "Perform benchmark of insert, update and delete transactions"<< endl;
  195.   ndbout << "  NdbAPI node with id = " << tNodeId << endl;
  196.   ndbout << "  " << tNoOfThreads << " thread(s) " << endl;
  197.   ndbout << "  " << tNoOfLoops << " iterations " << endl;
  198.   ndbout << "  " << tNoOfTables << " table(s) and " << 1 << " operation(s) per transaction " 
  199.  << endl;
  200.   ndbout << "  " << tNoOfAttributes << " attributes per table incl. pk" << endl;
  201.   ndbout << "  " << tNoOfOperations << " transaction(s) per thread and round " << endl;
  202.   if (theScanAbortTestFlag == 1) {
  203.     ndbout << "  Scan abort test after " << tAbortAfter << " tuples" << endl;
  204.   } // if
  205.   ndbout << "  " << tParallellism << " parallellism in scans" << endl;
  206.   ndbout << "  " << tAttributeSize << " is the number of 32 bit words per attribute " << 
  207.     endl << endl;
  208.   
  209. } // printInfo
  210. static void tellThreads(ThreadNdb *threadArrayP, StartType what)
  211. {
  212.   int i = 0;
  213.   for (i = 0; i < tNoOfThreads ; i++)
  214.     threadArrayP[i].threadStart = what;
  215. } // tellThreads
  216. static void waitForThreads(ThreadNdb *threadArrayP)
  217. {
  218.   int i = 0;
  219.   int cont = 1;
  220.   while (cont == 1){
  221.     NdbSleep_MilliSleep(10);
  222.     cont = 0;
  223.     
  224.     for (i = 0; i < tNoOfThreads ; i++) {
  225.       if (threadArrayP[i].threadReady == 0) {
  226. // ndbout << "Main is reporting thread " << i << " not ready" << endl;
  227. cont = 1;
  228.       } // if
  229.     } // for
  230.   } // while
  231. } // waitForThreads
  232. static void resetThreads(ThreadNdb *threadArrayP)
  233. {
  234.   int i = 0;
  235.   for (i = 0; i < tNoOfThreads ; i++) {
  236.     threadArrayP[i].threadReady = 0;
  237.     threadArrayP[i].threadResult = 0;
  238.     threadArrayP[i].threadStart = stIdle;
  239.     //ndbout << "threadStart[" << i << "]=" << 
  240.     //threadArrayP[i].threadStart << endl;
  241.   } // for
  242. } // resetThreads
  243. static int checkThreadResults(ThreadNdb *threadArrayP, char *action)
  244. {
  245.   int i = 0;
  246.   int retValue = 0;
  247.   for (i = 0; i < tNoOfThreads; i++) {
  248.     if (threadArrayP[i].threadResult != 0) {
  249.       ndbout << "Thread " << i << " reported fatal error " 
  250.      << threadArrayP[i].threadResult << " during " << action << endl;
  251.       retValue = -1;
  252.       break;
  253.     } // if
  254.   } // for
  255.   return(retValue);
  256. } // checkThreadResults
  257. NDB_COMMAND(flexScan, "flexScan", "flexScan", "flexScan", 65535)
  258. {
  259.   ndb_init();
  260.   ThreadNdb* pThreads = NULL;
  261.   Ndb* pMyNdb = NULL;
  262.   int                   tLoops = 0;
  263.   int                   check = 0;
  264.   int                   returnValue = NDBT_OK;
  265.   int                   every2ndScanDelete = 0; // Switch between scan delete and normal delete
  266.   flexScanErrorData = new ErrorData;
  267.   flexScanErrorData->resetErrorCounters();
  268.   if (readArguments(argc, argv) != 0) {
  269.     ndbout << "Wrong arguments to flexScan" << endl;
  270.     return NDBT_ProgramExit(NDBT_WRONGARGS);
  271.   } // if
  272.   /* print Setting */
  273.   flexScanErrorData->printSettings(ndbout);
  274.   check = setAttrNames();
  275.   if (check != 0) {
  276.     ndbout << "Couldn't set attribute names" << endl;
  277.     return NDBT_ProgramExit(NDBT_FAILED);
  278.   } // if
  279.   check = setTableNames();
  280.   if (check != 0) {
  281.     ndbout << "Couldn't set table names" << endl;
  282.     return NDBT_ProgramExit(NDBT_FAILED);
  283.   } // if
  284.   pMyNdb = new Ndb ("TEST_DB");
  285.   pMyNdb->init();
  286.   tNodeId = pMyNdb->getNodeId();
  287.   printInfo();
  288.                                   
  289.   NdbThread_SetConcurrencyLevel(tNoOfThreads + 2);
  290.   //NdbThread_SetConcurrencyLevel(tNoOfThreads + 8);
  291.   
  292.   pThreads = new ThreadNdb[tNoOfThreads];
  293.   if (pMyNdb->waitUntilReady(10000) != 0) {
  294.     ndbout << "NDB is not ready" << endl << "Benchmark failed"  << endl;
  295.     returnValue = NDBT_FAILED;
  296.   } // if
  297.   
  298.   else {
  299.     
  300.     if (createTables(pMyNdb) != 0) {
  301.       ndbout << "Could not create tables" << endl;
  302.       returnValue = NDBT_FAILED;
  303.     } // if
  304.     else {
  305.       sleepBeforeStartingTest(tSleepTime);
  306.       
  307.       resetThreads(pThreads);
  308.       // Create threads
  309.       for (int i = 0; i < tNoOfThreads ; i++){  
  310. pThreads[i].ThreadNo = i;
  311. // Ignore the case that thread creation may fail
  312. pThreads[i].threadLife = NdbThread_Create(flexScanThread,
  313.   (void**)&pThreads[i],
  314.   327680,
  315.   "flexScanThread", NDB_THREAD_PRIO_LOW);
  316. if (pThreads[i].threadLife == NULL) {
  317.   ndbout << "Could not create thread " << i << endl;
  318.   returnValue = NDBT_FAILED;
  319.   // Use the number of threads that were actually created
  320.   tNoOfThreads = i;
  321.   break; // break for loop
  322. } // if
  323.       } // for
  324.       
  325.       waitForThreads(pThreads);
  326.       if (checkThreadResults(pThreads, "init") != 0) {
  327. returnValue = NDBT_FAILED;
  328.       } // if
  329.       
  330.       if (returnValue == NDBT_OK) {
  331. ndbout << "All threads started" << endl;
  332. while (FOREVER) {
  333.   
  334.   resetThreads(pThreads);
  335.   
  336.   if ((tNoOfLoops != 0) && (tNoOfLoops <= tLoops)) {
  337.     break;
  338.   } // if
  339.   
  340.   // Insert
  341.   START_TIMER;
  342.   
  343.   tellThreads(pThreads, stInsert);
  344.   waitForThreads(pThreads);
  345.   
  346.   STOP_TIMER;
  347.   if (checkThreadResults(pThreads, "insert") != 0) {
  348.     returnValue = NDBT_FAILED;
  349.     break;
  350.   } // if
  351.   PRINT_TIMER("insert", tNoOfOperations*tNoOfThreads, tNoOfTables);
  352.   
  353.   resetThreads(pThreads);
  354.   
  355.   // Read
  356.   START_TIMER;
  357.   
  358.   tellThreads(pThreads, stRead);
  359.   waitForThreads(pThreads);
  360.   
  361.   STOP_TIMER;
  362.   if (checkThreadResults(pThreads, "read") != 0) {
  363.     returnValue = NDBT_FAILED;
  364.     break;
  365.   } // if
  366.   PRINT_TIMER("read", tNoOfOperations*tNoOfThreads, tNoOfTables);
  367.   
  368.   resetThreads(pThreads);
  369.   
  370.   // Update
  371.   START_TIMER;
  372.   
  373.   tellThreads(pThreads, stUpdate);
  374.   waitForThreads(pThreads);
  375.   
  376.   STOP_TIMER;
  377.   if (checkThreadResults(pThreads, "update") != 0) {
  378.     returnValue = NDBT_FAILED;
  379.     break;
  380.   } // if
  381.   PRINT_TIMER("update", tNoOfOperations*tNoOfThreads, tNoOfTables);
  382.   
  383.   resetThreads(pThreads);
  384.   
  385.   // Scan read
  386.   START_TIMER;
  387.   
  388.   tellThreads(pThreads, stScanRead);
  389.   waitForThreads(pThreads);
  390.   
  391.   STOP_TIMER;
  392.   if (checkThreadResults(pThreads, "scanread") != 0) {
  393.     returnValue = NDBT_FAILED;
  394.     break;
  395.   } // if
  396.   PRINT_TIMER("scanread", tNoOfTables*tNoOfThreads, 1);
  397.   
  398.   resetThreads(pThreads);
  399.   
  400.   // Update
  401.   START_TIMER;
  402.   
  403.   tellThreads(pThreads, stUpdate);
  404.   waitForThreads(pThreads);
  405.   
  406.   STOP_TIMER;
  407.   if (checkThreadResults(pThreads, "update") != 0) {
  408.     returnValue = NDBT_FAILED;
  409.     break;
  410.   } // if
  411.   PRINT_TIMER("update", tNoOfOperations*tNoOfThreads, tNoOfTables);
  412.   
  413.   resetThreads(pThreads);
  414.   
  415.   // Read
  416.   START_TIMER;
  417.   
  418.   tellThreads(pThreads, stRead);
  419.   waitForThreads(pThreads);
  420.   
  421.   STOP_TIMER;
  422.   if (checkThreadResults(pThreads, "read") != 0) {
  423.     returnValue = NDBT_FAILED;
  424.     break;
  425.   } // if
  426.   PRINT_TIMER("read", tNoOfOperations*tNoOfThreads, tNoOfTables);
  427.   
  428.   resetThreads(pThreads);
  429.   
  430.   // Only do scan update if told to do so
  431.   if (theNoScanUpdateFlag == 0) {
  432.     // Scan update
  433.     START_TIMER;
  434.     
  435.     tellThreads(pThreads, stScanUpdate);
  436.     waitForThreads(pThreads);
  437.     
  438.     STOP_TIMER;
  439.     if (checkThreadResults(pThreads, "scanupdate") != 0) {
  440.       returnValue = NDBT_FAILED;
  441.       break;
  442.     } // if
  443.     PRINT_TIMER("scanupdate", tNoOfTables*tNoOfThreads, 1);
  444.     
  445.     resetThreads(pThreads);
  446.     
  447.     // Read
  448.     START_TIMER;
  449.     
  450.     tellThreads(pThreads, stRead);
  451.     // tellThreads(pThreads, stScanRead);
  452.     waitForThreads(pThreads);
  453.     
  454.     STOP_TIMER;
  455.     if (checkThreadResults(pThreads, "read") != 0) {
  456.       returnValue = NDBT_FAILED;
  457.       break;
  458.     } // if
  459.     PRINT_TIMER("read", tNoOfOperations*tNoOfThreads, tNoOfTables);
  460.     
  461.     resetThreads(pThreads);
  462.   } // if theNoScanUpdateFlag
  463.   // Shift between delete and scan delete
  464.   if ((every2ndScanDelete % 2 == 0) || (theNoScanDeleteFlag == 1)){
  465.     // Delete
  466.     START_TIMER;
  467.     tellThreads(pThreads, stDelete);
  468.     waitForThreads(pThreads);
  469.     
  470.     STOP_TIMER;
  471.     if (checkThreadResults(pThreads, "delete") != 0) {
  472.       returnValue = NDBT_FAILED;
  473.       break;
  474.     } // if
  475.     PRINT_TIMER("delete", tNoOfOperations*tNoOfThreads, tNoOfTables);
  476.     resetThreads(pThreads);
  477.   } // if
  478.   else {
  479.     resetThreads(pThreads);   // Scan delete
  480.     START_TIMER;
  481.     tellThreads(pThreads, stScanDelete);
  482.     waitForThreads(pThreads);
  483.     
  484.     STOP_TIMER;
  485.     if (checkThreadResults(pThreads, "scandelete") != 0) {
  486.       returnValue = NDBT_FAILED;
  487.       break;
  488.     } // if
  489.     PRINT_TIMER("scandelete", tNoOfTables*tNoOfThreads, 1);
  490.     
  491.     resetThreads(pThreads);
  492.   } // else
  493.   every2ndScanDelete++;
  494.   resetThreads(pThreads);   // Verify delete
  495.   START_TIMER;
  496.   tellThreads(pThreads, stVerifyDelete);
  497.   waitForThreads(pThreads);
  498.   
  499.   STOP_TIMER;
  500.   if (checkThreadResults(pThreads, "verifydelete") != 0) {
  501.     returnValue = NDBT_FAILED;
  502.     break;
  503.   } // if
  504.   PRINT_TIMER("verifydelete", tNoOfOperations*tNoOfThreads*tNoOfTables, 1);
  505.   
  506.   resetThreads(pThreads);
  507.   
  508.   ndbout << "--------------------------------------------------" << endl;
  509.   tLoops++;
  510.   
  511. } // while
  512.       } // if
  513.     } // else
  514.   } // else
  515.   // Stop threads in a nice way
  516.   tellThreads(pThreads, stStop);
  517.   waitForThreads(pThreads);
  518.   // Clean up
  519.   delete [] pThreads;
  520.   delete pMyNdb;
  521.   flexScanErrorData->printErrorCounters(ndbout);
  522.   if (returnValue == NDBT_OK) {
  523.     ndbout << endl << "Benchmark completed successfully" << endl;
  524.   } // if
  525.   else {
  526.     ndbout << endl << "Benchmark failed" << endl;
  527.   } // else
  528.   // Exit via NDBT
  529.   return NDBT_ProgramExit(returnValue);;
  530. } // main
  531. void*
  532. flexScanThread(void* ThreadData)
  533. {
  534.   ThreadNdb* pThreadData = (ThreadNdb*)ThreadData;
  535.   unsigned int thread_no = pThreadData->ThreadNo;
  536.   unsigned int thread_base = (thread_no * 2000000) + (tNodeId * 26000);
  537.   int tThreadResult = 0;
  538.   Ndb* MyNdb = NULL;
  539.   int                   check = 0;
  540.   StartType        tType = stLast;
  541.   int*                  pkValue = NULL;
  542.   int* attrValue = NULL;
  543.   int* readValue = NULL;
  544.   int                   AllocSize = 0;
  545.   
  546.   AllocSize = tNoOfTables * (tNoOfAttributes-1) * tNoOfOperations * 
  547.     tAttributeSize * sizeof(int);
  548.   attrValue = (int*)malloc(AllocSize);
  549.   readValue = (int*)malloc(AllocSize);
  550.   pkValue = (int*)malloc(tNoOfOperations * sizeof(int));
  551.   if ((attrValue == NULL) || (readValue == NULL) || (pkValue == NULL)) {
  552.     tThreadResult = 98;
  553.     pThreadData->threadStart = stIdle;
  554.   } // if
  555.   
  556.   setAttrValues(attrValue, readValue, thread_base);
  557.   
  558.   MyNdb = new Ndb( "TEST_DB" );
  559.   MyNdb->init();
  560.   if (MyNdb->waitUntilReady(10000) != 0) {
  561.     tThreadResult = 99;
  562.     pThreadData->threadStart = stIdle;
  563.   } // if
  564.   
  565.   // Set primary key value, same for all tables
  566.   for (int c = 0; c < tNoOfOperations; c++) {
  567.     pkValue[c] = (int)(c + thread_base);
  568.   } // for
  569.   
  570.   while (FOREVER) {
  571.     pThreadData->threadResult = tThreadResult;
  572.     pThreadData->threadReady = 1;
  573.     
  574.     while (pThreadData->threadStart == stIdle) {
  575.       NdbSleep_MilliSleep(10);
  576.     } // while
  577.     
  578.     // Check if signal to exit is received
  579.     if (pThreadData->threadStart >= stStop){
  580.       pThreadData->threadReady = 1;
  581.       break;
  582.     } // if
  583.     tType = pThreadData->threadStart;
  584.     pThreadData->threadStart = stIdle;
  585.     
  586.     switch (tType) {
  587.     case stInsert:
  588.       check = insertRows(MyNdb, pkValue, attrValue, tType);
  589.       break;
  590.     case stRead:
  591.       check = readRows(MyNdb, pkValue, readValue);
  592.       Compare(attrValue, readValue);
  593.       break;
  594.     case stUpdate:
  595.       UpdateArray(attrValue);
  596.       check = insertRows(MyNdb, pkValue, attrValue, tType);
  597.       break;
  598.     case stScanRead:
  599.       //check = readRows(MyNdb, pkValue, readValue);
  600.       check = scanReadRows(MyNdb, readValue);
  601.       Compare(attrValue, readValue);
  602.       break;
  603.     case stScanUpdate:
  604.       UpdateArray(attrValue);
  605.       //tType = stUpdate;
  606.       //check = insertRows(MyNdb, pkValue, attrValue, tType);
  607.       check = scanUpdateRows(MyNdb, readValue, attrValue);
  608.       break;
  609.     case stDelete:
  610.       check = deleteRows(MyNdb, pkValue);
  611.       break;
  612.     case stScanDelete:
  613.       check = scanDeleteRows(MyNdb, readValue);
  614.       break;
  615.     case stVerifyDelete:
  616.       check = verifyDeleteRows(MyNdb, pkValue, readValue);
  617.       break;
  618.     default:
  619.       ndbout << "tType is " << tType << endl;
  620.       assert(false);
  621.       break;
  622.     } // switch
  623.     
  624.     tThreadResult = check;
  625.     
  626.     if (tThreadResult != 0) {
  627.       // Check if error is fatak or not
  628.     } // if
  629.     else {
  630.       continue;
  631.     } // else
  632.   } // while
  633.   // Clean up
  634.   delete MyNdb;
  635.   if (attrValue != NULL) {
  636.     free(attrValue);
  637.   } //if
  638.   if (readValue != NULL) {
  639.     free(readValue);
  640.   } // if
  641.   if (pkValue != NULL) {
  642.     free(pkValue);
  643.   } // if
  644.   
  645.   return NULL; // thread exits
  646. } // flexScanThread
  647. static int setAttrNames()
  648. {
  649.   int i = 0;
  650.   int  retVal = 0;
  651.   
  652.   for (i = 0; i < MAXATTR ; i++) {
  653.     retVal = BaseString::snprintf(attrName[i], MAXSTRLEN, "COL%d", i);
  654.     if (retVal < 0) {
  655.       return(-1);
  656.     } // if
  657.   } // for
  658.   return(0);
  659. } // setAttrNames
  660. static int setTableNames()
  661. {
  662.   // Note! Uses only uppercase letters in table name's
  663.   // so that we can look at the tables with SQL
  664.   int i = 0;
  665.   int retVal = 0;
  666.   for (i = 0; i < MAXTABLES ; i++) {
  667.     if (theStdTableNameFlag == 0) {
  668.       retVal = BaseString::snprintf(tableName[i], MAXSTRLEN, "TAB%d_%d", i, 
  669.        (int)(NdbTick_CurrentMillisecond() / 1000));
  670.     } // if 
  671.     else {
  672.       retVal = BaseString::snprintf(tableName[i], MAXSTRLEN, "TAB%d", i);
  673.     } // if else
  674.     if (retVal < 0) {
  675.       return(-1);
  676.     } // if
  677.   } // for
  678.   return(0);
  679. } // setTableNames
  680. // Create Table and Attributes. 
  681. static int createTables(Ndb* pMyNdb)
  682. {
  683.   
  684.   NdbSchemaCon *MySchemaTransaction = NULL;
  685.   NdbSchemaOp *MySchemaOp = NULL;
  686.   int i = 0;
  687.   int j = 0;
  688.   int check = 0;
  689.   
  690.   if (theTableCreateFlag == 0) {
  691.     
  692.     i = 0;
  693.     do {
  694.       i++;
  695.       ndbout << endl << "Creating " << tableName[i - 1] << "..." << endl;
  696.       MySchemaTransaction = NdbSchemaCon::startSchemaTrans(pMyNdb);      
  697.       if( MySchemaTransaction == NULL ) {
  698. return (-1);
  699.       } // if
  700.       MySchemaOp = MySchemaTransaction->getNdbSchemaOp();
  701.       if( MySchemaOp == NULL ) {
  702. NdbSchemaCon::closeSchemaTrans(MySchemaTransaction);
  703. return (-1);
  704.       } // if
  705. #if defined NDB_OSE || defined NDB_SOFTOSE
  706.       check = MySchemaOp->createTable(tableName[i - 1],
  707.       8, // Table Size
  708.       TupleKey,         // Key Type
  709.       40, // Nr of Pages
  710.       All,
  711.       6,
  712.       78,
  713.       80,
  714.       1,
  715.       false);
  716. #else
  717.       check = MySchemaOp->createTable(tableName[i - 1]
  718.       ,8 // Table Size
  719.       ,TupleKey         // Key Type
  720.       ,40); // Nr of Pages
  721. #endif      
  722.       if (check == -1) {
  723. NdbSchemaCon::closeSchemaTrans(MySchemaTransaction);
  724. return -1;
  725.       } // if
  726.       
  727.       check = MySchemaOp->createAttribute( (char*)attrName[0], TupleKey, 32, PKSIZE,
  728.    UnSigned, MMBased, NotNullAttribute );
  729.       if (check == -1) {
  730. NdbSchemaCon::closeSchemaTrans(MySchemaTransaction);
  731. return -1;
  732.       } // if
  733.       
  734.       for (j = 1; j < tNoOfAttributes ; j++) {
  735. check = MySchemaOp->createAttribute( (char*)attrName[j], NoKey, 32, tAttributeSize,
  736.      UnSigned, MMBased, NotNullAttribute );
  737. if (check == -1) {
  738.   NdbSchemaCon::closeSchemaTrans(MySchemaTransaction);
  739.   return -1;
  740. } // if
  741.       } // for
  742.       
  743.       if (MySchemaTransaction->execute() == -1) {
  744. ndbout <<  MySchemaTransaction->getNdbError().message << endl;
  745. ndbout << "Probably, " << tableName[i - 1] << " already exist" << endl;
  746.       } // if
  747.       
  748.       NdbSchemaCon::closeSchemaTrans(MySchemaTransaction);
  749.     } while (tNoOfTables > i);
  750.   }
  751.   return 0;
  752. } // createTables
  753. static void printUsage()
  754. {
  755.   ndbout << "Usage of flexScan:" << endl;
  756.   ndbout << "-f <path> Location of Ndb.cfg file, default: Ndb.cfg" << endl;
  757.   ndbout << "-t <int>  Number of threads to start, default 1" << endl;
  758.   ndbout << "-o <int>  Number of operations per loop, default 500" << endl;
  759.   ndbout << "-l <int>  Number of loops to run, default 1, 0=infinite" << endl;
  760.   ndbout << "-a <int>  Number of attributes, default 25" << endl;
  761.   ndbout << "-c <int>  Number of tables, default 1" << endl;
  762.   ndbout << "-s <int>  Size of each attribute, default 1" << endl;
  763.   ndbout << "-stdtables        Use standard table names" << endl;
  764.   ndbout << "-no_table_create  Don't create tables in db" << endl;
  765.   ndbout << "-sleep <int>      Sleep a number of seconds before running the test" << endl;
  766.   ndbout << "-p <int>          Parallellism to use 1-32, default:1" << endl;
  767.   ndbout << "-abort <int>      Test scan abort after a number of tuples" << endl;
  768.   ndbout << "-no_scan_update   Don't do scan updates" << endl;
  769.   ndbout << "-no_scan_delete   Don't do scan deletes" << endl;
  770.   ndbout << "-h                Print this text" << endl;
  771.   //  inputErrorArg();
  772.   flexScanErrorData->printCmdLineArgs(ndbout);
  773. }
  774. static int readArguments(int argc, const char** argv)
  775. {
  776.   int i = 1;
  777.   int retValue = 0;
  778.   int printFlag = 0;
  779.   tNoOfThreads = 1; // Set default Value
  780.   tNoOfTables = 1; // Default Value
  781.   while (argc > 1) {
  782.     if (strcmp(argv[i], "-t") == 0) {
  783.       if (argv[i + 1] != NULL) {
  784. tNoOfThreads = atoi(argv[i + 1]);
  785. if ((tNoOfThreads < 1) || (tNoOfThreads > MAXTHREADS)) {
  786.   retValue = -1;
  787. } // if
  788.       } // if
  789.       else {
  790. retValue = -1;
  791.       } // else
  792.     } // if
  793.     else if (strcmp(argv[i], "-o") == 0) {
  794.       if (argv[i + 1] != NULL) {
  795. tNoOfOperations = atoi(argv[i + 1]);
  796. if (tNoOfOperations < 1) {
  797.   retValue = -1;
  798. } // if
  799.       } // if
  800.       else {
  801. retValue = -1;
  802.       } // else
  803.     } // else if
  804.     else if (strcmp(argv[i], "-a") == 0) {
  805.       if (argv[i + 1] != NULL) {
  806. tNoOfAttributes = atoi(argv[i + 1]);
  807. if ((tNoOfAttributes < 2) || (tNoOfAttributes > MAXATTR)) {
  808.   retValue = -1;
  809. } // if
  810.       } // if
  811.       else {
  812. retValue = -1;
  813.       } // else
  814.     } // else if
  815.     else if (strcmp(argv[i], "-c") == 0) {
  816.       if (argv[i + 1] != NULL) {
  817. tNoOfTables = atoi(argv[i+1]);
  818. if ((tNoOfTables < 1) || (tNoOfTables > MAXTABLES)) {
  819.   retValue = -1;
  820. } // if
  821.       } // if
  822.       else {
  823. retValue = -1;
  824.       } // else
  825.     } // else if
  826.     else if (strcmp(argv[i], "-l") == 0) {
  827.       if (argv[i + 1] != NULL) {
  828. tNoOfLoops = atoi(argv[i+1]);
  829. if ((tNoOfLoops < 0) || (tNoOfLoops > 100000)) {
  830.   retValue = -1;
  831. } // if
  832.       } // if
  833.       else {
  834. retValue = -1;
  835.       } // else
  836.     } // else if
  837.     else if (strcmp(argv[i], "-s") == 0) {
  838.       if (argv[i + 1] != NULL) {
  839. tAttributeSize = atoi(argv[i+1]);
  840. if ((tAttributeSize < 1) || (tAttributeSize > MAXATTRSIZE)) {
  841.   retValue = -1;
  842. } // if
  843.       } // if
  844.       else {
  845. retValue = -1;
  846.       } // else
  847.     } // else if
  848.     else if (strcmp(argv[i], "-no_table_create") == 0) {
  849.       theTableCreateFlag = 1;
  850.       argc++;
  851.       i--;
  852.     } // else if
  853.     else if (strcmp(argv[i], "-stdtables") == 0) {
  854.       theStdTableNameFlag = 1;
  855.       argc++;
  856.       i--;
  857.     } // else if
  858.     else if (strcmp(argv[i], "-sleep") == 0) {
  859.       if (argv[i + 1] != NULL) {
  860. tSleepTime = atoi(argv[i+1]);
  861. if ((tSleepTime < 1) || (tSleepTime > 3600)) {
  862.   retValue = -1;
  863. } // if
  864.       } // if
  865.       else {
  866. retValue = -1;
  867.       } // else
  868.     } // else if
  869.     else if (strcmp(argv[i], "-abort") == 0) {
  870.       // Test scan abort after a number of tuples
  871.       theScanAbortTestFlag = 1;
  872.       if (argv[i + 1] != NULL) {
  873. tAbortAfter = atoi(argv[i + 1]);
  874.       } // if
  875.       else {
  876. retValue = -1;
  877.       } // else
  878.     } // else if
  879.     else if (strcmp(argv[i], "-p") == 0) {
  880.       if (argv[i + 1] != NULL) {
  881. tParallellism = atoi(argv[i + 1]);
  882. if ((tParallellism < 1) || (tParallellism > 32)) {
  883.   retValue = -1;
  884. } // if
  885.       } // if
  886.       else {
  887. retValue = -1;
  888.       } // else
  889.     } // else if
  890.     else if (strcmp(argv[i], "-h") == 0) {
  891.       printFlag = 1;
  892.       argc++;
  893.       i--;
  894.     } // else if
  895.     else if (strcmp(argv[i], "-no_scan_update") == 0) {
  896.       theNoScanUpdateFlag = 1;
  897.       argc++;
  898.       i--;
  899.     } // else if
  900.     else if (strcmp(argv[i], "-no_scan_delete") == 0) {
  901.       theNoScanDeleteFlag = 1;
  902.       argc++;
  903.       i--;
  904.     } // else if
  905.     else {
  906.       retValue = -1;
  907.     } // else
  908.     argc -= 2;
  909.     i = i + 2;
  910.   }
  911.   if ((retValue != 0) || (printFlag == 1)) {
  912.     printUsage();
  913.   } // if
  914.   return(retValue);
  915.   
  916. } // readArguments
  917. static void sleepBeforeStartingTest(int seconds)
  918. {
  919.   if (seconds > 0) {
  920.     ndbout << "Sleeping(" <<seconds << ")...";
  921.     NdbSleep_SecSleep(seconds);
  922.     ndbout << " done!" << endl;
  923.   } // if
  924. } // sleepBeforeStartingTest
  925. static void setAttrValues(int* attrValue, 
  926.   int* readValue, 
  927.   int Offset)
  928. {
  929.   int tableCount = 0;
  930.   int attrCount = 0;
  931.   int OpCount = 0;
  932.   int attrSize = 0;
  933.   int* pAttr = NULL;
  934.   int* pRead = NULL;
  935.   
  936.   // Set attribute values in memory array
  937.   for (tableCount = 0; tableCount < tNoOfTables; tableCount++) {
  938.     for (attrCount = 0; attrCount < tNoOfAttributes-1; attrCount++) { 
  939.       for (OpCount = 0; OpCount < tNoOfOperations; OpCount++) {
  940. pAttr = &(attrValue[tableCount*(tNoOfAttributes-1)*tNoOfOperations + 
  941.    attrCount*tNoOfOperations + OpCount]);
  942. pRead = &(readValue[tableCount*(tNoOfAttributes-1)*tNoOfOperations + 
  943.    attrCount*tNoOfOperations + OpCount]);
  944. for (attrSize = 0; attrSize < tAttributeSize; attrSize++){ 
  945.   *pAttr = (int)(Offset + tableCount + attrCount + OpCount + attrSize);
  946.   //ndbout << "attrValue[" << tableCount*(tNoOfAttributes-1)*tNoOfOperations + 
  947.   //attrCount*tNoOfOperations + OpCount + attrSize << "] = " <<
  948.   //attrValue[tableCount*(tNoOfAttributes-1)*tNoOfOperations + 
  949.   //attrCount*tNoOfOperations + OpCount + attrSize] << endl;
  950.   *pRead = 0;
  951.   pAttr++;
  952.   pRead++;
  953. } // for attrSize
  954.       } // for OpCount
  955.     } // for attrCount
  956.   } // for tableCount
  957.   
  958. } // setAttrValues
  959. static int insertRows(Ndb* pNdb, // NDB object
  960.       int* pkValue, // Primary key values
  961.       int* attrValue, // Attribute values
  962.       StartType tType)
  963. {
  964.   int tResult = 0;
  965.   int check = 0;
  966.   int tableCount = 0;
  967.   int attrCount = 0;
  968.   NdbConnection* MyTransaction = NULL;
  969.   NdbOperation* MyOperations[MAXTABLES] = {NULL};
  970.   int opCount = 0;
  971.   
  972.   for (opCount = 0; opCount < tNoOfOperations; opCount++) {
  973.     MyTransaction = pNdb->startTransaction();
  974.     if (MyTransaction == NULL) {
  975.       tResult = 1;
  976.     } // if
  977.     else {
  978.       for (tableCount = 0; tableCount < tNoOfTables; tableCount++) {
  979. MyOperations[tableCount] = 
  980.   MyTransaction->getNdbOperation(tableName[tableCount]);
  981. if (MyOperations[tableCount] == NULL) {
  982.   tResult = 2;
  983.   // Break for tableCount loop
  984.   break;
  985. } // if
  986. if (tType == stUpdate) {
  987.   check = MyOperations[tableCount]->updateTuple();
  988. } // if
  989. else if (tType == stInsert) {
  990.   check = MyOperations[tableCount]->insertTuple();
  991. } // else if
  992. else {
  993.   assert(false);
  994. } // else
  995. if (check == -1) {
  996.   tResult = 3;
  997.   break;
  998. } // if 
  999. check = MyOperations[tableCount]->equal((char*)attrName[0], 
  1000. (char*)&(pkValue[opCount]));
  1001. if (check == -1) {
  1002.   tResult = 7;
  1003.   break;
  1004. } // if
  1005. for (attrCount = 0; attrCount < tNoOfAttributes - 1; attrCount++) {
  1006.   int Index = tableCount * (tNoOfAttributes - 1) * tNoOfOperations * tAttributeSize +
  1007.     attrCount * tNoOfOperations * tAttributeSize + opCount * tAttributeSize;
  1008.   check = MyOperations[tableCount]->
  1009.     setValue((char*)attrName[attrCount + 1],
  1010.      (char*)&(attrValue[Index]));
  1011.   if (check == -1) {
  1012.     tResult = 8;
  1013.     break; // break attrCount loop
  1014.   } // if
  1015. } // for
  1016.       } // for tableCount
  1017.       
  1018.       // Execute transaction with insert one tuple in every table
  1019.       check = MyTransaction->execute(Commit);
  1020.       if (check == -1) {
  1021. ndbout << MyTransaction->getNdbError().message << endl;
  1022. // Add complete error handling here
  1023.               int retCode = flexScanErrorData->handleErrorCommon(MyTransaction->getNdbError());
  1024.               if (retCode == 1) {
  1025. if (MyTransaction->getNdbError().code != 626 && MyTransaction->getNdbError().code != 630){
  1026.                 ndbout_c("execute: %d, %d, %s", opCount, tType, MyTransaction->getNdbError().message);
  1027.                 ndbout_c("Error code = %d", MyTransaction->getNdbError().code);}
  1028.                 tResult = 20;
  1029.               } else if (retCode == 2) {
  1030.                 ndbout << "4115 should not happen in flexBench" << endl;
  1031.                 tResult = 20;
  1032.               } else if (retCode == 3) {
  1033. // --------------------------------------------------------------------
  1034. // We are not certain if the transaction was successful or not.
  1035. // We must reexecute but might very well find that the transaction
  1036. // actually was updated. Updates and Reads are no problem here. Inserts
  1037. // will not cause a problem if error code 630 arrives. Deletes will
  1038. // not cause a problem if 626 arrives.
  1039. // --------------------------------------------------------------------
  1040. /* What can we do here? */
  1041.                 ndbout_c("execute: %s", MyTransaction->getNdbError().message);
  1042.                  }//if(retCode == 3)
  1043.       } // if(check == -1)
  1044.       
  1045.       pNdb->closeTransaction(MyTransaction);
  1046.     } // else
  1047.   } // for opCount
  1048.   
  1049.   return(tResult);
  1050. } // insertRows
  1051. static int readRows(Ndb* pNdb,
  1052.     int* pkValue,
  1053.     int* readValue)
  1054. {
  1055.   int tResult = 0;
  1056.   int tableCount = 0;
  1057.   int attrCount = 0;
  1058.   int check = 0;
  1059.   NdbConnection* MyTransaction = NULL;
  1060.   NdbOperation* MyOperations[MAXTABLES] = {NULL};
  1061.   NdbRecAttr* tmp = NULL;
  1062.   int Value = 0;
  1063.   int Index = 0;
  1064.   int opCount = 0;
  1065.   for (opCount = 0; opCount < tNoOfOperations; opCount++) {
  1066.     MyTransaction = pNdb->startTransaction();
  1067.     if (MyTransaction == NULL) {
  1068.       tResult = 1;
  1069.     } // if
  1070.     else {
  1071.       for (tableCount = 0; tableCount < tNoOfTables; tableCount++) {
  1072. MyOperations[tableCount] = 
  1073.   MyTransaction->getNdbOperation(tableName[tableCount]);
  1074. if (MyOperations[tableCount] == NULL) {
  1075.   tResult = 2;
  1076.   // Break for tableCount loop
  1077.   break;
  1078. } // if
  1079. check = MyOperations[tableCount]->readTuple();
  1080. if (check == -1) {
  1081.   tResult = 3;
  1082.   break;
  1083. } // if
  1084. check = MyOperations[tableCount]->
  1085.   equal((char*)attrName[0], (char*)&(pkValue[opCount]));
  1086. if (check == -1) {
  1087.   tResult = 7;
  1088.   break;
  1089. } // if
  1090. for (int attrCount = 0; attrCount < tNoOfAttributes - 1; attrCount++) {
  1091.   Index = tableCount * (tNoOfAttributes - 1) * tNoOfOperations * tAttributeSize +
  1092.     attrCount * tNoOfOperations * tAttributeSize + opCount * tAttributeSize;
  1093.   tmp = MyOperations[tableCount]->
  1094.     getValue((char*)attrName[attrCount + 1], (char*)&(readValue[Index]));
  1095.   
  1096.   if (tmp == NULL) {
  1097.     tResult = 9;
  1098.     break;
  1099. } // if
  1100. } // for attrCount
  1101.       } // for tableCount
  1102.       // Execute transaction reading one tuple in every table
  1103.       check = MyTransaction->execute(Commit);
  1104.       if (check == -1) {
  1105. ndbout << MyTransaction->getNdbError().message << endl;
  1106. // Add complete error handling here
  1107.               int retCode = flexScanErrorData->handleErrorCommon(MyTransaction->getNdbError());
  1108.               if (retCode == 1) {
  1109. if (MyTransaction->getNdbError().code != 626 && MyTransaction->getNdbError().code != 630){
  1110.                 ndbout_c("execute: %d, %s", opCount, MyTransaction ->getNdbError().message );
  1111.                 ndbout_c("Error code = %d", MyTransaction->getNdbError().code );}
  1112.                 tResult = 20;
  1113.               } else if (retCode == 2) {
  1114.                 ndbout << "4115 should not happen in flexBench" << endl;
  1115.                 tResult = 20;
  1116.               } else if (retCode == 3) {
  1117. // --------------------------------------------------------------------
  1118. // We are not certain if the transaction was successful or not.
  1119. // We must reexecute but might very well find that the transaction
  1120. // actually was updated. Updates and Reads are no problem here. Inserts
  1121. // will not cause a problem if error code 630 arrives. Deletes will
  1122. // not cause a problem if 626 arrives.
  1123. // --------------------------------------------------------------------
  1124. /* What can we do here? */
  1125.                 ndbout_c("execute: %s", MyTransaction ->getNdbError().message );
  1126.                  }//if(retCode == 3)
  1127.       } // if
  1128.       
  1129.       pNdb->closeTransaction(MyTransaction);
  1130.     } // else
  1131.   } // for opCount
  1132.   return(tResult);
  1133. } // readRows
  1134. static int scanReadRows(Ndb* pNdb, int* readValue)
  1135. {
  1136.   int tResult = 0;
  1137.   int tableCount = 0;
  1138.   int attrCount = 0;
  1139.   int check = 0;
  1140.   int countAbort = 0; // Counts loops until scan abort if requested
  1141.   NdbConnection* MyTransaction = NULL;
  1142.   NdbOperation* MyOperation = NULL;
  1143.   NdbRecAttr* tmp = NULL;
  1144.   
  1145.   
  1146.   for (tableCount = 0; tableCount < tNoOfTables; tableCount++) {
  1147.     MyTransaction = pNdb->startTransaction();
  1148.     if (MyTransaction == NULL) {
  1149.       tResult = 1;
  1150.       break;
  1151.     } // if
  1152.     MyOperation = MyTransaction->getNdbOperation(tableName[tableCount]);
  1153.     if (MyOperation == NULL) {
  1154.       tResult = 2;
  1155.       break;
  1156.     } // if
  1157.     
  1158.     check = MyOperation->openScanRead(tParallellism);
  1159.     if (check == -1) {
  1160.       tResult = 10;
  1161.       break;
  1162.     } // if
  1163.     
  1164.     for (int attrCount = 0; attrCount < tNoOfAttributes-1; attrCount++) {
  1165.       // Get all attributes
  1166.       tmp = MyOperation->
  1167. getValue((char*)attrName[attrCount+1],
  1168.  (char*)&(readValue[tableCount*(tNoOfAttributes-1)*tNoOfOperations*tAttributeSize +
  1169.    attrCount*tNoOfOperations*tAttributeSize]));
  1170.       if (tmp == NULL) {
  1171. tResult = 9;
  1172. break;
  1173.       } // if
  1174.     } // for attrCount
  1175.     check = MyTransaction->executeScan();
  1176.     if (check == -1) {
  1177.       tResult = 12;
  1178.       break;
  1179.     } // if
  1180.     check = MyTransaction->nextScanResult();
  1181.     while (check == 0) {
  1182.       // Check if scan abort is requested
  1183.       if (theScanAbortTestFlag == 1) {
  1184. if (countAbort == tAbortAfter) {
  1185.   MyTransaction->stopScan();
  1186.   ndbout << "scanread aborted on request after " << countAbort*tParallellism << 
  1187.     " tuples" << endl;
  1188.   break; // break while loop
  1189. } // if
  1190. countAbort++;
  1191.       } // if
  1192.       check = MyTransaction->nextScanResult();
  1193.     } // while
  1194.     pNdb->closeTransaction(MyTransaction);
  1195.   } // for tableCount
  1196.     
  1197.     return(tResult);
  1198. } // scanReadRows
  1199. static int scanUpdateRows(Ndb* pNdb, 
  1200.   int* readValue,
  1201.   int* attrValue)
  1202. {
  1203.   int tResult = 0;
  1204.   int tableCount = 0;
  1205.   int attrCount = 0;
  1206.   int check = 0;
  1207.   int opCount = 0;
  1208.   NdbConnection* MyTransaction = NULL;
  1209.   NdbOperation* MyOperation = NULL;
  1210.   NdbConnection* MyTakeOverTrans = NULL;
  1211.   NdbOperation* MyTakeOverOp = NULL;
  1212.   NdbRecAttr* tTmp = NULL;
  1213.   for (tableCount = 0; tableCount < tNoOfTables; tableCount++) {
  1214.     MyTransaction = pNdb->startTransaction();
  1215.     if (MyTransaction == NULL) {
  1216.       tResult = 1;
  1217.       break; // break tableCount for loop
  1218.     } // if
  1219.     MyOperation = MyTransaction->getNdbOperation(tableName[tableCount]);
  1220.     if (MyOperation == NULL) {
  1221.       tResult = 2;
  1222.       break;
  1223.     } // if
  1224.     check = MyOperation->openScanExclusive(tParallellism);
  1225.     if (check == -1) {
  1226.       tResult = 11;
  1227.       break;
  1228.     } // if
  1229.     MyOperation->interpret_exit_ok();
  1230.     // Fetch all attributes
  1231.     for (int attrCount = 0; attrCount < tNoOfAttributes-1; attrCount++) {
  1232.       tTmp = MyOperation->
  1233. getValue((char*)attrName[attrCount+1],
  1234.  (char*)&(readValue[tableCount*(tNoOfAttributes-1)*tNoOfOperations*tAttributeSize +
  1235.    attrCount*tNoOfOperations*tAttributeSize]));
  1236.       if (tTmp == NULL) {
  1237. tResult = 9;
  1238. break; // break for loop
  1239.       } // if
  1240.     } // for
  1241.     if (tResult != 0) {
  1242.       break; // break while loop also
  1243.     } // if
  1244.     check = MyTransaction->executeScan();
  1245.     if (check == -1) {
  1246.       tResult = 12;
  1247.       break;
  1248.     } // if
  1249.     check = MyTransaction->nextScanResult();
  1250.     opCount = 0;
  1251.     while (check == 0) {
  1252.       MyTakeOverTrans = pNdb->startTransaction();
  1253.       MyTakeOverOp = MyOperation->takeOverForUpdate(MyTakeOverTrans);
  1254.       for (attrCount = 0; attrCount < tNoOfAttributes-1; attrCount++) {
  1255. check = MyTakeOverOp->setValue((char*)attrName[attrCount+1],
  1256.        (char*)&(attrValue[tableCount*(tNoOfAttributes-1)*tNoOfOperations*tAttributeSize +
  1257.  attrCount*tNoOfOperations*tAttributeSize + opCount*tAttributeSize]));
  1258.       } // for
  1259.       
  1260.       check = MyTakeOverTrans->execute(Commit);
  1261.       if (check == 0) {
  1262. check = MyTransaction->nextScanResult();
  1263. opCount++;
  1264.       } // if
  1265.       else {
  1266. tResult = 95;
  1267. /* MyTransaction, MyTakeOverTrans, Which one? */
  1268. // Any further error handling?
  1269. int retCode = flexScanErrorData->handleErrorCommon(MyTakeOverTrans->getNdbError());
  1270. if (retCode == 1) {
  1271.   if (MyTakeOverTrans->getNdbError().code != 626 && MyTakeOverTrans->getNdbError().code != 630){
  1272.     ndbout_c("execute: %s", MyTakeOverTrans->getNdbError().message);
  1273.     ndbout_c("Error code = %d", MyTakeOverTrans->getNdbError().code);}
  1274.   tResult = 20;
  1275. } else if (retCode == 2) {
  1276.   ndbout << "4115 should not happen in flexBench" << endl;
  1277.   tResult = 20;
  1278. } else if (retCode == 3) {
  1279.   // --------------------------------------------------------------------
  1280.   // We are not certain if the transaction was successful or not.
  1281.   // We must reexecute but might very well find that the transaction
  1282.   // actually was updated. Updates and Reads are no problem here. Inserts
  1283.   // will not cause a problem if error code 630 arrives. Deletes will
  1284.   // not cause a problem if 626 arrives.
  1285.   // --------------------------------------------------------------------
  1286.   /* What can we do here? */
  1287.   ndbout_c("execute: %s", MyTakeOverTrans->getNdbError().message);
  1288. }//if(retCode == 3)
  1289.       } // else
  1290.       pNdb->closeTransaction(MyTakeOverTrans);
  1291.     } // while
  1292.     
  1293.     pNdb->closeTransaction(MyTransaction);
  1294.   } // for
  1295.   return(tResult);
  1296. } // scanUpdateRows
  1297. static int scanDeleteRows(Ndb* pNdb, int* readValue)
  1298. {
  1299.   int tResult = 0;
  1300.   int tableCount = 0;
  1301.   int attrCount = 0;
  1302.   int check = 0;
  1303.   NdbRecAttr* tTmp = NULL;
  1304.   NdbConnection* MyTransaction = NULL;
  1305.   NdbOperation* MyOperation = NULL;
  1306.   NdbConnection* MyTakeOverTrans = NULL;
  1307.   NdbOperation* MyTakeOverOp = NULL;
  1308.   for (tableCount = 0; tableCount < tNoOfTables; tableCount++) {
  1309.     MyTransaction = pNdb->startTransaction();
  1310.     if (MyTransaction == NULL) {
  1311.       tResult = 1;
  1312.       break; // break tableCount for loop
  1313.     } // if
  1314.     MyOperation = MyTransaction->getNdbOperation(tableName[tableCount]);
  1315.     if (MyOperation == NULL) {
  1316.       tResult = 2;
  1317.       break;
  1318.     } // if
  1319.     check = MyOperation->openScanExclusive(tParallellism);
  1320.     if (check == -1) {
  1321.       tResult = 11;
  1322.       break;
  1323.     } // if
  1324.     MyOperation->interpret_exit_ok();
  1325.     for (int attrCount = 0; attrCount < tNoOfAttributes-1; attrCount++) {
  1326.       tTmp = MyOperation->
  1327. getValue((char*)attrName[attrCount+1],
  1328.  (char*)&(readValue[tableCount*(tNoOfAttributes-1)*tNoOfOperations +
  1329.    attrCount*tNoOfOperations]));
  1330.       if (tTmp == NULL) {
  1331. tResult = 9;
  1332. break;
  1333.       } // if
  1334.     } // for
  1335.     check = MyTransaction->executeScan();
  1336.     if (check == -1) {
  1337.       tResult = 12;
  1338.       break;
  1339.     } // if
  1340.     check = MyTransaction->nextScanResult();
  1341.     while (check == 0) {
  1342.       MyTakeOverTrans = pNdb->startTransaction();
  1343.       MyTakeOverOp = MyOperation->takeOverForDelete(MyTakeOverTrans);
  1344.       check = MyTakeOverOp->deleteTuple();
  1345.       check = MyTakeOverTrans->execute(Commit);
  1346.       //Error handling here
  1347.               int retCode =flexScanErrorData->handleErrorCommon(MyTakeOverTrans->getNdbError());
  1348.               if (retCode == 1) {
  1349. if (MyTakeOverTrans->getNdbError().code != 626 && MyTakeOverTrans->getNdbError().code != 630){
  1350.                 ndbout_c("execute: %s", MyTakeOverTrans->getNdbError().message );
  1351.                 ndbout_c("Error code = %d", MyTakeOverTrans->getNdbError().code );}
  1352.                 tResult = 20;
  1353.               } else if (retCode == 2) {
  1354.                 ndbout << "4115 should not happen in flexBench" << endl;
  1355.                 tResult = 20;
  1356.               } else if (retCode == 3) {
  1357. // --------------------------------------------------------------------
  1358. // We are not certain if the transaction was successful or not.
  1359. // We must reexecute but might very well find that the transaction
  1360. // actually was updated. Updates and Reads are no problem here. Inserts
  1361. // will not cause a problem if error code 630 arrives. Deletes will
  1362. // not cause a problem if 626 arrives.
  1363. // --------------------------------------------------------------------
  1364. /* What can we do here? */
  1365.                 ndbout_c("execute: %s", MyTakeOverTrans->getNdbError().message );
  1366.                  }//if(retCode == 3) End of error handling
  1367.       pNdb->closeTransaction(MyTakeOverTrans);
  1368.       check = MyTransaction->nextScanResult();
  1369.     } // while
  1370.     pNdb->closeTransaction(MyTransaction);
  1371.   } // for tableCount
  1372.   return(tResult);
  1373. } // scanDeleteRows
  1374. static int deleteRows(Ndb* pNdb,
  1375.       int* pkValue)
  1376. {
  1377.   int tResult = 0;
  1378.   NdbConnection* MyTransaction = NULL;
  1379.   int tableCount = 0;
  1380.   int opCount = 0;
  1381.   int check = 0;
  1382.   NdbOperation* MyOperations[MAXTABLES] = {NULL};
  1383.   for (opCount = 0; opCount < tNoOfOperations; opCount++) {
  1384.     MyTransaction = pNdb->startTransaction();
  1385.     if (MyTransaction == NULL) {
  1386.       tResult = 1;
  1387.     } // if
  1388.     else {
  1389.       for (tableCount = 0; tableCount < tNoOfTables; tableCount++) {
  1390. MyOperations[tableCount] = 
  1391.   MyTransaction->getNdbOperation(tableName[tableCount]);
  1392. if (MyOperations[tableCount] == NULL) {
  1393.   tResult = 2;
  1394.   // Break for tableCount loop
  1395.   break;
  1396. } // if
  1397. check = MyOperations[tableCount]->deleteTuple();
  1398. if (check == -1) {
  1399.   tResult = 3;
  1400.   break;
  1401. } // if
  1402. check = MyOperations[tableCount]->
  1403.   equal((char*)attrName[0], (char*)&(pkValue[opCount]));
  1404. if (check == -1) {
  1405.   tResult = 7;
  1406.   break;
  1407. } // if
  1408.       } // for tableCount
  1409.       
  1410.       // Execute transaction deleting one tuple in every table
  1411.       check = MyTransaction->execute(Commit);
  1412.       if (check == -1) {
  1413. ndbout << MyTransaction->getNdbError().message << endl;
  1414. // Add complete error handling here
  1415.               int retCode = flexScanErrorData->handleErrorCommon(MyTransaction->getNdbError());
  1416.               if (retCode == 1) {
  1417. if (MyTransaction->getNdbError().code != 626 && MyTransaction->getNdbError().code != 630){
  1418.                 ndbout_c("execute: %d, %s", opCount, MyTransaction->getNdbError().message );
  1419.                 ndbout_c("Error code = %d", MyTransaction->getNdbError().code );}
  1420.                 tResult = 20;
  1421.               } else if (retCode == 2) {
  1422.                 ndbout << "4115 should not happen in flexBench" << endl;
  1423.                 tResult = 20;
  1424.               } else if (retCode == 3) {
  1425. // --------------------------------------------------------------------
  1426. // We are not certain if the transaction was successful or not.
  1427. // We must reexecute but might very well find that the transaction
  1428. // actually was updated. Updates and Reads are no problem here. Inserts
  1429. // will not cause a problem if error code 630 arrives. Deletes will
  1430. // not cause a problem if 626 arrives.
  1431. // --------------------------------------------------------------------
  1432. /* What can we do here? */
  1433.                 ndbout_c("execute: %s", MyTransaction->getNdbError().message );
  1434.                  }//if(retCode == 3)
  1435.       } // if
  1436.       
  1437.       pNdb->closeTransaction(MyTransaction);
  1438.     } // else
  1439.   } // for opCount
  1440.   return(tResult);
  1441. } // deleteRows
  1442. ////////////////////////////////////////
  1443. //
  1444. // Name: verifyDeleteRows
  1445. //
  1446. // Purpose: Verifies that all tables are empty by reading every tuple
  1447. //          No deletions made here
  1448. //
  1449. // Returns: 'Standard' error codes
  1450. //
  1451. /////////////////////////////////////
  1452. static int verifyDeleteRows(Ndb* pNdb,
  1453.     int* pkValue,
  1454.     int* readValue)
  1455. {
  1456.   int tResult = 0;
  1457.   int tableCount = 0;
  1458.   int attrCount = 0;
  1459.   int check = 0;
  1460.   NdbConnection* MyTransaction = NULL;
  1461.   NdbOperation* MyOperations = NULL;
  1462.   NdbRecAttr* tmp = NULL;
  1463.   int Value = 0;
  1464.   int Index = 0;
  1465.   int opCount = 0;
  1466.   for (opCount = 0; opCount < tNoOfOperations; opCount++) {
  1467.     for (tableCount = 0; tableCount < tNoOfTables; tableCount++) {
  1468.       MyTransaction = pNdb->startTransaction();
  1469.       if (MyTransaction == NULL) {
  1470. tResult = 1;
  1471.       } // if
  1472.       else {
  1473. MyOperations = 
  1474.   MyTransaction->getNdbOperation(tableName[tableCount]);
  1475. if (MyOperations == NULL) {
  1476.   tResult = 2;
  1477.   // Break for tableCount loop
  1478.   break;
  1479. } // if
  1480. check = MyOperations->readTuple();
  1481. if (check == -1) {
  1482.   tResult = 3;
  1483.   break;
  1484. } // if
  1485. check = MyOperations->
  1486.   equal((char*)attrName[0], (char*)&(pkValue[opCount]));
  1487. if (check == -1) {
  1488.   tResult = 7;
  1489.   break;
  1490. } // if
  1491. for (int attrCount = 0; attrCount < tNoOfAttributes - 1; attrCount++) {
  1492.   Index = tableCount * (tNoOfAttributes - 1) * tNoOfOperations * tAttributeSize +
  1493.     attrCount * tNoOfOperations * tAttributeSize + opCount * tAttributeSize;
  1494.   tmp = MyOperations->
  1495.     getValue((char*)attrName[attrCount + 1], (char*)&(readValue[Index]));
  1496.   
  1497.   if (tmp == NULL) {
  1498.     tResult = 9;
  1499.     break;
  1500.   } // if
  1501. } // for attrCount
  1502. // Execute transaction reading one tuple in every table
  1503. check = MyTransaction->execute(Commit);
  1504. if ((check == -1) && (MyTransaction->getNdbError().code == 626)){
  1505.   // This is expected because everything should be deleted 
  1506. } // if
  1507. else if (check == 0) {
  1508.   // We have found a tuple that should have been deleted
  1509.   ndbout << "tuple " << tableName[tableCount] << ":" <<
  1510.     opCount << " was never deleted" << endl;
  1511.   tResult = 97;
  1512. } // else if
  1513. else {
  1514.   // Unexpected error
  1515.   ndbout << "Unexpected error during delete" << endl;
  1516.   assert(false);
  1517. } // else
  1518. pNdb->closeTransaction(MyTransaction);
  1519.       } // else
  1520.     } // for tableCount
  1521.   } // for opCount
  1522.   return(tResult);
  1523. } // verifyDeleteRows