From: Martin Zaun Date: October 8 2010 4:23am Subject: bzr commit into mysql-5.1-telco-7.1 branch (martin.zaun:3862) List-Archive: http://lists.mysql.com/commits/120337 Message-Id: <201010080424.o984M6tu021013@rcsinet13.oracle.com> MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="===============2000210230==" --===============2000210230== MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Content-Disposition: inline #At file:///Users/mz/mysql/ndb-7.1-opt64/ based on revid:martin.zaun@stripped 3862 Martin Zaun 2010-10-07 crund - added c++/ndbapi TWS benchmark. added: storage/ndb/test/crund/tws/ storage/ndb/test/crund/tws/run.properties.sample storage/ndb/test/crund/tws/tws_cpp/ storage/ndb/test/crund/tws/tws_cpp/README.txt storage/ndb/test/crund/tws/tws_cpp/TwsDriver.cpp === added directory 'storage/ndb/test/crund/tws' === added file 'storage/ndb/test/crund/tws/run.properties.sample' --- a/storage/ndb/test/crund/tws/run.properties.sample 1970-01-01 00:00:00 +0000 +++ b/storage/ndb/test/crund/tws/run.properties.sample 2010-10-08 04:23:30 +0000 @@ -0,0 +1,76 @@ +# benchmark settings +doJdbc=true +doClusterj=true +doNdbjtie=true +doInsert=true +doLookup=true +doUpdate=true +doDelete=true +doSingle=true +doBulk=true +doBatch=true + +# lock mode for lookup and read scans +lockMode=READ_COMMITTED +#lockMode=SHARED +#lockMode=EXCLUSIVE, + +# nRows >= 40000 +# jdbc bulk: 1217 'Out of operation records in local data manager +# (increase MaxNoOfLocalOperations)' from NDBCLUSTER +# +# nRows >= 500 +# "Job buffer congestion" crashes with node failure with unique indexes +# http://bugs.mysql.com/bug.php?id=56552 +# ndbjtie batch: ndb-7.1.8 revno 3782 crashes with node failure during +# clusterj single/bulk: ndb-7.1.8 revno 3782 crashes with node failure during +#nRows=16000 +#nRows=4000 +nRows=1000 +#nRows=500 +#nRows=250 +#nRows=10 + +#warmupRuns=1000 +#warmupRuns=100 +#warmupRuns=10 +#warmupRuns=1 +warmupRuns=0 + +#hotRuns=10000 +#hotRuns=1000 +#hotRuns=100 +#hotRuns=10 +hotRuns=1 + +# NDBAPI connection settings +ndb.mgmdConnect=localhost +ndb.catalog=testdb +ndb.schema=def + +# JDBC - MySQL settings +jdbc.url=jdbc:mysql://localhost/testdb +jdbc.driver=com.mysql.jdbc.Driver +jdbc.user=root +jdbc.password= + +# ClusterJ settings +com.mysql.clusterj.connectstring=localhost:1186 +com.mysql.clusterj.database=testdb +com.mysql.clusterj.connect.retries=4 +com.mysql.clusterj.connect.delay=5 +com.mysql.clusterj.connect.verbose=1 +com.mysql.clusterj.connect.timeout.before=30 +com.mysql.clusterj.connect.timeout.after=20 +com.mysql.clusterj.max.transactions=1024 + +com.mysql.clusterj.bindings.level=INFO +com.mysql.clusterj.core.level=INFO +com.mysql.clusterj.core.metadata.level=INFO +com.mysql.clusterj.core.query.level=INFO +com.mysql.clusterj.core.util.level=INFO +com.mysql.clusterj.tie.level=INFO +#handlers=java.util.logging.FileHandler +#java.util.logging.FileHandler.formatter=java.util.logging.SimpleFormatter +#java.util.logging.FileHandler.level=FINEST +#java.util.logging.FileHandler.pattern=./target/log%u \ No newline at end of file === added directory 'storage/ndb/test/crund/tws/tws_cpp' === added file 'storage/ndb/test/crund/tws/tws_cpp/README.txt' --- a/storage/ndb/test/crund/tws/tws_cpp/README.txt 1970-01-01 00:00:00 +0000 +++ b/storage/ndb/test/crund/tws/tws_cpp/README.txt 2010-10-08 04:23:30 +0000 @@ -0,0 +1,52 @@ + +How to Build and Run the NDB API TWS Benchmark +---------------------------------------------- + +This benchmark is built with +-> Gnu 'make' (using generic, hand-coded Makefiles) +-> Gnu g++ (or Solaris Studio CC as compilers) + +0) Configure external dependencies + + Edit the file + ../../env.properties + + and configure these five properties (shared with CRUND): + + MYSQL_HOME=${HOME}/mysql/bin-7.1-opt32 + TARGET_ARCH=-m32 + + NDB_INCLUDEOPT0=-I${MYSQL_HOME}/include/mysql/storage/ndb + NDB_INCLUDEOPT1=-I${MYSQL_HOME}/include/mysql/storage/ndb/ndbapi + NDB_LIBDIR=${MYSQL_HOME}/lib/mysql + + Important: TARGET_ARCH must match the MYSQL_HOME binaries. + +1) Build the binary + + Run once to build the include dependencies: + $ make dep + + Build either a Release or Debug binary: + $ make opt + $ make dbg + + For a list of available targets: + $ make help + +2) Run the benchmark + + Edit the benchmark's settings (copy from ../run.properties.sample) + ../run.properties + + Have a running NDB Cluster with loaded schema file: ../schema.sql. + + Run the benchmark: + $ make run.driver + or + $ ./TwsDriver -p ../run.properties + + The benchmark's result data is written to a generated log_XXX file. + +Comments or questions appreciated. +martin.zaun@stripped === added file 'storage/ndb/test/crund/tws/tws_cpp/TwsDriver.cpp' --- a/storage/ndb/test/crund/tws/tws_cpp/TwsDriver.cpp 1970-01-01 00:00:00 +0000 +++ b/storage/ndb/test/crund/tws/tws_cpp/TwsDriver.cpp 2010-10-08 04:23:30 +0000 @@ -0,0 +1,1611 @@ +/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil; -*- + * vim:expandtab:shiftwidth=4:tabstop=4:smarttab: + * + * Copyright (C) 2010 MySQL + * + * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + +#include "helpers.hpp" +#include "string_helpers.hpp" +#include "Properties.hpp" + +using std::cout; +using std::flush; +using std::endl; +using std::ios_base; +using std::string; +using std::wstring; +using std::vector; +using std::ofstream; +using std::ostringstream; + +using utils::Properties; +using utils::toBool; +using utils::toInt; +using utils::toString; + +// --------------------------------------------------------------------------- + +class Driver { +public: + + /** + * Parses the benchmark's command-line arguments. + */ + static void parseArguments(int argc, const char* argv[]); + + /** + * Creates an instance. + */ + Driver() {} + + /** + * Deletes an instance. + */ + virtual ~Driver() {} + + /** + * Runs the benchmark. + */ + void run(); + +protected: + + // command-line arguments + static vector< string > propFileNames; + static string logFileName; + + static void exitUsage(); + + // driver settings + Properties props; + bool renewConnection; + int warmupRuns; + int hotRuns; + + // driver resources + ofstream log; + string descr; + bool logHeader; + ostringstream header; + ostringstream rtimes; + struct timeval t0, t1; + long rta; + + // driver intializers/finalizers + virtual void init(); + virtual void close(); + virtual void loadProperties(); + virtual void initProperties(); + virtual void printProperties(); + virtual void openLogFile(); + virtual void closeLogFile(); + + // benchmark operations + virtual void runTests() = 0; + virtual void begin(const string& name); + virtual void commit(const string& name); + + // datastore operations + virtual void initConnection() = 0; + virtual void closeConnection() = 0; + //virtual void clearPersistenceContext() = 0; // not used + //virtual void clearData() = 0; // not used +}; + +// --------------------------------------------------------------------------- + +class TwsDriver : public Driver { +protected: + + // benchmark settings + enum LockMode { READ_COMMITTED, SHARED, EXCLUSIVE }; + static const char* toStr(LockMode mode); + enum XMode { SINGLE, BULK, BATCH }; + static const char* toStr(XMode mode); + bool doInsert; + bool doLookup; + bool doUpdate; + bool doDelete; + bool doSingle; + bool doBulk; + bool doBatch; + bool doVerify; + LockMode lockMode; + int nRows; + + // benchmark intializers/finalizers + virtual void initProperties(); + virtual void printProperties(); + + // benchmark operations + virtual void runTests(); + virtual void runLoads(); + virtual void runOperations() = 0; + void verify(Int32 exp, Int32 act); + void verify(const char* exp, const char* act); +}; + +// --------------------------------------------------------------------------- + +struct NdbApiTwsModel { + const NdbDictionary::Table* table_t0; + const NdbDictionary::Column* column_c0; + const NdbDictionary::Column* column_c1; + const NdbDictionary::Column* column_c2; + const NdbDictionary::Column* column_c3; + const NdbDictionary::Column* column_c4; + const NdbDictionary::Column* column_c5; + const NdbDictionary::Column* column_c6; + const NdbDictionary::Column* column_c7; + const NdbDictionary::Column* column_c8; + const NdbDictionary::Column* column_c9; + const NdbDictionary::Column* column_c10; + const NdbDictionary::Column* column_c11; + const NdbDictionary::Column* column_c12; + const NdbDictionary::Column* column_c13; + const NdbDictionary::Column* column_c14; + + int attr_c0; + int attr_c1; + int attr_c2; + int attr_c3; + int attr_c4; + int attr_c5; + int attr_c6; + int attr_c7; + int attr_c8; + int attr_c9; + int attr_c10; + int attr_c11; + int attr_c12; + int attr_c13; + int attr_c14; + + int width_c0; + int width_c1; + int width_c2; + int width_c3; + int width_c4; + int width_c5; + int width_c6; + int width_c7; + int width_c8; + int width_c9; + int width_c10; + int width_c11; + int width_c12; + int width_c13; + int width_c14; + int width_row; // sum of {width_c0 .. width_c14} + static const int nCols = 15; + + NdbApiTwsModel(Ndb* ndb); + + ~NdbApiTwsModel() {} + + static int columnWidth(const NdbDictionary::Column* c) { + int s = c->getSize(); // size of type or of base type + int al = c->getLength(); // length or max length, 1 for scalars + int at = c->getArrayType(); // size of length prefix, practically + return (s * al) + at; + } + +private: + + NdbApiTwsModel(const NdbApiTwsModel&); + NdbApiTwsModel& operator=(const NdbApiTwsModel&); +}; + +class NdbApiTwsDriver : public TwsDriver { +public: + + NdbApiTwsDriver() + : mgmd(NULL), ndb(NULL), tx(NULL), model(NULL), bb(NULL), ra(NULL) { + } + + ~NdbApiTwsDriver() { + assert(mgmd == NULL); assert(ndb == NULL); assert(tx == NULL); + assert(model == NULL); assert(bb == NULL); assert(ra == NULL); + } + +private: + + NdbApiTwsDriver(const NdbApiTwsDriver&); + NdbApiTwsDriver& operator=(const NdbApiTwsDriver&); + +protected: + + // NDB API settings + string mgmdConnect; + string catalog; + string schema; + + // NDB API resources + Ndb_cluster_connection* mgmd; + Ndb* ndb; + NdbTransaction* tx; + NdbOperation::LockMode ndbOpLockMode; + + // NDB Api metadata resources + NdbApiTwsModel* model; + + // NDB Api data resources + char* bb; + char* bb_pos; + NdbRecAttr** ra; + NdbRecAttr** ra_pos; + + // NDB API intializers/finalizers + virtual void initProperties(); + virtual void printProperties(); + virtual void init(); + virtual void close(); + void initNdbapiBuffers(); + void closeNdbapiBuffers(); + + // NDB API operations + virtual void runOperations(); + void runNdbapiInsert(XMode mode); + void ndbapiInsert(int c0); + void runNdbapiLookup(XMode mode); + void ndbapiLookup(int c0); + void ndbapiRead(int c0); + void runNdbapiUpdate(XMode mode); + void ndbapiUpdate(int c0); + void runNdbapiDelete(XMode mode); + void ndbapiDelete(int c0); + void ndbapiBeginTransaction(); + void ndbapiExecuteTransaction(); + void ndbapiCommitTransaction(); + void ndbapiRollbackTransaction(); + void ndbapiCloseTransaction(); + static void ndbapiToBuffer1blp(void* to, const char* from, size_t width); + static void ndbapiToString1blp(char* to, const void* from, size_t width); + + // NDB API datastore operations + virtual void initConnection(); + virtual void closeConnection(); + //virtual void clearPersistenceContext(); // not used + //virtual void clearData(); // not used +}; + +// --------------------------------------------------------------------------- +// Helper Macros & Functions +// --------------------------------------------------------------------------- + +// This benchmark's error handling of NDBAPI calls is rigorous but crude: +// - all calls' return value is checked for errors +// - all errors are reported and then followed by a process exit +#define ABORT_NDB_ERROR(error) \ + do { cout << "!!! error in " << __FILE__ << ", line: " << __LINE__ \ + << ", code: " << (int)(error).code \ + << ", msg: " << (error).message << "." << endl; \ + exit(-1); \ + } while (0) + +#define ABORT_GETTIMEOFDAY_ERROR() \ + do { cout << "!!! error in " << __FILE__ << ", line: " << __LINE__ \ + << ", gettimeofday() returned an error code." << endl; \ + exit(-1); \ + } while (0) + +#define ABORT_VERIFICATION_ERROR() \ + do { cout << "!!! error in " << __FILE__ << ", line: " << __LINE__ \ + << ", failed data verification." << endl; \ + exit(-1); \ + } while (0) + +// --------------------------------------------------------------------------- +// Driver Implementation +// --------------------------------------------------------------------------- + +vector< string > Driver::propFileNames; +string Driver::logFileName; + +void +Driver::exitUsage() +{ + cout << "usage: [options]" << endl + << " [-p ]... properties file name" << endl + << " [-l ] log file name for data output" << endl + << " [-h|--help] print usage message and exit" << endl + << endl; + exit(1); // return an error code +} + +void +Driver::parseArguments(int argc, const char* argv[]) +{ + for (int i = 1; i < argc; i++) { + const string arg = argv[i]; + if (arg.compare("-p") == 0) { + if (i >= argc) { + exitUsage(); + } + propFileNames.push_back(argv[++i]); + } else if (arg.compare("-l") == 0) { + if (i >= argc) { + exitUsage(); + } + logFileName = argv[++i]; + } else if (arg.compare("-h") == 0 || arg.compare("--help") == 0) { + exitUsage(); + } else { + cout << "unknown option: " << arg << endl; + exitUsage(); + } + } + + if (propFileNames.size() == 0) { + propFileNames.push_back("run.properties"); + } + + if (logFileName.empty()) { + logFileName = "log_"; + + // format, destination strings (static size) + const char format[] = "%Y%m%d_%H%M%S"; + const int size = sizeof("yyyymmdd_HHMMSS"); + char dest[size]; + + // get time, convert to timeinfo (statically allocated) then to string + const time_t now = time(0); + const int nchars = strftime(dest, size, format, localtime(&now)); + assert(nchars == size-1); + (void)nchars; + + logFileName += dest; + logFileName += ".txt"; + } + //cout << "logFileName='" << logFileName << "'" << endl; +} + +// ---------------------------------------------------------------------- + +void +Driver::run() { + init(); + + if (warmupRuns > 0) { + cout << endl + << "++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++" << endl + << "warmup runs ..." << endl + << "++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++" << endl; + + for (int i = 0; i < warmupRuns; i++) { + runTests(); + } + + // truncate log file, reset log buffers + closeLogFile(); + openLogFile(); + header.rdbuf()->str(""); + rtimes.rdbuf()->str(""); + } + + if (hotRuns > 0) { + cout << endl + << "++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++" << endl + << "hot runs ..." << endl + << "++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++" << endl; + + for (int i = 0; i < hotRuns; i++) { + runTests(); + } + + // write log buffers + log << descr << ", rtime[ms]" + << header.rdbuf()->str() << endl + << rtimes.rdbuf()->str() << endl << endl << endl; + } + + close(); +} + +void +Driver::init() { + loadProperties(); + initProperties(); + printProperties(); + openLogFile(); + + // clear log buffers + logHeader = true; + header.rdbuf()->str(""); + rtimes.rdbuf()->str(""); +} + +void +Driver::close() { + // clear log buffers + header.rdbuf()->str(""); + rtimes.rdbuf()->str(""); + + closeLogFile(); +} + +void +Driver::loadProperties() { + cout << endl; + for (vector::const_iterator i = propFileNames.begin(); + i != propFileNames.end(); ++i) { + cout << "reading properties file: " << *i << endl; + props.load(i->c_str()); + //cout << "props = {" << endl << props << "}" << endl; + } +} + +void +Driver::initProperties() { + cout << "setting driver properties ..." << flush; + + ostringstream msg; + + renewConnection = toBool(props[L"renewConnection"], false); + + warmupRuns = toInt(props[L"warmupRuns"], 0, -1); + if (warmupRuns < 0) { + msg << "[ignored] warmupRuns: '" + << toString(props[L"warmupRuns"]) << "'" << endl; + warmupRuns = 0; + } + + hotRuns = toInt(props[L"hotRuns"], 1, -1); + if (hotRuns < 0) { + msg << "[ignored] hotRuns: '" + << toString(props[L"hotRuns"]) << "'" << endl; + hotRuns = 1; + } + + //if (msg.tellp() == 0) // netbeans reports amibuities + if (msg.str().empty()) { + cout << " [ok]" << endl; + } else { + cout << endl << msg.str() << endl; + } +} + +void +Driver::printProperties() { + const ios_base::fmtflags f = cout.flags(); + // no effect calling manipulator function, not sure why + //cout << ios_base::boolalpha; + cout.flags(ios_base::boolalpha); + + cout << endl << "driver settings ..." << endl; + cout << "renewConnection: " << renewConnection << endl; + cout << "warmupRuns: " << warmupRuns << endl; + cout << "hotRuns: " << hotRuns << endl; + + cout.flags(f); +} + +void +Driver::openLogFile() { + cout << endl + << "opening results file:" << flush; + log.open(logFileName.c_str(), ios_base::out | ios_base::trunc); + assert(log.good()); + cout << " [ok: " << logFileName << "]" << endl; +} + +void +Driver::closeLogFile() { + cout << endl + << "closing results file:" << flush; + log.close(); + cout << " [ok: " << logFileName << "]" << endl; +} + +// --------------------------------------------------------------------------- + +void +Driver::begin(const string& name) { + cout << endl; + cout << name << endl; + + if (gettimeofday(&t0, NULL) != 0) + ABORT_GETTIMEOFDAY_ERROR(); +} + +void +Driver::commit(const string& name) { + if (gettimeofday(&t1, NULL) != 0) + ABORT_GETTIMEOFDAY_ERROR(); + + const long r_usec = (((t1.tv_sec - t0.tv_sec) * 1000000) + + (t1.tv_usec - t0.tv_usec)); + const long r_msec = r_usec / 1000; + + cout << "tx real time: " << r_msec + << "\tms" << endl; + rtimes << "\t" << r_msec; + rta += r_msec; + + if (logHeader) + header << "\t" << name; +} + +// --------------------------------------------------------------------------- +// TwsDriver Implementation +// --------------------------------------------------------------------------- + +void +TwsDriver::initProperties() { + Driver::initProperties(); + + cout << "setting tws properties ..." << flush; + + ostringstream msg; + + doInsert = toBool(props[L"doInsert"], true); + doLookup = toBool(props[L"doLookup"], true); + doUpdate = toBool(props[L"doUpdate"], true); + doDelete = toBool(props[L"doDelete"], true); + doSingle = toBool(props[L"doSingle"], true); + doBulk = toBool(props[L"doBulk"], true); + doBatch = toBool(props[L"doBatch"], true); + doVerify = toBool(props[L"doVerify"], true); + + string lm = toString(props[L"lockMode"]); + if (lm.empty()) { + lockMode = READ_COMMITTED; + } else if (lm.compare("READ_COMMITTED") == 0) { + lockMode = READ_COMMITTED; + } else if (lm.compare("SHARED") == 0) { + lockMode = SHARED; + } else if (lm.compare("EXCLUSIVE") == 0) { + lockMode = EXCLUSIVE; + } else { + msg << "[ignored] lockMode: '" << lm << "'" << endl; + lockMode = READ_COMMITTED; + } + + nRows = toInt(props[L"nRows"], 256, 0); + if (nRows < 1) { + msg << "[ignored] nRows: '" + << toString(props[L"nRows"]) << "'" << endl; + nRows = 256; + } + + //if (msg.tellp() == 0) // netbeans reports amibuities + if (msg.str().empty()) { + cout << " [ok]" << endl; + } else { + cout << endl << msg.str() << endl; + } +} + +void +TwsDriver::printProperties() { + Driver::printProperties(); + + const ios_base::fmtflags f = cout.flags(); + // no effect calling manipulator function, not sure why + //cout << ios_base::boolalpha; + cout.flags(ios_base::boolalpha); + + cout << endl << "tws settings..." << endl; + cout << "doInsert: " << doInsert << endl; + cout << "doLookup: " << doLookup << endl; + cout << "doUpdate: " << doUpdate << endl; + cout << "doDelete: " << doDelete << endl; + cout << "doSingle: " << doSingle << endl; + cout << "doBulk: " << doBulk << endl; + cout << "doBatch: " << doBatch << endl; + cout << "doVerify: " << doVerify << endl; + cout << "lockMode: " << toStr(lockMode) << endl; + cout << "nRows: " << nRows << endl; + + cout.flags(f); +} + +// ---------------------------------------------------------------------- + +void +TwsDriver::runTests() { + //initConnection(); + + //assert(rStart <= rEnd && rScale > 1); + //for (int i = rStart; i <= rEnd; i *= rScale) + runLoads(); + + //closeConnection(); +} + +void +TwsDriver::runLoads() { + // log buffers + rtimes << "nRows=" << nRows; + rta = 0L; + + // pre-run cleanup + if (renewConnection) { + closeConnection(); + initConnection(); + } + //clearData(); // not used + + runOperations(); + + cout << endl + << "total" << endl; + cout << "tx real time " << rta + << "\tms" << endl; + + // log buffers + if (logHeader) { + header << "\ttotal"; + logHeader = false; + } + rtimes << "\t" << rta << endl; + + cout << endl + << "------------------------------------------------------------" << endl; +} + +void +TwsDriver::verify(Int32 exp, Int32 act) { + if (doVerify) { + //cout << "XXX exp=" << exp << ", act=" << act << endl; + if (exp != act) { + ABORT_VERIFICATION_ERROR(); + } + } +} + +void +TwsDriver::verify(const char* exp, const char* act) { + if (doVerify) { + //cout << "XXX exp='" << exp << "', act='" << act << "'" << endl; + if (strcmp(exp, act) != 0) { + ABORT_VERIFICATION_ERROR(); + } + } +} + +const char* +TwsDriver::toStr(XMode mode) { + switch (mode) { + case SINGLE: + return "single"; + case BULK: + return "bulk"; + case BATCH: + return "batch"; + default: + assert(false); + return NULL; + }; +} + +const char* +TwsDriver::toStr(LockMode mode) { + switch (mode) { + case SINGLE: + return "READ_COMMITTED"; + case BULK: + return "bulk"; + case BATCH: + return "batch"; + default: + assert(false); + return NULL; + }; +} + +// --------------------------------------------------------------------------- +// NDB API Model Implementation +// --------------------------------------------------------------------------- + +NdbApiTwsModel::NdbApiTwsModel(Ndb* ndb) { + const NdbDictionary::Dictionary* dict = ndb->getDictionary(); + + // get table T0 + if ((table_t0 = dict->getTable("mytable")) == NULL) + ABORT_NDB_ERROR(dict->getNdbError()); + + // get columns of table T0 + if ((column_c0 = table_t0->getColumn("c0")) == NULL) + ABORT_NDB_ERROR(dict->getNdbError()); + if ((column_c1 = table_t0->getColumn("c1")) == NULL) + ABORT_NDB_ERROR(dict->getNdbError()); + if ((column_c2 = table_t0->getColumn("c2")) == NULL) + ABORT_NDB_ERROR(dict->getNdbError()); + if ((column_c3 = table_t0->getColumn("c3")) == NULL) + ABORT_NDB_ERROR(dict->getNdbError()); + if ((column_c4 = table_t0->getColumn("c4")) == NULL) + ABORT_NDB_ERROR(dict->getNdbError()); + if ((column_c5 = table_t0->getColumn("c5")) == NULL) + ABORT_NDB_ERROR(dict->getNdbError()); + if ((column_c6 = table_t0->getColumn("c6")) == NULL) + ABORT_NDB_ERROR(dict->getNdbError()); + if ((column_c7 = table_t0->getColumn("c7")) == NULL) + ABORT_NDB_ERROR(dict->getNdbError()); + if ((column_c8 = table_t0->getColumn("c8")) == NULL) + ABORT_NDB_ERROR(dict->getNdbError()); + if ((column_c9 = table_t0->getColumn("c9")) == NULL) + ABORT_NDB_ERROR(dict->getNdbError()); + if ((column_c10 = table_t0->getColumn("c10")) == NULL) + ABORT_NDB_ERROR(dict->getNdbError()); + if ((column_c11 = table_t0->getColumn("c11")) == NULL) + ABORT_NDB_ERROR(dict->getNdbError()); + if ((column_c12 = table_t0->getColumn("c12")) == NULL) + ABORT_NDB_ERROR(dict->getNdbError()); + if ((column_c13 = table_t0->getColumn("c13")) == NULL) + ABORT_NDB_ERROR(dict->getNdbError()); + if ((column_c14 = table_t0->getColumn("c14")) == NULL) + ABORT_NDB_ERROR(dict->getNdbError()); + + // get attribute ids for columns of table T0 + attr_c0 = column_c0->getAttrId(); + attr_c1 = column_c1->getAttrId(); + attr_c2 = column_c2->getAttrId(); + attr_c3 = column_c3->getAttrId(); + attr_c4 = column_c4->getAttrId(); + attr_c5 = column_c5->getAttrId(); + attr_c6 = column_c6->getAttrId(); + attr_c7 = column_c7->getAttrId(); + attr_c8 = column_c8->getAttrId(); + attr_c9 = column_c9->getAttrId(); + attr_c10 = column_c10->getAttrId(); + attr_c11 = column_c11->getAttrId(); + attr_c12 = column_c12->getAttrId(); + attr_c13 = column_c13->getAttrId(); + attr_c14 = column_c14->getAttrId(); + + width_c0 = columnWidth(column_c0); + width_c1 = columnWidth(column_c1); + width_c2 = columnWidth(column_c2); + width_c3 = columnWidth(column_c3); + width_c4 = columnWidth(column_c4); + width_c5 = columnWidth(column_c5); + width_c6 = columnWidth(column_c6); + width_c7 = columnWidth(column_c7); + width_c8 = columnWidth(column_c8); + width_c9 = columnWidth(column_c9); + width_c10 = columnWidth(column_c10); + width_c11 = columnWidth(column_c11); + width_c12 = columnWidth(column_c12); + width_c13 = columnWidth(column_c13); + width_c14 = columnWidth(column_c14); + + width_row = ( + + width_c0 + + width_c1 + + width_c2 + + width_c3 + + width_c4 + + width_c5 + + width_c6 + + width_c7 + + width_c8 + + width_c9 + + width_c10 + + width_c11 + + width_c12 + + width_c13 + + width_c14); +} + +// --------------------------------------------------------------------------- +// NdbApiTwsDriver Implementation +// --------------------------------------------------------------------------- + +void +NdbApiTwsDriver::init() { + TwsDriver::init(); + + // ndb_init must be called first + cout << endl + << "initializing NDBAPI ..." << flush; + int stat = ndb_init(); + if (stat != 0) + ABORT_ERROR("ndb_init() returned: " << stat); + cout << " [ok]" << endl; + + initConnection(); +} + +void +NdbApiTwsDriver::close() { + closeConnection(); + + // ndb_close must be called last + cout << "closing NDBAPI ... " << flush; + ndb_end(0); + cout << " [ok]" << endl; + + TwsDriver::close(); +} + +void +NdbApiTwsDriver::initProperties() { + TwsDriver::initProperties(); + + cout << "setting ndb properties ..." << flush; + + ostringstream msg; + + mgmdConnect = toString(props[L"ndb.mgmdConnect"]); + if (mgmdConnect.empty()) { + mgmdConnect = string("localhost"); + } + + catalog = toString(props[L"ndb.catalog"]); + if (catalog.empty()) { + catalog = string("testdb"); + } + + schema = toString(props[L"ndb.schema"]); + if (schema.empty()) { + schema = string("def"); + } + + //if (msg.tellp() == 0) { + if (msg.str().empty()) { + cout << " [ok]" << endl; + } else { + cout << endl << msg.str() << endl; + } + + descr = "ndbapi(" + mgmdConnect + ")"; +} + +void +NdbApiTwsDriver::printProperties() { + TwsDriver::printProperties(); + + const ios_base::fmtflags f = cout.flags(); + // no effect calling manipulator function, not sure why + //cout << ios_base::boolalpha; + cout.flags(ios_base::boolalpha); + + cout << endl << "ndb settings ..." << endl; + cout << "ndb.mgmdConnect: \"" << mgmdConnect << "\"" << endl; + cout << "ndb.catalog: \"" << catalog << "\"" << endl; + cout << "ndb.schema: \"" << schema << "\"" << endl; + + cout.flags(f); +} + +void +NdbApiTwsDriver::initNdbapiBuffers() { + assert(model->column_c0 != NULL); + assert(bb == NULL); + assert(ra == NULL); + + cout << "allocating ndbapi buffers ..." << flush; + bb = new char[model->width_row * nRows]; + ra = new NdbRecAttr*[model->nCols * nRows]; + cout << " [ok]" << endl; +} + +void +NdbApiTwsDriver::closeNdbapiBuffers() { + assert(bb != NULL); + assert(ra != NULL); + + cout << "releasing ndbapi buffers ..." << flush; + delete[] ra; + ra = NULL; + delete[] bb; + bb = NULL; + cout << " [ok]" << endl; +} + +// --------------------------------------------------------------------------- + +void +NdbApiTwsDriver::runOperations() { + cout << endl + << "running NDB API operations ..." << " [nRows=" << nRows << "]" + << endl; + + if (doSingle) { + if (doInsert) runNdbapiInsert(SINGLE); + if (doLookup) runNdbapiLookup(SINGLE); + if (doUpdate) runNdbapiUpdate(SINGLE); + if (doDelete) runNdbapiDelete(SINGLE); + } + if (doBulk) { + if (doInsert) runNdbapiInsert(BULK); + if (doLookup) runNdbapiLookup(BULK); + if (doUpdate) runNdbapiUpdate(BULK); + if (doDelete) runNdbapiDelete(BULK); + } + if (doBatch) { + if (doInsert) runNdbapiInsert(BATCH); + if (doLookup) runNdbapiLookup(BATCH); + if (doUpdate) runNdbapiUpdate(BATCH); + if (doDelete) runNdbapiDelete(BATCH); + } +} + +// Alternative Implementation: +// The recurring pattern of runNdbapiXXX(XMode mode) can be parametrized +// over the operation, for instance, by a member function template: +// +// template< XMode M, void (NdbApiTwsDriver::*OP)(int) > +// void runOp(string name); +// +// which tests the template parameter XMode and calls the operation +// ... +// if (M == SINGLE) { +// ... (this->*OP)(i); ... +// } +// ... +// while the caller selects the mode and function to be invoked +// ... +// switch (mode) { +// case SINGLE: +// runOp< SINGLE, &NdbApiTwsDriver::ndbapiInsert >(name); +// }... +// Alas, it turns out not worth it in terms of readability and lines of code. + +void +NdbApiTwsDriver::runNdbapiInsert(XMode mode) { + const string name = string("insert_") + toStr(mode); + begin(name); + + if (mode == SINGLE) { + for(int i = 0; i < nRows; i++) { + ndbapiBeginTransaction(); + ndbapiInsert(i); + ndbapiCommitTransaction(); + ndbapiCloseTransaction(); + } + } else { + ndbapiBeginTransaction(); + for(int i = 0; i < nRows; i++) { + ndbapiInsert(i); + if (mode == BULK) + ndbapiExecuteTransaction(); + } + ndbapiCommitTransaction(); + ndbapiCloseTransaction(); + } + + commit(name); +} + +void +NdbApiTwsDriver::ndbapiInsert(int c0) { + // get an insert operation for the table + NdbOperation* op = tx->getNdbOperation(model->table_t0); + if (op == NULL) + ABORT_NDB_ERROR(tx->getNdbError()); + if (op->insertTuple() != 0) + ABORT_NDB_ERROR(tx->getNdbError()); + + // values + Uint32 i = c0; + const int maxlen = 256; + char str[maxlen]; + snprintf(str, maxlen, "%d", i); + + // set values; key attribute needs to be set first + ndbapiToBuffer1blp(bb_pos, str, model->width_c0); + if (op->equal(model->attr_c0, bb_pos) != 0) // key + ABORT_NDB_ERROR(tx->getNdbError()); + bb_pos += model->width_c0; + + ndbapiToBuffer1blp(bb_pos, str, model->width_c1); + if (op->setValue(model->attr_c1, bb_pos) != 0) + ABORT_NDB_ERROR(tx->getNdbError()); + bb_pos += model->width_c1; + + if (op->setValue(model->attr_c2, i) != 0) + ABORT_NDB_ERROR(tx->getNdbError()); + bb_pos += model->width_c2; + + if (op->setValue(model->attr_c3, i) != 0) + ABORT_NDB_ERROR(tx->getNdbError()); + bb_pos += model->width_c3; + + if (op->setValue(model->attr_c4, (char*)NULL) != 0) + ABORT_NDB_ERROR(tx->getNdbError()); + bb_pos += model->width_c4; + + ndbapiToBuffer1blp(bb_pos, str, model->width_c5); + if (op->setValue(model->attr_c5, bb_pos) != 0) + ABORT_NDB_ERROR(tx->getNdbError()); + bb_pos += model->width_c5; + + ndbapiToBuffer1blp(bb_pos, str, model->width_c6); + if (op->setValue(model->attr_c6, bb_pos) != 0) + ABORT_NDB_ERROR(tx->getNdbError()); + bb_pos += model->width_c6; + + ndbapiToBuffer1blp(bb_pos, str, model->width_c7); + if (op->setValue(model->attr_c7, bb_pos) != 0) + ABORT_NDB_ERROR(tx->getNdbError()); + bb_pos += model->width_c7; + + ndbapiToBuffer1blp(bb_pos, str, model->width_c8); + if (op->setValue(model->attr_c8, bb_pos) != 0) + ABORT_NDB_ERROR(tx->getNdbError()); + bb_pos += model->width_c8; + + if (op->setValue(model->attr_c9, (char*)NULL) != 0) + ABORT_NDB_ERROR(tx->getNdbError()); + bb_pos += model->width_c9; + + if (op->setValue(model->attr_c10, (char*)NULL) != 0) + ABORT_NDB_ERROR(tx->getNdbError()); + bb_pos += model->width_c10; + + if (op->setValue(model->attr_c11, (char*)NULL) != 0) + ABORT_NDB_ERROR(tx->getNdbError()); + bb_pos += model->width_c11; + + if (op->setValue(model->attr_c12, (char*)NULL) != 0) + ABORT_NDB_ERROR(tx->getNdbError()); + bb_pos += model->width_c12; + + if (op->setValue(model->attr_c13, (char*)NULL) != 0) + ABORT_NDB_ERROR(tx->getNdbError()); + bb_pos += model->width_c13; + + if (op->setValue(model->attr_c14, (char*)NULL) != 0) + ABORT_NDB_ERROR(tx->getNdbError()); + bb_pos += model->width_c14; +} + +void +NdbApiTwsDriver::runNdbapiLookup(XMode mode) { + const string name = string("lookup_") + toStr(mode); + begin(name); + + if (mode == SINGLE) { + for(int i = 0; i < nRows; i++) { + ndbapiBeginTransaction(); + ndbapiLookup(i); + ndbapiCommitTransaction(); + ndbapiRead(i); + ndbapiCloseTransaction(); + } + } else { + ndbapiBeginTransaction(); + for(int i = 0; i < nRows; i++) { + ndbapiLookup(i); + + if (mode == BULK) + ndbapiExecuteTransaction(); + } + ndbapiCommitTransaction(); + for(int i = 0; i < nRows; i++) { + ndbapiRead(i); + } + ndbapiCloseTransaction(); + } + + commit(name); +} + +void +NdbApiTwsDriver::ndbapiLookup(int c0) { + // get a lookup operation for the table + NdbOperation* op = tx->getNdbOperation(model->table_t0); + if (op == NULL) + ABORT_NDB_ERROR(tx->getNdbError()); + if (op->readTuple(ndbOpLockMode) != 0) + ABORT_NDB_ERROR(tx->getNdbError()); + + // values + Uint32 i = c0; + const int maxlen = 256; + char str[maxlen]; + snprintf(str, maxlen, "%d", i); + + // set values; key attribute needs to be set first + ndbapiToBuffer1blp(bb_pos, str, model->width_c0); + if (op->equal(model->attr_c0, bb_pos) != 0) // key + ABORT_NDB_ERROR(tx->getNdbError()); + bb_pos += model->width_c0; + + // get attributes (not readable until after commit) + if ((*ra_pos = op->getValue(model->attr_c1, bb_pos)) == NULL) + ABORT_NDB_ERROR(tx->getNdbError()); + bb_pos += model->width_c1; + ra_pos++; + + if ((*ra_pos = op->getValue(model->attr_c2, bb_pos)) == NULL) + ABORT_NDB_ERROR(tx->getNdbError()); + bb_pos += model->width_c2; + ra_pos++; + + if ((*ra_pos = op->getValue(model->attr_c3, bb_pos)) == NULL) + ABORT_NDB_ERROR(tx->getNdbError()); + bb_pos += model->width_c3; + ra_pos++; + + if ((*ra_pos = op->getValue(model->attr_c4, bb_pos)) == NULL) + ABORT_NDB_ERROR(tx->getNdbError()); + bb_pos += model->width_c4; + ra_pos++; + + if ((*ra_pos = op->getValue(model->attr_c5, bb_pos)) == NULL) + ABORT_NDB_ERROR(tx->getNdbError()); + bb_pos += model->width_c5; + ra_pos++; + + if ((*ra_pos = op->getValue(model->attr_c6, bb_pos)) == NULL) + ABORT_NDB_ERROR(tx->getNdbError()); + bb_pos += model->width_c6; + ra_pos++; + + if ((*ra_pos = op->getValue(model->attr_c7, bb_pos)) == NULL) + ABORT_NDB_ERROR(tx->getNdbError()); + bb_pos += model->width_c7; + ra_pos++; + + if ((*ra_pos = op->getValue(model->attr_c8, bb_pos)) == NULL) + ABORT_NDB_ERROR(tx->getNdbError()); + bb_pos += model->width_c8; + ra_pos++; + + if ((*ra_pos = op->getValue(model->attr_c9, bb_pos)) == NULL) + ABORT_NDB_ERROR(tx->getNdbError()); + bb_pos += model->width_c9; + ra_pos++; + + if ((*ra_pos = op->getValue(model->attr_c10, bb_pos)) == NULL) + ABORT_NDB_ERROR(tx->getNdbError()); + bb_pos += model->width_c10; + ra_pos++; + + if ((*ra_pos = op->getValue(model->attr_c11, bb_pos)) == NULL) + ABORT_NDB_ERROR(tx->getNdbError()); + bb_pos += model->width_c11; + ra_pos++; + + if ((*ra_pos = op->getValue(model->attr_c12, bb_pos)) == NULL) + ABORT_NDB_ERROR(tx->getNdbError()); + bb_pos += model->width_c12; + ra_pos++; + + if ((*ra_pos = op->getValue(model->attr_c13, bb_pos)) == NULL) + ABORT_NDB_ERROR(tx->getNdbError()); + bb_pos += model->width_c13; + ra_pos++; + + if ((*ra_pos = op->getValue(model->attr_c14, bb_pos)) == NULL) + ABORT_NDB_ERROR(tx->getNdbError()); + bb_pos += model->width_c14; + ra_pos++; +} + +void +NdbApiTwsDriver::ndbapiRead(int c0) { + // values + const int maxlen = 256; + char str0[maxlen]; + snprintf(str0, maxlen, "%d", c0); + Int32 i1; + char str1[maxlen]; + + // no need to read key column + bb_pos += model->width_c0; + + ndbapiToString1blp(str1, bb_pos, model->width_c1); + verify(str0, str1); + bb_pos += model->width_c1; + ra_pos++; + + memcpy(&i1, bb_pos, model->width_c2); + verify(c0, i1); + bb_pos += model->width_c2; + ra_pos++; + + memcpy(&i1, bb_pos, model->width_c3); + verify(c0, i1); + bb_pos += model->width_c3; + ra_pos++; + + // null expected + verify(1, (*ra_pos)->isNULL()); + bb_pos += model->width_c4; + ra_pos++; + + ndbapiToString1blp(str1, bb_pos, model->width_c5); + verify(str0, str1); + bb_pos += model->width_c5; + ra_pos++; + + ndbapiToString1blp(str1, bb_pos, model->width_c6); + verify(str0, str1); + bb_pos += model->width_c6; + ra_pos++; + + ndbapiToString1blp(str1, bb_pos, model->width_c7); + verify(str0, str1); + bb_pos += model->width_c7; + ra_pos++; + + ndbapiToString1blp(str1, bb_pos, model->width_c8); + verify(str0, str1); + bb_pos += model->width_c8; + ra_pos++; + + // null expected + verify(1, (*ra_pos)->isNULL()); + bb_pos += model->width_c9; + ra_pos++; + + // null expected + verify(1, (*ra_pos)->isNULL()); + bb_pos += model->width_c10; + ra_pos++; + + // null expected + verify(1, (*ra_pos)->isNULL()); + bb_pos += model->width_c11; + ra_pos++; + + // null expected + verify(1, (*ra_pos)->isNULL()); + bb_pos += model->width_c12; + ra_pos++; + + // null expected + verify(1, (*ra_pos)->isNULL()); + bb_pos += model->width_c13; + ra_pos++; + + // null expected + verify(1, (*ra_pos)->isNULL()); + bb_pos += model->width_c14; + ra_pos++; +} + +void +NdbApiTwsDriver::runNdbapiUpdate(XMode mode) { + const string name = string("update_") + toStr(mode); + begin(name); + + if (mode == SINGLE) { + for(int i = 0; i < nRows; i++) { + ndbapiBeginTransaction(); + ndbapiUpdate(i); + ndbapiCommitTransaction(); + ndbapiCloseTransaction(); + } + } else { + ndbapiBeginTransaction(); + for(int i = 0; i < nRows; i++) { + ndbapiUpdate(i); + if (mode == BULK) + ndbapiExecuteTransaction(); + } + ndbapiCommitTransaction(); + ndbapiCloseTransaction(); + } + + commit(name); +} + +void +NdbApiTwsDriver::ndbapiUpdate(int c0) { + // get an update operation for the table + NdbOperation* op = tx->getNdbOperation(model->table_t0); + if (op == NULL) + ABORT_NDB_ERROR(tx->getNdbError()); + if (op->updateTuple() != 0) + ABORT_NDB_ERROR(tx->getNdbError()); + + // values + const int maxlen = 256; + char str0[maxlen]; + snprintf(str0, maxlen, "%d", c0); + int i = -c0; + char str1[maxlen]; + snprintf(str1, maxlen, "%d", i); + + // set values; key attribute needs to be set first + ndbapiToBuffer1blp(bb_pos, str0, model->width_c0); + if (op->equal(model->attr_c0, bb_pos) != 0) // key + ABORT_NDB_ERROR(tx->getNdbError()); + bb_pos += model->width_c0; + + ndbapiToBuffer1blp(bb_pos, str1, model->width_c1); + if (op->setValue(model->attr_c1, bb_pos) != 0) + ABORT_NDB_ERROR(tx->getNdbError()); + bb_pos += model->width_c1; + + if (op->setValue(model->attr_c2, i) != 0) + ABORT_NDB_ERROR(tx->getNdbError()); + bb_pos += model->width_c2; + + if (op->setValue(model->attr_c3, i) != 0) + ABORT_NDB_ERROR(tx->getNdbError()); + bb_pos += model->width_c3; + + ndbapiToBuffer1blp(bb_pos, str1, model->width_c5); + if (op->setValue(model->attr_c5, bb_pos) != 0) + ABORT_NDB_ERROR(tx->getNdbError()); + bb_pos += model->width_c5; + + ndbapiToBuffer1blp(bb_pos, str1, model->width_c6); + if (op->setValue(model->attr_c6, bb_pos) != 0) + ABORT_NDB_ERROR(tx->getNdbError()); + bb_pos += model->width_c6; + + ndbapiToBuffer1blp(bb_pos, str1, model->width_c7); + if (op->setValue(model->attr_c7, bb_pos) != 0) + ABORT_NDB_ERROR(tx->getNdbError()); + bb_pos += model->width_c7; + + ndbapiToBuffer1blp(bb_pos, str1, model->width_c8); + if (op->setValue(model->attr_c8, bb_pos) != 0) + ABORT_NDB_ERROR(tx->getNdbError()); + bb_pos += model->width_c8; +} + +void +NdbApiTwsDriver::runNdbapiDelete(XMode mode) { + const string name = string("delete_") + toStr(mode); + begin(name); + + if (mode == SINGLE) { + for(int i = 0; i < nRows; i++) { + ndbapiBeginTransaction(); + ndbapiDelete(i); + ndbapiCommitTransaction(); + ndbapiCloseTransaction(); + } + } else { + ndbapiBeginTransaction(); + for(int i = 0; i < nRows; i++) { + ndbapiDelete(i); + if (mode == BULK) + ndbapiExecuteTransaction(); + } + ndbapiCommitTransaction(); + ndbapiCloseTransaction(); + } + + commit(name); +} + +void +NdbApiTwsDriver::ndbapiDelete(int c0) { + // get a delete operation for the table + NdbOperation* op = tx->getNdbOperation(model->table_t0); + if (op == NULL) + ABORT_NDB_ERROR(tx->getNdbError()); + if (op->deleteTuple() != 0) + ABORT_NDB_ERROR(tx->getNdbError()); + + // values + Uint32 i = c0; + const int maxlen = 256; + char str[maxlen]; + snprintf(str, maxlen, "%d", i); + + // set values; key attribute needs to be set first + ndbapiToBuffer1blp(bb_pos, str, model->width_c0); + if (op->equal(model->attr_c0, bb_pos) != 0) // key + ABORT_NDB_ERROR(tx->getNdbError()); + bb_pos += model->width_c0; +} + +// ---------------------------------------------------------------------- + +void +NdbApiTwsDriver::ndbapiBeginTransaction() { + assert(tx == NULL); + + // prepare buffer for writing + bb_pos = bb; // clear + ra_pos = ra; + + // start a transaction + // must be closed with Ndb::closeTransaction or NdbTransaction::close + if ((tx = ndb->startTransaction()) == NULL) + ABORT_NDB_ERROR(ndb->getNdbError()); +} + +void +NdbApiTwsDriver::ndbapiExecuteTransaction() { + assert(tx != NULL); + + // execute but don't commit the current transaction + if (tx->execute(NdbTransaction::NoCommit) != 0 + || tx->getNdbError().status != NdbError::Success) + ABORT_NDB_ERROR(tx->getNdbError()); +} + +void +NdbApiTwsDriver::ndbapiCommitTransaction() { + assert(tx != NULL); + + // commit the current transaction + if (tx->execute(NdbTransaction::Commit) != 0 + || tx->getNdbError().status != NdbError::Success) + ABORT_NDB_ERROR(tx->getNdbError()); + + // prepare buffer for reading + bb_pos = bb; // rewind + ra_pos = ra; +} + +void +NdbApiTwsDriver::ndbapiCloseTransaction() { + assert(tx != NULL); + + // close the current transaction + // to be called irrespectively of success or failure + ndb->closeTransaction(tx); + tx = NULL; +} + +// --------------------------------------------------------------------------- + +void +NdbApiTwsDriver::initConnection() { + assert(mgmd == NULL); + assert(ndb == NULL); + assert(tx == NULL); + assert(model == NULL); + + cout << endl; + + // instantiate NDB cluster singleton + cout << "creating cluster conn ..." << flush; + assert(!mgmdConnect.empty()); + mgmd = new Ndb_cluster_connection(mgmdConnect.c_str()); + cout << " [ok]" << endl; // no useful mgmd->string conversion + + // connect to cluster management node (ndb_mgmd) + cout << "connecting to mgmd ..." << flush; + const int retries = 0; // number of retries (< 0 = indefinitely) + const int delay = 0; // seconds to wait after retry + const int verbose = 1; // print report of progess + // returns: 0 = success, 1 = recoverable error, -1 = non-recoverable error + if (mgmd->connect(retries, delay, verbose) != 0) + ABORT_ERROR("mgmd@" << mgmdConnect << " was not ready within " + << (retries * delay) << "s."); + cout << " [ok: " << mgmdConnect << "]" << endl; + + // optionally, connect and wait for reaching the data nodes (ndbds) + cout << "waiting for data nodes..." << flush; + const int initial_wait = 10; // seconds to wait until first node detected + const int final_wait = 0; // seconds to wait after first node detected + // returns: 0 all nodes live, > 0 at least one node live, < 0 error + if (mgmd->wait_until_ready(initial_wait, final_wait) < 0) + ABORT_ERROR("data nodes were not ready within " + << (initial_wait + final_wait) << "s."); + cout << " [ok]" << endl; + + // connect to database + cout << "connecting to database..." << flush; + ndb = new Ndb(mgmd, catalog.c_str(), schema.c_str()); + const int max_no_tx = 10; // maximum number of parallel tx (<=1024) + // note each scan or index scan operation uses one extra transaction + //if (ndb->init() != 0) + if (ndb->init(max_no_tx) != 0) + ABORT_NDB_ERROR(ndb->getNdbError()); + cout << " [ok: " + catalog + "." + schema + "]" << endl; + + cout << "caching metadata ..." << flush; + model = new NdbApiTwsModel(ndb); + cout << " [ok]" << endl; + + initNdbapiBuffers(); + + cout << "using lock mode for reads ..." << flush; + string lm; + switch (lockMode) { + case READ_COMMITTED: + ndbOpLockMode = NdbOperation::LM_CommittedRead; + lm = "LM_CommittedRead"; + break; + case SHARED: + ndbOpLockMode = NdbOperation::LM_Read; + lm = "LM_Read"; + break; + case EXCLUSIVE: + ndbOpLockMode = NdbOperation::LM_Exclusive; + lm = "LM_Exclusive"; + break; + default: + ndbOpLockMode = NdbOperation::LM_CommittedRead; + lm = "LM_CommittedRead"; + assert(false); + } + cout << " [ok: " + lm + "]" << endl; +} + +void +NdbApiTwsDriver::closeConnection() { + assert(mgmd != NULL); + assert(ndb != NULL); + assert(tx == NULL); + assert(model != NULL); + + cout << endl; + + closeNdbapiBuffers(); + + cout << "clearing metadata cache ..." << flush; + delete model; + model = NULL; + cout << " [ok]" << endl; + + cout << "closing database connection ..." << flush; + // no ndb->close(); + delete ndb; + ndb = NULL; + cout << " [ok]" << endl; + + cout << "closing cluster connection ..." << flush; + delete mgmd; + mgmd = NULL; + cout << " [ok]" << endl; +} + +//--------------------------------------------------------------------------- + +void +NdbApiTwsDriver::ndbapiToBuffer1blp(void* to, const char* from, size_t width) { + char* t = (char*)to; + size_t n = strlen(from); + assert(0 <= n && n < width && width < 256); // width <= 256 ? + + memcpy(t + 1, from, n); + *t = n; +} + +void +NdbApiTwsDriver::ndbapiToString1blp(char* to, const void* from, size_t width) { + const char* s = (const char*)from; + size_t n = *s; + assert(0 <= n && n < width && width < 256); // width <= 256 ? + + memcpy(to, s + 1, n); + to[n] = '\0'; +} + +// --------------------------------------------------------------------------- + +int +main(int argc, const char* argv[]) +{ + NdbApiTwsDriver::parseArguments(argc, argv); + NdbApiTwsDriver d; + d.run(); + + return 0; +} + +//--------------------------------------------------------------------------- --===============2000210230== MIME-Version: 1.0 Content-Type: text/bzr-bundle; charset="us-ascii"; name="bzr/martin.zaun@stripped" Content-Transfer-Encoding: 7bit Content-Disposition: inline # Bazaar merge directive format 2 (Bazaar 0.90) # revision_id: martin.zaun@stripped # target_branch: file:///Users/mz/mysql/ndb-7.1-opt64/ # testament_sha1: 75b5a4791ecb2212963a730c44cbb73c9e7c63fb # timestamp: 2010-10-07 21:23:36 -0700 # base_revision_id: martin.zaun@stripped\ # kal0tgjjm7igz641 # # Begin bundle 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 --===============2000210230==--