1
/* Copyright (C) 2005 MySQL AB
3
This program is free software; you can redistribute it and/or modify
4
it under the terms of the GNU General Public License as published by
5
the Free Software Foundation; version 2 of the License.
7
This program is distributed in the hope that it will be useful,
8
but WITHOUT ANY WARRANTY; without even the implied warranty of
9
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10
GNU General Public License for more details.
12
You should have received a copy of the GNU General Public License
13
along with this program; if not, write to the Free Software
14
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */
16
#include <ndb_global.h>
19
#include <NdbIndexStat.hpp>
20
#include <NdbTest.hpp>
22
#include <ndb_version.h>
28
* 0. err pct: count: 1000 min: -99.99 max: 99.92 avg: 6.88 stddev: 27.61
30
* 0. baseline with same options as handler
35
#define min(a, b) ((a) <= (b) ? (a) : (b))
36
#define max(a, b) ((a) >= (b) ? (a) : (b))
39
NdbOut::operator<<(double x)
42
sprintf(buf, "%.2f", x);
85
const char* g_progname = "testIndexStat";
86
static uint g_loop = 0;
88
static const char* g_tabname = "ts0";
89
static const char* g_indname = "ts0x1";
90
static const char g_numattrs = 3;
91
static const uint g_charlen = 10;
92
static const char* g_csname = "latin1_swedish_ci";
93
static CHARSET_INFO* g_cs;
95
// value and bound ranges
96
static uint g_val_b_max = 10;
97
static uint g_bnd_b_max = 20;
98
static const char* g_val_c_char = "bcd";
99
static const char* g_bnd_c_char = "abcde";
100
static uint g_val_d_max = 100;
101
static uint g_bnd_d_max = 200;
103
static Ndb_cluster_connection* g_ncc = 0;
104
static Ndb* g_ndb = 0;
105
static NdbDictionary::Dictionary* g_dic = 0;
106
static const NdbDictionary::Table* g_tab = 0;
107
static const NdbDictionary::Index* g_ind = 0;
109
static NdbIndexStat* g_stat = 0;
111
static NdbTransaction* g_con = 0;
112
static NdbOperation* g_op = 0;
113
static NdbScanOperation* g_scan_op = 0;
114
static NdbIndexScanOperation* g_rangescan_op = 0;
119
uint r = (uint)random();
133
static int& g_loglevel = g_opts.loglevel; // default log level
136
do { if (likely(x)) break; ndbout << "line " << __LINE__ << " FAIL " << #x << endl; errdb(); if (g_opts.abort) abort(); return -1; } while (0)
139
do { if (likely(x)) break; ndbout << "line " << __LINE__ << " FAIL " << #x << endl; if (g_opts.abort) abort(); return -1; } while (0)
142
do { if (likely(x)) break; ndbout << "line " << __LINE__ << " ASSERT " << #x << endl; abort(); } while (0)
145
do { if (likely(g_loglevel < n)) break; ndbout << x << endl; } while (0)
147
#define ll0(x) llx(0, x)
148
#define ll1(x) llx(1, x)
149
#define ll2(x) llx(2, x)
150
#define ll3(x) llx(3, x)
156
// g_ncc return no error...
158
const NdbError& e = g_ndb->getNdbError();
160
ll0(++any << " ndb: error " << e);
163
const NdbError& e = g_dic->getNdbError();
165
ll0(++any << " dic: error " << e);
168
const NdbError& e = g_con->getNdbError();
170
ll0(++any << " con: error " << e);
173
const NdbError& e = g_op->getNdbError();
175
ll0(++any << " op: error " << e);
177
if (g_scan_op != 0) {
178
const NdbError& e = g_scan_op->getNdbError();
180
ll0(++any << " scan_op: error " << e);
182
if (g_rangescan_op != 0) {
183
const NdbError& e = g_rangescan_op->getNdbError();
185
ll0(++any << " rangescan_op: error " << e);
188
const NdbError& e = g_stat->getNdbError();
190
ll0(++any << " stat: error " << e);
193
ll0("unknown db error");
196
// create table ts0 (
197
// a int unsigned, b smallint not null, c varchar(10), d int unsigned,
198
// primary key using hash (a), index (b, c, d) )
203
NdbDictionary::Table tab(g_tabname);
204
tab.setLogging(false);
206
NdbDictionary::Column col("a");
207
col.setType(NdbDictionary::Column::Unsigned);
208
col.setPrimaryKey(true);
212
NdbDictionary::Column col("b");
213
col.setType(NdbDictionary::Column::Smallint);
214
col.setNullable(false);
218
NdbDictionary::Column col("c");
219
col.setType(NdbDictionary::Column::Varchar);
220
col.setLength(g_charlen);
221
col.setCharset(g_cs);
222
col.setNullable(true);
226
NdbDictionary::Column col("d");
227
col.setType(NdbDictionary::Column::Unsigned);
228
col.setNullable(true);
231
NdbDictionary::Index ind(g_indname);
232
ind.setTable(g_tabname);
233
ind.setType(NdbDictionary::Index::OrderedIndex);
234
ind.setLogging(false);
235
ind.addColumnName("b");
236
ind.addColumnName("c");
237
ind.addColumnName("d");
238
g_dic = g_ndb->getDictionary();
239
if (! g_opts.keeptable) {
240
if (g_dic->getTable(g_tabname) != 0)
241
chkdb(g_dic->dropTable(g_tabname) == 0);
242
chkdb(g_dic->createTable(tab) == 0);
243
chkdb(g_dic->createIndex(ind) == 0);
245
if (g_dic->getTable(g_tabname) == 0) {
246
chkdb(g_dic->createTable(tab) == 0);
247
chkdb(g_dic->createIndex(ind) == 0);
249
g_opts.loaddata = false;
251
chkdb((g_tab = g_dic->getTable(g_tabname)) != 0);
252
chkdb((g_ind = g_dic->getIndex(g_indname, g_tabname)) != 0);
260
g_dic = g_ndb->getDictionary();
261
if (! g_opts.keeptable)
262
chkdb(g_dic->dropTable(g_tabname) == 0);
270
uchar c[1 + g_charlen];
273
// partial values for use in Bnd
275
void make(uint n = g_numattrs, bool is_val = true);
276
int cmp(const Val& val, uint n = g_numattrs) const;
280
operator<<(NdbOut& out, const Val& val)
283
if (val.numattrs >= 1) {
286
if (val.numattrs >= 2) {
291
char buf[1 + g_charlen];
292
sprintf(buf, "%.*s", val.c[0], &val.c[1]);
293
out << "'" << buf << "'";
296
if (val.numattrs >= 3) {
308
Val::make(uint n, bool is_val)
311
uint b_max = is_val ? g_val_b_max : g_bnd_b_max;
312
b = (int)urandom(2 * b_max) - (int)b_max;
315
if (urandom(100) < g_opts.nullkeys)
318
const char* c_char = is_val ? g_val_c_char : g_bnd_c_char;
320
uint len = urandom(urandom(g_charlen + 2));
323
for (j = 0; j < len; j++) {
324
uint k = urandom(strlen(c_char));
325
c[1 + j] = c_char[k];
331
if (urandom(100) < g_opts.nullkeys)
334
uint d_max = is_val ? g_val_d_max : g_bnd_d_max;
343
Val::cmp(const Val& val, uint n) const
346
if (k == 0 && n >= 1) {
352
if (k == 0 && n >= 2) {
353
if (! c_null && ! val.c_null) {
354
const uchar* s1 = &c[1];
355
const uchar* s2 = &val.c[1];
356
const uint l1 = (uint)c[0];
357
const uint l2 = (uint)val.c[0];
358
assert(l1 <= g_charlen && l2 <= g_charlen);
359
k = g_cs->coll->strnncollsp(g_cs, s1, l1, s2, l2, 0);
360
} else if (! c_null) {
362
} else if (! val.c_null) {
366
if (k == 0 && n >= 3) {
367
if (! d_null && ! val.d_null) {
372
} else if (! d_null) {
374
} else if (! val.d_null) {
391
operator<<(NdbOut& out, const Key& key)
393
out << key.val << " info:" << key.count;
397
static Key* g_keys = 0;
398
static Key* g_sortkeys = 0;
399
static uint g_sortcount = 0;
400
static Key* g_minkey = 0;
401
static Key* g_maxkey = 0;
418
size_t sz = sizeof(Key) * g_opts.rows;
419
g_keys = (Key*)my_malloc(sz, MYF(0));
420
g_sortkeys = (Key*)my_malloc(sz, MYF(0));
421
chkrc(g_keys != 0 && g_sortkeys != 0);
422
memset(g_keys, 0x1f, sz);
423
memset(g_sortkeys, 0x1f, sz);
431
for (i = 0; i < g_opts.rows; i++) {
432
Key& key = g_keys[i];
434
key.flag = false; // mark for dup generation done
436
for (i = 0; i < g_opts.rows; i++) {
437
Key& key = g_keys[i];
442
uint n = (urandom(fudge * (g_opts.dupkeys - 100)) + 99) / 100;
444
for (k = 1; k < n; k++) {
445
uint j = urandom(g_opts.rows);
447
Key& dst = g_keys[j];
453
} while (urandom(g_opts.tryhard) != 0);
461
const uint batch = 512;
462
chkdb((g_con = g_ndb->startTransaction()) != 0);
464
while (i < g_opts.rows) {
465
chkdb((g_op = g_con->getNdbOperation(g_tab)) != 0);
466
chkdb(g_op->insertTuple() == 0);
468
const Val& val = g_keys[i].val;
469
const char* a_addr = (const char*)&a;
470
const char* b_addr = (const char*)&val.b;
471
const char* c_addr = ! val.c_null ? (const char*)val.c : 0;
472
const char* d_addr = ! val.d_null ? (const char*)&val.d : 0;
474
chkdb(g_op->equal(no++, a_addr) == 0);
475
chkdb(g_op->setValue(no++, b_addr) == 0);
476
chkdb(g_op->setValue(no++, c_addr) == 0);
477
chkdb(g_op->setValue(no++, d_addr) == 0);
478
if (i++ % batch == 0) {
479
chkdb(g_con->execute(NdbTransaction::Commit) == 0);
480
g_ndb->closeTransaction(g_con);
483
chkdb((g_con = g_ndb->startTransaction()) != 0);
486
chkdb(g_con->execute(NdbTransaction::Commit) == 0);
487
g_ndb->closeTransaction(g_con);
490
ll0(g_tabname << ": inserted " << g_opts.rows << " rows");
499
char* r_addr = (char*)&r;
500
chkdb((g_con = g_ndb->startTransaction()) != 0);
501
chkdb((g_scan_op = g_con->getNdbScanOperation(g_tab)) != 0);
502
chkdb(g_scan_op->readTuples() == 0);
503
chkdb(g_scan_op->interpret_exit_last_row() == 0);
504
chkdb(g_scan_op->getValue(NdbDictionary::Column::ROW_COUNT, r_addr) != 0);
505
chkdb(g_con->execute(NdbTransaction::NoCommit) == 0);
509
chkdb((ret = g_scan_op->nextResult()) == 0 || ret == 1);
514
g_ndb->closeTransaction(g_con);
524
chkdb((g_con = g_ndb->startTransaction()) != 0);
525
chkdb((g_scan_op = g_con->getNdbScanOperation(g_tab)) != 0);
526
chkdb(g_scan_op->readTuples() == 0);
529
char* a_addr = (char*)&a;
530
char* b_addr = (char*)&val.b;
531
char* c_addr = (char*)val.c;
532
char* d_addr = (char*)&val.d;
537
chkdb(g_scan_op->getValue(no++, a_addr) != 0);
538
chkdb((b_ra = g_scan_op->getValue(no++, b_addr)) != 0);
539
chkdb((c_ra = g_scan_op->getValue(no++, c_addr)) != 0);
540
chkdb((d_ra = g_scan_op->getValue(no++, d_addr)) != 0);
541
chkdb(g_con->execute(NdbTransaction::NoCommit) == 0);
544
for (i = 0; i < g_opts.rows; i++)
549
chkdb((ret = g_scan_op->nextResult()) == 0 || ret == 1);
552
assert(b_ra->isNULL() == 0 && c_ra->isNULL() != -1 && d_ra->isNULL() != -1);
553
val.c_null = c_ra->isNULL();
554
val.d_null = d_ra->isNULL();
556
chkrc(i < g_opts.rows);
557
Key& key = g_keys[i];
559
chkrc(key.val.cmp(val) == 0);
565
g_ndb->closeTransaction(g_con);
568
for (i = 0; i < g_opts.rows; i++)
569
chkrc(g_keys[i].count == 1);
570
assert(count == g_opts.rows);
571
int level = g_opts.loaddata ? 1 : 0;
572
llx(level, g_tabname << ": scanned " << g_opts.rows << " rows");
579
if (g_opts.loaddata) {
580
chkrc(allockeys() == 0);
582
chkrc(insertdata() == 0);
584
chkrc(countrows() == 0);
585
chkrc(g_opts.rows != 0);
586
ll0(g_tabname << ": using old table of " << g_opts.rows << " rows");
587
chkrc(allockeys() == 0);
589
chkrc(scandata() == 0);
591
for (i = 0; i < g_opts.rows; i++)
592
ll3(i << ": " << g_keys[i]);
596
// true = match, index = match or next higher
598
sortval(const Val& val, int& index)
600
if (unlikely(g_sortcount == 0)) {
605
int hi = (int)g_sortcount;
610
ret = val.cmp(g_sortkeys[j].val);
617
} while (hi - lo > 1);
629
// insert sort with binary search
632
for (i = 0; i < g_opts.rows; i++) {
633
const Val& val = g_keys[i].val;
635
bool match = sortval(val, index);
636
Key& dst = g_sortkeys[index];
640
uint bytes = ((int)g_sortcount - index) * sizeof(Key);
641
memmove(&dst + 1, &dst, bytes);
647
g_minkey = &g_sortkeys[0];
648
g_maxkey = &g_sortkeys[g_sortcount - 1];
649
ll1("counted " << g_sortcount << " distinct keys");
655
* A bound is a partial key value (0 to g_numattrs attributes).
656
* It is not equal to any key value. Instead, it has a "side".
658
* side = 0 if the bound is empty
659
* side = -1 if the bound is "just before" its value
660
* side = +1 if the bound is "just after" its value
662
* This is another way of looking at strictness of non-empty
663
* start and end keys in a range.
665
* start key is strict if side = +1
666
* end key is strict if side = -1
668
* NDB API specifies strictness in the bound type of the last
669
* index attribute which is part of the start/end key.
671
* LE (0) - strict: n - side: -1
672
* LT (1) - strict: y - side: +1
673
* GE (2) - strict: n - side: +1
674
* GT (3) - strict: y - side: -1
676
* A non-empty bound divides keys into 2 disjoint subsets:
677
* keys before (cmp() == -1) and keys after (cmp() == +1).
680
Bnd& make(uint minattrs);
681
Bnd& make(uint minattrs, const Val& theval);
682
int cmp(const Val& val) const;
683
int type(uint lohi, uint colno) const; // for setBound
687
operator<<(NdbOut& out, const Bnd& bnd)
690
out << " side: " << bnd.side;
695
Bnd::make(uint minattrs)
697
uint numattrs = minattrs + urandom(g_numattrs - minattrs);
698
val.make(numattrs, false);
699
side = val.numattrs == 0 ? 0 : urandom(2) == 0 ? -1 : +1;
704
Bnd::make(uint minattrs, const Val& theval)
706
uint numattrs = minattrs + urandom(g_numattrs - minattrs);
708
val.numattrs = numattrs;
709
side = val.numattrs == 0 ? 0 : urandom(2) == 0 ? -1 : +1;
714
Bnd::cmp(const Val& theval) const
719
assert(theval.numattrs == g_numattrs);
720
int k = theval.cmp(val, val.numattrs);
733
assert(val.numattrs == 0);
735
ll3("cmp: val: " << theval << " bnd: " << *this <<
736
" return: " << ret << " at " << place);
741
Bnd::type(uint lohi, uint colno) const
744
assert(lohi <= 1 && colno < val.numattrs && (side == -1 || side == +1));
746
if (colno + 1 < val.numattrs)
753
if (colno + 1 < val.numattrs)
765
uint minattrs() const;
766
uint maxattrs() const;
767
int cmp(const Val& val) const; // -1,0,+1 = key is before,in,after range
768
uint rowcount() const;
778
operator<<(NdbOut& out, const Range& range)
780
out << "bnd0: " << range.bnd[0] << " bnd1: " << range.bnd[1];
785
Range::minattrs() const
787
return min(bnd[0].val.numattrs, bnd[1].val.numattrs);
791
Range::maxattrs() const
793
return max(bnd[0].val.numattrs, bnd[1].val.numattrs);
797
Range::cmp(const Val& theval) const
803
k = bnd[0].cmp(theval);
809
k = bnd[1].cmp(theval);
818
ll3("cmp: val: " << theval << " range: " << *this <<
819
" return: " << ret << " at " << place);
824
Range::rowcount() const
826
ll2("rowcount: " << *this);
828
// binary search for first and last in range
830
for (i = 0; i <= 1; i++) {
831
ll3("search i=" << i);
833
int hi = (int)g_sortcount;
838
ret = cmp(g_sortkeys[j].val);
850
} while (hi - lo > 1);
859
const int lo = max(lim[0], 0);
860
const int hi = min(lim[1], (int)g_sortcount - 1);
861
if (! g_opts.nochecks) {
863
for (i = 0; i < (int)g_sortcount; i++) {
864
int k = cmp(g_sortkeys[i].val);
868
assert(lo <= i && i <= hi);
878
for (i = lo; i <= hi; i++)
879
count += g_sortkeys[i].count;
880
ll2("count: " << count << " index lim: " << lim[0] << " " << lim[1]);
888
minattrs() == maxattrs() &&
889
bnd[0].val.cmp(bnd[1].val, minattrs()) == 0 &&
890
bnd[0].side < bnd[1].side;
893
static Range* g_ranges = 0;
907
size_t sz = sizeof(Range) * g_opts.ops;
908
g_ranges = (Range*)my_malloc(sz, MYF(0));
909
chkrc(g_ranges != 0);
910
memset(g_ranges, 0x1f, sz);
918
for (i = 0; i < g_opts.ops; i++) {
919
Range& range = g_ranges[i];
920
range.flag = false; // mark for dup generation done
921
bool fulleq = (urandom(100) < g_opts.eqscans);
922
bool eq = fulleq || (urandom(100) < g_opts.eqscans);
923
bool matcheq = eq && (urandom(10) != 0);
925
// random but prefer non-empty and no more than scanpct
927
range.bnd[0].make(0);
928
range.bnd[1].make(0);
929
uint count = range.rowcount();
930
if (count != 0 && 100 * count <= g_opts.scanpct * g_opts.rows)
932
} while (urandom(g_opts.tryhard) != 0);
934
uint minattrs = fulleq ? g_numattrs : 1;
936
range.bnd[0].make(minattrs);
938
uint m = urandom(g_sortcount);
939
const Val& val = g_sortkeys[m].val;
940
range.bnd[0].make(minattrs, val);
942
range.bnd[1] = range.bnd[0];
943
range.bnd[0].side = -1;
944
range.bnd[1].side = +1;
948
assert(range.iseq());
951
for (i = 0; i < g_opts.ops; i++) {
952
Range& range = g_ranges[i];
956
if (urandom(100) < g_opts.dupscans) {
957
uint j = urandom(g_opts.ops);
959
Range& dst = g_ranges[j];
961
dst.bnd[0] = range.bnd[0];
962
dst.bnd[1] = range.bnd[1];
966
} while (urandom(g_opts.tryhard) != 0);
972
setbounds(const Range& range)
974
// currently must do each attr in order
975
ll2("setbounds: " << range);
977
const Bnd (&bnd)[2] = range.bnd;
978
for (i = 0; i < g_numattrs; i++) {
979
const Uint32 no = i; // index attribute number
981
int type[2] = { -1, -1 };
982
for (j = 0; j <= 1; j++) {
983
if (no < bnd[j].val.numattrs)
984
type[j] = bnd[j].type(j, no);
986
for (j = 0; j <= 1; j++) {
990
if (no + 1 < bnd[j].val.numattrs)
991
t &= ~(uint)1; // strict bit is set on last bound only
992
const Val& val = bnd[j].val;
993
const void* addr = 0;
995
addr = (const void*)&val.b;
997
addr = ! val.c_null ? (const void*)val.c : 0;
999
addr = ! val.d_null ? (const void*)&val.d : 0;
1002
ll2("setBound attr:" << no << " type:" << t << " val: " << val);
1003
chkdb(g_rangescan_op->setBound(no, t, addr) == 0);
1012
g_stat = new NdbIndexStat(g_ind);
1013
chkdb(g_stat->alloc_cache(32) == 0);
1018
runstat(Range& range, int flags)
1020
ll2("runstat: " << range << " flags=" << flags);
1021
chkdb((g_con = g_ndb->startTransaction()) != 0);
1022
chkdb((g_rangescan_op = g_con->getNdbIndexScanOperation(g_ind, g_tab)) != 0);
1023
chkdb(g_rangescan_op->readTuples(NdbOperation::LM_CommittedRead) == 0);
1024
chkrc(setbounds(range) == 0);
1025
Uint64 count = ~(Uint64)0;
1026
chkdb(g_stat->records_in_range(g_ind, g_rangescan_op, g_opts.rows, &count, flags) == 0);
1027
g_ndb->closeTransaction(g_con);
1030
range.statrows = (uint)count;
1031
chkrc((Uint64)range.statrows == count);
1032
ll2("stat: " << range.statrows);
1037
runscan(Range& range)
1039
ll2("runscan: " << range);
1040
chkdb((g_con = g_ndb->startTransaction()) != 0);
1041
chkdb((g_rangescan_op = g_con->getNdbIndexScanOperation(g_ind, g_tab)) != 0);
1042
chkdb(g_rangescan_op->readTuples() == 0);
1043
chkrc(setbounds(range) == 0);
1045
char* a_addr = (char*)&a;
1047
chkdb(g_rangescan_op->getValue(no++, a_addr) != 0);
1048
chkdb(g_con->execute(NdbTransaction::NoCommit) == 0);
1051
for (i = 0; i < g_opts.rows; i++)
1052
g_keys[i].count = 0;
1056
chkdb((ret = g_rangescan_op->nextResult()) == 0 || ret == 1);
1060
chkrc(i < g_opts.rows);
1061
Key& key = g_keys[i];
1062
ll3("scan: " << key);
1063
int k = range.cmp(key.val);
1065
chkrc(key.count == 0);
1069
g_ndb->closeTransaction(g_con);
1072
if (! g_opts.nochecks) {
1073
for (i = 0; i < g_opts.rows; i++) {
1074
const Key& key = g_keys[i];
1075
int k = range.cmp(key.val);
1076
assert((k != 0 && key.count == 0) || (k == 0 && key.count == 1));
1078
assert(range.rowcount() == count);
1080
range.scanrows = count;
1081
ll2("scan: " << range.scanrows);
1089
for (i = 0; i < g_opts.ops; i++) {
1090
Range& range = g_ranges[i];
1091
ll1("range " << i << ": " << range);
1092
// simulate old handler code
1094
if (i < 32 || i % 20 == 0)
1095
flags |= NdbIndexStat::RR_UseDb;
1096
chkrc(runstat(range, flags) == 0);
1097
chkrc(runscan(range) == 0);
1098
// if stat is 0 then it is exact scan count
1099
chkrc(range.statrows != 0 || range.scanrows == 0);
1100
// measure error as fraction of total rows
1101
double x = (double)range.statrows;
1102
double y = (double)range.scanrows;
1103
double z = (double)g_opts.rows;
1104
double err = (x - y) / z;
1106
range.errpct = 100.0 * err;
1107
ll1("range " << i << ":" <<
1108
" stat: " << range.statrows << " scan: " << range.scanrows <<
1109
" errpct: " << range.errpct);
1125
void add(const Stat& stat);
1133
sum = minval = maxval = avg = varsum = var = stddev = 0.0;
1137
Stat::add(const Stat& stat)
1144
tmp.count = count + stat.count;
1145
tmp.sum = sum + stat.sum;
1146
tmp.minval = minval <= stat.minval ? minval : stat.minval;
1147
tmp.maxval = maxval >= stat.maxval ? maxval : stat.maxval;
1148
tmp.avg = tmp.sum / double(tmp.count);
1149
tmp.varsum = varsum + stat.varsum;
1150
tmp.var = tmp.varsum / double(tmp.count);
1151
tmp.stddev = sqrt(tmp.var);
1156
operator<<(NdbOut& out, const Stat& stat)
1158
out << stat.name << ": " << "count: " << stat.count
1159
<< " min: " << stat.minval << " max: " << stat.maxval
1160
<< " avg: " << stat.avg << " stddev: " << stat.stddev;
1164
template <class T, class V>
1166
computestat(Stat& stat)
1169
stat.name = V::name();
1170
const T* array = V::array();
1171
stat.count = V::count();
1172
assert(stat.count != 0);
1174
for (i = 0; i < stat.count; i++) {
1175
const T& item = array[i];
1176
double data = V::data(item);
1179
stat.minval = stat.maxval = data;
1181
if (stat.minval > data)
1183
if (stat.maxval < data)
1187
stat.avg = stat.sum / double(stat.count);
1189
for (i = 0; i < stat.count; i++) {
1190
const T& item = array[i];
1191
double data = V::data(item);
1192
double x = data - stat.avg;
1193
stat.varsum += x * x;
1195
stat.var = stat.varsum / double(stat.count);
1196
stat.stddev = sqrt(stat.var);
1200
static const char* name() { return "rec per key"; }
1201
static const Key* array() { return g_sortkeys; }
1202
static uint count() { return g_sortcount; }
1203
static double data(const Key& key) { return (double)key.rpk; }
1207
static const char* name() { return "rir err pct"; }
1208
static const Range* array() { return g_ranges; }
1209
static uint count() { return g_opts.ops; }
1210
static double data(const Range& range) { return (double)range.errpct; }
1213
template void computestat<Key, V_rpk>(Stat& stat);
1214
template void computestat<Range, V_rir>(Stat& stat);
1216
static Stat g_stat_rpk; // summaries over loops
1217
static Stat g_stat_rir;
1222
Stat stat_rpk; // records per key
1223
Stat stat_rir; // record in range
1228
computestat<Key, V_rpk>(stat_rpk);
1229
computestat<Range, V_rir>(stat_rir);
1230
if (g_opts.loop != 1) {
1231
ll0("=== loop " << g_loop << " summary ===");
1236
g_stat_rpk.add(stat_rpk);
1237
g_stat_rir.add(stat_rir);
1243
ll0("=== summary ===");
1253
if (g_opts.seed == 0)
1255
if (g_opts.seed != -1)
1256
seed = (uint)g_opts.seed;
1258
seed = 1 + (ushort)getpid();
1260
if (g_opts.seed != 0)
1264
ll0("seed=" << seed);
1272
g_cs = get_charset_by_name(g_csname, MYF(0));
1274
g_cs = get_charset_by_csname(g_csname, MY_CS_PRIMARY, MYF(0));
1276
for (g_loop = 0; g_opts.loop == 0 || g_loop < g_opts.loop; g_loop++) {
1277
ll0("=== loop " << g_loop << " ===");
1279
chkrc(createtable() == 0);
1280
chkrc(loaddata() == 0);
1282
chkrc(allocranges() == 0);
1284
chkrc(allocstat() == 0);
1285
chkrc(runscans() == 0);
1286
chkrc(droptable() == 0);
1295
static struct my_option
1298
NDB_STD_OPTS("testIndexStat"),
1299
{ "loglevel", 1001, "Logging level in this program 0-3 (default 0)",
1300
&g_opts.loglevel, &g_opts.loglevel, 0,
1301
GET_INT, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 },
1302
{ "seed", 1002, "Random seed (0=loop number, default -1=random)",
1303
&g_opts.seed, &g_opts.seed, 0,
1304
GET_INT, REQUIRED_ARG, -1, 0, 0, 0, 0, 0 },
1305
{ "loop", 1003, "Number of test loops (default 1, 0=forever)",
1306
&g_opts.loop, &g_opts.loop, 0,
1307
GET_INT, REQUIRED_ARG, 1, 0, 0, 0, 0, 0 },
1308
{ "rows", 1004, "Number of rows (default 100000)",
1309
&g_opts.rows, &g_opts.rows, 0,
1310
GET_UINT, REQUIRED_ARG, 100000, 0, 0, 0, 0, 0 },
1311
{ "ops", 1005, "Number of index scans per loop (default 1000)",
1312
&g_opts.ops, &g_opts.ops, 0,
1313
GET_UINT, REQUIRED_ARG, 1000, 0, 0, 0, 0, 0 },
1314
{ "dupkeys", 1006, "Pct records per key (min 100, default 1000)",
1315
&g_opts.dupkeys, &g_opts.dupkeys, 0,
1316
GET_UINT, REQUIRED_ARG, 1000, 0, 0, 0, 0, 0 },
1317
{ "scanpct", 1007, "Preferred max pct of total rows per scan (default 5)",
1318
&g_opts.scanpct, &g_opts.scanpct, 0,
1319
GET_UINT, REQUIRED_ARG, 5, 0, 0, 0, 0, 0 },
1320
{ "nullkeys", 1008, "Pct nulls in each key attribute (default 10)",
1321
&g_opts.nullkeys, &g_opts.nullkeys, 0,
1322
GET_UINT, REQUIRED_ARG, 10, 0, 0, 0, 0, 0 },
1323
{ "eqscans", 1009, "Pct scans for partial/full equality (default 50)",
1324
&g_opts.eqscans, &g_opts.eqscans, 0,
1325
GET_UINT, REQUIRED_ARG, 50, 0, 0, 0, 0, 0 },
1326
{ "dupscans", 1010, "Pct scans using same bounds (default 10)",
1327
&g_opts.dupscans, &g_opts.dupscans, 0,
1328
GET_UINT, REQUIRED_ARG, 10, 0, 0, 0, 0, 0 },
1329
{ "keeptable", 1011, "Use existing table and data if any and do not drop",
1330
&g_opts.keeptable, &g_opts.keeptable, 0,
1331
GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0 },
1332
{ "no-extra-checks", 1012, "Omit expensive consistency checks",
1333
&g_opts.nochecks, &g_opts.nochecks, 0,
1334
GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0 },
1335
{ "abort-on-error", 1013, "Dump core on any error",
1336
&g_opts.abort, &g_opts.abort, 0,
1337
GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0 },
1340
GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0 }
1348
<< ": measure records_in_range error as percentage of total rows" << endl;
1349
my_print_help(my_long_options);
1355
chkrc(g_opts.rows != 0);
1356
chkrc(g_opts.nullkeys <= 100);
1357
chkrc(g_opts.dupkeys >= 100);
1358
chkrc(g_opts.scanpct <= 100);
1359
chkrc(g_opts.eqscans <= 100);
1360
chkrc(g_opts.dupscans <= 100);
1367
g_ncc = new Ndb_cluster_connection();
1368
chkdb(g_ncc->connect(30) == 0);
1369
g_ndb = new Ndb(g_ncc, "TEST_DB");
1370
chkdb(g_ndb->init() == 0 && g_ndb->waitUntilReady(30) == 0);
1385
main(int argc, char** argv)
1388
const char* g_progname =
1389
strchr(argv[0], '/') ? strrchr(argv[0], '/') + 1 : argv[0];
1391
ndbout << g_progname;
1392
for (i = 1; i < argc; i++)
1393
ndbout << " " << argv[i];
1396
ret = handle_options(&argc, &argv, my_long_options, ndb_std_get_one_option);
1397
if (ret != 0 || argc != 0)
1398
return NDBT_ProgramExit(NDBT_WRONGARGS);
1399
if (checkoptions() == 0 && doconnect() == 0 && runtest() == 0) {
1401
return NDBT_ProgramExit(NDBT_OK);
1404
return NDBT_ProgramExit(NDBT_FAILED);