summaryrefslogtreecommitdiff
path: root/ndb/test/ndbapi/testDeadlock.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'ndb/test/ndbapi/testDeadlock.cpp')
-rw-r--r--ndb/test/ndbapi/testDeadlock.cpp523
1 files changed, 0 insertions, 523 deletions
diff --git a/ndb/test/ndbapi/testDeadlock.cpp b/ndb/test/ndbapi/testDeadlock.cpp
deleted file mode 100644
index 0070a7ecc83..00000000000
--- a/ndb/test/ndbapi/testDeadlock.cpp
+++ /dev/null
@@ -1,523 +0,0 @@
-/* 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 <ndb_global.h>
-#include <NdbMain.h>
-#include <NdbApi.hpp>
-#include <NdbOut.hpp>
-#include <NdbMutex.h>
-#include <NdbCondition.h>
-#include <NdbThread.h>
-#include <NdbTest.hpp>
-
-struct Opt {
- bool m_dbg;
- const char* m_scan;
- const char* m_tname;
- const char* m_xname;
- Opt() :
- m_dbg(true),
- m_scan("tx"),
- m_tname("T"),
- m_xname("X")
- {}
-};
-
-static void
-printusage()
-{
- Opt d;
- ndbout
- << "usage: testDeadlock" << endl
- << "-scan tx scan table, index [" << d.m_scan << "]" << endl
- ;
-}
-
-static Opt g_opt;
-
-static NdbMutex *ndbout_mutex= NULL;
-static Ndb_cluster_connection *g_cluster_connection= 0;
-#define DBG(x) \
- do { \
- if (! g_opt.m_dbg) break; \
- NdbMutex_Lock(ndbout_mutex); \
- ndbout << "line " << __LINE__ << " " << x << endl; \
- NdbMutex_Unlock(ndbout_mutex); \
- } while (0)
-
-#define CHK(x) \
- do { \
- if (x) break; \
- ndbout << "line " << __LINE__ << ": " << #x << " failed" << endl; \
- return -1; \
- } while (0)
-
-#define CHN(p, x) \
- do { \
- if (x) break; \
- ndbout << "line " << __LINE__ << ": " << #x << " failed" << endl; \
- ndbout << (p)->getNdbError() << endl; \
- return -1; \
- } while (0)
-
-// threads
-
-typedef int (*Runstep)(struct Thr& thr);
-
-struct Thr {
- enum State { Wait, Start, Stop, Stopped, Exit };
- State m_state;
- int m_no;
- Runstep m_runstep;
- int m_ret;
- NdbMutex* m_mutex;
- NdbCondition* m_cond;
- NdbThread* m_thread;
- void* m_status;
- Ndb* m_ndb;
- NdbConnection* m_con;
- NdbScanOperation* m_scanop;
- NdbIndexScanOperation* m_indexscanop;
- //
- Thr(int no);
- ~Thr();
- int run();
- void start(Runstep runstep);
- void stop();
- void stopped();
- void lock() { NdbMutex_Lock(m_mutex); }
- void unlock() { NdbMutex_Unlock(m_mutex); }
- void wait() { NdbCondition_Wait(m_cond, m_mutex); }
- void signal() { NdbCondition_Signal(m_cond); }
- void exit();
- void join() { NdbThread_WaitFor(m_thread, &m_status); }
-};
-
-static NdbOut&
-operator<<(NdbOut& out, const Thr& thr) {
- out << "thr " << thr.m_no;
- return out;
-}
-
-extern "C" { static void* runthread(void* arg); }
-
-Thr::Thr(int no)
-{
- m_state = Wait;
- m_no = no;
- m_runstep = 0;
- m_ret = 0;
- m_mutex = NdbMutex_Create();
- m_cond = NdbCondition_Create();
- assert(m_mutex != 0 && m_cond != 0);
- const unsigned stacksize = 256 * 1024;
- const NDB_THREAD_PRIO prio = NDB_THREAD_PRIO_LOW;
- m_thread = NdbThread_Create(runthread, (void**)this, stacksize, "me", prio);
- if (m_thread == 0) {
- DBG("create thread failed: errno=" << errno);
- m_ret = -1;
- }
- m_status = 0;
- m_ndb = 0;
- m_con = 0;
- m_scanop = 0;
- m_indexscanop = 0;
-}
-
-Thr::~Thr()
-{
- if (m_thread != 0)
- NdbThread_Destroy(&m_thread);
- if (m_cond != 0)
- NdbCondition_Destroy(m_cond);
- if (m_mutex != 0)
- NdbMutex_Destroy(m_mutex);
-}
-
-static void*
-runthread(void* arg) {
- Thr& thr = *(Thr*)arg;
- thr.run();
- return 0;
-}
-
-int
-Thr::run()
-{
- DBG(*this << " run");
- while (true) {
- lock();
- while (m_state != Start && m_state != Exit) {
- wait();
- }
- if (m_state == Exit) {
- DBG(*this << " exit");
- unlock();
- break;
- }
- m_ret = (*m_runstep)(*this);
- m_state = Stopped;
- signal();
- unlock();
- if (m_ret != 0) {
- DBG(*this << " error exit");
- break;
- }
- }
- delete m_ndb;
- m_ndb = 0;
- return 0;
-}
-
-void
-Thr::start(Runstep runstep)
-{
- lock();
- m_state = Start;
- m_runstep = runstep;
- signal();
- unlock();
-}
-
-void
-Thr::stopped()
-{
- lock();
- while (m_state != Stopped) {
- wait();
- }
- m_state = Wait;
- unlock();
-}
-
-void
-Thr::exit()
-{
- lock();
- m_state = Exit;
- signal();
- unlock();
-}
-
-// general
-
-static int
-runstep_connect(Thr& thr)
-{
- Ndb* ndb = thr.m_ndb = new Ndb(g_cluster_connection, "TEST_DB");
- CHN(ndb, ndb->init() == 0);
- CHN(ndb, ndb->waitUntilReady() == 0);
- DBG(thr << " connected");
- return 0;
-}
-
-static int
-runstep_starttx(Thr& thr)
-{
- Ndb* ndb = thr.m_ndb;
- assert(ndb != 0);
- CHN(ndb, (thr.m_con = ndb->startTransaction()) != 0);
- DBG("thr " << thr.m_no << " tx started");
- return 0;
-}
-
-/*
- * WL1822 flush locks
- *
- * Table T with 3 tuples X, Y, Z.
- * Two transactions (* = lock wait).
- *
- * - tx1 reads and locks Z
- * - tx2 scans X, Y, *Z
- * - tx2 returns X, Y before lock wait on Z
- * - tx1 reads and locks *X
- * - api asks for next tx2 result
- * - LQH unlocks X via ACC or TUX [*]
- * - tx1 gets lock on X
- * - tx1 returns X to api
- * - api commits tx1
- * - tx2 gets lock on Z
- * - tx2 returs Z to api
- *
- * The point is deadlock is avoided due to [*].
- * The test is for 1 db node and 1 fragment table.
- */
-
-static char wl1822_scantx = 0;
-
-static const Uint32 wl1822_valA[3] = { 0, 1, 2 };
-static const Uint32 wl1822_valB[3] = { 3, 4, 5 };
-
-static Uint32 wl1822_bufA = ~0;
-static Uint32 wl1822_bufB = ~0;
-
-// map scan row to key (A) and reverse
-static unsigned wl1822_r2k[3] = { 0, 0, 0 };
-static unsigned wl1822_k2r[3] = { 0, 0, 0 };
-
-static int
-wl1822_createtable(Thr& thr)
-{
- Ndb* ndb = thr.m_ndb;
- assert(ndb != 0);
- NdbDictionary::Dictionary* dic = ndb->getDictionary();
- // drop T
- if (dic->getTable(g_opt.m_tname) != 0)
- CHN(dic, dic->dropTable(g_opt.m_tname) == 0);
- // create T
- NdbDictionary::Table tab(g_opt.m_tname);
- tab.setFragmentType(NdbDictionary::Object::FragAllSmall);
- { NdbDictionary::Column col("A");
- col.setType(NdbDictionary::Column::Unsigned);
- col.setPrimaryKey(true);
- tab.addColumn(col);
- }
- { NdbDictionary::Column col("B");
- col.setType(NdbDictionary::Column::Unsigned);
- col.setPrimaryKey(false);
- tab.addColumn(col);
- }
- CHN(dic, dic->createTable(tab) == 0);
- // create X
- NdbDictionary::Index ind(g_opt.m_xname);
- ind.setTable(g_opt.m_tname);
- ind.setType(NdbDictionary::Index::OrderedIndex);
- ind.setLogging(false);
- ind.addColumn("B");
- CHN(dic, dic->createIndex(ind) == 0);
- DBG("created " << g_opt.m_tname << ", " << g_opt.m_xname);
- return 0;
-}
-
-static int
-wl1822_insertrows(Thr& thr)
-{
- // insert X, Y, Z
- Ndb* ndb = thr.m_ndb;
- assert(ndb != 0);
- NdbConnection* con;
- NdbOperation* op;
- for (unsigned k = 0; k < 3; k++) {
- CHN(ndb, (con = ndb->startTransaction()) != 0);
- CHN(con, (op = con->getNdbOperation(g_opt.m_tname)) != 0);
- CHN(op, op->insertTuple() == 0);
- CHN(op, op->equal("A", (char*)&wl1822_valA[k]) == 0);
- CHN(op, op->setValue("B", (char*)&wl1822_valB[k]) == 0);
- CHN(con, con->execute(Commit) == 0);
- ndb->closeTransaction(con);
- }
- DBG("inserted X, Y, Z");
- return 0;
-}
-
-static int
-wl1822_getscanorder(Thr& thr)
-{
- // cheat, table order happens to be key order in my test
- wl1822_r2k[0] = 0;
- wl1822_r2k[1] = 1;
- wl1822_r2k[2] = 2;
- wl1822_k2r[0] = 0;
- wl1822_k2r[1] = 1;
- wl1822_k2r[2] = 2;
- DBG("scan order determined");
- return 0;
-}
-
-static int
-wl1822_tx1_readZ(Thr& thr)
-{
- // tx1 read Z with exclusive lock
- NdbConnection* con = thr.m_con;
- assert(con != 0);
- NdbOperation* op;
- CHN(con, (op = con->getNdbOperation(g_opt.m_tname)) != 0);
- CHN(op, op->readTupleExclusive() == 0);
- CHN(op, op->equal("A", wl1822_valA[wl1822_r2k[2]]) == 0);
- wl1822_bufB = ~0;
- CHN(op, op->getValue("B", (char*)&wl1822_bufB) != 0);
- CHN(con, con->execute(NoCommit) == 0);
- CHK(wl1822_bufB == wl1822_valB[wl1822_r2k[2]]);
- DBG("tx1 locked Z");
- return 0;
-}
-
-static int
-wl1822_tx2_scanXY(Thr& thr)
-{
- // tx2 scan X, Y with exclusive lock
- NdbConnection* con = thr.m_con;
- assert(con != 0);
- NdbScanOperation* scanop;
- NdbIndexScanOperation* indexscanop;
- NdbResultSet* rs;
- if (wl1822_scantx == 't') {
- CHN(con, (scanop = thr.m_scanop = con->getNdbScanOperation(g_opt.m_tname)) != 0);
- DBG("tx2 scan exclusive " << g_opt.m_tname);
- }
- if (wl1822_scantx == 'x') {
- CHN(con, (scanop = thr.m_scanop = indexscanop = thr.m_indexscanop = con->getNdbIndexScanOperation(g_opt.m_xname, g_opt.m_tname)) != 0);
- DBG("tx2 scan exclusive " << g_opt.m_xname);
- }
- CHN(scanop, scanop->readTuplesExclusive(16) == 0);
- CHN(scanop, scanop->getValue("A", (char*)&wl1822_bufA) != 0);
- CHN(scanop, scanop->getValue("B", (char*)&wl1822_bufB) != 0);
- CHN(con, con->execute(NoCommit) == 0);
- unsigned row = 0;
- while (row < 2) {
- DBG("before row " << row);
- int ret;
- wl1822_bufA = wl1822_bufB = ~0;
- CHN(con, (ret = scanop->nextResult(true)) == 0);
- DBG("got row " << row << " a=" << wl1822_bufA << " b=" << wl1822_bufB);
- CHK(wl1822_bufA == wl1822_valA[wl1822_r2k[row]]);
- CHK(wl1822_bufB == wl1822_valB[wl1822_r2k[row]]);
- row++;
- }
- return 0;
-}
-
-static int
-wl1822_tx1_readX_commit(Thr& thr)
-{
- // tx1 read X with exclusive lock and commit
- NdbConnection* con = thr.m_con;
- assert(con != 0);
- NdbOperation* op;
- CHN(con, (op = con->getNdbOperation(g_opt.m_tname)) != 0);
- CHN(op, op->readTupleExclusive() == 0);
- CHN(op, op->equal("A", wl1822_valA[wl1822_r2k[2]]) == 0);
- wl1822_bufB = ~0;
- CHN(op, op->getValue("B", (char*)&wl1822_bufB) != 0);
- CHN(con, con->execute(NoCommit) == 0);
- CHK(wl1822_bufB == wl1822_valB[wl1822_r2k[2]]);
- DBG("tx1 locked X");
- CHN(con, con->execute(Commit) == 0);
- DBG("tx1 commit");
- return 0;
-}
-
-static int
-wl1822_tx2_scanZ_close(Thr& thr)
-{
- // tx2 scan Z with exclusive lock and close scan
- Ndb* ndb = thr.m_ndb;
- NdbConnection* con = thr.m_con;
- NdbScanOperation* scanop = thr.m_scanop;
- assert(ndb != 0 && con != 0 && scanop != 0);
- unsigned row = 2;
- while (true) {
- DBG("before row " << row);
- int ret;
- wl1822_bufA = wl1822_bufB = ~0;
- CHN(con, (ret = scanop->nextResult(true)) == 0 || ret == 1);
- if (ret == 1)
- break;
- DBG("got row " << row << " a=" << wl1822_bufA << " b=" << wl1822_bufB);
- CHK(wl1822_bufA == wl1822_valA[wl1822_r2k[row]]);
- CHK(wl1822_bufB == wl1822_valB[wl1822_r2k[row]]);
- row++;
- }
- ndb->closeTransaction(con);
- CHK(row == 3);
- return 0;
-}
-
-// threads are synced between each step
-static Runstep wl1822_step[][2] = {
- { runstep_connect, runstep_connect },
- { wl1822_createtable, 0 },
- { wl1822_insertrows, 0 },
- { wl1822_getscanorder, 0 },
- { runstep_starttx, runstep_starttx },
- { wl1822_tx1_readZ, 0 },
- { 0, wl1822_tx2_scanXY },
- { wl1822_tx1_readX_commit, wl1822_tx2_scanZ_close }
-};
-const unsigned wl1822_stepcount = sizeof(wl1822_step)/sizeof(wl1822_step[0]);
-
-static int
-wl1822_main(char scantx)
-{
- wl1822_scantx = scantx;
- static const unsigned thrcount = 2;
- // create threads for tx1 and tx2
- Thr* thrlist[2];
- int n;
- for (n = 0; n < thrcount; n++) {
- Thr& thr = *(thrlist[n] = new Thr(1 + n));
- CHK(thr.m_ret == 0);
- }
- // run the steps
- for (unsigned i = 0; i < wl1822_stepcount; i++) {
- DBG("step " << i << " start");
- for (n = 0; n < thrcount; n++) {
- Thr& thr = *thrlist[n];
- Runstep runstep = wl1822_step[i][n];
- if (runstep != 0)
- thr.start(runstep);
- }
- for (n = 0; n < thrcount; n++) {
- Thr& thr = *thrlist[n];
- Runstep runstep = wl1822_step[i][n];
- if (runstep != 0)
- thr.stopped();
- }
- }
- // delete threads
- for (n = 0; n < thrcount; n++) {
- Thr& thr = *thrlist[n];
- thr.exit();
- thr.join();
- delete &thr;
- }
- return 0;
-}
-
-NDB_COMMAND(testOdbcDriver, "testDeadlock", "testDeadlock", "testDeadlock", 65535)
-{
- ndb_init();
- if (ndbout_mutex == NULL)
- ndbout_mutex= NdbMutex_Create();
- while (++argv, --argc > 0) {
- const char* arg = argv[0];
- if (strcmp(arg, "-scan") == 0) {
- if (++argv, --argc > 0) {
- g_opt.m_scan = strdup(argv[0]);
- continue;
- }
- }
- printusage();
- return NDBT_ProgramExit(NDBT_WRONGARGS);
- }
-
- Ndb_cluster_connection con;
- if(con.connect(12, 5, 1) != 0)
- {
- return NDBT_ProgramExit(NDBT_FAILED);
- }
- g_cluster_connection= &con;
-
- if (
- strchr(g_opt.m_scan, 't') != 0 && wl1822_main('t') == -1 ||
- strchr(g_opt.m_scan, 'x') != 0 && wl1822_main('x') == -1
- ) {
- return NDBT_ProgramExit(NDBT_FAILED);
- }
- return NDBT_ProgramExit(NDBT_OK);
-}
-
-// vim: set sw=2 et: