4964 Jonas Oreland 2012-09-12
add missing file
added:
storage/ndb/test/ndbapi/testCoordTrans.cpp
4963 Jonas Oreland 2012-09-12
add missing file
added:
storage/ndb/src/common/debugger/signaldata/TcCommit.cpp
=== added file 'storage/ndb/test/ndbapi/testCoordTrans.cpp'
--- a/storage/ndb/test/ndbapi/testCoordTrans.cpp 1970-01-01 00:00:00 +0000
+++ b/storage/ndb/test/ndbapi/testCoordTrans.cpp 2012-09-12 13:36:13 +0000
@@ -0,0 +1,1872 @@
+/*
+ Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+
+ 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#include <NDBT_Test.hpp>
+#include <NDBT_ReturnCodes.h>
+#include <HugoTransactions.hpp>
+#include <UtilTransactions.hpp>
+#include <NdbRestarter.hpp>
+#include <signaldata/DumpStateOrd.hpp>
+
+extern unsigned opt_seed;
+
+/**
+ * adds rows randomly between 0 and records
+ */
+int
+runRandLoadTable(NDBT_Context* ctx, NDBT_Step* step)
+{
+ const int records = ctx->getNumRecords();
+ Ndb * pNdb = GETNDB(step);
+ HugoOperations hugoOps(*ctx->getTab());
+ hugoOps.startTransaction(pNdb);
+
+ int count = 0;
+ int batch = 0;
+ int retryAttempt = 0;
+ int maxRetries = 25;
+ for (int i = 0; i < records; i++)
+ {
+ if ((ndb_rand_r(&opt_seed) % 100) < 50)
+ {
+ int update_no = ndb_rand_r(&opt_seed);
+ hugoOps.pkWriteRecord(pNdb, i, 1, update_no);
+ batch++;
+ count++;
+ }
+
+ if (batch >= 128 || (batch > 0 && i == (records - 1)))
+ {
+ if (hugoOps.execute_Commit(pNdb) != 0)
+ {
+ /**
+ * TODO
+ */
+ NdbError err = hugoOps.getNdbError();
+ ERR(err);
+ if (err.status == NdbError::TemporaryError &&
+ retryAttempt < maxRetries)
+ {
+ i -= batch;
+ count -= batch;
+ retryAttempt++;
+ NdbSleep_MilliSleep(15);
+ }
+ }
+ hugoOps.closeTransaction(pNdb);
+ hugoOps.startTransaction(pNdb);
+ batch = 0;
+ }
+ }
+
+ assert(batch == 0);
+ hugoOps.closeTransaction(pNdb);
+
+ ndbout_c("loaded %u (of %u) rows", count, records);
+
+ return NDBT_OK;
+}
+
+class CoordTransTester
+{
+ /**
+ * This represents a row that we know the value of (i.e have the lock of)
+ */
+ struct Row
+ {
+ Row(int no, int val) {
+ row_no = no;
+ initial_deleted = current_deleted = false;
+ initial_updateno = current_updateno = val;
+ }
+
+ Row() {}
+
+ int row_no;
+
+ /**
+ * initial state of row (i.e for transaction(s) not participating)
+ */
+ bool initial_deleted;
+ int initial_updateno;
+
+ /**
+ * current state of row (i.e for transaction(s) participating)
+ */
+ bool current_deleted;
+ int current_updateno;
+ };
+
+ struct Participant
+ {
+ /**
+ * Does this participants "part" contain only operations
+ * that does not need commit/rollback
+ * (ndbapi will optimize away commit/rollback)
+ */
+ bool m_simple;
+
+ /**
+ * Does this participants "part" contain only reads
+ */
+ bool m_read_only;
+
+ Ndb * m_ndb;
+ NdbTransaction * m_trans;
+ };
+
+ unsigned m_seed;
+ unsigned m_max_row;
+ bool m_own_connection;
+
+ const NdbDictionary::Table * m_table;
+ NdbDictionary::Index * m_uk_index;
+ NdbDictionary::Index * m_oi_index;
+ Ndb_cluster_connection * m_cluster_connection;
+
+ char m_transid[NDBAPI_MAX_COORD_TRANSACTION_ID_SIZE];
+ Vector<Participant> m_trans;
+ Vector<Row> m_rows;
+
+ Vector<Uint32> m_actions; // Log of actions...
+public:
+ CoordTransTester (NDBT_Context* ctx,
+ unsigned seed, int p, int rows, int threads);
+ ~CoordTransTester();
+
+ int setup();
+ int start();
+ int step();
+ int end();
+ int cleanup();
+
+ enum Action
+ {
+ A_BEGIN = 0
+ ,A_JOIN = 1
+ ,A_INSERT = 2
+ ,A_UPDATE = 3
+ ,A_DELETE = 4
+ ,A_LOCK = 5
+ ,A_PKREAD = 6
+ ,A_UKREAD = 7
+ ,A_TABLESCAN = 8
+ ,A_INDEXSCAN = 9
+ ,A_COMMIT = 10
+ ,A_ROLLBACK = 11
+ ,A_COMMIT_LEAVE = 12
+ ,A_DISCONNECT = 13
+ ,A_NF_COMMIT = 14
+ ,A_NF_ROLLBACK = 15
+
+ ,A_LAST
+ };
+
+ // based on state...returns bitmask of possible actions
+ Uint32 computePossibleActions(Uint32 weight[A_LAST]);
+
+ int do_begin();
+ int do_join();
+ int do_insert();
+ int do_update();
+ int do_delete();
+ int do_lock();
+ int do_pkread();
+ int do_ukread();
+ int do_tablescan();
+ int do_indexscan();
+ int do_commit();
+ int do_rollback();
+ int do_commit_leave();
+ int do_disconnect();
+ int do_nf_commit();
+ int do_nf_rollback();
+
+ void fatal(int from);
+
+ void do_close();
+ Participant * getRandomParticant();
+ Row * searchRow(int row_no);
+
+ unsigned getRandomRowNo() {
+ return (unsigned)ndb_rand_r(&m_seed) % m_max_row;
+ }
+ Row * getRandomRow() {
+ assert(m_rows.size() > 0);
+ int i = ndb_rand_r(&m_seed) % m_rows.size();
+ return &m_rows[i];
+ }
+
+ /**
+ * Distribution of actions
+ */
+ int m_action_pct[A_LAST];
+};
+
+CoordTransTester::CoordTransTester(NDBT_Context * ctx,
+ unsigned seed, int p, int rows, int threads)
+{
+ m_max_row = (unsigned)rows;
+ m_seed = seed;
+ m_table = ctx->getTab();
+ m_uk_index = 0;
+ m_oi_index = 0;
+ m_own_connection = (ctx->getProperty("OwnConnection", Uint32(0)) != 0);
+ if (m_own_connection == false)
+ {
+ m_cluster_connection = &ctx->m_cluster_connection;
+ }
+ else
+ {
+ m_cluster_connection = 0;
+ }
+
+ {
+ Participant t;
+ m_trans.fill(p - 1, t);
+ }
+
+ m_action_pct[A_BEGIN] = 100 ;
+ m_action_pct[A_JOIN] = 50 ;
+ m_action_pct[A_INSERT] = 10 ;
+ m_action_pct[A_UPDATE] = 10 ;
+ m_action_pct[A_DELETE] = 10 ;
+ m_action_pct[A_LOCK] = 10 ;
+ m_action_pct[A_PKREAD] = 10 ;
+ m_action_pct[A_UKREAD] = 10 ;
+ m_action_pct[A_TABLESCAN] = 10 ;
+ m_action_pct[A_INDEXSCAN] = 10 ;
+ m_action_pct[A_COMMIT] = 5 ;
+ m_action_pct[A_ROLLBACK] = 5 ;
+ m_action_pct[A_COMMIT_LEAVE] = 5 ;
+ m_action_pct[A_DISCONNECT] = 2 ;
+ m_action_pct[A_NF_COMMIT] = 0;
+ m_action_pct[A_NF_ROLLBACK] = 0 ;
+
+ const char * str[] = {
+ "BEGIN",
+ "JOIN",
+ "INSERT",
+ "UPDATE",
+ "DELETE",
+ "LOCK",
+ "PKREAD",
+ "UKREAD",
+ "TABLESCAN",
+ "INDEXSCAN",
+ "COMMIT",
+ "ROLLBACK",
+ "COMMIT_LEAVE",
+ "DISCONNECT",
+ "NF_COMMIT",
+ "NF_ROLLBACK",
+ 0
+ };
+
+ for (Uint32 i = 0 ; str[i] != 0; i++)
+ {
+ BaseString search;
+ search.assfmt("%s_PCT", str[i]);
+ Uint32 pct = ctx->getProperty(search.c_str(), m_action_pct[i]);
+ m_action_pct[i] = pct;
+ }
+
+ /**
+ * only meaningfull with disconnect testing if using "own" connection
+ */
+ if (m_own_connection == 0)
+ {
+ m_action_pct[A_DISCONNECT] = 0;
+ }
+}
+
+CoordTransTester::~CoordTransTester()
+{
+}
+
+int
+CoordTransTester::setup()
+{
+ if (m_cluster_connection == 0)
+ {
+ for (Uint32 i = 0; i < 3; i++)
+ {
+ Ndb_cluster_connection * xncc = new Ndb_cluster_connection;
+ xncc->set_auto_reconnect(false);
+ if (xncc->connect(30, 1, 0) != 0)
+ {
+ delete xncc;
+ NdbSleep_MilliSleep(200);
+ continue;
+ }
+
+ if (xncc->wait_until_ready(30, 10) != 0)
+ {
+ delete xncc;
+ NdbSleep_MilliSleep(200);
+ continue;
+ }
+
+ m_cluster_connection = xncc;
+ break;
+ }
+
+ if (m_cluster_connection == 0)
+ {
+ return NDBT_FAILED;
+ }
+ }
+
+ return 0;
+}
+
+int
+CoordTransTester::start()
+{
+ for (Uint32 i = 0; i < m_trans.size(); i++)
+ {
+ Ndb* xndb = new Ndb(m_cluster_connection, "TEST_DB");
+ if (xndb == 0)
+ {
+ return NDBT_FAILED;
+ }
+ if (xndb->init(10) != 0)
+ {
+ delete xndb;
+ return NDBT_FAILED;
+ }
+
+ if (xndb->waitUntilReady(0) != 0)
+ {
+ delete xndb;
+ return NDBT_FAILED;
+ }
+
+ m_trans[i].m_simple = true;
+ m_trans[i].m_read_only = true;
+ m_trans[i].m_ndb = xndb;
+ m_trans[i].m_trans = 0;
+ }
+
+ return 0;
+}
+
+int
+CoordTransTester::step()
+{
+ Uint32 weights[A_LAST];
+ Uint32 sum = computePossibleActions(weights);
+
+ Uint32 randval = ((Uint32)ndb_rand_r(&m_seed) % sum);
+ Uint32 action = 0;
+ while (randval >= weights[action])
+ {
+ randval -= weights[action];
+ action++;
+ }
+
+ m_actions.push_back(action);
+
+ int res = -1;
+ switch(action){
+ case A_BEGIN:
+ res = do_begin();
+ break;
+ case A_JOIN:
+ res = do_join();
+ break;
+ case A_INSERT:
+ res = do_insert();
+ break;
+ case A_UPDATE:
+ res = do_update();
+ break;
+ case A_DELETE:
+ res = do_delete();
+ break;
+ case A_LOCK:
+ res = do_lock();
+ break;
+ case A_PKREAD:
+ res = do_pkread();
+ break;
+ case A_UKREAD:
+ res = do_ukread();
+ break;
+ case A_TABLESCAN:
+ res = do_tablescan();
+ break;
+ case A_INDEXSCAN:
+ res = do_indexscan();
+ break;
+ case A_COMMIT:
+ res = do_commit();
+ break;
+ case A_ROLLBACK:
+ res = do_rollback();
+ break;
+ case A_COMMIT_LEAVE:
+ res = do_commit_leave();
+ break;
+ case A_DISCONNECT:
+ res = do_disconnect();
+ break;
+ case A_NF_COMMIT:
+ res = do_nf_commit();
+ break;
+ case A_NF_ROLLBACK:
+ res = do_nf_rollback();
+ break;
+ }
+ assert(res != -1);
+
+ return res;
+}
+
+const int retries = 50;
+const int retrysleep = 50; // ms
+
+int
+CoordTransTester::do_begin()
+{
+ assert(m_trans[0].m_trans == 0);
+ for (int i = 0; i < retries; i++)
+ {
+ Participant * p = &m_trans[0];
+ if ((p->m_trans = p->m_ndb->startTransaction()) == 0)
+ {
+ const NdbError err = p->m_ndb->getNdbError();
+ if (err.status != NdbError::TemporaryError)
+ {
+ ERR(err);
+ fatal(__LINE__);
+ return NDBT_FAILED;
+ }
+ NdbSleep_MilliSleep(retrysleep);
+ continue;
+ }
+
+ m_trans[0].m_simple = true;
+ m_trans[0].m_read_only = true;
+ m_trans[0].m_trans->getCoordinatedTransactionId(m_transid,
+ sizeof(m_transid));
+
+ /**
+ * Currently...the transaction is not "usable"/started until
+ * atleast one operation has been performed on it...
+ * do a committedread on a random key
+ *
+ * TODO: We could lift this restriction!!
+ */
+ unsigned row_no = getRandomRowNo();
+ HugoOperations hugoOps(* m_table);
+ hugoOps.setTransaction(p->m_trans);
+ hugoOps.pkReadRecord(p->m_ndb, row_no, 1, NdbOperation::LM_CommittedRead);
+ hugoOps.setTransaction(NULL, true);
+
+ const NdbOperation * op = p->m_trans->getLastDefinedOperation();
+ int res = p->m_trans->execute(NoCommit, AO_IgnoreError);
+ if (res == 0)
+ {
+ /**
+ * ok...
+ */
+ break;
+ }
+
+ const NdbError opErr = op->getNdbError();
+ const NdbError transErr = p->m_trans->getNdbError();
+ if (opErr.status != NdbError::TemporaryError &&
+ transErr.status != NdbError::TemporaryError)
+ {
+ ERR(opErr);
+ ERR(transErr);
+ fatal(__LINE__);
+ return NDBT_FAILED;
+ }
+
+ p->m_trans->close();
+ p->m_trans = 0;
+ NdbSleep_MilliSleep(retrysleep);
+ }
+
+ if (m_trans[0].m_trans == 0)
+ {
+ fatal(__LINE__);
+ return NDBT_FAILED;
+ }
+
+ return 0;
+}
+
+int
+CoordTransTester::do_join()
+{
+ for (Uint32 i = 0; i < m_trans.size(); i++)
+ {
+ if (m_trans[i].m_trans == 0)
+ {
+ /**
+ *
+ */
+ NdbTransaction * pTrans = m_trans[i].m_ndb->joinTransaction(m_transid);
+ if ((m_trans[i].m_trans = pTrans) == 0)
+ {
+ const NdbError err = m_trans[i].m_ndb->getNdbError();
+ if (err.status != NdbError::TemporaryError)
+ {
+ ERR(err);
+ fatal(__LINE__);
+ return NDBT_FAILED;
+ }
+
+ NdbSleep_MilliSleep(retrysleep);
+ return do_rollback();
+ }
+ else
+ {
+ /**
+ * OK
+ */
+ m_trans[i].m_simple = true;
+ m_trans[i].m_read_only = true;
+ return 0;
+ }
+ }
+ }
+ assert(false);
+ return 0;
+}
+
+int
+CoordTransTester::do_insert()
+{
+ unsigned row_no = getRandomRowNo();
+ unsigned update_no = ndb_rand_r(&m_seed);
+
+ Participant * p = getRandomParticant();
+ p->m_simple = false;
+ p->m_read_only = false;
+ Row * r = searchRow(row_no);
+
+ HugoOperations hugoOps(* m_table);
+ hugoOps.setTransaction(p->m_trans);
+ hugoOps.pkWriteRecord(p->m_ndb, row_no, 1, update_no);
+ hugoOps.setTransaction(NULL, true);
+
+ const NdbOperation * op = p->m_trans->getLastDefinedOperation();
+ int res = p->m_trans->execute(NoCommit, AO_IgnoreError);
+
+ if (res == -1)
+ {
+ if (p->m_trans->getNdbError().status == NdbError::TemporaryError)
+ {
+ /**
+ * Any trans may get temporary error...
+ */
+ NdbSleep_MilliSleep(retrysleep);
+ return do_rollback();
+ }
+ }
+
+ if (op->getNdbError().status == NdbError::TemporaryError)
+ {
+ /**
+ * Any trans may get temporary error...
+ */
+ NdbSleep_MilliSleep(retrysleep);
+ return do_rollback();
+ }
+
+ if (r != 0)
+ {
+ /**
+ * we "owned" the row...should be ok to WRITE it again
+ */
+ if (res != 0)
+ {
+ ERR(op->getNdbError());
+ ERR(p->m_trans->getNdbError());
+ fatal(__LINE__);
+ return NDBT_FAILED;
+ }
+ r->current_deleted = false;
+ r->current_updateno = update_no;
+ return 0;
+ }
+
+ if (res == 0)
+ {
+ if (op->getNdbError().code == 0)
+ {
+ /**
+ * insert ok
+ */
+ Row r(row_no, update_no);
+ m_rows.push_back(r);
+ return 0;
+ }
+ else
+ {
+ /**
+ * insert failed...but transaction is alive => ok too
+ */
+ ERR(op->getNdbError());
+ ERR(p->m_trans->getNdbError());
+ return 0;
+ }
+ }
+ else
+ {
+ ERR(op->getNdbError());
+ ERR(p->m_trans->getNdbError());
+ fatal(__LINE__);
+ return NDBT_FAILED;
+ }
+
+ assert(false);
+
+ return 0;
+}
+
+int
+CoordTransTester::do_update()
+{
+ assert(m_rows.size() > 0);
+
+ Row * r = getRandomRow();
+ Participant * p = getRandomParticant();
+ p->m_simple = false;
+ p->m_read_only = false;
+ unsigned update_no = ndb_rand_r(&m_seed);
+
+ HugoOperations hugoOps(* m_table);
+ hugoOps.setTransaction(p->m_trans);
+ hugoOps.pkUpdateRecord(p->m_ndb, r->row_no, 1, update_no);
+ hugoOps.setTransaction(NULL, true);
+
+ const NdbOperation * op = p->m_trans->getLastDefinedOperation();
+ int res = p->m_trans->execute(NoCommit, AO_IgnoreError);
+
+ if (res == -1)
+ {
+ if (p->m_trans->getNdbError().status == NdbError::TemporaryError)
+ {
+ /**
+ * Any trans may get temporary error...
+ */
+ NdbSleep_MilliSleep(retrysleep);
+ return do_rollback();
+ }
+ }
+
+ if (res != 0)
+ {
+ ERR(op->getNdbError());
+ ERR(p->m_trans->getNdbError());
+ fatal(__LINE__);
+ return NDBT_FAILED;
+ }
+
+ if (op->getNdbError().status == NdbError::TemporaryError)
+ {
+ /**
+ * Any trans may get temporary error...
+ */
+ NdbSleep_MilliSleep(retrysleep);
+ return do_rollback();
+ }
+
+ if (r->current_deleted == true)
+ {
+ /**
+ * this should be a failure...
+ */
+ if (op->getNdbError().status != NdbError::PermanentError)
+ {
+ ERR(op->getNdbError());
+ fatal(__LINE__);
+ return NDBT_FAILED;
+ }
+ }
+ else
+ {
+ if (op->getNdbError().status != NdbError::Success)
+ {
+ fatal(__LINE__);
+ return NDBT_FAILED;
+ }
+ }
+
+ r->current_updateno = update_no;
+ return 0;
+}
+
+int
+CoordTransTester::do_delete()
+{
+ assert(m_rows.size() > 0);
+
+ Row * r = getRandomRow();
+ Participant * p = getRandomParticant();
+ p->m_simple = false;
+ p->m_read_only = false;
+
+ HugoOperations hugoOps(* m_table);
+ hugoOps.setTransaction(p->m_trans);
+ hugoOps.pkDeleteRecord(p->m_ndb, r->row_no, 1);
+ hugoOps.setTransaction(NULL, true);
+
+ const NdbOperation * op = p->m_trans->getLastDefinedOperation();
+ int res = p->m_trans->execute(NoCommit, AO_IgnoreError);
+
+ if (res == -1)
+ {
+ if (p->m_trans->getNdbError().status == NdbError::TemporaryError)
+ {
+ /**
+ * Any trans may get temporary error...
+ */
+ NdbSleep_MilliSleep(retrysleep);
+ return do_rollback();
+ }
+ }
+
+ if (res != 0)
+ {
+ ERR(op->getNdbError());
+ ERR(p->m_trans->getNdbError());
+ fatal(__LINE__);
+ return NDBT_FAILED;
+ }
+
+ if (op->getNdbError().status == NdbError::TemporaryError)
+ {
+ /**
+ * Any trans may get temporary error...
+ */
+ NdbSleep_MilliSleep(retrysleep);
+ return do_rollback();
+ }
+
+ if (r->current_deleted == true)
+ {
+ /**
+ * this should be a failure...
+ */
+ if (op->getNdbError().status != NdbError::PermanentError)
+ {
+ ERR(op->getNdbError());
+ fatal(__LINE__);
+ return NDBT_FAILED;
+ }
+ }
+ else
+ {
+ if (op->getNdbError().status != NdbError::Success)
+ {
+ ERR(op->getNdbError());
+ fatal(__LINE__);
+ return NDBT_FAILED;
+ }
+ }
+
+ r->current_deleted = true;
+ return 0;
+}
+
+int
+CoordTransTester::do_lock()
+{
+ unsigned row_no = getRandomRowNo();
+ Participant * p = getRandomParticant();
+ p->m_simple = false;
+
+ NDBT_ResultRow row(* m_table);
+ HugoCalculator calc(* m_table);
+
+ NdbOperation * pOp = p->m_trans->getNdbOperation(m_table);
+ pOp->readTuple(NdbOperation::LM_Read);
+
+ {
+ HugoOperations ops(* m_table);
+ ops.equalForRow(pOp, row_no);
+ }
+
+ for (int i = 0; i < m_table->getNoOfColumns(); i++)
+ {
+ NdbRecAttr * attr = pOp->getValue(m_table->getColumn(i)->getName());
+ if (attr == 0)
+ {
+ ERR(pOp->getNdbError());
+ fatal(__LINE__);
+ return NDBT_FAILED;
+ }
+
+ row.attributeStore(i) = attr;
+ }
+
+ const NdbOperation * op = p->m_trans->getLastDefinedOperation();
+ int res = p->m_trans->execute(NoCommit, AO_IgnoreError);
+
+ if (res == -1)
+ {
+ if (p->m_trans->getNdbError().status == NdbError::TemporaryError)
+ {
+ /**
+ * Any trans may get temporary error...
+ */
+ NdbSleep_MilliSleep(retrysleep);
+ return do_rollback();
+ }
+ }
+
+ if (res != 0)
+ {
+ ERR(op->getNdbError());
+ ERR(p->m_trans->getNdbError());
+ fatal(__LINE__);
+ return NDBT_FAILED;
+ }
+
+ if (op->getNdbError().status == NdbError::TemporaryError)
+ {
+ /**
+ * Any trans may get temporary error...
+ */
+ NdbSleep_MilliSleep(retrysleep);
+ return do_rollback();
+ }
+
+ if (op->getNdbError().code == 0)
+ {
+ /**
+ * Row round!!
+ */
+ if (calc.verifyRowValues(&row) != 0)
+ {
+ fatal(__LINE__);
+ return NDBT_FAILED;
+ }
+
+ int row_no = calc.getIdValue(&row);
+ Row * r = searchRow(row_no);
+ if (r)
+ {
+ if (r->current_deleted)
+ {
+ fatal(__LINE__);
+ return NDBT_FAILED;
+ }
+ else if (calc.getUpdatesValue(&row) != r->current_updateno)
+ {
+ fatal(__LINE__);
+ return NDBT_FAILED;
+ }
+ }
+ else
+ {
+ /**
+ * We now "own" row
+ */
+ Row r(row_no, calc.getUpdatesValue(&row));
+ m_rows.push_back(r);
+ }
+ }
+ else if (pOp->getNdbError().classification == NdbError::NoDataFound)
+ {
+ /**
+ * Row not found
+ */
+ Row * r = searchRow(row_no);
+ if (r)
+ {
+ if (!r->current_deleted)
+ {
+ fatal(__LINE__);
+ return NDBT_FAILED;
+ }
+ }
+ }
+ else if (pOp->getNdbError().status == NdbError::TemporaryError)
+ {
+ return do_rollback();
+ }
+ else
+ {
+ ERR(op->getNdbError());
+ fatal(__LINE__);
+ return NDBT_FAILED;
+ }
+
+ return 0;
+}
+
+int
+CoordTransTester::do_pkread()
+{
+ assert(m_rows.size() > 0);
+
+ Row * r = getRandomRow();
+ Participant * p = getRandomParticant();
+
+ HugoOperations hugoOps(* m_table);
+ hugoOps.setTransaction(p->m_trans);
+ hugoOps.pkReadRecord(p->m_ndb, r->row_no, 1, NdbOperation::LM_CommittedRead);
+ hugoOps.setTransaction(NULL, true);
+
+ const NdbOperation * op = p->m_trans->getLastDefinedOperation();
+ int res = p->m_trans->execute(NoCommit, AO_IgnoreError);
+
+ if (res == -1)
+ {
+ if (p->m_trans->getNdbError().status == NdbError::TemporaryError)
+ {
+ /**
+ * Any trans may get temporary error...
+ */
+ NdbSleep_MilliSleep(retrysleep);
+ return do_rollback();
+ }
+ }
+
+ if (res != 0)
+ {
+ ERR(op->getNdbError());
+ ERR(p->m_trans->getNdbError());
+ fatal(__LINE__);
+ return NDBT_FAILED;
+ }
+
+ if (r->current_deleted == true)
+ {
+ /**
+ * this should be a failure...
+ */
+ if (op->getNdbError().status != NdbError::PermanentError)
+ {
+ ERR(op->getNdbError());
+ fatal(__LINE__);
+ return NDBT_FAILED;
+ }
+ }
+ else
+ {
+ if (op->getNdbError().status != NdbError::Success)
+ {
+ ERR(op->getNdbError());
+ fatal(__LINE__);
+ return NDBT_FAILED;
+ }
+ }
+
+ return 0;
+}
+
+int
+CoordTransTester::do_ukread()
+{
+ assert(m_rows.size() > 0);
+ return 0;
+}
+
+int
+CoordTransTester::do_tablescan()
+{
+ assert(m_rows.size() > 0);
+
+ int line = 0;
+ NDBT_ResultRow row(* m_table);
+ HugoCalculator calc(* m_table);
+
+ Participant * p = getRandomParticant();
+ NdbScanOperation * pOp = 0;
+ do
+ {
+ if ((pOp = p->m_trans->getNdbScanOperation(m_table)) == 0)
+ {
+ line = __LINE__;
+ break;
+ }
+
+ if (pOp->readTuples(NdbOperation::LM_CommittedRead))
+ {
+ line = __LINE__;
+ break;
+ }
+
+ for (int i = 0; i < m_table->getNoOfColumns(); i++)
+ {
+ NdbRecAttr * attr = pOp->getValue(m_table->getColumn(i)->getName());
+ if (attr == 0)
+ {
+ line = __LINE__;
+ goto do_err;
+ }
+
+ row.attributeStore(i) = attr;
+ }
+
+ int res = p->m_trans->execute(NoCommit, AO_IgnoreError);
+
+ if (res == -1)
+ {
+ if (p->m_trans->getNdbError().status == NdbError::TemporaryError)
+ {
+ /**
+ * Any trans may get temporary error...
+ */
+ NdbSleep_MilliSleep(retrysleep);
+ return do_rollback();
+ }
+ line = __LINE__;
+ break;
+ }
+
+ while ((res = pOp->nextResult()) == 0)
+ {
+ if (calc.verifyRowValues(&row) != 0)
+ {
+ fatal(__LINE__);
+ pOp->close();
+ return NDBT_FAILED;
+ }
+
+ int row_no = calc.getIdValue(&row);
+ Row * r = searchRow(row_no);
+ if (r)
+ {
+ if (r->current_deleted)
+ {
+ fatal(__LINE__);
+ pOp->close();
+ return NDBT_FAILED;
+ }
+ else if (calc.getUpdatesValue(&row) != r->current_updateno)
+ {
+ fatal(__LINE__);
+ pOp->close();
+ return NDBT_FAILED;
+ }
+ }
+ }
+
+ if (res == 1) // EOF
+ {
+ /**
+ * OK
+ */
+ pOp->close();
+ return 0;
+ }
+
+ if (res == -1)
+ {
+ if (p->m_trans->getNdbError().status == NdbError::TemporaryError)
+ {
+ /**
+ * Any trans may get temporary error...
+ */
+ NdbSleep_MilliSleep(retrysleep);
+ return do_rollback();
+ }
+ line = __LINE__;
+ break;
+ }
+
+ } while (0);
+
+do_err:
+ NdbError err;
+ if (pOp)
+ {
+ err = pOp->getNdbError();
+ pOp->close();
+ pOp = 0;
+ }
+ else
+ {
+ err = p->m_trans->getNdbError();
+ }
+
+ if (err.status == NdbError::TemporaryError)
+ {
+ /**
+ * Any trans may get temporary error...
+ */
+ NdbSleep_MilliSleep(retrysleep);
+ return do_rollback();
+ }
+
+ ERR(err);
+ fatal(__LINE__);
+ return NDBT_FAILED;
+}
+
+int
+CoordTransTester::do_indexscan()
+{
+ assert(m_rows.size() > 0);
+ return 0;
+}
+
+static
+void
+commit_callback(int res, NdbTransaction* pTrans, void * callback_obj)
+{
+ int *res_ptr= (int *)callback_obj;
+ *res_ptr= res;
+}
+
+int
+CoordTransTester::do_commit()
+{
+ Vector<int> res;
+ {
+ int tmp = 0;
+ res.fill(m_trans.size() - 1, tmp);
+ }
+
+ // send all
+ for (Uint32 i = 0; i < m_trans.size(); i++)
+ {
+ if (m_trans[i].m_trans != 0)
+ {
+ Ndb * pNdb = m_trans[i].m_ndb;
+ NdbTransaction * pTrans = m_trans[i].m_trans;
+ pTrans->executeAsynchPrepare(Commit,
+ commit_callback,
+ &res[i]);
+ pNdb->sendPreparedTransactions();
+ }
+ }
+
+ // wait all
+ for (Uint32 i = 0; i < m_trans.size(); i++)
+ {
+ if (m_trans[i].m_trans != 0)
+ {
+ while(m_trans[i].m_ndb->pollNdb(100000) == 0)
+ ;
+ }
+ }
+
+ do_close();
+ return 0;
+}
+
+int
+CoordTransTester::do_rollback()
+{
+ for (Uint32 i = 0; i < m_trans.size(); i++)
+ {
+ if (m_trans[i].m_trans != 0)
+ {
+ m_trans[i].m_trans->execute(Rollback);
+ }
+ }
+
+ do_close();
+ return 0;
+}
+
+int
+CoordTransTester::do_commit_leave()
+{
+ // send all
+ for (Uint32 i = 0; i < m_trans.size(); i++)
+ {
+ if (m_trans[i].m_trans != 0)
+ {
+ NdbTransaction * pTrans = m_trans[i].m_trans;
+ int res = pTrans->execute(CommitOrLeave);
+ if (res == -1)
+ {
+ if (pTrans->getNdbError().status == NdbError::TemporaryError)
+ {
+ /**
+ * Any trans may get temporary error...
+ */
+ NdbSleep_MilliSleep(retrysleep);
+ return do_rollback();
+ }
+ }
+ }
+ }
+
+ do_close();
+ return 0;
+}
+
+int
+CoordTransTester::do_disconnect()
+{
+ NdbRestarter res;
+ Uint32 tcNodeId = 0;
+ Uint32 ownNodeId = m_cluster_connection->node_id();
+
+ for (Uint32 i = 0; i < m_trans.size(); i++)
+ {
+ if (m_trans[i].m_trans != 0)
+ {
+ NdbTransaction * pTrans = m_trans[i].m_trans;
+ tcNodeId = pTrans->getConnectedNodeId();
+ break;
+ }
+ }
+
+ int dump[] = { 900, (int)ownNodeId };
+ res.dumpStateOneNode(tcNodeId, dump, 2);
+
+ for (Uint32 i = 0; i < m_trans.size(); i++)
+ {
+ if (m_trans[i].m_trans != 0)
+ {
+ NdbTransaction * pTrans = m_trans[i].m_trans;
+ int res = pTrans->execute(Commit);
+ if (m_trans[i].m_simple)
+ {
+ /**
+ * can be get and not get problem...
+ */
+ }
+ else
+ {
+ if (res != -1)
+ {
+ fatal(__LINE__);
+ return NDBT_FAILED;
+ }
+ }
+ }
+ }
+
+ do_close();
+
+ // delete all Ndb objects
+ for (Uint32 i = 0; i < m_trans.size(); i++)
+ {
+ if (m_trans[i].m_ndb != 0)
+ {
+ delete m_trans[i].m_ndb;
+ m_trans[i].m_ndb = 0;
+ }
+ }
+
+ // delete cluster connection
+ delete m_cluster_connection;
+ m_cluster_connection = 0;
+
+ /**
+ * now reconnect
+ */
+ return setup() || start();
+}
+
+CoordTransTester::Participant *
+CoordTransTester::getRandomParticant()
+{
+ unsigned part = (unsigned)ndb_rand_r(&m_seed) % (5 * m_trans.size());
+ for (unsigned i = 0; ; i = (i + 1) % m_trans.size())
+ {
+ if (m_trans[i].m_trans == 0)
+ {
+ continue;
+ }
+ else if (part == 0)
+ {
+ return &m_trans[i];
+ }
+ else
+ {
+ part--;
+ }
+ }
+}
+
+int
+CoordTransTester::do_nf_commit()
+{
+ /**
+ * 1) start committing
+ * crash TC when receiving COMMITTED
+ *
+ * this tests take-over
+ *
+ * 2) start committing
+ * crash non-tc when receiving COMPLETE
+ *
+ * this tests TC coordinated trans
+ */
+ NdbRestarter res;
+ int val2[] = { DumpStateOrd::CmvmiSetRestartOnErrorInsert, 1 };
+
+ int tcNodeId = 0;
+ for (Uint32 i = 0; i < m_trans.size(); i++)
+ {
+ if (m_trans[i].m_trans != 0)
+ {
+ NdbTransaction * pTrans = m_trans[i].m_trans;
+ tcNodeId = (int)pTrans->getConnectedNodeId();
+ break;
+ }
+ }
+
+ ndbout_c("error 8020");
+ res.insertErrorInNode(tcNodeId, 8020);
+ if (res.dumpStateOneNode(tcNodeId, val2, 2))
+ {
+ return NDBT_FAILED;
+ }
+
+ Vector<int> ret;
+ {
+ int tmp = 0;
+ ret.fill(m_trans.size() - 1, tmp);
+ }
+
+ // send all
+ for (Uint32 i = 0; i < m_trans.size(); i++)
+ {
+ if (m_trans[i].m_trans != 0)
+ {
+ Ndb * pNdb = m_trans[i].m_ndb;
+ NdbTransaction * pTrans = m_trans[i].m_trans;
+ pTrans->executeAsynchPrepare(Commit,
+ commit_callback,
+ &ret[i]);
+ pNdb->sendPreparedTransactions();
+ }
+ }
+
+ // wait all
+ for (Uint32 i = 0; i < m_trans.size(); i++)
+ {
+ if (m_trans[i].m_trans != 0)
+ {
+ while(m_trans[i].m_ndb->pollNdb(100000) == 0)
+ ;
+ }
+ }
+
+ /**
+ * Now check result of transaction...
+ */
+ {
+ Uint32 cnt_rw = 0;
+ Uint32 cnt_simple = 0;
+ Uint32 cnt_started = 0;
+ for (Uint32 i = 0; i < m_trans.size(); i++)
+ {
+ if (m_trans[i].m_trans != 0)
+ {
+ cnt_started++;
+ if (m_trans[i].m_simple == true)
+ {
+ cnt_simple++;
+ }
+ if (m_trans[i].m_read_only == false)
+ {
+ assert(m_trans[i].m_simple == false);
+ cnt_rw++;
+ }
+ }
+ }
+
+ Uint32 cnt_ok = 0;
+ Uint32 cnt_nok = 0;
+ for (Uint32 i = 0; i < ret.size(); i++)
+ {
+ if (ret[i] == -1)
+ cnt_nok++;
+ if (ret[i] == 0)
+ cnt_ok++;
+ }
+
+ ndbout_c("cnt_started: %u cnt_simple: %u cnt_rw: %u cnt_ok: %u cnt_nok: %u",
+ cnt_started, cnt_simple, cnt_rw, cnt_ok, cnt_nok);
+
+ /**
+ * - simple transactions should get OK
+ * since they don't have any operation outstanding
+ * and commit then gets optimized away
+ *
+ * - if there is atleast one RW, then one should get OK too
+ *
+ * - if they are all RO...then it's 50%-50% wheather they get OK or not
+ *
+ */
+ if (cnt_rw > 0)
+ {
+ if (! (cnt_ok == cnt_simple + 1))
+ {
+ fatal(__LINE__);
+ return NDBT_FAILED;
+ }
+ }
+ else
+ {
+ if (! (cnt_ok >= cnt_simple))
+ {
+ fatal(__LINE__);
+ return NDBT_FAILED;
+ }
+ }
+ }
+
+ do_close();
+
+ ndbout_c("wait no start");
+ res.waitNodesNoStart(&tcNodeId, 1);
+ ndbout_c("start");
+ res.startNodes(&tcNodeId, 1);
+ ndbout_c("wait cluster started");
+ res.waitClusterStarted();
+ ndbout_c("started ok");
+
+ return 0;
+}
+
+int
+CoordTransTester::do_nf_rollback()
+{
+ /**
+ * 1) node-failure that gives rollback
+ * 2) node-failure during rollback
+ */
+ NdbRestarter res;
+ int val2[] = { DumpStateOrd::CmvmiSetRestartOnErrorInsert, 1 };
+
+ int tcNodeId = 0;
+ for (Uint32 i = 0; i < m_trans.size(); i++)
+ {
+ if (m_trans[i].m_trans != 0)
+ {
+ NdbTransaction * pTrans = m_trans[i].m_trans;
+ tcNodeId = (int)pTrans->getConnectedNodeId();
+ break;
+ }
+ }
+
+ unsigned c = (ndb_rand_r(&m_seed) & 64) == 64;
+ if (c && (m_rows.size() > 0))
+ {
+ ndbout_c("error 8029");
+ res.insertErrorInNode(tcNodeId, 8029);
+ if (res.dumpStateOneNode(tcNodeId, val2, 2))
+ {
+ return NDBT_FAILED;
+ }
+
+ /**
+ * run an op...crash TC when receiving LQHKEYCONF
+ */
+ Row * r = getRandomRow();
+ Participant * p = getRandomParticant();
+ HugoOperations hugoOps(* m_table);
+ hugoOps.setTransaction(p->m_trans);
+ hugoOps.pkWriteRecord(p->m_ndb, r->row_no, 1, r->current_updateno);
+ hugoOps.setTransaction(NULL, true);
+
+ int res = p->m_trans->execute(NoCommit, AO_IgnoreError);
+ if (res != -1)
+ {
+ return NDBT_FAILED;
+ }
+ }
+ else
+ {
+ ndbout_c("error 8024");
+ res.insertErrorInNode(tcNodeId, 8024);
+ if (res.dumpStateOneNode(tcNodeId, val2, 2))
+ {
+ return NDBT_FAILED;
+ }
+
+ for (Uint32 i = 0; i < m_trans.size(); i++)
+ {
+ if (m_trans[i].m_trans != 0)
+ {
+ m_trans[i].m_trans->execute(Rollback);
+ }
+ }
+ }
+
+ do_close();
+
+ ndbout_c("wait no start");
+ res.waitNodesNoStart(&tcNodeId, 1);
+ ndbout_c("start");
+ res.startNodes(&tcNodeId, 1);
+ ndbout_c("wait cluster started");
+ res.waitClusterStarted();
+ ndbout_c("started ok");
+
+ return do_rollback();
+}
+
+CoordTransTester::Row *
+CoordTransTester::searchRow(int row_no)
+{
+ for (unsigned i = 0; i < m_rows.size(); i++)
+ {
+ if (m_rows[i].row_no == row_no)
+ {
+ return &m_rows[i];
+ }
+ }
+ return 0;
+}
+
+void
+CoordTransTester::do_close()
+{
+ if (1)
+ {
+ BaseString actions;
+ actions.appfmt("%s", m_transid);
+ for (Uint32 i = 0; i < m_actions.size(); i++)
+ {
+ actions.appfmt(" %u", m_actions[i]);
+ }
+ printf("%s\n", actions.c_str());
+ }
+
+ for (Uint32 i = 0; i < m_trans.size(); i++)
+ {
+ if (m_trans[i].m_trans != 0)
+ {
+ m_trans[i].m_trans->close();
+ m_trans[i].m_trans = 0;
+ }
+ }
+
+ m_rows.clear();
+ m_actions.clear();
+}
+
+int
+CoordTransTester::end()
+{
+ do_rollback();
+
+ for (Uint32 i = 0; i < m_trans.size(); i++)
+ {
+ if (m_trans[i].m_ndb != 0)
+ {
+ delete m_trans[i].m_ndb;
+ m_trans[i].m_ndb = 0;
+ }
+ }
+
+ return 0;
+}
+
+int
+CoordTransTester::cleanup()
+{
+ if (m_own_connection)
+ {
+ if (m_cluster_connection != 0)
+ {
+ delete m_cluster_connection;
+ m_cluster_connection = 0;
+ }
+ }
+ return 0;
+}
+
+Uint32
+CoordTransTester::computePossibleActions(Uint32 weights[A_LAST])
+{
+ bzero(weights, sizeof(weights[0]) * A_LAST);
+ Uint32 sum = 0;
+ Uint32 cnt_rw = 0;
+ Uint32 cnt_started = 0;
+ for (Uint32 i = 0; i < m_trans.size(); i++)
+ {
+ if (m_trans[i].m_trans != 0)
+ {
+ cnt_started++;
+ if (m_trans[i].m_simple == false)
+ {
+ cnt_rw++;
+ }
+ }
+ }
+
+ if (cnt_started == 0)
+ {
+ /**
+ * we must start a transaction first
+ */
+ sum += (weights[A_BEGIN] = m_action_pct[A_BEGIN]);
+ return sum;
+ }
+
+ if (cnt_started < m_trans.size())
+ {
+ /**
+ * Not all started....
+ */
+ sum += (weights[A_JOIN] = m_action_pct[A_JOIN]);
+ }
+
+ /**
+ * If we have transaction...we can always commit/rollback...
+ * but it's only interesting if we have performed say 3 steps...
+ */
+ if (m_actions.size() > (1 + m_trans.size()))
+ {
+ /**
+ * Let likelihood of commit/rollback increase when size of trans increase
+ */
+ Uint32 k = 10;
+ Uint32 c = 10 * m_actions.size();
+ Uint32 d = 100;
+ sum += (weights[A_COMMIT] = (k + c * m_action_pct[A_COMMIT]) / d);
+ sum += (weights[A_ROLLBACK] = (k + c * m_action_pct[A_ROLLBACK]) / d);
+ sum += (weights[A_COMMIT_LEAVE] = (k + c * m_action_pct[A_COMMIT_LEAVE])/d);
+ if (cnt_rw > 0)
+ {
+ sum += (weights[A_NF_COMMIT] = (k + c * m_action_pct[A_NF_COMMIT])/d);
+ sum += (weights[A_NF_ROLLBACK] = (k + c * m_action_pct[A_NF_ROLLBACK])/d);
+ }
+ }
+
+ /**
+ * We can "always" try to insert...or lock a random row
+ */
+ sum += (weights[A_INSERT] = m_action_pct[A_INSERT]);
+ sum += (weights[A_LOCK] = m_action_pct[A_LOCK]);
+
+ if (m_rows.size())
+ {
+ sum += (weights[A_UPDATE] = m_action_pct[A_UPDATE]);
+ sum += (weights[A_DELETE] = m_action_pct[A_DELETE]);
+ sum += (weights[A_PKREAD] = m_action_pct[A_PKREAD]);
+ if (m_uk_index != 0)
+ {
+ sum += (weights[A_UKREAD] = m_action_pct[A_UKREAD]);
+ }
+ sum += (weights[A_TABLESCAN] = m_action_pct[A_TABLESCAN]);
+
+ if (m_oi_index != 0)
+ {
+ sum += (weights[A_INDEXSCAN] = m_action_pct[A_INDEXSCAN]);
+ }
+ }
+
+ if (cnt_started > 1)
+ {
+ sum += (weights[A_DISCONNECT] = m_action_pct[A_DISCONNECT]);
+ }
+
+ return sum;
+}
+
+void
+CoordTransTester::fatal(int line)
+{
+ BaseString actions;
+ actions.appfmt("%s", m_transid);
+ for (Uint32 i = 0; i < m_actions.size(); i++)
+ {
+ actions.appfmt(" %u", m_actions[i]);
+ }
+ printf("%s\n", actions.c_str());
+
+ printf(">>>abort line: %u : actions: %s<<<\n",
+ line,
+ actions.c_str());
+ fflush(stdout);
+ abort();
+}
+
+
+int
+runCoordTransBasic(NDBT_Context* ctx, NDBT_Step* step)
+{
+ const int nParticipants = ctx->getProperty("Participants", Uint32(2));
+ const int nThreads = ctx->getNoOfRunningSteps();
+ const int nRecords = ctx->getNumRecords();
+ const int nLoops = ctx->getNumLoops();
+ const int stepNo = step->getStepNo();
+ const unsigned seed = opt_seed + (unsigned)(stepNo * 0x37);
+ const int untilStopped = ctx->getProperty("UNTIL_STOPPED", Uint32(0));
+
+ if (ctx->getProperty("NF_COMMIT_PCT", Uint32(0)) != 0)
+ {
+ NdbRestarter res;
+ if (res.getNumDbNodes() < 2)
+ {
+ return NDBT_OK;
+ }
+ }
+
+ CoordTransTester tester(ctx, seed, nParticipants, nRecords, nThreads);
+ if (tester.setup())
+ {
+ tester.fatal(__LINE__);
+ return NDBT_FAILED;
+ }
+
+ for (int i = 0; (i < nLoops || untilStopped) && !ctx->isTestStopped(); i++)
+ {
+ if (tester.start() != 0)
+ {
+ tester.fatal(__LINE__);
+ return NDBT_FAILED;
+ }
+
+ Uint64 start = NdbTick_CurrentMillisecond();
+ do
+ {
+ if (tester.step() != 0)
+ {
+ tester.fatal(__LINE__);
+ return NDBT_FAILED;
+ }
+ } while (NdbTick_CurrentMillisecond() < (start + 6 * 1000) &&
+ !ctx->isTestStopped());
+
+ if (tester.end() != 0)
+ {
+ tester.fatal(__LINE__);
+ return NDBT_FAILED;
+ }
+ }
+
+ if (tester.cleanup() != 0)
+ {
+ tester.fatal(__LINE__);
+ return NDBT_FAILED;
+ }
+ return NDBT_OK;
+}
+
+int
+runRestarter(NDBT_Context* ctx, NDBT_Step* step)
+{
+ int loops = ctx->getNumLoops();
+ int randnode = ctx->getProperty("RandNode", (unsigned)0);
+ const int stepNo = step->getStepNo();
+ unsigned seed = opt_seed + (unsigned)(stepNo * 0x37);
+ NdbRestarter res;
+
+ if (res.getNumDbNodes() < 2)
+ {
+ ctx->stopTest();
+ return NDBT_OK;
+ }
+
+ if (res.waitClusterStarted() != 0)
+ {
+ g_err << "Cluster failed to start" << endl;
+ return NDBT_FAILED;
+ }
+
+ if (loops < res.getNumDbNodes())
+ {
+ loops = res.getNumDbNodes();
+ }
+
+ for (int i = 0; i < loops && !ctx->isTestStopped(); i++)
+ {
+ int id = i % res.getNumDbNodes();
+ if (randnode == 1)
+ {
+ id = ndb_rand_r(&seed) % res.getNumDbNodes();
+ }
+ int nodeId = res.getDbNodeId(id);
+ ndbout << "Restart node " << nodeId << endl;
+ if (res.restartOneDbNode(nodeId, false, true, true) != 0)
+ {
+ g_err << "Failed to restartNextDbNode" << endl;
+ return NDBT_FAILED;
+ }
+
+ if (res.waitNodesNoStart(&nodeId, 1))
+ {
+ g_err << "Failed to waitNodesNoStart" << endl;
+ return NDBT_FAILED;
+ }
+
+ if (res.startNodes(&nodeId, 1))
+ {
+ g_err << "Failed to start node" << endl;
+ return NDBT_FAILED;
+ }
+
+ if(res.waitClusterStarted() != 0)
+ {
+ g_err << "Cluster failed to start" << endl;
+ return NDBT_FAILED;
+ }
+ }
+
+ ctx->stopTest();
+
+ return NDBT_OK;
+}
+
+NDBT_TESTSUITE(testCoordTrans);
+TESTCASE("Basic","")
+{
+ INITIALIZER(runRandLoadTable);
+ STEP(runCoordTransBasic);
+}
+TESTCASE("Multi","")
+{
+ INITIALIZER(runRandLoadTable);
+ STEPS(runCoordTransBasic, 15);
+}
+TESTCASE("BasicAndDisconnect","")
+{
+ TC_PROPERTY("OwnConnection", 1);
+ INITIALIZER(runRandLoadTable);
+ STEPS(runCoordTransBasic, 2); // only 3 default configured api-slots...
+}
+TESTCASE("BasicAndNF","")
+{
+ TC_PROPERTY("COMMIT_PCT", Uint32(0));
+ TC_PROPERTY("ROLLBACK_PCT", Uint32(0));
+ TC_PROPERTY("COMMIT_LEAVE_PCT", Uint32(0));
+ TC_PROPERTY("NF_COMMIT_PCT", 5);
+ TC_PROPERTY("NF_ROLLBACK_PCT", 5);
+ INITIALIZER(runRandLoadTable);
+ STEPS(runCoordTransBasic, 1);
+}
+TESTCASE("MultiNF","")
+{
+ TC_PROPERTY("UNTIL_STOPPED", Uint32(1));
+ INITIALIZER(runRandLoadTable);
+ STEPS(runCoordTransBasic, 10);
+ STEP(runRestarter);
+}
+NDBT_TESTSUITE_END(testCoordTrans);
+
+int
+main(int argc, const char** argv)
+{
+ ndb_init();
+ NDBT_TESTSUITE_INSTANCE(testCoordTrans);
+ return testCoordTrans.execute(argc, argv);
+}
+
+template class Vector<CoordTransTester::Participant>;
+template class Vector<CoordTransTester::Row>;
No bundle (reason: useless for push emails).
| Thread |
|---|
| • bzr push into mysql-5.1-telco-7.0-coord branch (jonas.oreland:4963 to 4964) | Jonas Oreland | 13 Sep |