19 #include <ndb_global.h>
24 #include <NdbCondition.h>
25 #include <NdbThread.h>
26 #include <NdbTest.hpp>
46 <<
"usage: testDeadlock" << endl
47 <<
"-scan tx scan table, index [" << d.m_scan <<
"]" << endl
53 static NdbMutex *ndbout_mutex= NULL;
57 if (! g_opt.m_dbg) break; \
58 NdbMutex_Lock(ndbout_mutex); \
59 ndbout << "line " << __LINE__ << " " << x << endl; \
60 NdbMutex_Unlock(ndbout_mutex); \
66 ndbout << "line " << __LINE__ << ": " << #x << " failed" << endl; \
73 ndbout << "line " << __LINE__ << ": " << #x << " failed" << endl; \
74 ndbout << (p)->getNdbError() << endl; \
80 typedef int (*Runstep)(
struct Thr&
thr);
83 enum State { Wait, Start, Stop, Stopped, Exit };
100 void start(Runstep runstep);
103 void lock() { NdbMutex_Lock(m_mutex); }
104 void unlock() { NdbMutex_Unlock(m_mutex); }
105 void wait() { NdbCondition_Wait(m_cond, m_mutex); }
106 void signal() { NdbCondition_Signal(m_cond); }
108 void join() { NdbThread_WaitFor(m_thread, &m_status); }
112 operator<<(NdbOut& out,
const Thr&
thr) {
113 out <<
"thr " << thr.m_no;
117 extern "C" {
static void* runthread(
void* arg); }
125 m_mutex = NdbMutex_Create();
126 m_cond = NdbCondition_Create();
127 assert(m_mutex != 0 && m_cond != 0);
128 const unsigned stacksize = 256 * 1024;
129 const NDB_THREAD_PRIO prio = NDB_THREAD_PRIO_LOW;
130 m_thread = NdbThread_Create(runthread, (
void**)
this, stacksize,
"me", prio);
132 DBG(
"create thread failed: errno=" << errno);
145 NdbThread_Destroy(&m_thread);
147 NdbCondition_Destroy(m_cond);
149 NdbMutex_Destroy(m_mutex);
153 runthread(
void* arg) {
162 DBG(*
this <<
" run");
165 while (m_state != Start && m_state != Exit) {
168 if (m_state == Exit) {
169 DBG(*
this <<
" exit");
173 m_ret = (*m_runstep)(*this);
178 DBG(*
this <<
" error exit");
188 Thr::start(Runstep runstep)
201 while (m_state != Stopped) {
220 runstep_connect(
Thr& thr)
222 Ndb* ndb = thr.m_ndb =
new Ndb(g_cluster_connection,
"TEST_DB");
223 CHN(ndb, ndb->
init() == 0);
225 DBG(thr <<
" connected");
230 runstep_starttx(
Thr& thr)
232 Ndb* ndb = thr.m_ndb;
235 DBG(
"thr " << thr.m_no <<
" tx started");
261 static char wl1822_scantx = 0;
263 static const Uint32 wl1822_valA[3] = { 0, 1, 2 };
264 static const Uint32 wl1822_valB[3] = { 3, 4, 5 };
266 static Uint32 wl1822_bufA = ~0;
267 static Uint32 wl1822_bufB = ~0;
270 static unsigned wl1822_r2k[3] = { 0, 0, 0 };
271 static unsigned wl1822_k2r[3] = { 0, 0, 0 };
274 wl1822_createtable(
Thr& thr)
276 Ndb* ndb = thr.m_ndb;
280 if (dic->
getTable(g_opt.m_tname) != 0)
281 CHN(dic, dic->
dropTable(g_opt.m_tname) == 0);
287 col.setPrimaryKey(
true);
292 col.setPrimaryKey(
false);
298 ind.setTable(g_opt.m_tname);
300 ind.setLogging(
false);
303 DBG(
"created " << g_opt.m_tname <<
", " << g_opt.m_xname);
308 wl1822_insertrows(
Thr& thr)
311 Ndb* ndb = thr.m_ndb;
315 for (
unsigned k = 0; k < 3; k++) {
319 CHN(op, op->
equal(
"A", (
char*)&wl1822_valA[k]) == 0);
320 CHN(op, op->
setValue(
"B", (
char*)&wl1822_valB[k]) == 0);
321 CHN(con, con->
execute(Commit) == 0);
324 DBG(
"inserted X, Y, Z");
329 wl1822_getscanorder(
Thr& thr)
338 DBG(
"scan order determined");
343 wl1822_tx1_readZ(
Thr& thr)
351 CHN(op, op->
equal(
"A", wl1822_valA[wl1822_r2k[2]]) == 0);
353 CHN(op, op->
getValue(
"B", (
char*)&wl1822_bufB) != 0);
354 CHN(con, con->
execute(NoCommit) == 0);
355 CHK(wl1822_bufB == wl1822_valB[wl1822_r2k[2]]);
361 wl1822_tx2_scanXY(
Thr& thr)
369 if (wl1822_scantx ==
't') {
371 DBG(
"tx2 scan exclusive " << g_opt.m_tname);
373 if (wl1822_scantx ==
'x') {
374 CHN(con, (scanop = thr.m_scanop = indexscanop = thr.m_indexscanop = con->
getNdbIndexScanOperation(g_opt.m_xname, g_opt.m_tname)) != 0);
375 DBG(
"tx2 scan exclusive " << g_opt.m_xname);
377 CHN(scanop, scanop->readTuplesExclusive(16) == 0);
378 CHN(scanop, scanop->
getValue(
"A", (
char*)&wl1822_bufA) != 0);
379 CHN(scanop, scanop->
getValue(
"B", (
char*)&wl1822_bufB) != 0);
380 CHN(con, con->
execute(NoCommit) == 0);
383 DBG(
"before row " << row);
385 wl1822_bufA = wl1822_bufB = ~0;
386 CHN(con, (ret = scanop->
nextResult(
true)) == 0);
387 DBG(
"got row " << row <<
" a=" << wl1822_bufA <<
" b=" << wl1822_bufB);
388 CHK(wl1822_bufA == wl1822_valA[wl1822_r2k[row]]);
389 CHK(wl1822_bufB == wl1822_valB[wl1822_r2k[row]]);
396 wl1822_tx1_readX_commit(
Thr& thr)
404 CHN(op, op->
equal(
"A", wl1822_valA[wl1822_r2k[2]]) == 0);
406 CHN(op, op->
getValue(
"B", (
char*)&wl1822_bufB) != 0);
407 CHN(con, con->
execute(NoCommit) == 0);
408 CHK(wl1822_bufB == wl1822_valB[wl1822_r2k[2]]);
410 CHN(con, con->
execute(Commit) == 0);
416 wl1822_tx2_scanZ_close(
Thr& thr)
419 Ndb* ndb = thr.m_ndb;
422 assert(ndb != 0 && con != 0 && scanop != 0);
425 DBG(
"before row " << row);
427 wl1822_bufA = wl1822_bufB = ~0;
428 CHN(con, (ret = scanop->
nextResult(
true)) == 0 || ret == 1);
431 DBG(
"got row " << row <<
" a=" << wl1822_bufA <<
" b=" << wl1822_bufB);
432 CHK(wl1822_bufA == wl1822_valA[wl1822_r2k[row]]);
433 CHK(wl1822_bufB == wl1822_valB[wl1822_r2k[row]]);
442 static Runstep wl1822_step[][2] = {
443 { runstep_connect, runstep_connect },
444 { wl1822_createtable, 0 },
445 { wl1822_insertrows, 0 },
446 { wl1822_getscanorder, 0 },
447 { runstep_starttx, runstep_starttx },
448 { wl1822_tx1_readZ, 0 },
449 { 0, wl1822_tx2_scanXY },
450 { wl1822_tx1_readX_commit, wl1822_tx2_scanZ_close }
452 const unsigned wl1822_stepcount =
sizeof(wl1822_step)/
sizeof(wl1822_step[0]);
455 wl1822_main(
char scantx)
457 wl1822_scantx = scantx;
458 static const unsigned thrcount = 2;
462 for (n = 0; n < thrcount; n++) {
463 Thr& thr = *(thrlist[
n] =
new Thr(1 + n));
467 for (
unsigned i = 0;
i < wl1822_stepcount;
i++) {
468 DBG(
"step " <<
i <<
" start");
469 for (n = 0; n < thrcount; n++) {
470 Thr& thr = *thrlist[
n];
471 Runstep runstep = wl1822_step[
i][
n];
475 for (n = 0; n < thrcount; n++) {
476 Thr& thr = *thrlist[
n];
477 Runstep runstep = wl1822_step[
i][
n];
483 for (n = 0; n < thrcount; n++) {
484 Thr& thr = *thrlist[
n];
492 NDB_COMMAND(testOdbcDriver,
"testDeadlock",
"testDeadlock",
"testDeadlock", 65535)
495 if (ndbout_mutex == NULL)
496 ndbout_mutex= NdbMutex_Create();
497 while (++argv, --argc > 0) {
498 const char* arg = argv[0];
499 if (strcmp(arg,
"-scan") == 0) {
500 if (++argv, --argc > 0) {
501 g_opt.m_scan = strdup(argv[0]);
506 return NDBT_ProgramExit(NDBT_WRONGARGS);
512 return NDBT_ProgramExit(NDBT_FAILED);
514 g_cluster_connection= &con;
516 if ((strchr(g_opt.m_scan,
't') != 0 && wl1822_main(
't') == -1) ||
517 (strchr(g_opt.m_scan,
'x') != 0 && wl1822_main(
'x') == -1))
519 return NDBT_ProgramExit(NDBT_FAILED);
521 return NDBT_ProgramExit(NDBT_OK);