testScanPerf.cpp 9.33 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
/* Copyright (C) 2003 MySQL AB

   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 2 of the License, or
   (at your option) any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */

#include <NDBT.hpp>
#include <NDBT_Test.hpp>
#include <HugoTransactions.hpp>
#include <UtilTransactions.hpp>
#include <random.h>
#include <getarg.h>

struct Parameter {
  char * name;
  unsigned value;
  unsigned min;
  unsigned max; 
};

#define P_BATCH   0
#define P_PARRA   1
#define P_LOCK    2
#define P_FILT    3
#define P_BOUND   4
#define P_ACCESS  5
#define P_FETCH   6
#define P_ROWS    7
#define P_LOOPS   8
#define P_CREATE  9
41
#define P_RESET  11
42
#define P_MULTI  12
43

44
#define P_MAX 13
45 46 47 48 49 50 51 52 53 54 55 56 57 58

static 
Parameter 
g_paramters[] = {
  { "batch",       0, 0, 1 }, // 0, 15
  { "parallelism", 0, 0, 1 }, // 0,  1
  { "lock",        0, 0, 2 }, // read, exclusive, dirty
  { "filter",      0, 0, 3 }, // all, none, 1, 100
  { "range",       0, 0, 3 }, // all, none, 1, 100
  { "access",      0, 0, 2 }, // scan, idx, idx sorted
  { "fetch",       0, 0, 1 }, // No, yes
  { "size",  1000000, 1, ~0 },
  { "iterations",  3, 1, ~0 },
  { "create_drop", 1, 0, 1 },
59
  { "data",        1, 0, 1 },
60 61
  { "q-reset bounds", 0, 1, 0 },
  { "multi read range", 1000, 1, ~0 }
62 63 64 65 66 67 68 69 70 71 72 73 74
};

static Ndb* g_ndb = 0;
static const NdbDictionary::Table * g_table;
static const NdbDictionary::Index * g_index;
static char g_tablename[256];
static char g_indexname[256];

int create_table();
int run_scan();

int
main(int argc, const char** argv){
75
  ndb_init();
76 77 78 79 80 81 82
  int verbose = 1;
  int optind = 0;

  struct getargs args[1+P_MAX] = {
    { "verbose", 'v', arg_flag, &verbose, "Print verbose status", "verbose" }
  };
  const int num_args = 1 + P_MAX;
83 84
  int i;
  for(i = 0; i<P_MAX; i++){
85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101
    args[i+1].long_name = g_paramters[i].name;
    args[i+1].short_name = * g_paramters[i].name;
    args[i+1].type = arg_integer;
    args[i+1].value = &g_paramters[i].value;
    BaseString tmp;
    tmp.assfmt("min: %d max: %d", g_paramters[i].min, g_paramters[i].max);
    args[i+1].help = strdup(tmp.c_str());
    args[i+1].arg_help = 0;
  }
  
  if(getarg(args, num_args, argc, argv, &optind)) {
    arg_printusage(args, num_args, argv[0], "tabname1 tabname2 ...");
    return NDBT_WRONGARGS;
  }

  myRandom48Init(NdbTick_CurrentMillisecond());

102 103 104 105 106 107 108
  Ndb_cluster_connection con;
  if(con.connect(12, 5, 1))
  {
    return NDBT_ProgramExit(NDBT_FAILED);
  }

  g_ndb = new Ndb(&con, "TEST_DB");
109 110 111 112 113 114 115 116
  if(g_ndb->init() != 0){
    g_err << "init() failed" << endl;
    goto error;
  }
  if(g_ndb->waitUntilReady() != 0){
    g_err << "Wait until ready failed" << endl;
    goto error;
  }
117
  for(i = optind; i<argc; i++){
118 119
    const char * T = argv[i];
    g_info << "Testing " << T << endl;
120 121
    BaseString::snprintf(g_tablename, sizeof(g_tablename), T);
    BaseString::snprintf(g_indexname, sizeof(g_indexname), "IDX_%s", T);
122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139
    if(create_table())
      goto error;
    if(run_scan())
      goto error;
  }

  if(g_ndb) delete g_ndb;
  return NDBT_OK;
 error:
  if(g_ndb) delete g_ndb;
  return NDBT_FAILED;
}

