mariadb/storage/ndb/test/ndbapi/testScanPerf.cpp
kent@kent-amd64.(none) be15e3bc15 Merge mysql.com:/home/kent/bk/main/mysql-5.0
into  mysql.com:/home/kent/bk/main/mysql-5.1
2006-12-23 20:20:40 +01:00

371 lines
9.3 KiB
C++

/* Copyright (C) 2003 MySQL AB
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
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
#define P_RESET 11
#define P_MULTI 12
#define P_MAX 13
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 },
{ "data", 1, 0, 1 },
{ "q-reset bounds", 0, 1, 0 },
{ "multi read range", 1000, 1, ~0 }
};
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){
ndb_init();
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;
int i;
for(i = 0; i<P_MAX; i++){
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());
Ndb_cluster_connection con;
if(con.connect(12, 5, 1))
{
return NDBT_ProgramExit(NDBT_FAILED);
}
g_ndb = new Ndb(&con, "TEST_DB");
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;
}
for(i = optind; i<argc; i++){
const char * T = argv[i];
g_info << "Testing " << T << endl;
BaseString::snprintf(g_tablename, sizeof(g_tablename), T);
BaseString::snprintf(g_indexname, sizeof(g_indexname), "IDX_%s", T);
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){
g_ndb->getDictionary()->dropTable(g_tablename);
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);
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;
}
}
return 0;
}
inline
void err(NdbError e){
ndbout << e << endl;
}
int
run_scan(){
int iter = g_paramters[P_LOOPS].value;
NDB_TICKS start1, stop;
int sum_time= 0;
int sample_rows = 0;
int tot_rows = 0;
NDB_TICKS sample_start = NdbTick_CurrentMillisecond();
Uint32 tot = g_paramters[P_ROWS].value;
if(g_paramters[P_BOUND].value >= 2 || g_paramters[P_FILT].value == 2)
iter *= g_paramters[P_ROWS].value;
NdbScanOperation * pOp = 0;
NdbIndexScanOperation * pIOp = 0;
NdbConnection * pTrans = 0;
int check = 0;
for(int i = 0; i<iter; i++){
start1 = NdbTick_CurrentMillisecond();
pTrans = pTrans ? pTrans : g_ndb->startTransaction();
if(!pTrans){
g_err << "Failed to start transaction" << endl;
err(g_ndb->getNdbError());
return -1;
}
int par = g_paramters[P_PARRA].value;
int bat = 0; // g_paramters[P_BATCH].value;
NdbScanOperation::LockMode lm;
switch(g_paramters[P_LOCK].value){
case 0:
lm = NdbScanOperation::LM_CommittedRead;
break;
case 1:
lm = NdbScanOperation::LM_Read;
break;
case 2:
lm = NdbScanOperation::LM_Exclusive;
break;
default:
abort();
}
if(g_paramters[P_ACCESS].value == 0){
pOp = pTrans->getNdbScanOperation(g_tablename);
assert(pOp);
pOp->readTuples(lm, bat, par);
} else {
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;
pIOp->readTuples(lm, bat, par, ord);
}
else
{
pIOp->reset_bounds();
}
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;
#if 0
fix_eq_bound(pIOp, row);
#else
pIOp->setBound((Uint32)0, NdbIndexScanOperation::BoundEQ, &row);
#endif
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);
pIOp->end_of_bound(i);
}
if(g_paramters[P_RESET].value == 2)
goto execute;
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);
if(g_paramters[P_RESET].value == 1)
g_paramters[P_RESET].value = 2;
for(int i = 0; i<g_table->getNoOfColumns(); i++){
pOp->getValue(i);
}
if(g_paramters[P_RESET].value == 1)
g_paramters[P_RESET].value = 2;
execute:
int rows = 0;
check = pTrans->execute(NoCommit);
assert(check == 0);
int fetch = g_paramters[P_FETCH].value;
while((check = pOp->nextResult(true)) == 0){
do {
rows++;
} while(!fetch && ((check = pOp->nextResult(false)) == 0));
if(check == -1){
err(pTrans->getNdbError());
return -1;
}
assert(check == 2);
}
if(check == -1){
err(pTrans->getNdbError());
return -1;
}
assert(check == 1);
if(g_paramters[P_RESET].value == 0)
{
pTrans->close();
pTrans = 0;
}
stop = NdbTick_CurrentMillisecond();
int time_passed= (int)(stop - start1);
sample_rows += rows;
sum_time+= time_passed;
tot_rows+= rows;
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;
}
}
g_err.println("Avg time: %d ms = %u rows/sec", sum_time/tot_rows,
(1000*tot_rows)/sum_time);
return 0;
}