18 #include <ndb_global.h>
21 #include <NdbTest.hpp>
22 #include <ndb_version.h>
28 #if !defined(min) || !defined(max)
29 #define min(x, y) ((x) < (y) ? (x) : (y))
30 #define max(x, y) ((x) > (y) ? (x) : (y))
70 my_bool abort_on_error;
77 my_bool no_implicit_nulls;
78 my_bool no_missing_update;
85 my_bool separate_events;
91 static const uint g_maxpk = 1000;
92 static const uint g_maxtab = 100;
93 static const uint g_maxopstringpart = 100;
94 static const char* g_opstringpart[g_maxopstringpart];
95 static uint g_opstringparts = 0;
96 static uint g_loop = 0;
99 static Ndb* g_ndb = 0;
105 static const uint g_charlen = 5;
106 static const char* g_charval =
"abcdefgh";
107 static const char* g_csname =
"latin1_swedish_ci";
109 static uint g_blobinlinesize = 256;
110 static uint g_blobpartsize = 2000;
111 static const uint g_maxblobsize = 100000;
119 uint r = (uint)ndb_rand();
134 urandom(uint per, uint cent)
136 return urandom(cent) < per;
139 static int& g_loglevel = g_opts.loglevel;
142 do { if (x) break; ndbout << "line " << __LINE__ << " FAIL " << #x << endl; errdb(); if (g_opts.abort_on_error) abort(); return -1; } while (0)
145 do { if (x) break; ndbout << "line " << __LINE__ << " FAIL " << #x << endl; if (g_opts.abort_on_error) abort(); return -1; } while (0)
148 do { if (x) break; ndbout << "line " << __LINE__ << " ASSERT " << #x << endl; abort(); } while (0)
151 do { if (g_loglevel < 0) break; ndbout << x << endl; } while (0)
154 do { if (g_loglevel < 1) break; ndbout << x << endl; } while (0)
157 do { if (g_loglevel < 2) break; ndbout << x << endl; } while (0)
160 do { if (g_loglevel < 3) break; ndbout << x << endl; } while (0)
170 ll0(++any <<
" ndb: error " << e);
175 ll0(++any <<
" dic: error " << e);
180 ll0(++any <<
" con: error " << e);
185 ll0(++any <<
" op: error " << e);
187 if (g_scan_op != 0) {
190 ll0(++any <<
" scan_op: error " << e);
195 ll0(++any <<
" evt_op: error " << e);
200 ll0(++any <<
" bh: error " << e);
203 ll0(
"unknown db error");
217 bool isblob()
const {
225 static const Col g_col[] = {
228 g_charlen, 1 + g_charlen, 0, 0, 0 },
237 g_charlen, g_charlen, 0, 0, 0 },
240 0, 0, g_blobinlinesize, g_blobpartsize, 0 },
243 0, 0, g_blobinlinesize, g_blobpartsize, 4 },
246 0, 0, g_blobinlinesize, 0, 0 }
249 static const uint g_maxcol =
sizeof(g_col)/
sizeof(g_col[0]);
250 static const uint g_blobcols = 3;
258 else if (g_opts.one_blob)
259 n -= (g_blobcols - 2);
273 getcol(
const char*
name)
276 for (i = 0; i < ncol(); i++)
277 if (strcmp(g_col[i].name, name) == 0)
293 sprintf(tabname,
"tem%d", idx);
294 sprintf(evtname,
"tem%dev", idx);
298 static Tab* g_tablst[g_maxtab];
303 return g_opts.maxtab;
309 assert(i < maxtab() && g_tablst[i] != 0);
316 ll2(
"createtable: " << t.tabname);
319 tab.setLogging(
false);
321 chkrc((cs = get_charset_by_name(g_csname, MYF(0))) != 0);
323 for (i = 0; i < ncol(); i++) {
324 const Col& c = t.col[
i];
327 col.setPrimaryKey(c.pk);
328 col.setNullable(c.nullable);
334 col.setLength(c.length);
338 col.setBlobVersion(g_opts.blob_version);
339 col.setInlineSize(c.inlinesize);
340 col.setPartSize(c.partsize);
341 col.setStripeSize(g_opts.blob_version == 1 ? 4 : c.stripesize);
345 col.setBlobVersion(g_opts.blob_version);
346 col.setInlineSize(c.inlinesize);
347 col.setPartSize(c.partsize);
348 col.setStripeSize(g_opts.blob_version == 1 ? 4 : c.stripesize);
357 if (! g_opts.use_table) {
358 if (g_dic->
getTable(t.tabname) != 0)
362 chkdb((t.tab = g_dic->
getTable(t.tabname)) != 0);
364 if (! g_opts.use_table) {
370 char pk2[1 + g_charlen + 1];
372 sprintf(pk2 + 1,
"%-u", pk1);
373 *(uchar*)pk2 = (uchar)(strlen(pk2 + 1));
374 chkdb(g_op->
equal(
"pk1", (
char*)&pk1) == 0);
375 chkdb(g_op->
equal(
"pk2", (
char*)&pk2[0]) == 0);
376 chkdb(g_con->
execute(Commit) == 0);
388 for (uint i = 0; i < maxtab(); i++)
389 chkrc(createtable(tab(i)) == 0);
396 ll2(
"droptable: " << t.tabname);
397 if (! g_opts.use_table) {
410 for (uint i = 0; i < maxtab(); i++)
411 chkrc(droptable(tab(i)) == 0);
418 ll2(
"createevent: " << t.evtname);
423 evt.setTable(*t.tab);
426 for (i = 0; i < ncol(); i++) {
427 const Col& c = g_col[
i];
428 evt.addEventColumn(c.name);
430 evt.setReport(NdbDictionary::Event::ER_UPDATED);
431 evt.mergeEvents(! g_opts.separate_events);
432 #if 0 // XXX random bugs
433 if (g_dic->
getEvent(t.evtname) != 0)
439 chkdb((t.evt = g_dic->
getEvent(t.evtname)) != 0);
448 for (uint i = 0; i < maxtab(); i++)
449 chkrc(createevent(tab(i)) == 0);
454 dropevent(
Tab& t,
bool force =
false)
456 ll2(
"dropevent: " << t.evtname);
458 chkdb(g_dic->
dropEvent(t.evtname) == 0 || force);
465 dropevents(
bool force =
false)
468 for (uint i = 0; i < maxtab(); i++) {
469 if (force && g_tablst[i] == 0)
471 chkrc(dropevent(tab(i), force) == 0 || force);
477 struct Txt {
char* val; uint len; };
478 union Ptr { Uint32* u32;
char* ch; uchar* uch;
Txt* txt;
void* v; };
480 char pk2[g_charlen + 1];
482 char cc1[g_charlen + 1];
493 memset(pk2, 0,
sizeof(pk2));
495 memset(cc1, 0,
sizeof(cc1));
496 tx1.val = tx2.val = bl1.val = 0;
497 tx1.len = tx2.len = bl1.len = 0;
505 for (i = 0; i < g_maxcol; i++)
514 tx1.val = tx2.val = bl1.val = 0;
515 tx1.len = tx2.len = bl1.len = 0;
520 cmpcol(
const Col& c,
const Data& d1,
const Data& d2)
523 if (d1.ind[i] != d2.ind[i])
525 if (d1.ind[i] == 0) {
528 if (*d1.ptr[i].u32 != *d2.ptr[i].u32)
532 if (memcmp(d1.ptr[i].ch, d2.ptr[i].ch, c.size) != 0)
537 uint l1 = d1.ptr[
i].uch[0];
538 uint l2 = d2.ptr[
i].uch[0];
541 if (memcmp(d1.ptr[i].ch, d2.ptr[i].ch, l1) != 0)
550 if (t1.len != t2.len)
552 if (memcmp(t1.val, t2.val, t1.len) != 0)
565 operator<<(NdbOut& out,
const Data& d)
568 for (i = 0; i < ncol(); i++) {
569 const Col& c = getcol(i);
570 out << (i == 0 ?
"" :
" ") << c.name;
571 out << (! (d.noop & (1 << i)) ?
"=" :
":");
580 out << *d.ptr[
i].u32;
584 char buf[g_charlen + 1];
585 memcpy(buf, d.ptr[i].ch, g_charlen);
589 if (n == 0 || buf[n - 1] != 0x20)
593 out <<
"'" << buf <<
"'";
598 char buf[g_charlen + 1];
599 uint l = d.ptr[
i].uch[0];
600 assert(l <= g_charlen);
601 memcpy(buf, &d.ptr[i].ch[1], l);
603 out <<
"'" << buf <<
"'";
612 while (j < txt.len) {
617 while (j < txt.len && txt.val[j] == c[0])
641 static const uint g_optypes = 3;
649 enum Kind { OP = 1, EV = 2 };
650 enum Type { UNDEF = -1, INS, DEL, UPD, NUL };
664 void init(Kind a_kind, Type a_type = UNDEF) {
666 assert(kind == OP || kind == EV);
668 next_op = next_com = next_gci = next_ev = next_free = 0;
670 num_op = num_com = 0;
683 operator<<(NdbOut& out, Op::Type optype)
706 operator<<(NdbOut& out,
const Op& op)
709 out <<
" " << op.data[0];
710 out <<
" [" << op.data[1] <<
"]";
712 out <<
" gci:" << op.gci;
719 Op::Type optype = Op::UNDEF;
731 ll0(
"EVT: " << *ev <<
": bad event type " << hex << (uint)te);
741 Counter(
const char* a_name) : name(a_name), count(0) {
743 friend class NdbOut& operator<<(NdbOut& out,
const Counter& counter) {
744 out << counter.name <<
"(" << counter.count <<
")";
765 static Op* g_opfree = 0;
766 static uint g_freeops = 0;
767 static uint g_usedops = 0;
768 static uint g_gciops = 0;
769 static uint g_maxcom = 10;
770 static uint g_seq = 0;
772 static uint g_num_ev = 0;
774 static const uint g_maxgcis = 500;
781 Uint64 gcinum[g_maxgcis];
782 Uint32 gcievtypes[g_maxgcis][2];
788 uint ev_pos[g_maxpk];
802 for (i = 0; i < (int)g_maxgcis; i++) {
803 gcinum[
i] = (Uint64)0;
804 gcievtypes[
i][0] = gcievtypes[
i][1] = (Uint32)0;
809 for (i = 0; i < (int)g_maxpk; i++) {
814 for (j = 0; i < 2; j ++) {
815 for (i = 0; i < (int)g_maxcol; i++) {
821 int addgci(Uint64 gci)
823 assert(gcicnt < g_maxgcis);
824 chkrc(gcicnt == 0 || gcinum[gcicnt - 1] < gci);
825 gcinum[gcicnt++] = gci;
828 void addevtypes(Uint64 gci, Uint32 evtypes, uint i)
830 assert(gcicnt != 0 && gci == gcinum[gcicnt - 1]);
831 assert(evtypes != 0);
833 gcievtypes[gcicnt - 1][
i] |= evtypes;
837 static Run* g_runlst[g_maxtab];
848 assert(i < maxrun() && g_runlst[i] != 0);
856 for (i = 0; i < maxrun(); i++)
857 g_tablst[i] = g_runlst[i] =
new Run(i);
861 getop(Op::Kind a_kind, Op::Type a_type = Op::UNDEF)
864 assert(g_freeops == 0);
867 op->next_free = g_opfree;
873 g_opfree = op->next_free;
874 assert(g_freeops != 0);
877 op->init(a_kind, a_type);
879 ll3(
"getop: " << op);
886 ll3(
"freeop: " << op);
890 op->next_free = g_opfree;
893 assert(g_usedops != 0);
902 for (pk1 = 0; pk1 < g_opts.maxpk; pk1++)
905 for (pk1 = 0; pk1 < g_opts.maxpk; pk1++) {
906 if (r.pk_op[pk1] != 0) {
907 Op* tot_op = r.pk_op[pk1];
908 while (tot_op->next_gci != 0) {
909 Op* gci_op = tot_op->next_gci;
910 while (gci_op->next_com != 0) {
911 Op* com_op = gci_op->next_com;
912 while (com_op->next_op != 0) {
913 Op* op = com_op->next_op;
914 com_op->next_op = op->next_op;
917 gci_op->next_com = com_op->next_com;
920 tot_op->next_gci = gci_op->next_gci;
926 if (r.pk_ev[pk1] != 0) {
927 Op* tot_op = r.pk_ev[pk1];
928 while (tot_op->next_ev != 0) {
929 Op* ev = tot_op->next_ev;
930 tot_op->next_ev = ev->next_ev;
947 for (uint i = 0; i < maxrun(); i++)
949 assert(g_usedops == 0);
950 g_gciops = g_num_ev = 0;
956 while (g_opfree != 0) {
957 Op* tmp_op = g_opfree;
958 g_opfree = g_opfree->next_free;
962 assert(g_freeops == 0);
971 { Op::INS, Op::DEL, Op::NUL },
972 { Op::INS, Op::UPD, Op::INS },
973 { Op::DEL, Op::INS, Op::UPD },
974 { Op::UPD, Op::DEL, Op::DEL },
975 { Op::UPD, Op::UPD, Op::UPD }
978 static const uint g_ncomp =
sizeof(g_comp)/
sizeof(g_comp[0]);
981 checkop(
const Op* op, Uint32& pk1)
983 Op::Type optype = op->type;
984 assert(optype != Op::UNDEF);
985 if (optype == Op::NUL)
987 chkrc(optype == Op::INS || optype == Op::DEL || optype == Op::UPD);
988 const Data& d0 = op->data[0];
989 const Data& d1 = op->data[1];
991 const Col& c = getcol(
"pk1");
992 chkrc(d0.ind[c.no] == 0);
994 chkrc(pk1 < g_opts.maxpk);
997 for (i = 0; i < ncol(); i++) {
998 const Col& c = getcol(i);
999 const int ind0 = d0.ind[
i];
1000 const int ind1 = d1.ind[
i];
1004 if (optype == Op::INS)
1006 if (optype == Op::DEL)
1008 if (optype == Op::UPD)
1012 if (optype == Op::INS)
1013 chkrc(ind0 >= 0 && ind1 == -1);
1014 if (optype == Op::DEL)
1015 chkrc(ind0 == -1 && ind1 >= 0);
1016 if (optype == Op::UPD)
1017 chkrc(ind0 == -1 || ind1 >= 0);
1020 chkrc(ind0 <= 0 && ind1 <= 0);
1025 for (j = 0; j < 2; j++) {
1026 const Data& d = op->data[j];
1027 if (d.ind[i] == 0) {
1030 for (k = 0; k < (int)txt.len; k++) {
1031 chkrc(strchr(g_charval, txt.val[k]) != 0);
1041 comptype(Op::Type t1, Op::Type t2)
1044 for (i = 0; i < g_ncomp; i++)
1045 if (g_comp[i].t1 == t1 && g_comp[i].t2 == t2)
1054 if ((d3.ind[i] = d1.ind[i]) == 0) {
1056 memmove(d3.ptr[i].v, d1.ptr[i].v, c.size);
1061 t3.val =
new char [t1.len];
1063 memcpy(t3.val, t1.val, t1.len);
1069 copydata(
const Data& d1,
Data& d3,
bool pk,
bool nonpk)
1072 for (i = 0; i < ncol(); i++) {
1073 const Col& c = g_col[
i];
1074 if ((c.pk && pk) || (! c.pk && nonpk))
1080 compdata(
const Data& d1,
const Data& d2,
Data& d3,
bool pk,
bool nonpk)
1083 for (i = 0; i < ncol(); i++) {
1084 const Col& c = g_col[
i];
1085 if ((c.pk && pk) || (! c.pk && nonpk)) {
1087 if (d1.ind[i] == -1 && d2.ind[i] == -1)
1089 else if (d1.ind[i] == -1 && d2.ind[i] != -1)
1091 else if (d1.ind[i] != -1 && d2.ind[i] == -1)
1102 copyop(
const Op* op1,
Op* op3)
1104 op3->type = op1->type;
1105 copydata(op1->data[0], op3->data[0],
true,
true);
1106 copydata(op1->data[1], op3->data[1],
true,
true);
1107 op3->gci = op1->gci;
1109 reqrc(checkop(op3, pk1_tmp) == 0);
1113 compop(
const Op* op1,
const Op* op2,
Op* op3)
1115 assert(op1->type != Op::UNDEF && op2->type != Op::UNDEF);
1117 if (op2->type == Op::NUL) {
1121 if (op1->type == Op::NUL) {
1126 op1->kind == Op::OP && op2->kind == Op::OP ? Op::OP : Op::EV;
1127 Op* res_op = getop(kind);
1128 chkrc((comp = comptype(op1->type, op2->type)) != 0);
1129 res_op->type = comp->t3;
1130 if (res_op->type == Op::INS) {
1132 compdata(op1->data[0], op2->data[0], res_op->data[0],
true,
true);
1135 if (res_op->type == Op::DEL) {
1137 copydata(op2->data[0], res_op->data[0],
true,
false);
1138 copydata(op1->data[1], res_op->data[1],
true,
true);
1140 if (res_op->type == Op::UPD && op1->type == Op::DEL) {
1142 copydata(op2->data[0], res_op->data[0],
true,
true);
1143 copydata(op1->data[0], res_op->data[1],
true,
false);
1144 copydata(op1->data[1], res_op->data[1],
true,
true);
1146 if (res_op->type == Op::UPD && op1->type == Op::UPD) {
1148 compdata(op1->data[0], op2->data[0], res_op->data[0],
true,
true);
1149 compdata(op2->data[1], op1->data[1], res_op->data[1],
true,
true);
1151 assert(op1->gci == op2->gci);
1152 res_op->gci = op2->gci;
1154 reqrc(checkop(res_op, pk1_tmp) == 0);
1155 copyop(res_op, op3);
1161 createeventop(
Run& r)
1163 ll2(
"createeventop: " << r.tabname);
1167 for (i = 0; i < ncol(); i++) {
1168 const Col& c = g_col[
i];
1169 Data (&d)[2] = g_rec_ev->data;
1171 chkdb((r.ev_ra[0][i] = r.evt_op->
getValue(c.name, (
char*)d[0].ptr[i].v)) != 0);
1172 chkdb((r.ev_ra[1][i] = r.evt_op->
getPreValue(c.name, (
char*)d[1].ptr[i].v)) != 0);
1174 chkdb((r.ev_bh[0][i] = r.evt_op->
getBlobHandle(c.name)) != 0);
1175 chkdb((r.ev_bh[1][i] = r.evt_op->getPreBlobHandle(c.name)) != 0);
1184 ll1(
"createeventop");
1185 for (uint i = 0; i < maxrun(); i++)
1186 chkrc(createeventop(
run(i)) == 0);
1191 executeeventop(
Run& r)
1193 ll2(
"executeeventop: " << r.tabname);
1194 chkdb(r.evt_op->
execute() == 0);
1201 ll1(
"executeeventop");
1202 for (uint i = 0; i < maxrun(); i++)
1203 chkrc(executeeventop(
run(i)) == 0);
1208 dropeventop(
Run& r,
bool force =
false)
1210 ll2(
"dropeventop: " << r.tabname);
1211 if (r.evt_op != 0) {
1219 dropeventops(
bool force =
false)
1221 ll1(
"dropeventops");
1222 for (uint i = 0; i < maxrun(); i++) {
1223 if (force && g_runlst[i] == 0)
1225 chkrc(dropeventop(
run(i), force) == 0 || force);
1234 ll1(
"waitgci " << ngci);
1242 char pk2[1 + g_charlen + 1];
1244 sprintf(pk2 + 1,
"%-u", pk1);
1245 *(uchar*)pk2 = (uchar)(strlen(pk2 + 1));
1248 chkdb(g_op->
equal(
"pk1", (
char*)&pk1) == 0);
1249 chkdb(g_op->
equal(
"pk2", (
char*)&pk2[0]) == 0);
1250 chkdb(g_con->
execute(Commit) == 0);
1256 if (i == 1 && gci[0] + ngci <= gci[1]) {
1257 ll1(
"waitgci: " << gci[0] <<
" " << gci[1]);
1270 ll2(
"scantable: " << r.tabname);
1273 Op* rec_op = getop(Op::OP);
1274 Data& d0 = rec_op->data[0];
1279 for (i = 0; i < ncol(); i++) {
1280 const Col& c = getcol(i);
1282 chkdb((ra[i] = g_scan_op->
getValue(c.name, (
char*)d0.ptr[i].v)) != 0);
1287 chkdb(g_con->
execute(NoCommit) == 0);
1289 while ((ret = g_scan_op->
nextResult()) == 0) {
1290 Uint32 pk1 = d0.pk1;
1291 if (pk1 >= g_opts.maxpk)
1293 rec_op->type = Op::INS;
1294 for (i = 0; i < ncol(); i++) {
1295 const Col& c = getcol(i);
1301 ret = bh[
i]->getDefined(ind);
1308 txt.len = (uint)len64;
1310 txt.val =
new char [txt.len];
1311 memset(txt.val,
'X', txt.len);
1312 Uint32 len = txt.len;
1314 assert(ret == 0 && len == txt.len);
1316 chkdb(g_con->
execute(NoCommit) == 0);
1317 assert(memchr(txt.val,
'X', txt.len) == 0);
1323 assert(r.pk_op[pk1] == 0);
1324 Op* tot_op = r.pk_op[pk1] = getop(Op::OP);
1325 copyop(rec_op, tot_op);
1326 tot_op->type = Op::INS;
1340 for (uint i = 0; i < maxrun(); i++)
1341 chkrc(scantable(
run(i)) == 0);
1346 makedata(
const Col& c,
Data& d, Uint32 pk1, Op::Type optype)
1353 Uint32* p = d.ptr[
i].u32;
1359 char* p = d.ptr[
i].ch;
1360 sprintf(p,
"%-*u", g_charlen, pk1);
1365 char* p = &d.ptr[
i].ch[1];
1366 sprintf(p,
"%-u", pk1);
1367 uint len = pk1 % g_charlen;
1370 p[j] =
'a' + j % 26;
1373 d.ptr[
i].uch[0] = len;
1381 }
else if (optype == Op::DEL) {
1383 }
else if (i == getcol(
"seq").no) {
1386 }
else if (optype == Op::INS && ! g_opts.no_implicit_nulls && c.nullable && urandom(10, 100)) {
1389 }
else if (optype == Op::UPD && ! g_opts.no_missing_update && urandom(10, 100)) {
1392 }
else if (! g_opts.no_nulls && c.nullable && urandom(10, 100)) {
1398 Uint32* p = d.ptr[
i].u32;
1405 char* p = d.ptr[
i].ch;
1406 uint u = urandom(g_charlen);
1408 u = urandom(g_charlen);
1410 for (j = 0; j < g_charlen; j++) {
1411 uint v = urandom(strlen(g_charval));
1412 p[j] = j < u ? g_charval[v] : 0x20;
1423 if (g_opts.tweak & 1) {
1424 uint u = g_blobinlinesize + (tinyblob ? 0 : g_blobpartsize);
1425 uint v = (g_opts.tweak & 2) ? 0 : urandom(strlen(g_charval));
1426 txt.val =
new char [u];
1428 memset(txt.val, g_charval[v], u);
1431 uint u = urandom(tinyblob ? g_blobinlinesize : g_maxblobsize);
1434 txt.val =
new char [u];
1439 uint k = 1 + urandom(u - 1);
1442 uint v = urandom(strlen(g_charval));
1443 memset(&txt.val[j], g_charval[v], k);
1457 makeop(
const Op* prev_op,
Op* op, Uint32 pk1, Op::Type optype)
1460 const Data& dp = prev_op->data[0];
1461 Data& d0 = op->data[0];
1462 Data& d1 = op->data[1];
1464 for (i = 0; i < ncol(); i++) {
1465 const Col& c = getcol(i);
1466 makedata(c, d0, pk1, optype);
1467 if (optype == Op::INS) {
1469 }
else if (optype == Op::DEL) {
1470 assert(dp.ind[i] >= 0);
1472 }
else if (optype == Op::UPD) {
1473 assert(dp.ind[i] >= 0);
1474 if (d0.ind[i] == -1)
1481 Uint32 pk1_tmp = ~(Uint32)0;
1482 reqrc(checkop(op, pk1_tmp) == 0);
1483 reqrc(pk1 == pk1_tmp);
1487 approxblobops(
Op* op)
1489 uint avg_blob_size = g_maxblobsize / 4;
1490 uint avg_blob_ops = avg_blob_size / 2000;
1492 if (! g_opts.no_blobs) {
1494 if (! g_opts.one_blob)
1496 if (op->type == Op::UPD)
1505 ll1(
"makeops: " << r.tabname);
1508 if (g_opts.opstring == 0) {
1509 if (r.tableops + r.blobops >= g_opts.maxops)
1511 pk1 = urandom(g_opts.maxpk);
1513 if (pk1 >= g_opts.maxpk)
1516 ll2(
"makeops: pk1=" << pk1);
1519 Op* tot_op = r.pk_op[pk1];
1521 tot_op = r.pk_op[pk1] = getop(Op::OP, Op::NUL);
1522 assert(tot_op->type == Op::NUL || tot_op->type == Op::INS);
1524 Op* last_gci = tot_op;
1525 while (last_gci->next_gci != 0)
1526 last_gci = last_gci->next_gci;
1527 Op* gci_op = getop(Op::OP, Op::NUL);
1528 last_gci->next_gci = gci_op;
1529 Op* com_op = getop(Op::OP, Op::NUL);
1530 gci_op->next_com = com_op;
1533 if (g_opts.opstring == 0) {
1534 len = 1 + urandom(g_maxcom - 1);
1535 len = 1 + urandom(len - 1);
1541 if (g_opts.opstring == 0) {
1545 optype = (Op::Type)urandom(g_optypes);
1546 }
while ((tot_op->type == Op::NUL &&
1547 (optype == Op::DEL || optype == Op::UPD)) ||
1548 (tot_op->type == Op::INS && optype == Op::INS));
1550 const char* str = g_opstringpart[g_loop % g_opstringparts];
1551 uint m = strlen(str);
1552 uint k = tot_op->num_com + tot_op->num_op;
1560 const char* p =
"idu";
1561 const char* q = strchr(p, c);
1563 optype = (Op::Type)(q - p);
1565 Op* op = getop(Op::OP);
1566 makeop(tot_op, op, pk1, optype);
1568 r.blobops += approxblobops(op);
1570 Op* last_op = com_op;
1571 while (last_op->next_op != 0)
1572 last_op = last_op->next_op;
1573 last_op->next_op = op;
1575 reqrc(compop(com_op, op, com_op) == 0);
1576 reqrc(compop(tot_op, op, tot_op) == 0);
1577 assert(tot_op->type == Op::NUL || tot_op->type == Op::INS);
1579 com_op->num_op += 1;
1580 tot_op->num_op += 1;
1584 copyop(com_op, gci_op);
1585 tot_op->num_com += 1;
1589 ll1(
"makeops: " << r.tabname <<
": com recs = " << r.gciops);
1596 for (i = 0; i < maxrun(); i++)
1597 run(i).skip =
false;
1598 if (g_opts.opstring != 0) {
1599 ll1(
"using all tables due to fixed ops");
1602 for (i = 0; i + 1 < maxrun(); i++)
1603 run(urandom(maxrun())).
skip =
true;
1605 for (i = 0; i < maxrun(); i++) {
1606 if (!
run(i).skip) {
1607 ll2(
"use table " <<
run(i).tabname);
1611 ll0(
"selecttables: use " << cnt <<
"/" << maxrun() <<
" in this loop");
1618 for (uint i = 0; i < maxrun(); i++)
1621 ll0(
"makeops: used records = " << g_usedops);
1625 addndbop(
Run& r,
Op* op)
1643 for (i = 0; i < ncol(); i++) {
1644 const Col& c = getcol(i);
1645 const Data& d = op->data[0];
1648 chkdb(g_op->
equal(c.name, (
const char*)d.ptr[i].v) == 0);
1650 if (op->type != Op::DEL) {
1651 for (i = 0; i < ncol(); i++) {
1652 const Col& c = getcol(i);
1653 const Data& d = op->data[0];
1656 if (d.noop & (1 << i))
1658 assert(d.ind[i] >= 0);
1661 chkdb(g_op->
setValue(c.name, (
const char*)d.ptr[i].v) == 0);
1663 chkdb(g_op->
setValue(c.name, (
const char*)0) == 0);
1668 chkdb(g_bh->
setValue(txt.val, txt.len) == 0);
1683 Op* gci_op[g_maxtab][g_maxpk];
1687 for (i = 0; i < (int)maxrun(); i++) {
1689 for (pk1 = 0; pk1 < g_opts.maxpk; pk1++) {
1692 Op* tot_op = r.pk_op[pk1];
1695 if (tot_op->next_gci == 0) {
1696 assert(g_loop != 0 && tot_op->type == Op::INS);
1700 assert(tot_op->next_gci != 0);
1701 gci_op[
i][pk1] = tot_op->next_gci;
1707 unsigned int i = urandom(maxrun());
1708 pk1 = urandom(g_opts.maxpk);
1709 if (gci_op[i][pk1] == 0)
1714 Op* com_op = gci_op[
i][pk1]->next_com;
1715 assert(com_op != 0);
1717 Op* op = com_op->next_op;
1720 ll2(
"runops:" << *op);
1721 chkrc(addndbop(r, op) == 0);
1724 chkdb(g_con->
execute(Commit) == 0);
1727 gci_op[
i][pk1]->gci = com_op->gci = val;
1728 ll2(
"commit: " <<
run(i).tabname <<
" gci=" << com_op->gci);
1732 gci_op[
i][pk1] = gci_op[
i][pk1]->next_gci;
1733 if (gci_op[i][pk1] == 0) {
1746 ll2(
"mergeops: " << r.tabname);
1749 for (pk1 = 0; pk1 < g_opts.maxpk; pk1++) {
1750 Op* tot_op = r.pk_op[pk1];
1753 Op* gci_op = tot_op->next_gci;
1755 assert(g_loop != 0 && tot_op->type == Op::INS);
1758 while (gci_op != 0) {
1759 Op* com_op = gci_op->next_com;
1760 assert(com_op != 0 && com_op->next_com == 0);
1761 assert(gci_op->gci == com_op->gci);
1762 Op* last_com = com_op;
1763 Op* gci_op2 = gci_op->next_gci;
1764 while (gci_op2 != 0 && gci_op->gci == gci_op2->gci) {
1766 last_com = last_com->next_com = gci_op2->next_com;
1768 reqrc(compop(gci_op, gci_op2, gci_op) == 0);
1770 Op* tmp_op = gci_op2;
1771 gci_op2 = gci_op2->next_gci;
1774 assert(r.gciops != 0 && g_gciops != 0);
1778 gci_op = gci_op->next_gci = gci_op2;
1781 ll1(
"mergeops: " << r.tabname <<
": gci recs = " << r.gciops);
1787 for (uint i = 0; i < maxrun(); i++)
1789 ll1(
"mergeops: used recs = " << g_usedops <<
" gci recs = " << g_gciops);
1796 ll2(
"cmppostpre: " << r.tabname);
1798 for (pk1 = 0; pk1 < g_opts.maxpk; pk1++) {
1799 Op* tot_op = r.pk_op[pk1];
1800 Op* gci_op = tot_op ? tot_op->next_gci : 0;
1801 while (gci_op != 0) {
1802 if (gci_op->type == Op::UPD) {
1803 Data (&d)[2] = gci_op->data;
1805 for (i = 0; i < ncol(); i++) {
1806 const Col& c = getcol(i);
1808 (d[0].ind[
i] == 1 && d[1].ind[
i] == 1) ||
1809 (d[0].ind[i] == 0 && d[1].ind[i] == 0 && cmpcol(c, d[0], d[1])== 0);
1811 d[0].ppeq |= (1 <<
i);
1812 d[1].ppeq |= (1 <<
i);
1816 gci_op = gci_op->next_gci;
1825 for (uint i = 0; i < maxrun(); i++)
1833 for (i = 0; i < maxrun(); i++) {
1834 if (
run(i).evt_op == evt_op)
1837 chkrc(i < maxrun());
1842 geteventdata(
Run& r)
1844 Data (&d)[2] = g_rec_ev->data;
1846 for (j = 0; j < 2; j++) {
1847 for (i = 0; i < (int)ncol(); i++) {
1848 const Col& c = getcol(i);
1855 ret = bh->getDefined(ind);
1862 txt.len = (uint)len64;
1864 txt.val =
new char [txt.len];
1865 memset(txt.val,
'X', txt.len);
1866 Uint32 len = txt.len;
1868 assert(ret == 0 && len == txt.len);
1877 addgcievents(Uint64 gci)
1879 ll1(
"getgcieventops");
1881 uint seen_current = 0;
1891 chkrc((i = findevent(evt_op)) != -1);
1892 run(i).addevtypes(gci, evtypes, 0);
1893 seen_current += (g_evt_op == evt_op);
1896 chkrc(seen_current == 1);
1897 ll1(
"addgcievents: " << count);
1907 ll1(
"poll " << npoll);
1908 Uint64 gci = (Uint64)0;
1909 while (npoll != 0) {
1916 g_rec_ev->init(Op::EV);
1920 Uint64 newgci = g_evt_op->
getGCI();
1921 assert(newgci != 0);
1922 g_rec_ev->gci = newgci;
1923 if (gci != newgci) {
1924 ll1(
"new gci: " << gci <<
" -> " << newgci);
1928 for (i = 0; i < maxtab(); i++)
1929 chkrc(
run(i).addgci(gci) == 0);
1930 chkrc(addgcievents(gci) == 0);
1933 chkrc((i = findevent(g_evt_op)) != -1);
1936 chkrc(seteventtype(g_rec_ev, evtype) == 0);
1937 r.addevtypes(gci, (Uint32)evtype, 1);
1939 ll2(
"runevents: EVT: " << *g_rec_ev);
1941 Uint32 pk1 = ~(Uint32)0;
1942 chkrc(checkop(g_rec_ev, pk1) == 0);
1944 Op* tot_ev = r.pk_ev[pk1];
1946 tot_ev = r.pk_ev[pk1] = getop(Op::EV);
1947 Op* last_ev = tot_ev;
1948 while (last_ev->next_ev != 0)
1949 last_ev = last_ev->next_ev;
1951 Op* ev = getop(Op::EV);
1952 copyop(g_rec_ev, ev);
1953 g_rec_ev->freemem();
1954 last_ev->next_ev = ev;
1958 ll1(
"runevents: used ops = " << g_usedops <<
" events = " << g_num_ev);
1963 cmpopevdata(
const Data& d1,
const Data& d2)
1966 for (i = 0; i < ncol(); i++) {
1967 const Col& c = getcol(i);
1968 if (cmpcol(c, d1, d2) != 0) {
1969 if ((d1.ppeq & (1 << i)) && d2.ind[i] == -1)
1980 cmpopevdata(
const Data (&d1)[2],
const Data (&d2)[2])
1982 if (cmpopevdata(d1[0], d2[0]) != 0)
1984 if (cmpopevdata(d1[1], d2[1]) != 0)
1990 matchevent(
Run& r,
Op* ev)
1992 Data (&d2)[2] = ev->data;
1994 Uint32 pk1 = d2[0].pk1;
1995 chkrc(pk1 < g_opts.maxpk);
1999 int g_loglevel = loop == 0 ? g_opts.loglevel : 2;
2000 ll1(
"matchevent: " << r.tabname <<
": pk1=" << pk1 <<
" type=" << ev->type);
2001 ll2(
"EVT: " << *ev);
2002 Op* tot_op = r.pk_op[pk1];
2003 Op* gci_op = tot_op ? tot_op->next_gci : 0;
2006 while (gci_op != 0) {
2007 ll2(
"GCI: " << *gci_op);
2009 Op* com_op = gci_op->next_com;
2010 assert(com_op != 0);
2011 while (com_op != 0) {
2012 ll2(
"COM: " << *com_op);
2013 Op* op = com_op->next_op;
2016 ll2(
"OP : " << *op);
2019 com_op = com_op->next_com;
2022 if (gci_op->type != Op::NUL) {
2023 const Data (&d1)[2] = gci_op->data;
2024 if (cmpopevdata(d1, d2) == 0) {
2026 if (gci_op->type != ev->type) {
2027 ll2(
"***: wrong type " << gci_op->type <<
" != " << ev->type);
2030 if (gci_op->match) {
2031 ll2(
"***: duplicate match");
2034 if (pos != r.ev_pos[pk1]) {
2035 ll2(
"***: wrong pos " << pos <<
" != " << r.ev_pos[pk1]);
2038 if (gci_op->gci != ev->gci) {
2039 ll2(
"***: wrong gci " << gci_op->gci <<
" != " << ev->gci);
2043 ok = gci_op->match =
true;
2049 gci_op = gci_op->next_gci;
2052 ll2(
"matchevent: match");
2055 ll0(
"matchevent: ERROR: no match");
2056 if (g_loglevel >= 2)
2066 ll1(
"matchevents: " << r.tabname);
2069 for (pk1 = 0; pk1 < g_opts.maxpk; pk1++) {
2070 Op* tot_ev = r.pk_ev[pk1];
2073 Op* ev = tot_ev->next_ev;
2075 if (matchevent(r, ev) < 0)
2081 chkrc(nomatch == 0);
2089 for (uint i = 0; i < maxrun(); i++)
2090 chkrc(matchevents(
run(i)) == 0);
2097 ll1(
"matchops: " << r.tabname);
2100 for (pk1 = 0; pk1 < g_opts.maxpk; pk1++) {
2101 Op* tot_op = r.pk_op[pk1];
2104 Op* gci_op = tot_op->next_gci;
2105 while (gci_op != 0) {
2106 if (gci_op->type == Op::NUL) {
2107 ll2(
"GCI: " << *gci_op <<
" [skip NUL]");
2108 }
else if (gci_op->match) {
2109 ll2(
"GCI: " << *gci_op <<
" [match OK]");
2111 ll0(
"GCI: " << *gci_op);
2112 Op* com_op = gci_op->next_com;
2113 assert(com_op != 0);
2114 ll0(
"COM: " << *com_op);
2115 Op* op = com_op->next_op;
2118 ll0(
"OP : " << *op);
2121 ll0(
"no matching event");
2124 gci_op = gci_op->next_gci;
2127 chkrc(nomatch == 0);
2135 for (uint i = 0; i < maxrun(); i++)
2136 chkrc(matchops(
run(i)) == 0);
2141 matchgcievents(
Run& r)
2143 ll1(
"matchgcievents: " << r.tabname);
2145 for (i = 0; i < r.gcicnt; i++) {
2146 Uint32 t0 = r.gcievtypes[
i][0];
2147 Uint32 t1 = r.gcievtypes[
i][1];
2148 ll1(
"gci: " << r.gcinum[i] << hex <<
" report: " << t0 <<
" seen: " << t1);
2151 chkrc(t0 == 0 && t1 == 0);
2152 if (t0 == 0 && t1 == 0)
2158 chkrc((~t0 & t1) == 0);
2161 if (g_opts.separate_events) {
2165 chkrc((t0 & ~t1) == 0);
2174 ll1(
"matchgcievents");
2175 for (uint i = 0; i < maxrun(); i++)
2176 chkrc(matchgcievents(
run(i)) == 0);
2185 if (g_opts.seed == 0)
2187 if (g_opts.seed != (uint)-1)
2188 seed = (uint)g_opts.seed;
2190 seed = 1 + (ushort)getpid();
2192 if (g_opts.seed != 0)
2196 ll0(
"seed=" << seed);
2205 chkrc(createtables() == 0);
2206 chkrc(createevents() == 0);
2207 for (g_loop = 0; g_opts.loop == 0 || g_loop < g_opts.loop; g_loop++) {
2208 ll0(
"=== loop " << g_loop <<
" ===");
2211 chkrc(scantable() == 0);
2213 g_rec_ev = getop(Op::EV);
2214 chkrc(createeventop() == 0);
2215 chkrc(executeeventop() == 0);
2216 chkrc(waitgci(3) == 0);
2217 chkrc(runops() == 0);
2218 if (! g_opts.separate_events)
2221 chkrc(runevents() == 0);
2222 ll0(
"counts: gci ops = " << g_gciops <<
" ev ops = " << g_num_ev);
2223 chkrc(matchevents() == 0);
2224 chkrc(matchops() == 0);
2225 chkrc(matchgcievents() == 0);
2226 chkrc(dropeventops() == 0);
2228 chkrc(waitgci(1) == 0);
2230 chkrc(dropevents() == 0);
2231 chkrc(droptables() == 0);
2240 NDB_STD_OPTS(
"test_event_merge"),
2241 {
"abort-on-error", NDB_OPT_NOSHORT,
"Do abort() on any error",
2242 (uchar **)&g_opts.abort_on_error, (uchar **)&g_opts.abort_on_error, 0,
2243 GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0 },
2244 {
"loglevel", NDB_OPT_NOSHORT,
"Logging level in this program 0-3 (default 0)",
2245 (uchar **)&g_opts.loglevel, (uchar **)&g_opts.loglevel, 0,
2246 GET_INT, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 },
2247 {
"loop", NDB_OPT_NOSHORT,
"Number of test loops (default 5, 0=forever)",
2248 (uchar **)&g_opts.loop, (uchar **)&g_opts.loop, 0,
2249 GET_INT, REQUIRED_ARG, 5, 0, 0, 0, 0, 0 },
2250 {
"maxops", NDB_OPT_NOSHORT,
"Approx number of PK operations per table (default 1000)",
2251 (uchar **)&g_opts.maxops, (uchar **)&g_opts.maxops, 0,
2252 GET_UINT, REQUIRED_ARG, 1000, 0, 0, 0, 0, 0 },
2253 {
"maxpk", NDB_OPT_NOSHORT,
"Number of different PK values (default 10, max 1000)",
2254 (uchar **)&g_opts.maxpk, (uchar **)&g_opts.maxpk, 0,
2255 GET_UINT, REQUIRED_ARG, 10, 0, 0, 0, 0, 0 },
2256 {
"maxtab", NDB_OPT_NOSHORT,
"Number of tables (default 10, max 100)",
2257 (uchar **)&g_opts.maxtab, (uchar **)&g_opts.maxtab, 0,
2258 GET_INT, REQUIRED_ARG, 10, 0, 0, 0, 0, 0 },
2259 {
"no-blobs", NDB_OPT_NOSHORT,
"Omit blob attributes (5.0: true)",
2260 (uchar **)&g_opts.no_blobs, (uchar **)&g_opts.no_blobs, 0,
2261 GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0 },
2262 {
"no-implicit-nulls", NDB_OPT_NOSHORT,
"Insert must include all attrs"
2263 " i.e. no implicit NULLs",
2264 (uchar **)&g_opts.no_implicit_nulls, (uchar **)&g_opts.no_implicit_nulls, 0,
2265 GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0 },
2266 {
"no-missing-update", NDB_OPT_NOSHORT,
"Update must include all non-PK attrs",
2267 (uchar **)&g_opts.no_missing_update, (uchar **)&g_opts.no_missing_update, 0,
2268 GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0 },
2269 {
"no-multiops", NDB_OPT_NOSHORT,
"Allow only 1 operation per commit",
2270 (uchar **)&g_opts.no_multiops, (uchar **)&g_opts.no_multiops, 0,
2271 GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0 },
2272 {
"no-nulls", NDB_OPT_NOSHORT,
"Create no NULL values",
2273 (uchar **)&g_opts.no_nulls, (uchar **)&g_opts.no_nulls, 0,
2274 GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0 },
2275 {
"one-blob", NDB_OPT_NOSHORT,
"Only one blob attribute (default 2)",
2276 (uchar **)&g_opts.one_blob, (uchar **)&g_opts.one_blob, 0,
2277 GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0 },
2278 {
"opstring", NDB_OPT_NOSHORT,
"Operations to run e.g. idiucdc (c is commit) or"
2279 " iuuc:uudc (the : separates loops)",
2280 (uchar **)&g_opts.opstring, (uchar **)&g_opts.opstring, 0,
2281 GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 },
2282 {
"seed", NDB_OPT_NOSHORT,
"Random seed (0=loop number, default -1=random)",
2283 (uchar **)&g_opts.seed, (uchar **)&g_opts.seed, 0,
2284 GET_INT, REQUIRED_ARG, -1, 0, 0, 0, 0, 0 },
2285 {
"separate-events", NDB_OPT_NOSHORT,
"Do not combine events per GCI (5.0: true)",
2286 (uchar **)&g_opts.separate_events, (uchar **)&g_opts.separate_events, 0,
2287 GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0 },
2288 {
"tweak", NDB_OPT_NOSHORT,
"Whatever the source says",
2289 (uchar **)&g_opts.tweak, (uchar **)&g_opts.tweak, 0,
2290 GET_UINT, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 },
2291 {
"use-table", NDB_OPT_NOSHORT,
"Use existing tables",
2292 (uchar **)&g_opts.use_table, (uchar **)&g_opts.use_table, 0,
2293 GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0 },
2294 {
"blob-version", NDB_OPT_NOSHORT,
"Blob version 1 or 2 (default 2)",
2295 (uchar**)&g_opts.blob_version, (uchar**)&g_opts.blob_version, 0,
2296 GET_INT, REQUIRED_ARG, 2, 0, 0, 0, 0, 0 },
2299 GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0 }
2306 if (g_opts.separate_events) {
2307 g_opts.no_blobs =
true;
2309 if (g_opts.no_multiops) {
2312 if (g_opts.opstring != 0) {
2313 uint len = strlen(g_opts.opstring);
2314 char* str =
new char [len + 1];
2315 memcpy(str, g_opts.opstring, len + 1);
2318 g_opstringpart[g_opstringparts++] = s;
2325 for (i = 0; i < g_opstringparts; i++) {
2326 const char* s = g_opstringpart[
i];
2328 if (strchr(
"iduc", *s++) == 0) {
2329 ll0(
"opstring chars are i,d,u,c");
2333 if (s == g_opstringpart[i] || s[-1] !=
'c') {
2334 ll0(
"opstring chain must end in 'c'");
2339 if (g_opts.no_nulls) {
2340 g_opts.no_implicit_nulls =
true;
2342 if (g_opts.maxpk > g_maxpk ||
2343 g_opts.maxtab > (
int)g_maxtab) {
2346 if (g_opts.blob_version < 1 || g_opts.blob_version > 2) {
2356 chkdb(g_ncc->
connect(30) == 0);
2357 g_ndb =
new Ndb(g_ncc,
"TEST_DB");
2358 chkdb(g_ndb->init() == 0 && g_ndb->waitUntilReady(30) == 0);
2363 main(
int argc,
char** argv)
2366 const char* progname =
2367 strchr(argv[0],
'/') ? strrchr(argv[0],
'/') + 1 : argv[0];
2369 for (
int i = 1; i < argc; i++)
2370 ndbout <<
" " << argv[i];
2373 ret = handle_options(&argc, &argv, my_long_options, ndb_std_get_one_option);
2374 if (ret != 0 || argc != 0 || checkopts() != 0)
2375 return NDBT_ProgramExit(NDBT_WRONGARGS);
2376 if (doconnect() == 0 && runtest() == 0) {
2379 return NDBT_ProgramExit(NDBT_OK);
2385 return NDBT_ProgramExit(NDBT_FAILED);