int
create_table(){
  NdbDictionary::Dictionary* dict = g_ndb->getDictionary();
  assert(dict);
  if(g_paramters[P_CREATE].value){
140
    g_ndb->getDictionary()->dropTable(g_tablename);
141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169
    const NdbDictionary::Table * pTab = NDBT_Tables::getTable(g_tablename);
    assert(pTab);
    NdbDictionary::Table copy = * pTab;
    copy.setLogging(false);
    if(dict->createTable(copy) != 0){
      g_err << "Failed to create table: " << g_tablename << endl;
      return -1;
    }

    NdbDictionary::Index x(g_indexname);
    x.setTable(g_tablename);
    x.setType(NdbDictionary::Index::OrderedIndex);
    x.setLogging(false);
    for (unsigned k = 0; k < copy.getNoOfColumns(); k++){
      if(copy.getColumn(k)->getPrimaryKey()){
	x.addColumnName(copy.getColumn(k)->getName());
      }
    }

    if(dict->createIndex(x) != 0){
      g_err << "Failed to create index: " << endl;
      return -1;
    }
  }
  g_table = dict->getTable(g_tablename);
  g_index = dict->getIndex(g_indexname, g_tablename);
  assert(g_table);
  assert(g_index);

170 171 172 173 174 175 176 177 178
  if(g_paramters[P_CREATE].value)
  {
    int rows = g_paramters[P_ROWS].value;
    HugoTransactions hugoTrans(* g_table);
    if (hugoTrans.loadTable(g_ndb, rows)){
      g_err.println("Failed to load %s with %d rows", 
		    g_table->getName(), rows);
      return -1;
    }
179 180 181 182 183 184 185 186 187 188 189 190 191
  }
  
  return 0;
}

inline 
void err(NdbError e){
  ndbout << e << endl;
}

int
run_scan(){
  int iter = g_paramters[P_LOOPS].value;
192 193
  NDB_TICKS start1, stop;
  int sum_time= 0;
194

195
  int sample_rows = 0;
196
  int tot_rows = 0;
197 198
  NDB_TICKS sample_start = NdbTick_CurrentMillisecond();

199 200
  Uint32 tot = g_paramters[P_ROWS].value;

201
  if(g_paramters[P_BOUND].value >= 2 || g_paramters[P_FILT].value == 2)
202 203 204 205 206 207 208
    iter *= g_paramters[P_ROWS].value;

  NdbScanOperation * pOp = 0;
  NdbIndexScanOperation * pIOp = 0;
  NdbConnection * pTrans = 0;
  int check = 0;

209 210
  for(int i = 0; i<iter; i++){
    start1 = NdbTick_CurrentMillisecond();
211
    pTrans = pTrans ? pTrans : g_ndb->startTransaction();
212 213 214 215 216 217 218 219 220 221 222
    if(!pTrans){
      g_err << "Failed to start transaction" << endl;
      err(g_ndb->getNdbError());
      return -1;
    }
    
    int par = g_paramters[P_PARRA].value;
    int bat = g_paramters[P_BATCH].value;
    NdbScanOperation::LockMode lm;
    switch(g_paramters[P_LOCK].value){
    case 0:
223
      lm = NdbScanOperation::LM_CommittedRead;
224 225
      break;
    case 1:
226
      lm = NdbScanOperation::LM_Read;
227 228
      break;
    case 2:
229
      lm = NdbScanOperation::LM_Exclusive;
230 231 232 233 234 235 236 237
      break;
    default:
      abort();
    }

    if(g_paramters[P_ACCESS].value == 0){
      pOp = pTrans->getNdbScanOperation(g_tablename);
      assert(pOp);
238
      pOp->readTuples(lm, bat, par);
239
    } else {
240 241 242 243
      if(g_paramters[P_RESET].value == 0 || pIOp == 0)
      {
	pOp= pIOp= pTrans->getNdbIndexScanOperation(g_indexname, g_tablename);
	bool ord = g_paramters[P_ACCESS].value == 2;
244
	pIOp->readTuples(lm, bat, par, ord);
245 246 247 248 249 250
      }
      else
      {
	pIOp->reset_bounds();
      }

251 252 253 254 255 256 257 258 259 260 261
      switch(g_paramters[P_BOUND].value){
      case 0: // All
	break;
      case 1: // None
	pIOp->setBound((Uint32)0, NdbIndexScanOperation::BoundEQ, 0);
	break;
      case 2: { // 1 row
      default:  
	assert(g_table->getNoOfPrimaryKeys() == 1); // only impl. so far
	int tot = g_paramters[P_ROWS].value;
	int row = rand() % tot;
262
#if 0
263
	fix_eq_bound(pIOp, row);
264 265
#else
	pIOp->setBound((Uint32)0, NdbIndexScanOperation::BoundEQ, &row);
266
#endif
267 268 269 270 271 272 273 274 275 276 277
	if(g_paramters[P_RESET].value == 2)
	  goto execute;
	break;
      }
      case 3: { // read multi
	int multi = g_paramters[P_MULTI].value;
	int tot = g_paramters[P_ROWS].value;
	for(; multi > 0 && i < iter; --multi, i++)
	{
	  int row = rand() % tot;
	  pIOp->setBound((Uint32)0, NdbIndexScanOperation::BoundEQ, &row);
278
	  pIOp->end_of_bound(i);
279 280 281
	}
	if(g_paramters[P_RESET].value == 2)
	  goto execute;
282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315
	break;
      }
      }
    }
    assert(pOp);
    
    switch(g_paramters[P_FILT].value){
    case 0: // All
      check = pOp->interpret_exit_ok();
      break;
    case 1: // None
      check = pOp->interpret_exit_nok();
      break;
    case 2: { // 1 row
    default:  
      assert(g_table->getNoOfPrimaryKeys() == 1); // only impl. so far
      abort();
#if 0
      int tot = g_paramters[P_ROWS].value;
      int row = rand() % tot;
      NdbScanFilter filter(pOp) ;   
      filter.begin(NdbScanFilter::AND);
      fix_eq(filter, pOp, row);
      filter.end();
      break;
#endif
    }
    }
    if(check != 0){
      err(pOp->getNdbError());
      return -1;
    }
    assert(check == 0);

316 317 318
    if(g_paramters[P_RESET].value == 1)
      g_paramters[P_RESET].value = 2;
    
319 320 321
    for(int i = 0; i<g_table->getNoOfColumns(); i++){
      pOp->getValue(i);
    }
322 323 324

    if(g_paramters[P_RESET].value == 1)
      g_paramters[P_RESET].value = 2;
325
execute:
326 327 328 329
    int rows = 0;
    check = pTrans->execute(NoCommit);
    assert(check == 0);
    int fetch = g_paramters[P_FETCH].value;
330
    while((check = pOp->nextResult(true)) == 0){
331 332
      do {
	rows++;
333
      } while(!fetch && ((check = pOp->nextResult(false)) == 0));
334 335 336 337 338 339 340 341 342 343 344 345
      if(check == -1){
        err(pTrans->getNdbError());
        return -1;
      }
      assert(check == 2);
    }

    if(check == -1){
      err(pTrans->getNdbError());
      return -1;
    }
    assert(check == 1);
346 347 348 349 350
    if(g_paramters[P_RESET].value == 0)
    {
      pTrans->close();
      pTrans = 0;
    }
351
    stop = NdbTick_CurrentMillisecond();
352
    
353
    int time_passed= (int)(stop - start1);
354
    sample_rows += rows;
355
    sum_time+= time_passed;
356
    tot_rows+= rows;
357 358 359 360 361 362 363 364 365 366
    
    if(sample_rows >= tot)
    {
      int sample_time = (int)(stop - sample_start);
      g_info << "Found " << sample_rows << " rows" << endl;
      g_err.println("Time: %d ms = %u rows/sec", sample_time,
		    (1000*sample_rows)/sample_time);
      sample_rows = 0;
      sample_start = stop;
    }
367
  }
368 369 370
  
  g_err.println("Avg time: %d ms = %u rows/sec", sum_time/tot_rows,
                (1000*tot_rows)/sum_time);
371 372
  return 0;
}