List:Commits« Previous MessageNext Message »
From:Martin Zaun Date:October 19 2010 11:20pm
Subject:bzr push into mysql-5.1-telco-7.1 branch (martin.zaun:3900 to 3901)
View as plain text  
 3901 Martin Zaun	2010-10-19 [merge]
      crund - merge

    removed:
      storage/ndb/test/crund/martins_little_helpers/src/utils/Properties.cpp
      storage/ndb/test/crund/src/com/mysql/cluster/crund/JdoLoad.java
      storage/ndb/test/crund/tws_benchmark/run.properties.sample
      storage/ndb/test/crund/tws_benchmark/schema.sql
      storage/ndb/test/crund/tws_benchmark/src/Main.java
    added:
      storage/ndb/test/crund/src/com/mysql/cluster/crund/CrundDriver.java
      storage/ndb/test/crund/src/crundndb/CrundDriver.cpp
      storage/ndb/test/crund/src/crundndb/CrundDriver.hpp
      storage/ndb/test/crund/src/crundndb/Driver.hpp
      storage/ndb/test/crund/src/crundndb/NdbApiDriver.cpp
      storage/ndb/test/crund/src/crundndb/NdbApiDriver.hpp
      storage/ndb/test/crund/tws/
      storage/ndb/test/crund/tws/README.txt
      storage/ndb/test/crund/tws/run.properties.sample
      storage/ndb/test/crund/tws/schema.sql
      storage/ndb/test/crund/tws/tws_cpp/
      storage/ndb/test/crund/tws/tws_cpp/Driver.cpp
      storage/ndb/test/crund/tws/tws_cpp/Driver.hpp
      storage/ndb/test/crund/tws/tws_cpp/NdbApiTwsDriver.cpp
      storage/ndb/test/crund/tws/tws_cpp/NdbApiTwsDriver.hpp
      storage/ndb/test/crund/tws/tws_cpp/README.txt
      storage/ndb/test/crund/tws/tws_cpp/TwsDriver.cpp
      storage/ndb/test/crund/tws/tws_cpp/TwsDriver.hpp
      storage/ndb/test/crund/tws/tws_java/nbproject/private_sample/configs/
      storage/ndb/test/crund/tws/tws_java/nbproject/private_sample/configs/server-dbg.properties
      storage/ndb/test/crund/tws/tws_java/nbproject/private_sample/configs/server-opt.properties
      storage/ndb/test/crund/tws/tws_java/src/com/
      storage/ndb/test/crund/tws/tws_java/src/com/mysql/
      storage/ndb/test/crund/tws/tws_java/src/com/mysql/cluster/
      storage/ndb/test/crund/tws/tws_java/src/com/mysql/cluster/benchmark/
      storage/ndb/test/crund/tws/tws_java/src/com/mysql/cluster/benchmark/tws/
      storage/ndb/test/crund/tws/tws_java/src/com/mysql/cluster/benchmark/tws/ClusterjLoad.java
      storage/ndb/test/crund/tws/tws_java/src/com/mysql/cluster/benchmark/tws/Driver.java
      storage/ndb/test/crund/tws/tws_java/src/com/mysql/cluster/benchmark/tws/JdbcLoad.java
      storage/ndb/test/crund/tws/tws_java/src/com/mysql/cluster/benchmark/tws/NdbjtieLoad.java
      storage/ndb/test/crund/tws/tws_java/src/com/mysql/cluster/benchmark/tws/TwsDriver.java
      storage/ndb/test/crund/tws/tws_java/src/com/mysql/cluster/benchmark/tws/TwsLoad.java
    renamed:
      storage/ndb/test/crund/src/crundndb/Operations.cpp => storage/ndb/test/crund/src/crundndb/CrundNdbApiOperations.cpp
      storage/ndb/test/crund/src/crundndb/Operations.hpp => storage/ndb/test/crund/src/crundndb/CrundNdbApiOperations.hpp
      storage/ndb/test/crund/tws_benchmark/ => storage/ndb/test/crund/tws/tws_java/
    modified:
      .bzrignore
      storage/ndb/test/crund/Makefile
      storage/ndb/test/crund/Makefile.defaults
      storage/ndb/test/crund/build.xml
      storage/ndb/test/crund/config_samples/env.properties
      storage/ndb/test/crund/martins_little_helpers/src/utils/Makefile
      storage/ndb/test/crund/martins_little_helpers/src/utils/Properties.hpp
      storage/ndb/test/crund/martins_little_helpers/src/utils/string_helpers.hpp
      storage/ndb/test/crund/scripts/load_shema.sh
      storage/ndb/test/crund/src/com/mysql/cluster/crund/A.java
      storage/ndb/test/crund/src/com/mysql/cluster/crund/ClusterjLoad.java
      storage/ndb/test/crund/src/com/mysql/cluster/crund/Driver.java
      storage/ndb/test/crund/src/com/mysql/cluster/crund/JdbcLoad.java
      storage/ndb/test/crund/src/com/mysql/cluster/crund/JpaLoad.java
      storage/ndb/test/crund/src/com/mysql/cluster/crund/NdbApiLoad.java
      storage/ndb/test/crund/src/com/mysql/cluster/crund/NdbBase.java
      storage/ndb/test/crund/src/com/mysql/cluster/crund/NdbJTieLoad.java
      storage/ndb/test/crund/src/com/mysql/cluster/crund/NdbjLoad.java
      storage/ndb/test/crund/src/crundndb/Driver.cpp
      storage/ndb/test/crund/src/crundndb/Makefile
      storage/ndb/test/crund/src/crundndb/com_mysql_cluster_crund_NdbApiLoad.cpp
      storage/ndb/test/crund/tws/tws_java/README.txt
      storage/ndb/test/crund/tws/tws_java/nbproject/configs_sample/server-dbg.properties
      storage/ndb/test/crund/tws/tws_java/nbproject/configs_sample/server-opt.properties
      storage/ndb/test/crund/tws/tws_java/nbproject/private_sample/config.properties
      storage/ndb/test/crund/src/crundndb/CrundNdbApiOperations.cpp
      storage/ndb/test/crund/src/crundndb/CrundNdbApiOperations.hpp
 3900 Jonas Oreland	2010-10-19 [merge]
      ndb - merge 70 to 71

    modified:
      storage/ndb/src/kernel/blocks/dbdict/Dbdict.cpp
      storage/ndb/src/kernel/blocks/dbdict/Dbdict.hpp
=== modified file '.bzrignore'
--- a/.bzrignore	2010-09-29 10:02:15 +0000
+++ b/.bzrignore	2010-10-08 11:17:35 +0000
@@ -3124,7 +3124,7 @@ storage/ndb/test/crund/*.properties
 storage/ndb/test/crund/build/
 storage/ndb/test/crund/javadoc/
 storage/ndb/test/crund/lib/
-storage/ndb/test/crund/log*
+storage/ndb/test/crund/**/log*
 storage/ndb/test/crund/martins_little_helpers/src/utils/Properties_test
 storage/ndb/test/crund/martins_little_helpers/src/utils/hrt_stopwatch_test
 storage/ndb/test/crund/martins_little_helpers/src/utils/hrt_utils_test
@@ -3132,12 +3132,14 @@ storage/ndb/test/crund/martins_little_he
 storage/ndb/test/crund/martins_little_helpers/src/utils/utils_JniInstrumentationTest.h
 storage/ndb/test/crund/scripts/ndblog
 storage/ndb/test/crund/scripts/results
-storage/ndb/test/crund/src/crundndb/Driver
+storage/ndb/test/crund/src/crundndb/NdbApiDriver
 storage/ndb/test/crund/src/crundndb/com_mysql_cluster_crund_NdbApiLoad.h
-storage/ndb/test/crund/tws_benchmark/build/
-storage/ndb/test/crund/tws_benchmark/nbproject/configs/
-storage/ndb/test/crund/tws_benchmark/nbproject/private/
-storage/ndb/test/crund/tws_benchmark/run.properties
+storage/ndb/test/crund/tws/tws_java/build/
+storage/ndb/test/crund/tws/tws_java/nbproject/configs/
+storage/ndb/test/crund/tws/tws_java/nbproject/private/
+storage/ndb/test/crund/tws/tws_java/run.properties
+storage/ndb/test/crund/tws/*.properties
+storage/ndb/test/crund/tws/tws_cpp/TwsDriver
 
 libmysqld/examples/mysqltest.cc
 libmysqld/debug_sync.cc

=== modified file 'storage/ndb/test/crund/Makefile'
--- a/storage/ndb/test/crund/Makefile	2010-09-27 05:31:17 +0000
+++ b/storage/ndb/test/crund/Makefile	2010-10-19 22:56:45 +0000
@@ -2,7 +2,7 @@
 
   SRC		= ./src
 
-.PHONY:	all help dep dbg opt prf clean clobber distclean check
+.PHONY:	all help dep dbg opt prf clean mostlclean clobber distclean check
 all:	dbg
 
 help:
@@ -16,7 +16,7 @@ help:
 	@echo "distclean	-- delete also database and server log files"
 	@echo "check		-- perform self-tests (if any)"
 
-dep dbg opt prf clean mostlyclean check:
+dep dbg opt prf clean mostlyclean clobber check:
 	ant $@
 	@cd $(SRC)/crundndb && $(MAKE) $(MFLAGS) $@
 
@@ -32,8 +32,10 @@ distclean:
 # read the generic settings
 include	env.properties
 
-run.driver:	$(SRC)/crundndb/Driver
-	LD_LIBRARY_PATH=${NDB_LIBDIR} $(SRC)/crundndb/Driver \
+# not sure if needed:
+#	LD_LIBRARY_PATH=${NDB_LIBDIR}:$(SRC)/crundndb/Driver 
+run.driver:	$(SRC)/crundndb/NdbApiDriver
+	$(SRC)/crundndb/NdbApiDriver \
 	-p crundRun.properties -p crundNdbapi.properties
 #
 #run.driver:

=== modified file 'storage/ndb/test/crund/Makefile.defaults'
--- a/storage/ndb/test/crund/Makefile.defaults	2010-09-29 10:02:15 +0000
+++ b/storage/ndb/test/crund/Makefile.defaults	2010-10-08 11:17:35 +0000
@@ -144,7 +144,9 @@
 
 # Default Targets Section:
 
-.PHONY:	dep depend dbg opt prf clean mostlyclean distclean check
+.PHONY:	dep depend dbg opt prf clean mostlyclean clobber distclean check
+
+help:
 
 dep depend:
 	@set -e; \
@@ -180,7 +182,7 @@ clean:
 
 # library-archiving removes .o files with empty .depend file,
 # so, better delete it only as part of mostlyclean
-mostlyclean:	clean
+mostlyclean clobber:	clean
 	rm -rf $(MOSTLYCLEAN) .depend
 
 distclean:	mostlyclean

=== modified file 'storage/ndb/test/crund/build.xml'
--- a/storage/ndb/test/crund/build.xml	2010-10-01 08:58:08 +0000
+++ b/storage/ndb/test/crund/build.xml	2010-10-08 11:17:35 +0000
@@ -198,14 +198,15 @@
   </target>
 
   <!-- deletes also log files -->
-  <target name="clobber" depends="clean">
+  <target name="clobber" depends="mostlyclean"/>
+  <target name="mostlyclean" depends="clean">
     <delete includeEmptyDirs="true" quiet="true" >
       <fileset dir="${basedir}" includes="log_*"/>
     </delete>
   </target>
 
   <!-- deletes also database files -->
-  <target name="distclean" depends="clobber">
+  <target name="distclean" depends="mostlyclean">
     <delete verbose="true">
       <fileset dir="${src.java}" includes="**/*~" defaultexcludes="no"/>
     </delete>
@@ -288,13 +289,13 @@
        # Driver
        ################################################################# -->
 
-  <!-- compiles the benchmark driver -->
+  <!-- compiles the benchmark drivers -->
   <target name="compile.driver" depends="set.compile,init">
     <javac srcdir="${src.java}" destdir="${build}" debug="${debug}"
-	   includes="com/mysql/cluster/crund/Driver.java"/>
+	   includes="com/mysql/cluster/crund/*Driver.java"/>
   </target>
 
-  <!-- compiles the benchmark driver with optimizations -->
+  <!-- compiles the benchmark drivers with optimizations -->
   <target name="compile.driver.opt" depends="set.compile.opt,compile.driver"/>
 
   <!-- #################################################################
@@ -881,7 +882,7 @@
     <taskdef name="openjpac"
     classname="org.apache.openjpa.ant.PCEnhancerTask"/>
 
-    <- invoke enhancer on all .jdo files below the current directory ->
+    <- invoke enhancer on all .java files below the current directory ->
     <openjpac>
       <fileset dir=".">
         <include name="**/model/*.java" />

=== modified file 'storage/ndb/test/crund/config_samples/env.properties'
--- a/storage/ndb/test/crund/config_samples/env.properties	2010-10-01 04:10:21 +0000
+++ b/storage/ndb/test/crund/config_samples/env.properties	2010-10-05 08:48:30 +0000
@@ -197,26 +197,6 @@ COMMONS_POOL_JAR=${HOME}/mysql/lib/commo
 # The Following are Obsolete:
 # ----------------------------------------------------------------------
 
-#
-# The JDO API Jar File
-#
-
-# Must be set & valid when building/running
-# - ClusterjLoad (annotation processing)
-
-JDO_API_JAR=${HOME}/mysql/lib/jdo2-api-2.1.1.jar
-
-# Comments:
-# - get from here:
-#   http://db.apache.org/jdo/releases/release-2.1.1.cgi
-# (- merged the jdo2-api-..., jdo2-model-... jar files all into one?)
-
-#
-# The NDB/J (ndb-bindings) Jar and Library Paths
-#
-
-# ----------------------------------------------------------------------
-
 # Must be set & valid when building/running
 # - NdbjLoad
 # - ClusterjLoad

=== modified file 'storage/ndb/test/crund/martins_little_helpers/src/utils/Makefile'
--- a/storage/ndb/test/crund/martins_little_helpers/src/utils/Makefile	2010-10-01 04:10:21 +0000
+++ b/storage/ndb/test/crund/martins_little_helpers/src/utils/Makefile	2010-10-06 06:15:04 +0000
@@ -89,7 +89,6 @@ utils_HrtStopwatch.h:	$(API_PKG_PATH)/Hr
 	$(COMPILE.javah) utils.HrtStopwatch
 
 libutils.a:	libutils.a(hrt_utils.o hrt_stopwatch.o hrt_gstopwatch.o) \
-	libutils.a(Properties.o) \
 	libutils.a(utils_HrtStopwatch.o)
 
 libutils.so:	libutils.a

=== removed file 'storage/ndb/test/crund/martins_little_helpers/src/utils/Properties.cpp'
--- a/storage/ndb/test/crund/martins_little_helpers/src/utils/Properties.cpp	2010-02-14 05:05:31 +0000
+++ b/storage/ndb/test/crund/martins_little_helpers/src/utils/Properties.cpp	1970-01-01 00:00:00 +0000
@@ -1,438 +0,0 @@
-/*
- * Properties.cpp
- *
- */
-
-#include "Properties.hpp"
-
-#include <fstream>
-#include <cassert>
-#include <climits>
-
-using std::istream;
-using std::ostream;
-using std::ifstream;
-using std::ofstream;
-using std::cout;
-using std::wcout;
-using std::endl;
-using std::wstring;
-using std::streambuf;
-using std::stringbuf;
-
-using utils::Properties;
-
-// ---------------------------------------------------------------------------
-
-inline bool
-Properties::isWS(int c)
-{
-    switch (c) {
-    case 0x09: // '\t' HT
-    case 0x0c: // '\f' FF
-    case 0x20: // ' '  SPACE
-        return true;
-    }
-    return false;
-}
-
-inline bool
-Properties::isNL(int c)
-{
-    switch (c) {
-    case 0x0a: // '\n' LF
-    case 0x0d: // '\r' CR
-        return true;
-    }
-    return false;
-}
-
-inline bool
-Properties::isComment(int c)
-{
-    switch (c) {
-    case 0x21: // '!'
-    case 0x23: // '#'
-        return true;
-    }
-    return false;
-}
-
-inline bool
-Properties::isAssign(int c)
-{
-    switch (c) {
-    case 0x3a: // ':'
-    case 0x3d: // '='
-        return true;
-    }
-    return false;
-}
-
-inline bool
-Properties::isKeyTerminator(int c)
-{
-    return isWS(c) || isAssign(c) || isNL(c);
-}
-
-inline bool
-Properties::isEsc(int c)
-{
-    switch (c) {
-    case 0x5c: // '\\'
-        return true;
-    }
-    return false;
-}
-
-inline void
-Properties::skipWS(streambuf& ib)
-{
-    int c;
-    while ((c = ib.snextc()) != EOF && isWS(c));
-}
-
-inline void
-Properties::skipComment(streambuf& ib)
-{
-    int c;
-    // comments cannot have escaped line terminators
-    while ((c = ib.snextc()) != EOF && !isNL(c));
-    ib.sbumpc();
-}
-
-inline void
-Properties::readIgnored(streambuf& ib)
-{
-    int c;
-    while ((c = ib.sgetc()) != EOF) {
-        if (isWS(c)) {
-            skipWS(ib);
-            c = ib.sgetc();
-        }
-        if (isNL(c)) {
-            ib.sbumpc();
-            continue;
-        }
-        if (isComment(c)) {
-            ib.sbumpc();
-            skipComment(ib);
-            continue;
-        }
-        return;
-    }
-}
-
-inline void
-Properties::readEsc(wstring& s, streambuf& ib)
-{
-    int c = ib.sgetc();
-    switch (c) {
-    case EOF:
-        return;
-    case 0x0a: // '\n' LF
-    case 0x0d: // '\r' CR
-        // escaped EOL (CR, LF, CRLF)
-        if ((c = ib.snextc()) != 0x0a) // '\n' LF
-            ib.sungetc();
-        skipWS(ib);
-        return;
-    case 0x6e: // 'n'
-        // LF ("newline") char escape
-        c = 0x0a; // '\n'
-        break;
-    case 0x72: // 'r'
-        // CR ("return") char escape
-        c = 0x0d; // '\r'
-        break;
-    case 0x75: { // 'u'
-        // unicode escape
-        c = ib.sbumpc();
-        // store input characters in case not an escape sequence
-        wstring raw;
-        raw += c; // silently drop backslash by general rule
-        unsigned int d = 0;
-        for (int i = 0; i < 4; i++) {
-            d <<= 4;
-            c = ib.sbumpc();
-            raw += static_cast<wchar_t>(c); // exlicit cast preferred
-            switch (c) {
-            case 0x30: case 0x31: case 0x32: case 0x33: case 0x34:
-            case 0x35: case 0x36: case 0x37: case 0x38: case 0x39:
-                // '0'..'9'
-                d += c - 0x30; // - '0'
-                break;
-            case 0x41: case 0x42: case 0x43: case 0x44: case 0x45: case 0x46:
-                // 'A'..'F'
-                d += 10 + c - 0x41; // - 'A'
-                break;
-            case 0x61: case 0x62: case 0x63: case 0x64: case 0x65: case 0x66:
-                // 'a'..'f'
-                d += 10 + c - 0x61; // - 'a'
-                break;
-            case EOF:
-            default:
-                // not a unicode escape sequence, write the raw char sequence
-                s += static_cast<wchar_t>(c); // exlicit cast preferred
-                return;
-            }
-        }
-        s += static_cast<wchar_t>(d); // exlicit cast preferred
-        return;
-    }
-    default:
-        // unrecognized escape no error, silently drop preceding backslash
-        break;
-    }
-    s += static_cast<wchar_t>(c); // exlicit cast preferred
-    ib.sbumpc();
-}
-
-inline void
-Properties::readKey(wstring& s, streambuf& ib)
-{
-    int c;
-    while ((c = ib.sgetc()) != EOF) {
-        if (isKeyTerminator(c)) {
-            if (isNL(c)) {
-                return;
-            }
-            if (isWS(c)) {
-                skipWS(ib);
-                c = ib.sgetc();
-            }
-            if (isAssign(c)) {
-                skipWS(ib);
-            }
-            return;
-        }
-
-        ib.sbumpc();
-        if (isEsc(c)) {
-            readEsc(s, ib);
-        } else {
-            s += static_cast<wchar_t>(c); // exlicit cast preferred
-        }
-    }
-}
-
-inline void
-Properties::readValue(wstring& s, streambuf& ib)
-{
-    int c;
-    while ((c = ib.sgetc()) != EOF) {
-        ib.sbumpc();
-        if (isNL(c)) {
-            return;
-        }
-
-        if (isEsc(c)) {
-            readEsc(s, ib);
-        } else {
-            s += static_cast<wchar_t>(c); // exlicit cast preferred
-        }
-    }
-}
-
-inline bool
-Properties::isPrintableAscii(wchar_t c)
-{
-    return (L'\x20' <= c && c <= L'\x7e');
-}
-
-inline void
-Properties::writeAsciiEsc(streambuf& os, wchar_t c)
-{
-    assert (L'\x20' <= c && c <= L'\x7e');
-    char d;
-    switch (c) {
-    case L'\t':     // HT
-        d = '\x74'; // 't'
-        break;
-    case L'\n':    // LF
-        d = '\x6e'; // 'n'
-        break;
-    case L'\f':    // FF
-        d = '\x66'; // 'f'
-        break;
-    case L'\r':    // CR
-        d = '\x72'; // 'r'
-        break;
-    case L' ':     // SPACE
-    case L'!':
-    case L'#':
-    case L':':
-    case L'=':
-    case L'\\':
-        d = static_cast<char>(c); // exlicit cast preferred
-        break;
-    default:
-        // write the raw character
-        int n = os.sputc(static_cast<char>(c)); // explicit cast preferred
-        assert (n != EOF); // XXX handle error
-        (void)n;
-        return;
-    }
-    int n = os.sputc('\x5c'); // '\\'
-    assert (n != EOF); // XXX handle error
-    n = os.sputc(d);
-    assert (n != EOF); // XXX handle error
-}
-
-inline void
-Properties::writeUnicodeEsc(streambuf& os, wchar_t c)
-{
-    assert (c < L'\x20' || L'\x7e' < c);
-
-    // subsequent code depends upon a UCS-2 (UTF-16) or UTF-32
-    // encoding of wide characters
-    const int w = sizeof(wchar_t);
-    assert (w == 2 || w == 4);
-    assert (CHAR_BIT == 8);
-
-    // write unicode escape sequence as "\\unnnn" or "\Unnnnnnnn"
-    int n = os.sputc('\x5c'); // '\\'
-    assert (n != EOF); // XXX handle error
-    n = os.sputc(w == 2 ? '\x75' : '\x55'); // 'u' : 'U'
-    assert (n != EOF); // XXX handle error
-    static const char ascii[] = { '\x30', '\x31', '\x32', '\x33',
-                                  '\x34', '\x35', '\x36', '\x37',
-                                  '\x38', '\x39', '\x41', '\x42',
-                                  '\x43', '\x44', '\x45', '\x46' }; // '0'..'F'
-    for (unsigned int i = w * 8 - 4; i >= 0; i -= 4) {
-        n = os.sputc(ascii[(c>>i) & 0xF]);
-        assert (n != EOF); // XXX handle error
-    }
-}
-
-inline void
-Properties::writeKey(streambuf& os, const wstring& s)
-{
-    for (wstring::const_iterator i = s.begin(); i != s.end(); ++i) {
-        const wchar_t c = *i;
-        if (isPrintableAscii(c))
-            writeAsciiEsc(os, c);
-        else
-            writeUnicodeEsc(os, c);
-    }
-}
-
-inline void
-Properties::writeValue(streambuf& os, const wstring& s)
-{
-    wstring::const_iterator i = s.begin();
-    for (; i != s.end() && *i == L'\x20'; ++i) { // L' '  SPACE
-        // write leading spaces escaped
-        writeAsciiEsc(os, *i);
-    }
-    for (; i != s.end(); ++i) {
-        const wchar_t c = *i;
-        if (c == L'\x20') { // L' '  SPACE
-            // write embedded or tailing spaces unescaped
-            int n = os.sputc('\x20'); // ' '  SPACE
-            assert (n != EOF); // XXX handle error
-            (void)n;
-        } else if (isPrintableAscii(c)) {
-            writeAsciiEsc(os, c);
-        } else {
-            writeUnicodeEsc(os, c);
-        }
-    }
-}
-
-//---------------------------------------------------------------------------
-
-void
-Properties::load(const char* filename)
-{
-    assert (filename);
-    ifstream ifs;
-    ifs.open(filename);
-    assert (ifs.good()); // XXX handle error
-    assert (!ifs.bad()); // XXX handle error
-    load(ifs);
-    ifs.close();
-}
-
-void
-Properties::load(istream& is)
-{
-    streambuf* ib = is.rdbuf();
-    assert (ib != NULL); // XXX handle error
-    load(*ib);
-}
-
-void
-Properties::load(streambuf& ib)
-{
-    while (ib.sgetc() != EOF) {
-        readIgnored(ib);
-        if (ib.sgetc() == EOF)
-            return;
-
-        // parse property
-        wstring k;
-        readKey(k, ib);
-        wstring v;
-        readValue(v, ib);
-        //wcout << "('" << k << "', '" << v << "')" << endl;
-        (*this)[k] = v; // YYY
-        //this->operator[](k) = v;
-    }
-}
-
-void
-Properties::store(const char* filename, const wstring* header) const
-{
-    assert (filename);
-    ofstream ofs;
-    ofs.open(filename);
-    assert (ofs.good()); // XXX handle error
-    assert (!ofs.bad()); // XXX handle error
-    store(ofs, header);
-    ofs.close();
-}
-
-void
-Properties::store(ostream& os, const wstring* header) const
-{
-    streambuf* ob = os.rdbuf();
-    assert (ob != NULL); // XXX handle error
-    store(*ob, header);
-}
-
-void
-Properties::store(streambuf& os, const wstring* header) const
-{
-    // subsequent code for writing the header, keys and values
-    // depends upon UCS-2 (UTF-16) or UTF-32 character encoding
-    const int w = sizeof(wchar_t);
-    assert (w == 2 || w == 4);
-    assert (CHAR_BIT == 8);
-    assert (L'!' == '\x21');
-    assert (L'A' == '\x41');
-    assert (L'a' == '\x61');
-    assert (L'~' == '\x7e');
-    (void)w;
-    
-    if (header != NULL) {
-        int n = os.sputc('\x23'); // '#'
-        assert (n != EOF); // XXX handle error
-        writeKey(os, *header);
-        n = os.sputc('\x0a'); // '\n'
-        assert (n != EOF); // XXX handle error
-    }
-
-    for (const_iterator i = begin(); i != end(); ++i) {
-        const wstring& key = i->first;
-        const wstring& value = i->second;
-        writeKey(os, key);
-        int n = os.sputc('\x3d'); // '='
-        assert (n != EOF); // XXX handle error
-        writeValue(os, value);
-        n = os.sputc('\x0a'); // '\n'
-        assert (n != EOF); // XXX handle error
-    }
-}
-
-// ---------------------------------------------------------------------------

=== modified file 'storage/ndb/test/crund/martins_little_helpers/src/utils/Properties.hpp'
--- a/storage/ndb/test/crund/martins_little_helpers/src/utils/Properties.hpp	2010-02-14 05:05:31 +0000
+++ b/storage/ndb/test/crund/martins_little_helpers/src/utils/Properties.hpp	2010-10-08 11:17:35 +0000
@@ -8,15 +8,26 @@
 
 #include <map>
 #include <string>
+#include <ios>
 #include <iostream>
+#include <istream>
+#include <ostream>
+#include <streambuf>
+#include <fstream>
+#include <cassert>
+#include <climits>
 
 namespace utils {
     
 using std::map;
 using std::wstring;
+using std::ios_base;
 using std::istream;
-using std::streambuf;
+//using std::wistream;
 using std::ostream;
+//using std::wostream;
+using std::streambuf;
+//using std::wstreambuf;
 
 /**
  * The Properties class is a specialized map container that stores
@@ -58,40 +69,65 @@ class Properties : public map<wstring, w
 {
 public:
     /**
-     * Reads properties from the file and adds them to this
+     * Reads properties from the character file and adds them to this
      * property table.
      */
-    void load(const char* filename);
+    void load(const char* filename)
+        throw (ios_base::failure);
 
     /**
-     * Reads properties from the input stream and adds them to this
-     * property table.
+     * Reads properties from the character input stream and adds them
+     * to this property table.
      */
-    void load(istream& is);
+    void load(istream& is)
+        throw (ios_base::failure);
 
     /**
-     * Reads properties from the input byte buffer and adds them to this
-     * property table.
+     * Reads properties from the character buffer and adds them
+     * to this property table.
      *
      * The line-oriented format is the same as used by Java Properties.
      * The byte stream is read under the ISO 8859-1 character encoding,
      * so, all non-ISO 8859-1 characters of the key and value strings
      * need to be expressed as an escape sequence.
      */
-    void load(streambuf& ib);
+    void load(streambuf& ib)
+        throw (ios_base::failure);
 
     /**
-     * Writes this property table to the file.
+     * Reads properties from the wide character input stream and adds them
+     * to this property table.
+     */
+    // not implemented yet
+    //void load(wistream& is)
+    //    throw (ios_base::failure);
+
+    /**
+     * Reads properties from the wide character buffer and adds them
+     * to this property table.
+     *
+     * The byte stream is read under the UTF-32/UCS-4 character encoding,
+     * and characters of the key and value strings are not parsed as an
+     * escape sequence.
      */
-    void store(const char* filename, const wstring* header = NULL) const;
+    // not implemented yet
+    //void load(wstreambuf& ib)
+    //    throw (ios_base::failure);
 
     /**
-     * Writes this property table to the output stream.
+     * Writes this property table to the character file.
      */
-    void store(ostream& os, const wstring* header = NULL) const;
+    void store(const char* filename, const wstring* header = NULL) const
+        throw (ios_base::failure);
 
     /**
-     * Writes this property table to the output byte buffer.
+     * Writes this property table to the character output stream.
+     */
+    void store(ostream& os, const wstring* header = NULL) const
+        throw (ios_base::failure);
+
+    /**
+     * Writes this property table to the character buffer.
      *
      * The format is suitable for reading the properties using the load
      * function.  The stream is written using the ISO 8859-1 character
@@ -102,7 +138,31 @@ public:
      * header string, and a line separator are first written to the output
      * stream. Thus, the header can serve as an identifying comment.
      */
-    void store(streambuf& ob, const wstring* header = NULL) const;
+    void store(streambuf& ob, const wstring* header = NULL) const
+        throw (ios_base::failure);
+
+    /**
+     * Writes this property table to the wide character output stream.
+     */
+    // not implemented yet
+    //void store(wostream& os, const wstring* header = NULL) const
+    //    throw (ios_base::failure);
+
+    /**
+     * Writes this property table to the wide character buffer.
+     *
+     * The format is suitable for reading the properties using the load
+     * function.  The stream is written using the UTF-32/UCS-4 character
+     * encoding, and characters of the key and value strings are not
+     * rendered as an escape sequence.
+     *
+     * If the header argument is not null, then an ASCII # character, the
+     * header string, and a line separator are first written to the output
+     * stream. Thus, the header can serve as an identifying comment.
+     */
+    // not implemented yet
+    //void store(wstreambuf& ob, const wstring* header = NULL) const
+    //    throw (ios_base::failure);
 
 protected:
     static bool isWS(int c);
@@ -122,6 +182,7 @@ protected:
     static void writeUnicodeEsc(streambuf& os, wchar_t c);
     static void writeKey(streambuf& os, const wstring& s);
     static void writeValue(streambuf& os, const wstring& s);
+    static void writeChar(streambuf& os, char c);
 };
 
 inline istream&
@@ -131,6 +192,16 @@ operator>>(istream& s, Properties& p)
     return s;
 }
 
+/*
+// not implemented yet
+inline wistream&
+operator>>(wistream& s, Properties& p)
+{
+    p.load(s);
+    return s;
+}
+*/
+
 inline ostream&
 operator<<(ostream& s, const Properties& p)
 {
@@ -138,6 +209,451 @@ operator<<(ostream& s, const Properties&
     return s;
 }
 
+/*
+// not implemented yet
+inline wostream&
+operator<<(wostream& s, const Properties& p)
+{
+    p.store(s);
+    return s;
+}
+*/
+
+
+// ---------------------------------------------------------------------------
+// Properties Implementation
+// ---------------------------------------------------------------------------
+
+using std::cout;
+using std::wcout;
+using std::endl;
+using std::ifstream;
+using std::ofstream;
+using std::streambuf;
+using std::stringbuf;
+
+// ---------------------------------------------------------------------------
+
+inline bool
+Properties::isWS(int c)
+{
+    switch (c) {
+    case 0x09: // '\t' HT
+    case 0x0c: // '\f' FF
+    case 0x20: // ' '  SPACE
+        return true;
+    }
+    return false;
+}
+
+inline bool
+Properties::isNL(int c)
+{
+    switch (c) {
+    case 0x0a: // '\n' LF
+    case 0x0d: // '\r' CR
+        return true;
+    }
+    return false;
+}
+
+inline bool
+Properties::isComment(int c)
+{
+    switch (c) {
+    case 0x21: // '!'
+    case 0x23: // '#'
+        return true;
+    }
+    return false;
+}
+
+inline bool
+Properties::isAssign(int c)
+{
+    switch (c) {
+    case 0x3a: // ':'
+    case 0x3d: // '='
+        return true;
+    }
+    return false;
+}
+
+inline bool
+Properties::isKeyTerminator(int c)
+{
+    return isWS(c) || isAssign(c) || isNL(c);
+}
+
+inline bool
+Properties::isEsc(int c)
+{
+    switch (c) {
+    case 0x5c: // '\\'
+        return true;
+    }
+    return false;
+}
+
+inline void
+Properties::skipWS(streambuf& ib)
+{
+    int c;
+    while ((c = ib.snextc()) != EOF && isWS(c));
+}
+
+inline void
+Properties::skipComment(streambuf& ib)
+{
+    int c;
+    // comments cannot have escaped line terminators
+    while ((c = ib.snextc()) != EOF && !isNL(c));
+    ib.sbumpc();
+}
+
+inline void
+Properties::readIgnored(streambuf& ib)
+{
+    int c;
+    while ((c = ib.sgetc()) != EOF) {
+        if (isWS(c)) {
+            skipWS(ib);
+            c = ib.sgetc();
+        }
+        if (isNL(c)) {
+            ib.sbumpc();
+            continue;
+        }
+        if (isComment(c)) {
+            ib.sbumpc();
+            skipComment(ib);
+            continue;
+        }
+        return;
+    }
+}
+
+inline void
+Properties::readEsc(wstring& s, streambuf& ib)
+{
+    int c = ib.sgetc();
+    switch (c) {
+    case EOF:
+        return;
+    case 0x0a: // '\n' LF
+    case 0x0d: // '\r' CR
+        // escaped EOL (CR, LF, CRLF)
+        if ((c = ib.snextc()) != 0x0a) // '\n' LF
+            ib.sungetc();
+        skipWS(ib);
+        return;
+    case 0x6e: // 'n'
+        // LF ("newline") char escape
+        c = 0x0a; // '\n'
+        break;
+    case 0x72: // 'r'
+        // CR ("return") char escape
+        c = 0x0d; // '\r'
+        break;
+    case 0x75: { // 'u'
+        // unicode escape
+        c = ib.sbumpc();
+        // store input characters in case not an escape sequence
+        wstring raw;
+        raw += c; // silently drop backslash by general rule
+        unsigned int d = 0;
+        for (int i = 0; i < 4; i++) {
+            d <<= 4;
+            c = ib.sbumpc();
+            raw += static_cast<wchar_t>(c); // exlicit cast preferred
+            switch (c) {
+            case 0x30: case 0x31: case 0x32: case 0x33: case 0x34:
+            case 0x35: case 0x36: case 0x37: case 0x38: case 0x39:
+                // '0'..'9'
+                d += c - 0x30; // - '0'
+                break;
+            case 0x41: case 0x42: case 0x43: case 0x44: case 0x45: case 0x46:
+                // 'A'..'F'
+                d += 10 + c - 0x41; // - 'A'
+                break;
+            case 0x61: case 0x62: case 0x63: case 0x64: case 0x65: case 0x66:
+                // 'a'..'f'
+                d += 10 + c - 0x61; // - 'a'
+                break;
+            case EOF:
+            default:
+                // not a unicode escape sequence, write the raw char sequence
+                s += static_cast<wchar_t>(c); // exlicit cast preferred
+                return;
+            }
+        }
+        s += static_cast<wchar_t>(d); // exlicit cast preferred
+        return;
+    }
+    default:
+        // unrecognized escape no error, silently drop preceding backslash
+        break;
+    }
+    s += static_cast<wchar_t>(c); // exlicit cast preferred
+    ib.sbumpc();
+}
+
+inline void
+Properties::readKey(wstring& s, streambuf& ib)
+{
+    int c;
+    while ((c = ib.sgetc()) != EOF) {
+        if (isKeyTerminator(c)) {
+            if (isNL(c)) {
+                return;
+            }
+            if (isWS(c)) {
+                skipWS(ib);
+                c = ib.sgetc();
+            }
+            if (isAssign(c)) {
+                skipWS(ib);
+            }
+            return;
+        }
+
+        ib.sbumpc();
+        if (isEsc(c)) {
+            readEsc(s, ib);
+        } else {
+            s += static_cast<wchar_t>(c); // exlicit cast preferred
+        }
+    }
+}
+
+inline void
+Properties::readValue(wstring& s, streambuf& ib)
+{
+    int c;
+    while ((c = ib.sgetc()) != EOF) {
+        ib.sbumpc();
+        if (isNL(c)) {
+            return;
+        }
+
+        if (isEsc(c)) {
+            readEsc(s, ib);
+        } else {
+            s += static_cast<wchar_t>(c); // exlicit cast preferred
+        }
+    }
+}
+
+inline bool
+Properties::isPrintableAscii(wchar_t c)
+{
+    return (L'\x20' <= c && c <= L'\x7e');
+}
+
+inline void
+Properties::writeChar(streambuf& os, char c)
+{
+    int n = os.sputc(c);
+    if (n == EOF)
+        throw ios_base::failure("Error writing to streambuf");
+}
+
+inline void
+Properties::writeAsciiEsc(streambuf& os, wchar_t c)
+{
+    assert(L'\x20' <= c && c <= L'\x7e');
+    char d;
+    switch (c) {
+    case L'\t':     // HT
+        d = '\x74'; // 't'
+        break;
+    case L'\n':    // LF
+        d = '\x6e'; // 'n'
+        break;
+    case L'\f':    // FF
+        d = '\x66'; // 'f'
+        break;
+    case L'\r':    // CR
+        d = '\x72'; // 'r'
+        break;
+    case L' ':     // SPACE
+    case L'!':
+    case L'#':
+    case L':':
+    case L'=':
+    case L'\\':
+        d = static_cast<char>(c); // exlicit cast preferred
+        break;
+    default:
+        // write the raw character
+        writeChar(os, static_cast<char>(c)); // explicit cast preferred
+        return;
+    }
+    writeChar(os, '\x5c'); // '\\'
+    writeChar(os, d);
+}
+
+inline void
+Properties::writeUnicodeEsc(streambuf& os, wchar_t c)
+{
+    assert(c < L'\x20' || L'\x7e' < c);
+
+    // subsequent code depends upon a UCS-2 (UTF-16) or UTF-32
+    // encoding of wide characters
+    const int w = sizeof(wchar_t);
+    assert(w == 2 || w == 4);
+    assert(CHAR_BIT == 8);
+
+    // write unicode escape sequence as "\\unnnn" or "\Unnnnnnnn"
+    writeChar(os, '\x5c'); // '\\'
+    writeChar(os, w == 2 ? '\x75' : '\x55'); // 'u' : 'U'
+    static const char ascii[] = { '\x30', '\x31', '\x32', '\x33',
+                                  '\x34', '\x35', '\x36', '\x37',
+                                  '\x38', '\x39', '\x41', '\x42',
+                                  '\x43', '\x44', '\x45', '\x46' }; // '0'..'F'
+    for (unsigned int i = w * 8 - 4; i >= 0; i -= 4) {
+        writeChar(os, ascii[(c>>i) & 0xF]);
+    }
+}
+
+inline void
+Properties::writeKey(streambuf& os, const wstring& s)
+{
+    for (wstring::const_iterator i = s.begin(); i != s.end(); ++i) {
+        const wchar_t c = *i;
+        if (isPrintableAscii(c))
+            writeAsciiEsc(os, c);
+        else
+            writeUnicodeEsc(os, c);
+    }
+}
+
+inline void
+Properties::writeValue(streambuf& os, const wstring& s)
+{
+    wstring::const_iterator i = s.begin();
+    for (; i != s.end() && *i == L'\x20'; ++i) { // L' '  SPACE
+        // write leading spaces escaped
+        writeAsciiEsc(os, *i);
+    }
+    for (; i != s.end(); ++i) {
+        const wchar_t c = *i;
+        if (c == L'\x20') { // L' '  SPACE
+            // write embedded or tailing spaces unescaped
+            writeChar(os, '\x20'); // ' '  SPACE
+        } else if (isPrintableAscii(c)) {
+            writeAsciiEsc(os, c);
+        } else {
+            writeUnicodeEsc(os, c);
+        }
+    }
+}
+
+// ---------------------------------------------------------------------------
+
+inline void
+Properties::load(const char* filename)
+    throw (ios_base::failure)
+{
+    assert(filename);
+    ifstream ifs;
+    ifs.exceptions(ifstream::failbit | ifstream::badbit);
+    ifs.open(filename);
+    assert(!ifs.bad()); // thrown ios_base::failure
+    load(ifs);
+    ifs.close();
+}
+
+inline void
+Properties::load(istream& is)
+    throw (ios_base::failure)
+{
+    istream::iostate exceptions = is.exceptions(); // backup
+    is.exceptions(istream::failbit | istream::badbit);
+    streambuf* ib = is.rdbuf();
+    assert(ib != NULL); // thrown ios_base::failure
+    load(*ib);
+    is.exceptions(exceptions); // restore
+}
+
+inline void
+Properties::load(streambuf& ib)
+    throw (ios_base::failure)
+{
+    while (ib.sgetc() != EOF) {
+        readIgnored(ib);
+        if (ib.sgetc() == EOF)
+            return;
+
+        // parse property
+        wstring k;
+        readKey(k, ib);
+        wstring v;
+        readValue(v, ib);
+        //wcout << "('" << k << "', '" << v << "')" << endl;
+        (*this)[k] = v; // YYY
+        //this->operator[](k) = v;
+    }
+}
+
+inline void
+Properties::store(const char* filename, const wstring* header) const
+    throw (ios_base::failure)
+{
+    assert(filename);
+    ofstream ofs;
+    ofs.exceptions(ifstream::failbit | ifstream::badbit);
+    ofs.open(filename);
+    assert(!ofs.bad());
+    store(ofs, header);
+    ofs.close();
+}
+
+inline void
+Properties::store(ostream& os, const wstring* header) const
+    throw (ios_base::failure)
+{
+    ostream::iostate exceptions = os.exceptions(); // backup
+    os.exceptions(istream::failbit | istream::badbit);
+    streambuf* ob = os.rdbuf();
+    assert(ob != NULL); // thrown ios_base::failure
+    store(*ob, header);
+    os.exceptions(exceptions); // restore
+}
+
+inline void
+Properties::store(streambuf& os, const wstring* header) const
+    throw (ios_base::failure)
+{
+    // subsequent code for writing the header, keys and values
+    // depends upon UCS-2 (UTF-16) or UTF-32 character encoding
+    const int w = sizeof(wchar_t);
+    assert(w == 2 || w == 4);
+    assert(CHAR_BIT == 8);
+    assert(L'!' == '\x21');
+    assert(L'A' == '\x41');
+    assert(L'a' == '\x61');
+    assert(L'~' == '\x7e');
+    (void)w;
+    
+    if (header != NULL) {
+        writeChar(os, '\x23'); // '#'
+        writeKey(os, *header);
+        writeChar(os, '\x0a'); // '\n'
+    }
+
+    for (const_iterator i = begin(); i != end(); ++i) {
+        const wstring& key = i->first;
+        const wstring& value = i->second;
+        writeKey(os, key);
+        writeChar(os, '\x3d'); // '='
+        writeValue(os, value);
+        writeChar(os, '\x0a'); // '\n'
+    }
+}
+
+// ---------------------------------------------------------------------------
+
 } // utils
 
 #endif // Properties_hpp

=== modified file 'storage/ndb/test/crund/martins_little_helpers/src/utils/string_helpers.hpp'
--- a/storage/ndb/test/crund/martins_little_helpers/src/utils/string_helpers.hpp	2010-10-01 04:10:21 +0000
+++ b/storage/ndb/test/crund/martins_little_helpers/src/utils/string_helpers.hpp	2010-10-05 08:48:30 +0000
@@ -35,7 +35,7 @@ using std::set;
  * "true"; otherwise, false.
  */
 inline bool
-toBool(const wstring& ws)
+toBool(const wstring& ws, bool vdefault)
 {
     // can't get manipulators to compile
     //bool r;
@@ -52,12 +52,18 @@ toBool(const wstring& ws)
     //std::transform(ws.begin(), ws.end(), t.begin(),
     //               static_cast< int (*)(int) >(std::tolower));
 
-    // short & simple
-    return  ((ws.length() == 4)
-             && (ws[0] == L'T' || ws[0] == L't')
-             && (ws[1] == L'R' || ws[1] == L'r')
-             && (ws[2] == L'U' || ws[2] == L'u')
-             && (ws[3] == L'E' || ws[3] == L'e'));
+    bool val;
+    if (ws.length() == 0) {
+        val = vdefault;
+    } else {
+        // short & simple
+        val = ((ws.length() == 4)
+               && (ws[0] == L'T' || ws[0] == L't')
+               && (ws[1] == L'R' || ws[1] == L'r')
+               && (ws[2] == L'U' || ws[2] == L'u')
+               && (ws[3] == L'E' || ws[3] == L'e'));
+    }
+    return val;
 }
 
 /**

=== modified file 'storage/ndb/test/crund/scripts/load_shema.sh'
--- a/storage/ndb/test/crund/scripts/load_shema.sh	2010-09-27 05:31:17 +0000
+++ b/storage/ndb/test/crund/scripts/load_shema.sh	2010-10-08 11:17:35 +0000
@@ -51,7 +51,7 @@ for ((i=3; i>=0; i--)) ; do
 
   echo
   echo "load tws schema..."
-  "$MYSQL_BIN/mysql" -v < ../tws_benchmark/schema.sql
+  "$MYSQL_BIN/mysql" -v < ../tws/schema.sql
   s=$?
   echo "mysql exit status: $s"
 

=== modified file 'storage/ndb/test/crund/src/com/mysql/cluster/crund/A.java'
--- a/storage/ndb/test/crund/src/com/mysql/cluster/crund/A.java	2010-02-14 05:05:31 +0000
+++ b/storage/ndb/test/crund/src/com/mysql/cluster/crund/A.java	2010-10-05 08:48:30 +0000
@@ -101,7 +101,7 @@ public class A implements Serializable {
 
     // while implementing Serializable...
     static private final long serialVersionUID = -3359921162347129079L;
-     
+
     // while implementing Serializable...
     private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
         in.defaultReadObject();

=== modified file 'storage/ndb/test/crund/src/com/mysql/cluster/crund/ClusterjLoad.java'
--- a/storage/ndb/test/crund/src/com/mysql/cluster/crund/ClusterjLoad.java	2010-09-27 05:31:17 +0000
+++ b/storage/ndb/test/crund/src/com/mysql/cluster/crund/ClusterjLoad.java	2010-10-19 22:56:45 +0000
@@ -39,45 +39,58 @@ import java.util.Set;
 /**
  * A benchmark implementation against a ClusterJ database.
  */
-public class ClusterjLoad extends Driver {
+public class ClusterjLoad extends CrundDriver {
 
-    // ClusterJ connection
+    // ClusterJ settings
     protected String mgmdConnect;
+
+    // ClusterJ resources
     protected SessionFactory sessionFactory;
     protected Session session;
 
-    protected abstract class ClusterjOp extends Op {
-        public ClusterjOp(String name) {
-            super(name);
-        }
-
-        public void init() {}
-
-        public void close() {}
-    };
+    // ----------------------------------------------------------------------
+    // ClusterJ intializers/finalizers
+    // ----------------------------------------------------------------------
 
     @Override
     protected void initProperties() {
         super.initProperties();
 
+        out.print("setting clusterj properties ...");
+
+        final StringBuilder msg = new StringBuilder();
+        final String eol = System.getProperty("line.separator");
+
         // check required properties
         mgmdConnect
             = props.getProperty(Constants.PROPERTY_CLUSTER_CONNECTSTRING);
-        descr = "->ClusterJ->NDB JTie->NDBAPI(" + mgmdConnect + ")";
+
+        if (msg.length() == 0) {
+            out.println(" [ok]");
+        } else {
+            out.println();
+            out.print(msg.toString());
+        }
+
+        // have mgmdConnect initialized first
+        descr = "->clusterj(" + mgmdConnect + ")";
     }
 
     @Override
     protected void printProperties() {
         super.printProperties();
-        out.println("ndb.mgmdConnect             " + mgmdConnect);
+
+        out.println();
+        out.println("clusterj settings ...");
+        out.println("ndb.mgmdConnect                 " + mgmdConnect);
         for (Iterator<Map.Entry<Object,Object>> i
                  = props.entrySet().iterator(); i.hasNext();) {
             Map.Entry<Object,Object> e = i.next();
             final String k = (String)e.getKey();
             if (k.startsWith("com.mysql.clusterj")) {
                 final StringBuilder s = new StringBuilder("..");
-                s.append(k, 10, k.length());
-                while (s.length() < 27) s.append(' ');
+                s.append(k, 18, k.length());
+                while (s.length() < 31) s.append(' ');
                 out.println(s + " " + e.getValue());
             }
         }
@@ -86,6 +99,7 @@ public class ClusterjLoad extends Driver
     @Override
     protected void init() throws Exception {
         super.init();
+
         // load native library (better diagnostics doing it explicitely)
         out.println();
         //loadSystemLibrary("ndbj");
@@ -96,7 +110,7 @@ public class ClusterjLoad extends Driver
         out.print("creating SessionFactory ...");
         out.flush();
         sessionFactory = ClusterJHelper.getSessionFactory(props);
-        out.println(" [SessionFactory: 1]");
+        out.println("     [SessionFactory: 1]");
     }
 
     @Override
@@ -106,25 +120,24 @@ public class ClusterjLoad extends Driver
         if (sessionFactory != null)
             sessionFactory.close();
         sessionFactory = null;
-        out.println("  [ok]");
+        out.println("      [ok]");
+
         super.close();
     }
 
-    protected void initConnection() {
-        out.print("creating Session ...");
-        out.flush();
-        session = sessionFactory.getSession();
-        out.println("        [Session: 1]");
-    }
+    // ----------------------------------------------------------------------
+    // ClusterJ operations
+    // ----------------------------------------------------------------------
 
-    protected void closeConnection() {
-        out.print("closing Session ...");
-        out.flush();
-        if (session != null)
-            session.close();
-        session = null;
-        out.println("         [ok]");
-    }
+    protected abstract class ClusterjOp extends Op {
+        public ClusterjOp(String name) {
+            super(name);
+        }
+
+        public void init() {}
+
+        public void close() {}
+    };
 
     protected int checkFields(IA o) {
         final int cint = o.getCint();
@@ -155,18 +168,21 @@ public class ClusterjLoad extends Driver
         ops.add(
             new ClusterjOp("insA") {
                 public void run(int countA, int countB) {
+                    beginTransaction();
                     for (int i = 0; i < countA; i++) {
                         final IA o = session.newInstance(IA.class);
                         assert o != null;
                         o.setId(i);
                         session.persist(o);
                     }
+                    commitTransaction();
                 }
             });
 
         ops.add(
             new ClusterjOp("insB0") {
                 public void run(int countA, int countB) {
+                    beginTransaction();
                     for (int i = 0; i < countB; i++) {
                         final IB0 o = session.newInstance(IB0.class);
                         assert o != null;
@@ -174,12 +190,14 @@ public class ClusterjLoad extends Driver
                         o.setCvarbinary_def(null);
                         session.persist(o);
                     }
+                    commitTransaction();
                 }
             });
 
         ops.add(
             new ClusterjOp("setAByPK") {
                 public void run(int countA, int countB) {
+                    beginTransaction();
                     for (int i = 0; i < countA; i++) {
                         // blind update
                         final IA o = session.newInstance(IA.class);
@@ -191,12 +209,14 @@ public class ClusterjLoad extends Driver
                         o.setCdouble((double)i);
                         session.updatePersistent(o);
                     }
+                    commitTransaction();
                 }
             });
 
         ops.add(
             new ClusterjOp("setB0ByPK") {
                 public void run(int countA, int countB) {
+                    beginTransaction();
                     for (int i = 0; i < countB; i++) {
                         // blind update
                         final IB0 o = session.newInstance(IB0.class);
@@ -208,12 +228,14 @@ public class ClusterjLoad extends Driver
                         o.setCdouble((double)i);
                         session.updatePersistent(o);
                     }
+                    commitTransaction();
                 }
             });
 
         ops.add(
             new ClusterjOp("getAByPK") {
                 public void run(int countA, int countB) {
+                    beginTransaction();
                     for (int i = 0; i < countA; i++) {
                         final IA o = session.find(IA.class, i);
                         assert o != null;
@@ -222,12 +244,14 @@ public class ClusterjLoad extends Driver
                         final int j = checkFields(o);
                         verify(j == id);
                     }
+                    commitTransaction();
                 }
             });
 
         ops.add(
             new ClusterjOp("getB0ByPK") {
                 public void run(int countA, int countB) {
+                    beginTransaction();
                     for (int i = 0; i < countB; i++) {
                         final IB0 o = session.find(IB0.class, i);
                         assert o != null;
@@ -236,6 +260,7 @@ public class ClusterjLoad extends Driver
                         final int j = checkFields(o);
                         verify(j == id);
                     }
+                    commitTransaction();
                 }
             });
 
@@ -246,6 +271,7 @@ public class ClusterjLoad extends Driver
             ops.add(
                 new ClusterjOp("setVarbinary" + l) {
                     public void run(int countA, int countB) {
+                        beginTransaction();
                         for (int i = 0; i < countB; i++) {
                             // blind update
                             final IB0 o = session.newInstance(IB0.class);
@@ -254,23 +280,27 @@ public class ClusterjLoad extends Driver
                             o.setCvarbinary_def(b);
                             session.updatePersistent(o);
                         }
+                        commitTransaction();
                     }
                 });
 
             ops.add(
                 new ClusterjOp("getVarbinary" + l) {
                     public void run(int countA, int countB) {
+                        beginTransaction();
                         for (int i = 0; i < countB; i++) {
                             final IB0 o = session.find(IB0.class, i);
                             assert o != null;
                             verify(Arrays.equals(b, o.getCvarbinary_def()));
                         }
+                        commitTransaction();
                     }
                 });
 
             ops.add(
                 new ClusterjOp("clearVarbinary" + l) {
                     public void run(int countA, int countB) {
+                        beginTransaction();
                         for (int i = 0; i < countB; i++) {
                             // blind update
                             final IB0 o = session.newInstance(IB0.class);
@@ -279,10 +309,11 @@ public class ClusterjLoad extends Driver
                             o.setCvarbinary_def(null);
                             session.updatePersistent(o);
                         }
+                        commitTransaction();
                     }
                 });
-        }        
-        
+        }
+
         for (int i = 0, l = 1; l <= maxVarcharChars; l *= 10, i++) {
             final String s = strings[i];
             assert l == s.length();
@@ -290,6 +321,7 @@ public class ClusterjLoad extends Driver
             ops.add(
                 new ClusterjOp("setVarchar" + l) {
                     public void run(int countA, int countB) {
+                        beginTransaction();
                         for (int i = 0; i < countB; i++) {
                             // blind update
                             final IB0 o = session.newInstance(IB0.class);
@@ -298,23 +330,27 @@ public class ClusterjLoad extends Driver
                             o.setCvarchar_def(s);
                             session.updatePersistent(o);
                         }
+                        commitTransaction();
                     }
                 });
 
             ops.add(
                 new ClusterjOp("getVarchar" + l) {
                     public void run(int countA, int countB) {
+                        beginTransaction();
                         for (int i = 0; i < countB; i++) {
                             final IB0 o = session.find(IB0.class, i);
                             assert o != null;
                             verify(s.equals(o.getCvarchar_def()));
                         }
+                        commitTransaction();
                     }
                 });
 
             ops.add(
                 new ClusterjOp("clearVarchar" + l) {
                     public void run(int countA, int countB) {
+                        beginTransaction();
                         for (int i = 0; i < countB; i++) {
                             // blind update
                             final IB0 o = session.newInstance(IB0.class);
@@ -323,13 +359,15 @@ public class ClusterjLoad extends Driver
                             o.setCvarchar_def(null);
                             session.updatePersistent(o);
                         }
+                        commitTransaction();
                     }
                 });
         }
-        
+
         ops.add(
             new ClusterjOp("setB0->A") {
                 public void run(int countA, int countB) {
+                    beginTransaction();
                     for (int i = 0; i < countB; i++) {
                         // blind update
                         final IB0 b0 = session.newInstance(IB0.class);
@@ -339,12 +377,14 @@ public class ClusterjLoad extends Driver
                         b0.setAid(aId);
                         session.updatePersistent(b0);
                     }
+                    commitTransaction();
                 }
             });
 
         ops.add(
             new ClusterjOp("navB0->A") {
                 public void run(int countA, int countB) {
+                    beginTransaction();
                     for (int i = 0; i < countB; i++) {
                         final IB0 b0 = session.find(IB0.class, i);
                         assert b0 != null;
@@ -356,6 +396,7 @@ public class ClusterjLoad extends Driver
                         final int j = checkFields(a);
                         verify(j == id);
                     }
+                    commitTransaction();
                 }
             });
 
@@ -373,6 +414,7 @@ public class ClusterjLoad extends Driver
                 }
 
                 public void run(int countA, int countB) {
+                    beginTransaction();
                     // QueryBuilder is the sessionFactory for queries
                     final QueryBuilder builder
                         = session.getQueryBuilder();
@@ -399,12 +441,14 @@ public class ClusterjLoad extends Driver
                             verify(j == id);
                         }
                     }
+                    commitTransaction();
                 }
             });
 
         ops.add(
             new ClusterjOp("nullB0->A") {
                 public void run(int countA, int countB) {
+                    beginTransaction();
                     for (int i = 0; i < countB; i++) {
                         // blind update
                         final IB0 b0 = session.newInstance(IB0.class);
@@ -412,12 +456,14 @@ public class ClusterjLoad extends Driver
                         assert b0 != null;
                         b0.setAid(0);
                     }
+                    commitTransaction();
                 }
             });
 
         ops.add(
             new ClusterjOp("delB0ByPK") {
                 public void run(int countA, int countB) {
+                    beginTransaction();
                     for (int i = 0; i < countB; i++) {
                         // blind delete
                         final IB0 o = session.newInstance(IB0.class);
@@ -425,12 +471,14 @@ public class ClusterjLoad extends Driver
                         o.setId(i);
                         session.remove(o);
                     }
+                    commitTransaction();
                 }
             });
 
         ops.add(
             new ClusterjOp("delAByPK") {
                 public void run(int countA, int countB) {
+                    beginTransaction();
                     for (int i = 0; i < countA; i++) {
                         // blind delete
                         final IA o = session.newInstance(IA.class);
@@ -438,12 +486,14 @@ public class ClusterjLoad extends Driver
                         o.setId(i);
                         session.remove(o);
                     }
+                    commitTransaction();
                 }
             });
 
         ops.add(
             new ClusterjOp("insA_attr") {
                 public void run(int countA, int countB) {
+                    beginTransaction();
                     for (int i = 0; i < countA; i++) {
                         final IA o = session.newInstance(IA.class);
                         assert o != null;
@@ -454,12 +504,14 @@ public class ClusterjLoad extends Driver
                         o.setCdouble((double)-i);
                         session.persist(o);
                     }
+                    commitTransaction();
                 }
             });
 
         ops.add(
             new ClusterjOp("insB0_attr") {
                 public void run(int countA, int countB) {
+                    beginTransaction();
                     for (int i = 0; i < countB; i++) {
                         final IB0 o = session.newInstance(IB0.class);
                         assert o != null;
@@ -471,31 +523,36 @@ public class ClusterjLoad extends Driver
                         o.setCvarbinary_def(null);
                         session.persist(o);
                     }
+                    commitTransaction();
                 }
             });
 
         ops.add(
             new ClusterjOp("delAllB0") {
                 public void run(int countA, int countB) {
+                    beginTransaction();
                     int del = session.deletePersistentAll(IB0.class);
                     assert del == countB;
+                    commitTransaction();
                 }
             });
 
         ops.add(
             new ClusterjOp("delAllA") {
                 public void run(int countA, int countB) {
+                    beginTransaction();
                     int del = session.deletePersistentAll(IA.class);
                     assert del == countA;
+                    commitTransaction();
                 }
             });
 
         // prepare queries
-        for (Iterator<Driver.Op> i = ops.iterator(); i.hasNext();) {
+        for (Iterator<CrundDriver.Op> i = ops.iterator(); i.hasNext();) {
             ((ClusterjOp)i.next()).init();
         }
 
-        out.println(" [ClusterjOp: " + ops.size() + "]");
+        out.println("     [ClusterjOp: " + ops.size() + "]");
     }
 
     protected void closeOperations() {
@@ -503,12 +560,12 @@ public class ClusterjLoad extends Driver
         out.flush();
 
         // close all queries
-        for (Iterator<Driver.Op> i = ops.iterator(); i.hasNext();) {
+        for (Iterator<CrundDriver.Op> i = ops.iterator(); i.hasNext();) {
             ((ClusterjOp)i.next()).close();
         }
         ops.clear();
 
-        out.println("      [ok]");
+        out.println("          [ok]");
     }
 
     protected void beginTransaction() {
@@ -519,8 +576,24 @@ public class ClusterjLoad extends Driver
         session.currentTransaction().commit();
     }
 
-    protected void rollbackTransaction() {
-        session.currentTransaction().rollback();
+    // ----------------------------------------------------------------------
+    // ClusterJ datastore operations
+    // ----------------------------------------------------------------------
+
+    protected void initConnection() {
+        out.print("creating Session ...");
+        out.flush();
+        session = sessionFactory.getSession();
+        out.println("            [Session: 1]");
+    }
+
+    protected void closeConnection() {
+        out.print("closing Session ...");
+        out.flush();
+        if (session != null)
+            session.close();
+        session = null;
+        out.println("             [ok]");
     }
 
     protected void clearPersistenceContext() {
@@ -533,7 +606,7 @@ public class ClusterjLoad extends Driver
 
         session.currentTransaction().begin();
         int delB0 = session.deletePersistentAll(IB0.class);
-        out.print("    [B0: " + delB0);
+        out.print("        [B0: " + delB0);
         out.flush();
         int delA = session.deletePersistentAll(IA.class);
         out.print(", A: " + delA);

=== added file 'storage/ndb/test/crund/src/com/mysql/cluster/crund/CrundDriver.java'
--- a/storage/ndb/test/crund/src/com/mysql/cluster/crund/CrundDriver.java	1970-01-01 00:00:00 +0000
+++ b/storage/ndb/test/crund/src/com/mysql/cluster/crund/CrundDriver.java	2010-10-19 22:56:45 +0000
@@ -0,0 +1,432 @@
+/* -*- mode: java; c-basic-offset: 4; indent-tabs-mode: nil; -*-
+ *  vim:expandtab:shiftwidth=4:tabstop=4:smarttab:
+ *
+ *  Copyright (C) 2008 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
+ */
+
+package com.mysql.cluster.crund;
+
+import java.util.Properties;
+import java.util.List;
+import java.util.Set;
+import java.util.HashSet;
+import java.util.ArrayList;
+import java.util.Date;
+import java.text.SimpleDateFormat;
+
+import java.io.FileInputStream;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.io.InputStream;
+
+
+/**
+ * This class benchmarks standard database operations over a series
+ * of transactions on an increasing data set.
+ * <p>
+ * The abstract database operations are variations of: Create,
+ * Read, Update, Navigate, and Delete -- hence, the benchmark's name: CRUND.
+ * <p>
+ * The actual operations are defined by subclasses to allow measuring the
+ * operation performance across different datastore implementations.
+ *
+ * @see <a href="http://www.urbandictionary.com/define.php?term=crund">Urban Dictionary: crund</a>
+ * <ol>
+ * <li> used to debase people who torture others with their illogical
+ * attempts to make people laugh;
+ * <li> reference to cracking obsolete jokes;
+ * <li> a dance form;
+ * <li> to hit hard or smash.
+ * </ol>
+ */
+abstract public class CrundDriver extends Driver {
+
+    // benchmark settings
+    protected boolean renewConnection;
+    protected boolean renewOperations;
+    protected boolean logSumOfOps;
+    protected boolean allowExtendedPC;
+    protected int aStart;
+    protected int bStart;
+    protected int aEnd;
+    protected int bEnd;
+    protected int aScale;
+    protected int bScale;
+    protected int maxVarbinaryBytes;
+    protected int maxVarcharChars;
+    protected int maxBlobBytes;
+    protected int maxTextChars;
+    protected final Set<String> exclude = new HashSet<String>();
+
+    // ----------------------------------------------------------------------
+    // benchmark intializers/finalizers
+    // ----------------------------------------------------------------------
+
+    protected void init() throws Exception {
+        super.init();
+        // do work here
+    }    
+
+    protected void close() throws Exception {
+        // do work here
+        super.close();
+    }
+
+    protected void initProperties() {
+        super.initProperties();
+
+        out.print("setting crund properties ...");
+
+        final StringBuilder msg = new StringBuilder();
+        final String eol = System.getProperty("line.separator");
+
+        renewConnection = parseBoolean("renewConnection", false);
+        renewOperations = parseBoolean("renewOperations", false);
+        logSumOfOps = parseBoolean("logSumOfOps", true);
+        allowExtendedPC = parseBoolean("allowExtendedPC", false);
+
+        aStart = parseInt("aStart", 256);
+        if (aStart < 1) {
+            msg.append("[ignored] aStart:               " + aStart + eol);
+            aStart = 256;
+        }
+        aEnd = parseInt("aEnd", aStart);
+        if (aEnd < aStart) {
+            msg.append("[ignored] aEnd:                 "+ aEnd + eol);
+            aEnd = aStart;
+        }
+        aScale = parseInt("aScale", 2);
+        if (aScale < 2) {
+            msg.append("[ignored] aScale:               " + aScale + eol);
+            aScale = 2;
+        }
+
+        bStart = parseInt("bStart", 256);
+        if (bStart < 1) {
+            msg.append("[ignored] bStart:               " + bStart + eol);
+            bStart = 256;
+        }
+        bEnd = parseInt("bEnd", bStart);
+        if (bEnd < bStart) {
+            msg.append("[ignored] bEnd:                 " + bEnd + eol);
+            bEnd = bStart;
+        }
+        bScale = parseInt("bScale", 2);
+        if (bScale < 2) {
+            msg.append("[ignored] bScale:               " + bScale + eol);
+            bScale = 2;
+        }
+
+        maxVarbinaryBytes = parseInt("maxVarbinaryBytes", 100);
+        if (maxVarbinaryBytes < 0) {
+            msg.append("[ignored] maxVarbinaryBytes:    "
+                       + maxVarbinaryBytes + eol);
+            maxVarbinaryBytes = 100;
+        }
+        maxVarcharChars = parseInt("maxVarcharChars", 100);
+        if (maxVarcharChars < 0) {
+            msg.append("[ignored] maxVarcharChars:      "
+                       + maxVarcharChars + eol);
+            maxVarcharChars = 100;
+        }
+
+        maxBlobBytes = parseInt("maxBlobBytes", 1000);
+        if (maxBlobBytes < 0) {
+            msg.append("[ignored] maxBlobBytes:         "
+                       + maxBlobBytes + eol);
+            maxBlobBytes = 1000;
+        }
+        maxTextChars = parseInt("maxTextChars", 1000);
+        if (maxTextChars < 0) {
+            msg.append("[ignored] maxTextChars:         "
+                       + maxTextChars + eol);
+            maxTextChars = 1000;
+        }
+
+        // initialize exclude set
+        final String[] e = props.getProperty("exclude", "").split(",");
+        for (int i = 0; i < e.length; i++) {
+            exclude.add(e[i]);
+        }
+
+        if (msg.length() == 0) {
+            out.println("    [ok: "
+                        + "A=" + aStart + ".." + aEnd
+                        + ", B=" + bStart + ".." + bEnd + "]");
+        } else {
+            out.println();
+            out.print(msg.toString());
+        }
+    }
+
+    protected void printProperties() {
+        super.printProperties();
+
+        out.println();
+        out.println("crund settings ...");
+        out.println("renewConnection:                " + renewConnection);
+        out.println("renewOperations:                " + renewOperations);
+        out.println("logSumOfOps:                    " + logSumOfOps);
+        out.println("allowExtendedPC:                " + allowExtendedPC);
+        out.println("aStart:                         " + aStart);
+        out.println("bStart:                         " + bStart);
+        out.println("aEnd:                           " + aEnd);
+        out.println("bEnd:                           " + bEnd);
+        out.println("aScale:                         " + aScale);
+        out.println("bScale:                         " + bScale);
+        out.println("maxVarbinaryBytes:              " + maxVarbinaryBytes);
+        out.println("maxVarcharChars:                " + maxVarcharChars);
+        out.println("maxBlobBytes:                   " + maxBlobBytes);
+        out.println("maxTextChars:                   " + maxTextChars);
+        out.println("exclude:                        " + exclude);
+    }
+
+    // ----------------------------------------------------------------------
+    // benchmark operations
+    // ----------------------------------------------------------------------
+
+    // a database operation to be benchmarked
+    protected abstract class Op {
+        final protected String name;
+
+        public Op(String name) { this.name = name; }
+
+        public String getName() { return name; }
+
+        public abstract void run(int countA, int countB) throws Exception;
+    };
+
+    // the list of database operations to be benchmarked
+    protected final List<Op> ops = new ArrayList<Op>();
+
+    // manages list of database operations
+    abstract protected void initOperations() throws Exception;
+    abstract protected void closeOperations() throws Exception;
+
+    protected void runTests() throws Exception {
+        out.println();
+        initConnection();
+        initOperations();
+
+        assert (aStart <= aEnd && aScale > 1);
+        assert (bStart <= bEnd && bScale > 1);
+        for (int i = aStart; i <= aEnd; i *= aScale) {
+            for (int j = bStart; j <= bEnd; j *= bScale) {
+                try {
+                    runLoads(i, j);
+                } catch (Exception ex) {
+                    // already in rollback for database/orm exceptions
+                    throw ex;
+                }
+            }
+        }
+
+        out.println();
+        out.println("------------------------------------------------------------");
+        out.println();
+
+        clearData();
+        closeOperations();
+        closeConnection();
+    }
+
+    protected void runLoads(int countA, int countB) throws Exception {
+        out.println();
+        out.println("------------------------------------------------------------");
+
+        if (countA > countB) {
+            out.println("skipping operations ..."
+                        + "         [A=" + countA + ", B=" + countB + "]");
+            return;
+        }
+        out.println("running operations ..."
+                    + "          [A=" + countA + ", B=" + countB + "]");
+
+        // log buffers
+        if (logRealTime) {
+            rtimes.append("A=" + countA + ", B=" + countB);
+            ta = 0;
+        }
+        if (logMemUsage) {
+            musage.append("A=" + countA + ", B=" + countB);
+            ma = 0;
+        }
+
+        // pre-run cleanup
+        if (renewConnection) {
+            closeOperations();
+            closeConnection();
+            initConnection();
+            initOperations();
+        } else if (renewOperations) {
+            closeOperations();
+            initOperations();
+        }
+        clearData();
+
+        runOperations(countA, countB);
+
+        if (logSumOfOps) {
+            out.println();
+            out.println("total");
+            if (logRealTime) {
+                out.println("tx real time                    " + ta
+                            + "\tms");
+            }
+            if (logMemUsage) {
+                out.println("net mem usage                   "
+                            + (ma >= 0 ? "+" : "") + ma
+                            + "\tKiB");
+            }
+        }
+
+        // log buffers
+        if (logHeader) {
+            if (logSumOfOps) {
+                header.append("\ttotal");
+            }
+            logHeader = false;
+        }
+        if (logRealTime) {
+            if (logSumOfOps) {
+                rtimes.append("\t" + ta);
+            }
+            rtimes.append(endl);
+        }
+        if (logMemUsage) {
+            if (logSumOfOps) {
+                musage.append("\t" + ma);
+            }
+            musage.append(endl);
+        }
+    }
+
+    protected void runOperations(int countA, int countB) throws Exception {
+        for (Op op : ops) {
+            // pre-tx cleanup
+            if (!allowExtendedPC) {
+                // effectively prevent caching beyond Tx scope by clearing
+                // any data/result caches before the next transaction
+                clearPersistenceContext();
+            }
+            runOp(op, countA, countB);
+        }
+    }
+
+    protected void runOp(Op op, int countA, int countB) throws Exception {
+        final String name = op.getName();
+        if (!exclude.contains(name)) {
+            begin(name);
+            op.run(countA, countB);
+            finish(name);
+        }
+    }
+
+    // reports an error if a condition is not met
+    static protected final void verify(boolean cond) {
+        //assert (cond);
+        if (!cond)
+            throw new RuntimeException("data verification failed.");
+    }
+
+    static protected final void verify(int exp, int act) {
+        if (exp != act)
+            throw new RuntimeException("data verification failed:"
+                                       + " expected = " + exp
+                                       + ", actual = " + act);
+    }
+
+    static protected final void verify(String exp, String act) {
+        if ((exp == null && act != null)
+            || (exp != null && !exp.equals(act)))
+            throw new RuntimeException("data verification failed:"
+                                       + " expected = '" + exp + "'"
+                                       + ", actual = '" + act + "'");
+    }
+
+    // ----------------------------------------------------------------------
+    // helpers
+    // ----------------------------------------------------------------------
+
+    static final protected String myString(int n) {
+        final StringBuilder s = new StringBuilder();
+        switch (n) {
+        case 1:
+            s.append('i');
+            break;
+        case 2:
+            for (int i = 0; i < 10; i++) s.append('x');
+            break;
+        case 3:
+            for (int i = 0; i < 100; i++) s.append('c');
+            break;
+        case 4:
+            for (int i = 0; i < 1000; i++) s.append('m');
+            break;
+        case 5:
+            for (int i = 0; i < 10000; i++) s.append('X');
+            break;
+        case 6:
+            for (int i = 0; i < 100000; i++) s.append('C');
+            break;
+        case 7:
+            for (int i = 0; i < 1000000; i++) s.append('M');
+            break;
+        default:
+            throw new IllegalArgumentException("unsupported 10**n = " + n);
+        }
+        return s.toString();
+    }
+
+    static final protected byte[] myBytes(String s) {
+        final char[] c = s.toCharArray();
+        final int n = c.length;
+        final byte[] b = new byte[n];
+        for (int i = 0; i < n; i++) b[i] = (byte)c[i];
+        return b;
+    }
+
+    // some string and byte constants
+    static final protected String string1 = myString(1);
+    static final protected String string2 = myString(2);
+    static final protected String string3 = myString(3);
+    static final protected String string4 = myString(4);
+    static final protected String string5 = myString(5);
+    static final protected String string6 = myString(6);
+    static final protected String string7 = myString(7);
+    static final protected byte[] bytes1 = myBytes(string1);
+    static final protected byte[] bytes2 = myBytes(string2);
+    static final protected byte[] bytes3 = myBytes(string3);
+    static final protected byte[] bytes4 = myBytes(string4);
+    static final protected byte[] bytes5 = myBytes(string5);
+    static final protected byte[] bytes6 = myBytes(string6);
+    static final protected byte[] bytes7 = myBytes(string7);
+    static final protected String[] strings
+        = { string1, string2, string3, string4, string5, string6, string7 };
+    static final protected byte[][] bytes
+        = { bytes1, bytes2, bytes3, bytes4, bytes5, bytes6, bytes7 };
+
+    // ----------------------------------------------------------------------
+    // datastore operations
+    // ----------------------------------------------------------------------
+
+    abstract protected void initConnection() throws Exception;
+    abstract protected void closeConnection() throws Exception;
+    abstract protected void clearPersistenceContext() throws Exception;
+    abstract protected void clearData() throws Exception;
+}

=== modified file 'storage/ndb/test/crund/src/com/mysql/cluster/crund/Driver.java'
--- a/storage/ndb/test/crund/src/com/mysql/cluster/crund/Driver.java	2010-10-01 04:10:21 +0000
+++ b/storage/ndb/test/crund/src/com/mysql/cluster/crund/Driver.java	2010-10-19 22:56:45 +0000
@@ -22,8 +22,6 @@ package com.mysql.cluster.crund;
 
 import java.util.Properties;
 import java.util.List;
-import java.util.Set;
-import java.util.HashSet;
 import java.util.ArrayList;
 import java.util.Date;
 import java.text.SimpleDateFormat;
@@ -56,182 +54,154 @@ import java.io.InputStream;
  */
 abstract public class Driver {
 
-    /**
-     *  The stream to write messages to.
-     */
+    // console
     static protected final PrintWriter out = new PrintWriter(System.out, true);
-
-    /**
-     *  The stream to write error messages to.
-     */
     static protected final PrintWriter err = new PrintWriter(System.err, true);
 
-    /**
-     *  Shortcut to the end-of-line character sequence.
-     */
+    // shortcuts
     static protected final String endl = System.getProperty("line.separator");
+    static protected final Runtime rt = Runtime.getRuntime();
 
-    /**
-     *  Shortcut to the Runtime.
-     */
-    static private final Runtime rt = Runtime.getRuntime();
-
-    // command-line arguments
+    // driver command-line arguments
     static private final List<String> propFileNames = new ArrayList<String>();
-    static private String logFileName
-        = ("log_"
-           + new SimpleDateFormat("yyyyMMdd_HHMMss").format(new Date())
-           + ".txt");
+    static private String logFileName;
 
-    // the data output writer
-    private PrintWriter log;
-
-    // benchmark settings
+    // driver settings
     protected final Properties props = new Properties();
-    protected String descr = "";
     protected boolean logRealTime;
     protected boolean logMemUsage;
     protected boolean includeFullGC;
-    protected boolean logSumOfOps;
-    protected boolean renewOperations;
-    protected boolean renewConnection;
-    protected boolean allowExtendedPC;
-    protected int aStart;
-    protected int bStart;
-    protected int aEnd;
-    protected int bEnd;
-    protected int aScale;
-    protected int bScale;
-    protected int maxVarbinaryBytes;
-    protected int maxVarcharChars;
-    protected int maxBlobBytes;
-    protected int maxTextChars;
     protected int warmupRuns;
     protected int hotRuns;
-    protected final Set<String> exclude = new HashSet<String>();
 
-    // ----------------------------------------------------------------------
+    // driver resources
+    protected PrintWriter log;
+    protected String descr = "";
+    protected boolean logHeader;
+    protected StringBuilder header;
+    protected StringBuilder rtimes;
+    protected StringBuilder musage;
+    protected long t0 = 0, t1 = 0, ta = 0;
+    protected long m0 = 0, m1 = 0, ma = 0;
 
-    static final protected String myString(int n) {
-        final StringBuilder s = new StringBuilder();
-        switch (n) {
-        case 1:
-            s.append('i');
-            break;
-        case 2:
-            for (int i = 0; i < 10; i++) s.append('x');
-            break;
-        case 3:
-            for (int i = 0; i < 100; i++) s.append('c');
-            break;
-        case 4:
-            for (int i = 0; i < 1000; i++) s.append('m');
-            break;
-        case 5:
-            for (int i = 0; i < 10000; i++) s.append('X');
-            break;
-        case 6:
-            for (int i = 0; i < 100000; i++) s.append('C');
-            break;
-        case 7:
-            for (int i = 0; i < 1000000; i++) s.append('M');
-            break;
-        default:
-            throw new IllegalArgumentException("unsupported 10**n = " + n);
-        }
-        return s.toString();
-    }
-    
-    static final protected byte[] myBytes(String s) {
-        final char[] c = s.toCharArray();
-        final int n = c.length;
-        final byte[] b = new byte[n];
-        for (int i = 0; i < n; i++) b[i] = (byte)c[i];
-        return b;
-    }
-    
-    // some string and byte constants
-    static final protected String string1 = myString(1);
-    static final protected String string2 = myString(2);
-    static final protected String string3 = myString(3);
-    static final protected String string4 = myString(4);
-    static final protected String string5 = myString(5);
-    static final protected String string6 = myString(6);
-    static final protected String string7 = myString(7);
-    static final protected byte[] bytes1 = myBytes(string1);
-    static final protected byte[] bytes2 = myBytes(string2);
-    static final protected byte[] bytes3 = myBytes(string3);
-    static final protected byte[] bytes4 = myBytes(string4);
-    static final protected byte[] bytes5 = myBytes(string5);
-    static final protected byte[] bytes6 = myBytes(string6);
-    static final protected byte[] bytes7 = myBytes(string7);
-    static final protected String[] strings
-        = { string1, string2, string3, string4, string5, string6, string7 };
-    static final protected byte[][] bytes
-        = { bytes1, bytes2, bytes3, bytes4, bytes5, bytes6, bytes7 };
-    
+    // ----------------------------------------------------------------------
+    // driver usage
     // ----------------------------------------------------------------------
 
     /**
-     * A database operation to be benchmarked.
+     * Prints a command-line usage message and exits.
      */
-    protected abstract class Op {
-        final protected String name;
+    static protected void exitUsage() {
+        out.println("usage: [options]");
+        out.println("    [-p <file name>]...    a properties file name");
+        out.println("    [-l <file name>]       log file name for data output");
+        out.println("    [-h|--help]            print usage message and exit");
+        out.println();
+        System.exit(1); // return an error code
+    }
 
-        public Op(String name) {
-            this.name = name;
+    /**
+     * Parses the benchmark's command-line arguments.
+     */
+    static public void parseArguments(String[] args) {
+        for (int i = 0; i < args.length; i++) {
+            final String arg = args[i];
+            if (arg.equals("-p")) {
+                if (i >= args.length) {
+                    exitUsage();
+                }
+                propFileNames.add(args[++i]);
+            } else if (arg.equals("-l")) {
+                if (i >= args.length) {
+                    exitUsage();
+                }
+                logFileName = args[++i];
+            } else if (arg.equals("-h") || arg.equals("--help")) {
+                exitUsage();
+            } else {
+                out.println("unknown option: " + arg);
+                exitUsage();
+            }
         }
 
-        public String getName() {
-            return name;
+        if (propFileNames.size() == 0) {
+            propFileNames.add("run.properties");
         }
 
-        public abstract void run(int countA, int countB) throws Exception;
-    };
+        if (logFileName == null) {
+            SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd_HHMMss");
+            logFileName = ("log_" + sdf.format(new Date()) + ".txt");
+        }
+    }
 
     /**
-     * The list of database operations to be benchmarked.
-     * While the list instance is final, its content is managed by methods
-     * initOperations() and closeOperations() as defined by subclasses.
+     * Creates an instance.
      */
-    protected final List<Op> ops = new ArrayList<Op>();
-
-    // buffers collecting the header and data lines written to log
-    boolean logHeader;
-    private StringBuilder header;
-    private StringBuilder rtimes;
-    private StringBuilder musage;
-
-    // benchmark data fields
-    private long t0 = 0, t1 = 0, ta = 0;
-    private long m0 = 0, m1 = 0, ma = 0;
-
-    // benchmark methods to be defined by subclasses
-    abstract protected void initConnection() throws Exception;
-    abstract protected void closeConnection() throws Exception;
-    abstract protected void initOperations() throws Exception;
-    abstract protected void closeOperations() throws Exception;
-    abstract protected void clearPersistenceContext() throws Exception;
-    abstract protected void clearData() throws Exception;
-    abstract protected void beginTransaction() throws Exception;
-    abstract protected void commitTransaction() throws Exception;
-    abstract protected void rollbackTransaction() throws Exception;
+    public Driver() {}
 
     /**
-     * Reports an error if a condition is not met.
-     *
-     * An invariant method to ensure the consistent application
-     * of verifying read results.
+     * Runs the benchmark.
      */
-    static protected final void verify(boolean cond) {
-        //assert (cond);
-        if (!cond)
-            throw new RuntimeException("wrong data; verification failed");
+    public void run() {
+        try {
+            init();
+
+            if (warmupRuns > 0) {
+                out.println();
+                out.println("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++");
+                out.println("warmup runs ...");
+                out.println("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++");
+
+                for (int i = 0; i < warmupRuns; i++) {
+                    runTests();
+                }
+
+                // truncate log file, reset log buffers
+                closeLogFile();
+                openLogFile();
+                header = new StringBuilder();
+                rtimes = new StringBuilder();
+                musage = new StringBuilder();
+                logHeader = true;
+            }
+            
+            if (hotRuns > 0) {
+                out.println();
+                out.println("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++");
+                out.println("hot runs ...");
+                out.println("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++");
+
+                for (int i = 0; i < hotRuns; i++) {
+                    runTests();
+                }
+
+                // write log buffers
+                if (logRealTime) {
+                    log.println(descr + ", rtime[ms]"
+                                + header.toString() + endl
+                                + rtimes.toString() + endl + endl + endl);
+                }
+                if (logMemUsage) {
+                    log.println(descr + ", net musage[KiB]"
+                                + header.toString() + endl
+                                + musage.toString() + endl + endl + endl);
+                }
+            }
+            
+            close();
+        } catch (Exception ex) {
+            // end the program regardless of threads
+            out.println("caught " + ex);
+            ex.printStackTrace();
+            System.exit(2); // return an error code
+        }
     }
 
-    /**
-     * Loads a dynamically linked system library and reports any failures.
-     */
+    // ----------------------------------------------------------------------
+    // driver intializers/finalizers
+    // ----------------------------------------------------------------------
+
+    // loads a dynamically linked system library and reports any failures
     static protected void loadSystemLibrary(String name) {
         out.print("loading libary ...");
         out.flush();
@@ -252,101 +222,60 @@ abstract public class Driver {
                         + name + "'; caught exception: " + e);
             throw e;
         }
-        out.println("          [" + name + "]");
+        out.println("              [" + name + "]");
     }
 
-    // ----------------------------------------------------------------------
-
-    /**
-     * Runs the entire benchmark.
-     */
-    public void run() {
-        try {
-            init();
-
-            // warmup runs
-            for (int i = 0; i < warmupRuns; i++) {
-                runTests();
-            }
-            
-            // truncate log file, reset log buffers
-            out.println();
-            out.println("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++");
-            out.println("start logging results ...");
-            out.println("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++");
-            out.println();
-            logHeader = true;
-            header = new StringBuilder();
-            rtimes = new StringBuilder();
-            musage = new StringBuilder();
-            closeLogFile();
-            openLogFile();
-
-            // hot runs
-            for (int i = 0; i < hotRuns; i++) {
-                runTests();
-            }
-            
-            // write log buffers
-            if (logRealTime) {
-                log.println(descr + ", rtime[ms]"
-                            + header.toString() + endl
-                            + rtimes.toString() + endl + endl + endl);
-            }
-            if (logMemUsage) {
-                log.println(descr + ", net musage[KiB]"
-                            + header.toString() + endl
-                            + musage.toString() + endl + endl + endl);
-            }
-
-            close();
-        } catch (Exception ex) {
-            // end the program regardless of threads
-            out.println("caught " + ex);
-            ex.printStackTrace();
-            System.exit(2); // return an error code
+    // attempts to run the JVM's Garbage Collector
+    static private void gc() {
+        // empirically determined limit after which no further
+        // reduction in memory usage has been observed
+        //final int nFullGCs = 5;
+        final int nFullGCs = 10;
+        for (int i = 0; i < nFullGCs; i++) {
+            //out.print("gc: ");
+            long oldfree;
+            long newfree = rt.freeMemory();
+            do {
+                oldfree = newfree;
+                rt.runFinalization();
+                rt.gc();
+                newfree = rt.freeMemory();
+                //out.print('.');
+            } while (newfree > oldfree);
+            //out.println();
         }
     }
 
-    /**
-     * Initializes the benchmark's resources.
-     */
+    // initializes the driver's resources.
     protected void init() throws Exception {
         loadProperties();
         initProperties();
         printProperties();
         openLogFile();
 
-        // init log buffers
+        // clear log buffers
         logHeader = true;
         header = new StringBuilder();
         rtimes = new StringBuilder();
         musage = new StringBuilder();
     }
 
-    /**
-     * Releases the benchmark's resources.
-     */
+    // releases the driver's resources.
     protected void close() throws Exception {
-        // close log buffers
+        // clear log buffers
         header = null;
         rtimes = null;
         musage = null;
 
         closeLogFile();
+        props.clear();
     }
 
-    /**
-     * Loads the benchmark's properties from properties files.
-     */
+    // loads the benchmark's properties from properties files
     private void loadProperties() throws IOException {
-        if (propFileNames.size() == 0) {
-            propFileNames.add("crund.properties");
-        }
-        
         out.println();
         for (String fn : propFileNames) {
-            out.println("reading properties file:    " + fn);
+            out.println("reading properties file:        " + fn);
             InputStream is = null;
             try {
                 is = new FileInputStream(fn);
@@ -358,17 +287,13 @@ abstract public class Driver {
         }
     }
 
-    /**
-     * Retrieves a property's value and parses it as a boolean.
-     */
-    protected boolean parseBoolean(String k) {
-        return Boolean.parseBoolean(props.getProperty(k));
+    // retrieves a property's value and parses it as a boolean
+    protected boolean parseBoolean(String k, boolean vdefault) {
+        final String v = props.getProperty(k);
+        return (v == null ? vdefault : Boolean.parseBoolean(v));
     }
-    
-    /**
-     * Retrieves a property's value and parses it as a signed decimal integer.
-     * @throws NumberFormatException with a descriptive error message
-     */
+
+    // retrieves a property's value and parses it as a signed decimal integer
     protected int parseInt(String k, int vdefault) {
         final String v = props.getProperty(k);
         try {
@@ -381,255 +306,76 @@ abstract public class Driver {
             throw nfe;
         }
     }
-    
-    /**
-     * Initializes the benchmark properties.
-     */
+
+    // initializes the benchmark properties
     protected void initProperties() {
         //props.list(out);
-        out.print("initializing properties ... ");
+        out.print("setting driver properties ...");
+        out.flush();
 
-        final StringBuilder msg = new StringBuilder();        
-        final String eol = System.getProperty("line.separator");        
+        final StringBuilder msg = new StringBuilder();
+        final String eol = System.getProperty("line.separator");
+
+        logRealTime = parseBoolean("logRealTime", true);
+        logMemUsage = parseBoolean("logMemUsage", false);
+        includeFullGC = parseBoolean("includeFullGC", false);
 
-        logRealTime = parseBoolean("logRealTime");
-        logMemUsage = parseBoolean("logMemUsage");
-        includeFullGC = parseBoolean("includeFullGC");
-        logSumOfOps = parseBoolean("logSumOfOps");
-        renewOperations = parseBoolean("renewOperations");
-        renewConnection = parseBoolean("renewConnection");
-        allowExtendedPC = parseBoolean("allowExtendedPC");
-
-        aStart = parseInt("aStart", 256);
-        if (aStart < 1) {
-            msg.append("[ignored] aStart:            " + aStart + eol);
-            aStart = 256;
-        }
-        aEnd = parseInt("aEnd", aStart);
-        if (aEnd < aStart) {
-            msg.append("[ignored] aEnd:              "+ aEnd + eol);
-            aEnd = aStart;
-        }
-        aScale = parseInt("aScale", 2);
-        if (aScale < 2) {
-            msg.append("[ignored] aScale:            " + aScale + eol);
-            aScale = 2;
-        }
-
-        bStart = parseInt("bStart", 256);
-        if (bStart < 1) {
-            msg.append("[ignored] bStart:            " + bStart + eol);
-            bStart = 256;
-        }
-        bEnd = parseInt("bEnd", bStart);
-        if (bEnd < bStart) {
-            msg.append("[ignored] bEnd:              " + bEnd + eol);
-            bEnd = bStart;
-        }
-        bScale = parseInt("bScale", 2);
-        if (bScale < 2) {
-            msg.append("[ignored] bScale:            " + bScale + eol);
-            bScale = 2;
-        }
-
-        maxVarbinaryBytes = parseInt("maxVarbinaryBytes", 100);
-        maxVarcharChars = parseInt("maxVarcharChars", 100);
-        maxBlobBytes = parseInt("maxBlobBytes", 1000);
-        maxTextChars = parseInt("maxTextChars", 1000);
         warmupRuns = parseInt("warmupRuns", 0);
-        hotRuns = parseInt("hotRuns", 1);
+        if (warmupRuns < 0) {
+            msg.append("[ignored] warmupRuns:           " + warmupRuns + eol);
+            warmupRuns = 0;
+        }
 
-        // initialize exclude set
-        final String[] e = props.getProperty("exclude", "").split(",");
-        for (int i = 0; i < e.length; i++) {
-            exclude.add(e[i]);
+        hotRuns = parseInt("hotRuns", 1);
+        if (hotRuns < 1) {
+            msg.append("[ignored] hotRuns:              " + hotRuns + eol);
+            hotRuns = 1;
         }
 
         if (msg.length() == 0) {
-            out.println("[ok]");
+            out.println("   [ok]");
         } else {
             out.println();
             out.print(msg.toString());
         }
-        out.println("data set:                   "
-                    + "[A=" + aStart + ".." + aEnd
-                    + ", B=" + bStart + ".." + bEnd + "]");
     }
-    
-    /**
-     * Prints the benchmark's properties.
-     */
+
+    // prints the benchmark's properties
     protected void printProperties() {
         out.println();
-        out.println("main settings:");
-        out.println("logRealTime:                " + logRealTime);
-        out.println("logMemUsage:                " + logMemUsage);
-        out.println("includeFullGC:              " + includeFullGC);
-        out.println("logSumOfOps:                " + logSumOfOps);
-        out.println("renewOperations:            " + renewOperations);
-        out.println("renewConnection:            " + renewConnection);
-        out.println("allowExtendedPC:            " + allowExtendedPC);
-        out.println("aStart:                     " + aStart);
-        out.println("bStart:                     " + bStart);
-        out.println("aEnd:                       " + aEnd);
-        out.println("bEnd:                       " + bEnd);
-        out.println("aScale:                     " + aScale);
-        out.println("bScale:                     " + bScale);
-        out.println("maxVarbinaryBytes:          " + maxVarbinaryBytes);
-        out.println("maxVarcharChars:            " + maxVarcharChars);
-        out.println("maxBlobBytes:               " + maxBlobBytes);
-        out.println("maxTextChars:               " + maxTextChars);
-        out.println("warmupRuns:                 " + warmupRuns);
-        out.println("hotRuns:                    " + hotRuns);
-        out.println("exclude:                    " + exclude);
+        out.println("driver settings ...");
+        out.println("logRealTime:                    " + logRealTime);
+        out.println("logMemUsage:                    " + logMemUsage);
+        out.println("includeFullGC:                  " + includeFullGC);
+        out.println("warmupRuns:                     " + warmupRuns);
+        out.println("hotRuns:                        " + hotRuns);
     }
 
-    /**
-     * Opens the benchmark's data log file.
-     */
+    // opens the benchmark's data log file
     private void openLogFile() throws IOException {
         out.println();
-        out.println("writing results to file:    " + logFileName);
+        out.println("writing results to file:        " + logFileName);
         log = new PrintWriter(new FileWriter(logFileName, false));
     }
 
-    /**
-     * Closes the benchmark's data log file.
-     */
+    // closes the benchmark's data log file
     private void closeLogFile() throws IOException {
-        out.print("closing files ...    ");
+        out.print("closing files ...");
         out.flush();
         if (log != null) {
             log.close();
             log = null;
         }
-        out.println("       [ok]");
+        out.println("               [ok]");
     }
 
     // ----------------------------------------------------------------------
+    // benchmark operations
+    // ----------------------------------------------------------------------
 
-    /**
-     * Runs a series of benchmark operations on scaled-up data.
-     */
-    protected void runTests() throws Exception {
-        initConnection();
-        initOperations();
-
-        assert (aStart <= aEnd && aScale > 1);
-        assert (bStart <= bEnd && bScale > 1);
-        for (int i = aStart; i <= aEnd; i *= aScale) {
-            for (int j = bStart; j <= bEnd; j *= bScale) {
-                try {
-                    runOperations(i, j);
-                } catch (Exception ex) {
-                    // already in rollback for database/orm exceptions
-                    //rollbackTransaction();
-                    throw ex;
-                }
-            }
-        }
-
-        out.println();
-        out.println("------------------------------------------------------------");
-        out.println();
-
-        clearData();
-        closeOperations();
-        closeConnection();
-    }
-
-    /**
-     * Runs a series of benchmark operations.
-     */
-    protected void runOperations(int countA, int countB) throws Exception {
-        out.println();
-        out.println("------------------------------------------------------------");
-
-        if (countA > countB) {
-            out.println("skipping operations ...     "
-                        + "[A=" + countA + ", B=" + countB + "]");
-            return;
-        }
-        out.println("running operations ...      "
-                    + "[A=" + countA + ", B=" + countB + "]");
-
-        // log buffers
-        if (logRealTime) {
-            rtimes.append("A=" + countA + ", B=" + countB);
-            ta = 0;
-        }
-        if (logMemUsage) {
-            musage.append("A=" + countA + ", B=" + countB);
-            ma = 0;
-        }
-        
-        // pre-run cleanup
-        if (renewConnection) {
-            closeOperations();
-            closeConnection();
-            initConnection();
-            initOperations();
-        } else if (renewOperations) {
-            closeOperations();
-            initOperations();
-        }
-        clearData();
-
-        // run operations
-        for (Op op : ops) {
-            // pre-tx cleanup
-            if (!allowExtendedPC) {
-                // effectively prevent caching beyond Tx scope by clearing
-                // any data/result caches before the next transaction
-                clearPersistenceContext();
-            }
-            runOp(op, countA, countB);
-        }
-        if (logHeader) {
-            if (logSumOfOps)
-                header.append("\ttotal");
-        }
-
-        // log buffers
-        logHeader = false;
-        if (logRealTime) {
-            if (logSumOfOps) {
-                rtimes.append("\t" + ta);
-                out.println();
-                out.println("total");
-                out.println("tx real time\t\t= " + ta
-                            + "\tms [begin..commit]");
-            }
-            rtimes.append(endl);
-        }
-        if (logMemUsage) {
-            if (logSumOfOps) {
-                musage.append("\t" + ma);
-                out.println();
-                out.println("total");
-                out.println("net mem usage\t\t= " + (ma >= 0 ? "+" : "") + ma
-                            + "\tKiB");
-            }
-            musage.append(endl);
-        }               
-    }
-
-    /**
-     * Runs a benchmark operation.
-     */
-    protected void runOp(Op op, int countA, int countB) throws Exception {
-        final String name = op.getName();
-        if (!exclude.contains(name)) {
-            begin(name);
-            op.run(countA, countB);
-            commit(name);
-        }
-    }
+    abstract protected void runTests() throws Exception;
 
-    /**
-     * Begins a benchmarked transaction.
-     */
-    protected void begin(String name) throws Exception {
+    protected void begin(String name) {
         out.println();
         out.println(name);
 
@@ -644,16 +390,9 @@ abstract public class Driver {
             //t0 = System.currentTimeMillis();
             t0 = System.nanoTime() / 1000000;
         }
-
-        beginTransaction();
     }
 
-    /**
-     * Closes a benchmarked transaction.
-     */
-    protected void commit(String name) throws Exception {
-        commitTransaction();
-
+    protected void finish(String name) {
         // attempt one full GC, before timing tx end
         if (includeFullGC) {
             rt.gc();
@@ -663,8 +402,8 @@ abstract public class Driver {
             //t1 = System.currentTimeMillis();
             t1 = System.nanoTime() / 1000000;
             final long t = t1 - t0;
-            out.println("tx real time\t\t= " + t
-                        + "\tms [begin..commit]");
+            out.println("tx real time                    " + t
+                        + "\tms");
             //rtimes.append("\t" + (Math.round(t / 100.0) / 10.0));
             rtimes.append("\t" + t);
             ta += t;
@@ -677,7 +416,8 @@ abstract public class Driver {
             final long m0K = (m0 / 1024);
             final long m1K = (m1 / 1024);
             final long mK = m1K - m0K;
-            out.println("net mem usage\t\t= " + (mK >= 0 ? "+" : "") + mK
+            out.println("net mem usage                   "
+                        + (mK >= 0 ? "+" : "") + mK
                         + "\tKiB [" + m0K + "K->" + m1K + "K]");
             musage.append("\t" + mK);
             ma += mK;
@@ -686,66 +426,4 @@ abstract public class Driver {
         if (logHeader)
             header.append("\t" + name);
     }
-
-    /**
-     * Attempts to run the JVM's Garbage Collector.
-     */
-    static private void gc() {
-        // empirically determined limit after which no further
-        // reduction in memory usage has been observed
-        //final int nFullGCs = 5;
-        final int nFullGCs = 10;
-        for (int i = 0; i < nFullGCs; i++) {
-            //out.print("gc: ");
-            long oldfree;
-            long newfree = rt.freeMemory();
-            do {
-                oldfree = newfree;
-                rt.runFinalization();
-                rt.gc();
-                newfree = rt.freeMemory();
-                //out.print('.');
-            } while (newfree > oldfree);
-            //out.println();
-        }
-    }
-
-    // ----------------------------------------------------------------------
-
-    /**
-     * Prints a command-line usage message and exits.
-     */
-    static private void exitUsage() {
-        out.println("usage: [options]");
-        out.println("    [-p <file name>]...    a properties file name");
-        out.println("    [-l <file name>]       log file name for data output");
-        out.println("    [-h|--help]            print usage message and exit");
-        out.println();
-        System.exit(1); // return an error code
-    }
-
-    /**
-     * Parses the benchmark's command-line arguments.
-     */
-    static public void parseArguments(String[] args) {
-        for (int i = 0; i < args.length; i++) {
-            final String arg = args[i];
-            if (arg.equals("-p")) {
-                if (i >= args.length) {
-                    exitUsage();
-                }
-                propFileNames.add(args[++i]);
-            } else if (arg.equals("-l")) {
-                if (i >= args.length) {
-                    exitUsage();
-                }
-                logFileName = args[++i];
-            } else if (arg.equals("-h") || arg.equals("--help")) {
-                exitUsage();
-            } else {
-                out.println("unknown option: " + arg);
-                exitUsage();
-            }
-        }
-    }
 }

=== modified file 'storage/ndb/test/crund/src/com/mysql/cluster/crund/JdbcLoad.java'
--- a/storage/ndb/test/crund/src/com/mysql/cluster/crund/JdbcLoad.java	2010-09-04 01:20:28 +0000
+++ b/storage/ndb/test/crund/src/com/mysql/cluster/crund/JdbcLoad.java	2010-10-19 22:56:45 +0000
@@ -33,39 +33,32 @@ import java.sql.ResultSet;
 /**
  * A benchmark implementation against a JDBC/SQL database.
  */
-public class JdbcLoad extends Driver {
+public class JdbcLoad extends CrundDriver {
 
-    // JDBC connection
+    // JDBC settings
     protected String driver;
     protected String url;
+    protected String user;
+    protected String password;
+    protected boolean autoCommit;
+
+    // JDBC resources
     protected Connection conn;
     protected PreparedStatement delAllA;
     protected PreparedStatement delAllB0;
 
-    protected abstract class JdbcOp extends Op {
-        final protected String sql;
-        protected PreparedStatement stmt;
-
-        public JdbcOp(String name, String sql) {
-            super(name);
-            this.sql = sql;
-        }
-
-        public void init() throws SQLException {
-            if (stmt == null)
-                stmt = conn.prepareStatement(sql);
-        }
-
-        public void close() throws SQLException {
-            if (stmt != null)
-                stmt.close();
-            stmt = null;
-        }
-    };
+    // ----------------------------------------------------------------------
+    // JDBC intializers/finalizers
+    // ----------------------------------------------------------------------
 
     protected void initProperties() {
         super.initProperties();
 
+        out.print("setting jdbc properties ...");
+
+        final StringBuilder msg = new StringBuilder();
+        final String eol = System.getProperty("line.separator");
+
         // load the JDBC driver class
         driver = props.getProperty("jdbc.driver");
         if (driver == null) {
@@ -85,42 +78,63 @@ public class JdbcLoad extends Driver {
             throw new RuntimeException("Missing property: jdbc.url");
         }
 
+        user = props.getProperty("jdbc.user");
+        password = props.getProperty("jdbc.password");
+
+        // single ops not supported yet
+        autoCommit = parseBoolean("jdbc.autoCommit", false);
+        if (autoCommit) {
+            msg.append("[ignored] autoCommit:           " + autoCommit + eol);
+            autoCommit = false;
+        }
+
+        if (msg.length() == 0) {
+            out.println("     [ok]");
+        } else {
+            out.println();
+            out.print(msg.toString());
+        }
+
+        // have url initialized first
         descr = "->" + url;
-    }
+     }
 
     protected void printProperties() {
         super.printProperties();
-        out.println("jdbc.driver:                " + driver);
-        out.println("jdbc.url:                   " + url);
-    }
 
-    protected void initConnection() throws SQLException {
-        out.print("initializing connection ...");
-        out.flush();
-        final String user = props.getProperty("jdbc.user");
-        final String password = props.getProperty("jdbc.password");
-        final String autoCommit = props.getProperty("jdbc.autoCommit");
-        conn = DriverManager.getConnection(url, user, password);
-        conn.setAutoCommit(Boolean.getBoolean(autoCommit));
-        delAllA = conn.prepareStatement("DELETE FROM a");
-        delAllB0 = conn.prepareStatement("DELETE FROM b0");
-        out.println(" [Conn: 1]");
+        out.println();
+        out.println("jdbc settings ...");
+        out.println("jdbc.driver:                    " + driver);
+        out.println("jdbc.url:                       " + url);
+        out.println("jdbc.user:                      \"" + user + "\"");
+        out.println("jdbc.password:                  \"" + password + "\"");
+        out.println("jdbc.autoCommit:                " + autoCommit);
     }
 
-    protected void closeConnection() throws SQLException {
-        out.print("closing connection ...");
-        out.flush();
-        if (delAllB0 != null)
-            delAllB0.close();
-        delAllB0 = null;
-        if (delAllA != null)
-            delAllA.close();
-        delAllA = null;
-        if (conn != null)
-            conn.close();
-        conn = null;
-        out.println("      [ok]");
-    }
+    // ----------------------------------------------------------------------
+    // JDBC operations
+    // ----------------------------------------------------------------------
+
+    protected abstract class JdbcOp extends Op {
+        final protected String sql;
+        protected PreparedStatement stmt;
+
+        public JdbcOp(String name, String sql) {
+            super(name);
+            this.sql = sql;
+        }
+
+        public void init() throws SQLException {
+            if (stmt == null)
+                stmt = conn.prepareStatement(sql);
+        }
+
+        public void close() throws SQLException {
+            if (stmt != null)
+                stmt.close();
+            stmt = null;
+        }
+    };
 
     static protected void setCommonAttributes(PreparedStatement stmt, int i)
         throws SQLException {
@@ -171,6 +185,7 @@ public class JdbcLoad extends Driver {
                                 verify(cnts[i] == 1);
                             }
                         }
+                        conn.commit();
                     }
                 });
 
@@ -193,6 +208,7 @@ public class JdbcLoad extends Driver {
                                 verify(cnts[i] == 1);
                             }
                         }
+                        conn.commit();
                     }
                 });
 
@@ -220,6 +236,7 @@ public class JdbcLoad extends Driver {
                                 verify(cnts[i] == 1);
                             }
                         }
+                        conn.commit();
                     }
                 });
 
@@ -247,6 +264,7 @@ public class JdbcLoad extends Driver {
                                 verify(cnts[i] == 1);
                             }
                         }
+                        conn.commit();
                     }
                 });
 
@@ -279,6 +297,7 @@ public class JdbcLoad extends Driver {
                                 rs.close();
                             }
                         }
+                        conn.commit();
                     }
                 });
 
@@ -311,6 +330,7 @@ public class JdbcLoad extends Driver {
                                 rs.close();
                             }
                         }
+                        conn.commit();
                     }
                 });
 
@@ -339,6 +359,7 @@ public class JdbcLoad extends Driver {
                                     verify(cnts[i] == 1);
                                 }
                             }
+                            conn.commit();
                         }
                     });
 
@@ -356,6 +377,7 @@ public class JdbcLoad extends Driver {
                                 verify(!rs.next());
                                 rs.close();
                             }
+                            conn.commit();
                         }
                     });
 
@@ -379,10 +401,11 @@ public class JdbcLoad extends Driver {
                                     verify(cnts[i] == 1);
                                 }
                             }
+                            conn.commit();
                         }
                     });
             }
-        
+
             for (int i = 0, l = 1; l <= maxVarcharChars; l *= 10, i++) {
                 final String s = strings[i];
                 assert l == s.length();
@@ -408,6 +431,7 @@ public class JdbcLoad extends Driver {
                                     verify(cnts[i] == 1);
                                 }
                             }
+                            conn.commit();
                         }
                     });
 
@@ -425,6 +449,7 @@ public class JdbcLoad extends Driver {
                                 verify(!rs.next());
                                 rs.close();
                             }
+                            conn.commit();
                         }
                     });
 
@@ -448,6 +473,7 @@ public class JdbcLoad extends Driver {
                                     verify(cnts[i] == 1);
                                 }
                             }
+                            conn.commit();
                         }
                     });
             }
@@ -477,6 +503,7 @@ public class JdbcLoad extends Driver {
                                     verify(cnts[i] == 1);
                                 }
                             }
+                            conn.commit();
                         }
                     });
 
@@ -494,6 +521,7 @@ public class JdbcLoad extends Driver {
                                 verify(!rs.next());
                                 rs.close();
                             }
+                            conn.commit();
                         }
                     });
             }
@@ -523,6 +551,7 @@ public class JdbcLoad extends Driver {
                                     verify(cnts[i] == 1);
                                 }
                             }
+                            conn.commit();
                         }
                     });
 
@@ -540,6 +569,7 @@ public class JdbcLoad extends Driver {
                                 verify(!rs.next());
                                 rs.close();
                             }
+                            conn.commit();
                         }
                     });
             }
@@ -565,6 +595,7 @@ public class JdbcLoad extends Driver {
                                 verify(cnts[i] == 1);
                             }
                         }
+                        conn.commit();
                     }
                 });
 
@@ -583,6 +614,7 @@ public class JdbcLoad extends Driver {
                             verify(!rs.next());
                             rs.close();
                         }
+                        conn.commit();
                     }
                 });
 
@@ -601,6 +633,7 @@ public class JdbcLoad extends Driver {
                             verify(!rs.next());
                             rs.close();
                         }
+                        conn.commit();
                     }
                 });
 
@@ -642,6 +675,7 @@ public class JdbcLoad extends Driver {
                             verify(!rs.next());
                             rs.close();
                         }
+                        conn.commit();
                     }
                 });
 
@@ -663,6 +697,7 @@ public class JdbcLoad extends Driver {
                             rs.close();
                         }
                         verify(cnt == countB);
+                        conn.commit();
                     }
                 });
 
@@ -685,6 +720,7 @@ public class JdbcLoad extends Driver {
                                 verify(cnts[i] == 1);
                             }
                         }
+                        conn.commit();
                     }
                 });
 
@@ -708,6 +744,7 @@ public class JdbcLoad extends Driver {
                                 verify(cnts[i] == 1);
                             }
                         }
+                        conn.commit();
                     }
                 });
 
@@ -731,6 +768,7 @@ public class JdbcLoad extends Driver {
                                 verify(cnts[i] == 1);
                             }
                         }
+                        conn.commit();
                     }
                 });
 
@@ -754,6 +792,7 @@ public class JdbcLoad extends Driver {
                                 verify(cnts[i] == 1);
                             }
                         }
+                        conn.commit();
                     }
                 });
 
@@ -777,6 +816,7 @@ public class JdbcLoad extends Driver {
                                 verify(cnts[i] == 1);
                             }
                         }
+                        conn.commit();
                     }
                 });
 
@@ -786,6 +826,7 @@ public class JdbcLoad extends Driver {
                     public void run(int countA, int countB) throws SQLException {
                         int cnt = stmt.executeUpdate();
                         verify(cnt == countB);
+                        conn.commit();
                     }
                 });
 
@@ -795,38 +836,56 @@ public class JdbcLoad extends Driver {
                     public void run(int countA, int countB) throws SQLException {
                         int cnt = stmt.executeUpdate();
                         verify(cnt == countA);
+                        conn.commit();
                     }
                 });
         }
-        
+
         // prepare all statements
-        for (Iterator<Driver.Op> i = ops.iterator(); i.hasNext();) {
+        for (Iterator<CrundDriver.Op> i = ops.iterator(); i.hasNext();) {
             ((JdbcOp)i.next()).init();
         }
-        out.println(" [JdbcOp: " + ops.size() + "]");
+        out.println("     [JdbcOp: " + ops.size() + "]");
     }
 
     protected void closeOperations() throws SQLException {
         out.print("closing statements ...");
         out.flush();
         // close all statements
-        for (Iterator<Driver.Op> i = ops.iterator(); i.hasNext();) {
+        for (Iterator<CrundDriver.Op> i = ops.iterator(); i.hasNext();) {
             ((JdbcOp)i.next()).close();
         }
         ops.clear();
-        out.println("      [ok]");
+        out.println("          [ok]");
     }
 
-    protected void beginTransaction() {
-        // nothing to do for JDBC
-    }
+    // ----------------------------------------------------------------------
+    // JDBC datastore operations
+    // ----------------------------------------------------------------------
 
-    protected void commitTransaction() throws SQLException {
-        conn.commit();
+    protected void initConnection() throws SQLException {
+        out.print("initializing connection ...");
+        out.flush();
+        conn = DriverManager.getConnection(url, user, password);
+        conn.setAutoCommit(autoCommit);
+        delAllA = conn.prepareStatement("DELETE FROM a");
+        delAllB0 = conn.prepareStatement("DELETE FROM b0");
+        out.println("     [Conn: 1]");
     }
 
-    protected void rollbackTransaction() throws SQLException {
-        conn.rollback();
+    protected void closeConnection() throws SQLException {
+        out.print("closing connection ...");
+        out.flush();
+        if (delAllB0 != null)
+            delAllB0.close();
+        delAllB0 = null;
+        if (delAllA != null)
+            delAllA.close();
+        delAllA = null;
+        if (conn != null)
+            conn.close();
+        conn = null;
+        out.println("          [ok]");
     }
 
     protected void clearPersistenceContext() {
@@ -837,7 +896,7 @@ public class JdbcLoad extends Driver {
         out.print("deleting all rows ...");
         out.flush();
         int delB0 = delAllB0.executeUpdate();
-        out.print("       [B0: " + delB0);
+        out.print("           [B0: " + delB0);
         out.flush();
         int delA = delAllA.executeUpdate();
         out.print(", A: " + delA);

=== removed file 'storage/ndb/test/crund/src/com/mysql/cluster/crund/JdoLoad.java'
--- a/storage/ndb/test/crund/src/com/mysql/cluster/crund/JdoLoad.java	2010-02-14 05:05:31 +0000
+++ b/storage/ndb/test/crund/src/com/mysql/cluster/crund/JdoLoad.java	1970-01-01 00:00:00 +0000
@@ -1,487 +0,0 @@
-/* -*- mode: java; c-basic-offset: 4; indent-tabs-mode: nil; -*-
- *  vim:expandtab:shiftwidth=4:tabstop=4:smarttab:
- *
- *  Copyright (C) 2008 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
- */
-
-package com.mysql.cluster.crund;
-
-import java.util.Collection;
-import java.util.Iterator;
-
-import javax.jdo.*;
-
-/**
- * A benchmark implementation against a JDO-mapped datastore.
- */
-public class JdoLoad extends Driver {
-
-    // non-static fields
-    protected PersistenceManagerFactory pmf;
-    protected PersistenceManager pm;
-    protected Query getAllA;
-    protected Query getAllB0;
-    protected Query getAByB0;
-    protected Query getB0ByA;
-
-    protected void init() {
-        // init PersistenceManagerFactory
-        final String driver = props.getProperty("jdo.driver");
-        final String url = props.getProperty("jdo.url");
-        final String user = props.getProperty("jdo.user");
-        final String password = props.getProperty("jdo.password");
-        try {
-            pmf = JDOHelper.getPersistenceManagerFactory();
-            pmf.setConnectionDriverName(driver);
-            pmf.setConnectionURL(url);
-            pmf.setConnectionUserName(user);
-            pmf.setConnectionPassword(password);
-            //pmf.setConnectionMinPool(1);
-            //pmf.setConnectionMaxPool(1);
-            //pmf.setOptimistic(false);
-            //pmf.setRetainValues(false);
-        } catch (Exception e) {
-            out.println("caught " + e);
-            e.printStackTrace();
-            throw new RuntimeException("Cannot get PersistenceManagerFactory");
-        }
-    }
-
-    protected void close() {
-        if (pmf == null)
-            pmf.close();
-        pmf = null;
-    }
-
-    protected void initConnection() {
-        if (pm != null)
-            pm.close();
-        pm = pmf.getPersistenceManager();
-    }
-
-    protected void closeConnection() {
-        if (pm != null)
-            pm.close();
-        pm = null;
-    }
-
-    protected void initOperations() {
-/*
-        Extent<A> extentA = pm.getExtent(A.class, false);
-        Extent<B0> extentB0 = pm.getExtent(B0.class, false);
-
-        getAllA = pm.newQuery(extentA);
-
-        getAllB0 = pm.newQuery(extentB0);
-
-        getAByB0 = pm.newQuery(extentA, "b0s.contains(b0) & b0.id==id");
-        getAByB0.declareParameters("int id");
-        getAByB0.declareVariables("scalability.B0 b0");
-
-        getB0ByA = pm.newQuery(extentB0, "a.id == id");
-        getB0ByA.declareParameters("int id");
-*/
-    }
-
-    protected void closeOperations() {
-    }
-
-    protected void beginTransaction() {
-        pm.currentTransaction().begin();
-    }
-
-    protected void commitTransaction() {
-        pm.currentTransaction().commit();
-    }
-
-    protected void rollbackTransaction() {
-        pm.currentTransaction().rollback();
-    }
-
-    protected void clearPersistenceContext() {
-        // XXX adapt to JDO (retain values...)
-        // as long as we haven't created the EM with a Tx PC scope
-        // (i.e. emf.createEntityManager(PersistenceContextType.TRANSACTION))
-        // we effectively prevent caching beyond Tx scope by clearing
-        // the EM's PC
-        //pm.clear();
-    }
-
-    protected void clearData() {
-        out.println();
-        out.println("delete all objects");
-
-        beginTransaction();
-        pm.deletePersistentAll((Collection)getAllA.execute());
-        commitTransaction();
-
-        beginTransaction();
-        pm.deletePersistentAll((Collection)getAllB0.execute());
-        commitTransaction();
-    }
-
-/*
-    protected void create0(int countA, int countB0) {
-        Object o[] = new Object[countA];
-        for (int i = 0; i < countA; i++) {
-            o[i] = createA(i);
-        }
-    }
-
-    protected void create1(int countA, int countB0) {
-        Object o[] = new Object[countB0];
-        for (int i = 0; i < countB0; i++) {
-            o[i] = createB0(countA + i);
-        }
-    }
-
-    protected void delete0(int countA, int countB0) {
-        //TODO: iterate extent <-> JDBC
-        //Collection result = (Collection)getAllA.execute();
-        //pm.deletePersistentAll(result);
-    }
-
-    protected void delete1(int countA, int countB0) {
-        //TODO: iterate extent <-> JDBC
-        //Collection result = (Collection)getAllB0.execute();
-        //pm.deletePersistentAll(result);
-    }
-
-    protected void query0(int countA, int countB0) {
-        Collection result = (Collection)getAllA.execute();
-        for (Iterator i = result.iterator(); i.hasNext();) {
-            A o = (A) i.next();
-        }
-    }
-
-    protected void query1(int countA, int countB0) {
-        Collection result = (Collection)getAllB0.execute();
-        for (Iterator i = result.iterator(); i.hasNext();) {
-            B0 o = (B0) i.next();
-        }
-    }
-
-    protected void setRel0(int countA, int countB0) {
-        Collection aResult = (Collection)getAllA.execute();
-        Collection b0Result = (Collection)getAllB0.execute();
-        final int rAB0 = countA / countB0;
-        final int rB0A = countB0 / countA;
-        if (rAB0 <= 1) {
-            Iterator j = b0Result.iterator();
-            Iterator i = aResult.iterator();
-            while (i.hasNext()) {
-                A a = (A) i.next();
-                for (int r = 0; r < rB0A; r++) {
-                    B0 b0 = (B0) j.next();
-                    a.getB0s().add(b0);
-                    b0 = null;
-                }
-                a = null;
-            }
-            i = null;
-            j = null;
-        } else {
-            Iterator j = b0Result.iterator();
-            Iterator i = aResult.iterator();
-            while (i.hasNext()) {
-                A a = null;
-                for (int r = 0; r < rAB0; r++)
-                    a = (A) i.next();
-                B0 b0 = (B0) j.next();
-                a.getB0s().add(b0);
-                b0 = null;
-                a = null;
-            }
-            i = null;
-            j = null;
-        }
-        aResult = null;
-        b0Result = null;
-    }
-
-    protected void setRel1(int countA, int countB0) {
-        Collection aResult = (Collection)getAllA.execute();
-        Collection b0Result = (Collection)getAllB0.execute();
-        final int rAB0 = countA / countB0;
-        final int rB0A = countB0 / countA;
-        if (rAB0 <= 1) {
-            Iterator j = b0Result.iterator();
-            for (Iterator i = aResult.iterator(); i.hasNext();) {
-                A a = (A) i.next();
-                for (int r = 0; r < rB0A; r++) {
-                    B0 b0 = (B0) j.next();
-                    b0.setA(a);
-                }
-            }
-        } else {
-            Iterator j = b0Result.iterator();
-            for (Iterator i = aResult.iterator(); i.hasNext();) {
-                A a = null;
-                for (int r = 0; r < rAB0; r++)
-                    a = (A) i.next();
-                B0 b0 = (B0) j.next();
-                b0.setA(a);
-            }
-        }
-    }
-
-    protected void delRel0(int countA, int countB0) {
-        Collection aResult = (Collection)getAllA.execute();
-        for (Iterator i = aResult.iterator(); i.hasNext();) {
-            A a = (A) i.next();
-            a.getB0s().clear();
-        }
-    }
-
-    protected void delRel1(int countA, int countB0) {
-        Collection b0Result = (Collection)getAllB0.execute();
-        for (Iterator i = b0Result.iterator(); i.hasNext();) {
-            B0 b0 = (B0) i.next();
-            b0.setA(null);
-        }
-    }
-
-    protected void delRel2(int countA, int countB0) {
-        Collection aResult = (Collection)getAllA.execute();
-        for (Iterator i = aResult.iterator(); i.hasNext();) {
-            A a = (A) i.next();
-            for (Iterator j = a.getB0s().iterator(); j.hasNext();) {
-                B0 b0 = (B0) j.next();
-                a.getB0s().remove(b0);
-            }
-        }
-    }
-
-    protected void queryRel0(int countA, int countB0) {
-        Collection aResult = (Collection)getAllA.execute();
-        for (Iterator i = aResult.iterator(); i.hasNext();) {
-            A a = (A) i.next();
-            Collection b0Result
-                = (Collection)getB0ByA.execute(new java.lang.Integer(a.getId()));
-            for (Iterator j = b0Result.iterator(); j.hasNext();) {
-                B0 b0 = (B0) j.next();
-            }
-        }
-    }
-
-    protected void queryRel1(int countA, int countB0) {
-        Collection b0Result = (Collection)getAllB0.execute();
-        for (Iterator i = b0Result.iterator(); i.hasNext();) {
-            B0 b0 = (B0) i.next();
-            Collection aResult
-                = (Collection)getAByB0.execute(new java.lang.Integer(b0.getId()));
-            for (Iterator j = aResult.iterator(); j.hasNext();) {
-                A a = (A) j.next();
-            }
-        }
-    }
-
-    protected void fetchInt0(int countA, int countB0) {
-        Collection aResult = (Collection)getAllA.execute();
-        for (Iterator i = aResult.iterator(); i.hasNext();) {
-            A a = (A) i.next();
-            a.getCint();
-        }
-    }
-
-    protected void fetchInt1(int countA, int countB0) {
-        Collection b0Result = (Collection)getAllB0.execute();
-        for (Iterator i = b0Result.iterator(); i.hasNext();) {
-            B0 b0 = (B0) i.next();
-            b0.getCint();
-        }
-    }
-
-    protected void fetchLong0(int countA, int countB0) {
-        Collection aResult = (Collection)getAllA.execute();
-        for (Iterator i = aResult.iterator(); i.hasNext();) {
-            A a = (A) i.next();
-            a.getClong();
-        }
-    }
-
-    protected void fetchLong1(int countA, int countB0) {
-        Collection b0Result = (Collection)getAllB0.execute();
-        for (Iterator i = b0Result.iterator(); i.hasNext();) {
-            B0 b0 = (B0) i.next();
-            b0.getClong();
-        }
-    }
-
-    protected void fetchFloat0(int countA, int countB0) {
-        Collection aResult = (Collection)getAllA.execute();
-        for (Iterator i = aResult.iterator(); i.hasNext();) {
-            A a = (A) i.next();
-            a.getCfloat();
-        }
-    }
-
-    protected void fetchFloat1(int countA, int countB0) {
-        Collection b0Result = (Collection)getAllB0.execute();
-        for (Iterator i = b0Result.iterator(); i.hasNext();) {
-            B0 b0 = (B0) i.next();
-            b0.getCfloat();
-        }
-    }
-
-    protected void fetchDouble0(int countA, int countB0) {
-        Collection aResult = (Collection)getAllA.execute();
-        for (Iterator i = aResult.iterator(); i.hasNext();) {
-            A a = (A) i.next();
-            a.getCdouble();
-        }
-    }
-
-    protected void fetchDouble1(int countA, int countB0) {
-        Collection b0Result = (Collection)getAllB0.execute();
-        for (Iterator i = b0Result.iterator(); i.hasNext();) {
-            B0 b0 = (B0) i.next();
-            b0.getCdouble();
-        }
-    }
-
-    protected void fetchString0(int countA, int countB0) {
-        Collection aResult = (Collection)getAllA.execute();
-        for (Iterator i = aResult.iterator(); i.hasNext();) {
-            A a = (A) i.next();
-            a.getCstring();
-        }
-    }
-
-    protected void fetchString1(int countA, int countB0) {
-        Collection b0Result = (Collection)getAllB0.execute();
-        for (Iterator i = b0Result.iterator(); i.hasNext();) {
-            B0 b0 = (B0) i.next();
-            b0.getCstring();
-        }
-    }
-
-    protected void updateInt0(int countA, int countB0) {
-        Collection aResult = (Collection)getAllA.execute();
-        for (Iterator i = aResult.iterator(); i.hasNext();) {
-            A a = (A) i.next();
-            a.setCint(0);
-        }
-    }
-
-    protected void updateInt1(int countA, int countB0) {
-        Collection b0Result = (Collection)getAllB0.execute();
-        for (Iterator i = b0Result.iterator(); i.hasNext();) {
-            B0 b0 = (B0) i.next();
-            b0.setCint(0);
-        }
-    }
-
-    protected void updateLong0(int countA, int countB0) {
-        Collection aResult = (Collection)getAllA.execute();
-        for (Iterator i = aResult.iterator(); i.hasNext();) {
-            A a = (A) i.next();
-            a.setClong(0);
-        }
-    }
-
-    protected void updateLong1(int countA, int countB0) {
-        Collection b0Result = (Collection)getAllB0.execute();
-        for (Iterator i = b0Result.iterator(); i.hasNext();) {
-            B0 b0 = (B0) i.next();
-            b0.setClong(0);
-        }
-    }
-
-    protected void updateFloat0(int countA, int countB0) {
-        Collection aResult = (Collection)getAllA.execute();
-        for (Iterator i = aResult.iterator(); i.hasNext();) {
-            A a = (A) i.next();
-            a.setCfloat(0);
-        }
-    }
-
-    protected void updateFloat1(int countA, int countB0) {
-        Collection b0Result = (Collection)getAllB0.execute();
-        for (Iterator i = b0Result.iterator(); i.hasNext();) {
-            B0 b0 = (B0) i.next();
-            b0.setCfloat(0);
-        }
-    }
-
-    protected void updateDouble0(int countA, int countB0) {
-        Collection aResult = (Collection)getAllA.execute();
-        for (Iterator i = aResult.iterator(); i.hasNext();) {
-            A a = (A) i.next();
-            a.setCdouble(0);
-        }
-    }
-
-    protected void updateDouble1(int countA, int countB0) {
-        Collection b0Result = (Collection)getAllB0.execute();
-        for (Iterator i = b0Result.iterator(); i.hasNext();) {
-            B0 b0 = (B0) i.next();
-            b0.setCdouble(0);
-        }
-    }
-
-    protected void updateString0(int countA, int countB0) {
-        Collection aResult = (Collection)getAllA.execute();
-        for (Iterator i = aResult.iterator(); i.hasNext();) {
-            A a = (A) i.next();
-            a.setCstring("newAString");
-        }
-    }
-
-    protected void updateString1(int countA, int countB0) {
-        Collection b0Result = (Collection)getAllB0.execute();
-        for (Iterator i = b0Result.iterator(); i.hasNext();) {
-            B0 b0 = (B0) i.next();
-            b0.setCstring("newB0String");
-        }
-    }
-
-    protected A createA(int id) {
-        A o = new A();
-        o.setId(id);
-        o.setCint(id);
-        o.setClong((long)id);
-        o.setCfloat((float)id);
-        o.setCdouble((double)id);
-        o.setCstring("aString");
-        pm.makePersistent(o);
-        return o;
-    }
-
-    protected B0 createB0(int id) {
-        B0 o = new B0();
-        o.setId(id);
-        o.setCint(id);
-        o.setClong((long)id);
-        o.setCfloat((float)id);
-        o.setCdouble((double)id);
-        o.setCstring("b0String");
-        pm.makePersistent(o);
-        return o;
-    }
-*/
-
-    // ----------------------------------------------------------------------
-
-    static public void main(String[] args) {
-        System.out.println("JdoLoad.main()");
-        parseArguments(args);
-        new JdoLoad().run();
-        System.out.println();
-        System.out.println("JdoLoad.main(): done.");
-    }
-}

=== modified file 'storage/ndb/test/crund/src/com/mysql/cluster/crund/JpaLoad.java'
--- a/storage/ndb/test/crund/src/com/mysql/cluster/crund/JpaLoad.java	2010-09-04 01:20:28 +0000
+++ b/storage/ndb/test/crund/src/com/mysql/cluster/crund/JpaLoad.java	2010-10-19 22:56:45 +0000
@@ -35,32 +35,36 @@ import javax.persistence.PersistenceCont
 /**
  * A benchmark implementation against a JPA-mapped database.
  */
-public class JpaLoad extends Driver {
+public class JpaLoad extends CrundDriver {
 
-    // JPA database connection
+    // JPA settings
     protected String driver;
     protected String url;
+    protected String user;
+    protected String password;
     protected String connectionRetainMode;
-    protected String ndbConnectString;
     protected String brokerFactory;
+    protected String ndbConnectString;
+    protected String ndbDatabase;
+
+    // JPA resources
     protected EntityManagerFactory emf;
     protected EntityManager em;
     protected Query delAllA;
     protected Query delAllB0;
 
-    protected abstract class JpaOp extends Op {
-        public JpaOp(String name) {
-            super(name);
-        }
-
-        public void init() {}
-
-        public void close() {}
-    };
+    // ----------------------------------------------------------------------
+    // JPA intializers/finalizers
+    // ----------------------------------------------------------------------
 
     protected void initProperties() {
         super.initProperties();
 
+        out.print("setting jpa properties ...");
+
+        final StringBuilder msg = new StringBuilder();
+        final String eol = System.getProperty("line.separator");
+
         // load the JDBC driver class
         driver = props.getProperty("openjpa.ConnectionDriverName");
         if (driver == null) {
@@ -81,45 +85,68 @@ public class JpaLoad extends Driver {
             throw new RuntimeException("Missing property: "
                                        + "openjpa.ConnectionURL");
         }
-        
+
+        user = props.getProperty("openjpa.ConnectionUserName");
+        password = props.getProperty("openjpa.ConnectionPassword");
+
         connectionRetainMode = props.getProperty("openjpa.ConnectionRetainMode");
         if (connectionRetainMode == null) {
             throw new RuntimeException("Missing property: "
                                        + "openjpa.ConnectionRetainMode");
         }
 
-        ndbConnectString = props.getProperty("openjpa.ndb.connectString");
-        if (url == null) {
-            throw new RuntimeException("Missing property: "
-                                       + "openjpa.ndb.connectString");
-        }
-
         brokerFactory = props.getProperty("openjpa.BrokerFactory");
-        if (url == null) {
-            throw new RuntimeException("Missing property: "
-                                       + "openjpa.BrokerFactory");
-        }
-
-        descr = "->JPA->" + url;
+        ndbConnectString = props.getProperty("openjpa.ndb.connectString");
+        ndbDatabase = props.getProperty("openjpa.ndb.database");
+        if ("ndb".equals(brokerFactory)) {
+            if (ndbConnectString == null) {
+                throw new RuntimeException("Missing property: "
+                                           + "openjpa.ndb.connectString");
+            }
+            if (ndbDatabase == null) {
+                throw new RuntimeException("Missing property: "
+                                           + "openjpa.ndb.database");
+            }
+        }
+
+        if (msg.length() == 0) {
+            out.println("      [ok]");
+        } else {
+            out.println();
+            out.print(msg.toString());
+        }
+
+        // have brokerFactory... initialized first
+        final String c =  ("ndb".equals(brokerFactory)
+                           ? ("clusterj(" + ndbConnectString + ")")
+                           : url);
+        descr = "->jpa->" + c;
     }
 
     protected void printProperties() {
         super.printProperties();
-        out.println("openjpa.ConnectionDriverName: " + driver);
-        out.println("openjpa.ConnectionURL:        " + url);
-        out.println("openjpa.ConnectionRetainMode: " + connectionRetainMode);
-        out.println("openjpa.ndb.connectString:    " + ndbConnectString);
-        out.println("openjpa.BrokerFactory:        " + brokerFactory);
+
+        out.println();
+        out.println("jpa settings ...");
+        out.println("openjpa.ConnectionDriverName:   " + driver);
+        out.println("openjpa.ConnectionURL:          " + url);
+        out.println("openjpa.ConnectionUserName:     \"" + user + "\"");
+        out.println("openjpa.ConnectionPassword:     \"" + password + "\"");
+        out.println("openjpa.ConnectionRetainMode:   " + connectionRetainMode);
+        out.println("openjpa.BrokerFactory:          " + brokerFactory);
+        out.println("openjpa.ndb.connectString:      " + ndbConnectString);
+        out.println("openjpa.ndb.database:           " + ndbDatabase);
     }
 
     protected void init() throws Exception {
         super.init();
+
         out.println();
         out.print("creating EMFactory ...");
         out.flush();
         // create EMF by standard API, which allows vendors to pool factories
         emf = Persistence.createEntityManagerFactory("crundjpa", props);
-        out.println("      [EMF: 1]");
+        out.println("          [EMF: 1]");
     }
 
     protected void close() throws Exception {
@@ -128,41 +155,24 @@ public class JpaLoad extends Driver {
         if (emf != null)
             emf.close();
         emf = null;
-        out.println("       [ok]");
+        out.println("           [ok]");
+
         super.close();
     }
 
-    protected void initConnection() {
-        out.print("creating EntityManager ...");
-        out.flush();
-        // See: clearPersistenceContext() for !allowExtendedPC
-        // Tx-scope EM supported by JPA only by container injection:
-        //   em = emf.createEntityManager(PersistenceContextType.TRANSACTION);
-        em = emf.createEntityManager();
-        // XXX check query.setHint(...) for standardized optimizations, e.g.:
-        //import org.eclipse.persistence.config.QueryHints;
-        //import org.eclipse.persistence.config.QueryType;        
-        //import org.eclipse.persistence.config.PessimisticLock;        
-        //import org.eclipse.persistence.config.HintValues;
-        //query.setHint(QueryHints.QUERY_TYPE, QueryType.ReadObject);
-        //query.setHint(QueryHints.PESSIMISTIC_LOCK, PessimisticLock.LockNoWait);
-        //query.setHint("eclipselink.batch", "e.address");
-        //query.setHint("eclipselink.join-fetch", "e.address");
-        delAllA = em.createQuery("DELETE FROM A");
-        delAllB0 = em.createQuery("DELETE FROM B0");
-        out.println("  [EM: 1]");
-    }
+    // ----------------------------------------------------------------------
+    // JPA operations
+    // ----------------------------------------------------------------------
 
-    protected void closeConnection() {
-        out.print("closing EntityManager ...");
-        out.flush();
-        delAllB0 = null;
-        delAllA = null;
-        if (em != null)
-            em.close();
-        em = null;
-        out.println("   [ok]");
-    }
+    protected abstract class JpaOp extends Op {
+        public JpaOp(String name) {
+            super(name);
+        }
+
+        public void init() {}
+
+        public void close() {}
+    };
 
     protected void setCommonFields(A o, int i) {
         assert o != null;
@@ -171,7 +181,7 @@ public class JpaLoad extends Driver {
         o.setCfloat((float)i);
         o.setCdouble((double)i);
     }
-    
+
     protected void setCommonFields(B0 o, int i) {
         assert o != null;
         o.setCint(i);
@@ -179,7 +189,7 @@ public class JpaLoad extends Driver {
         o.setCfloat((float)i);
         o.setCdouble((double)i);
     }
-    
+
     protected void verifyCommonFields(A o, int i) {
         assert o != null;
         final int id = o.getId();
@@ -215,80 +225,96 @@ public class JpaLoad extends Driver {
         ops.add(
             new JpaOp("insA") {
                 public void run(int countA, int countB) {
+                    beginTransaction();
                     for (int i = 0; i < countA; i++) {
                         final A o = new A();
                         o.setId(i);
                         em.persist(o);
                     }
+                    commitTransaction();
                 }
             });
 
         ops.add(
             new JpaOp("insB0") {
                 public void run(int countA, int countB) {
+                    beginTransaction();
                     for (int i = 0; i < countB; i++) {
                         final B0 o = new B0();
                         o.setId(i);
                         em.persist(o);
                     }
+                    commitTransaction();
                 }
             });
 
         ops.add(
             new JpaOp("setAByPK_bulk") {
                 public void run(int countA, int countB) {
+                    beginTransaction();
                     // OpenJPA 1.2.1 fails to parse a unary '-' operator
                     final int upd = em.createQuery("UPDATE A o SET o.cint = 0-(o.id), o.clong = 0-(o.id), o.cfloat = 0-(o.id), o.cdouble = 0-(o.id)").executeUpdate();
                     assert upd == countA;
+                    commitTransaction();
                 }
             });
 
         ops.add(
             new JpaOp("setB0ByPK_bulk") {
                 public void run(int countA, int countB) {
+                    beginTransaction();
                     // OpenJPA 1.2.1 fails to parse a unary '-' operator
                     final int upd = em.createQuery("UPDATE B0 o SET o.cint = 0-(o.id), o.clong = 0-(o.id), o.cfloat = 0-(o.id), o.cdouble = 0-(o.id)").executeUpdate();
                     assert upd == countB;
+                    commitTransaction();
                 }
             });
 
         ops.add(
             new JpaOp("setAByPK") {
                 public void run(int countA, int countB) {
+                    beginTransaction();
                     for (int i = 0; i < countA; i++) {
                         final A o = em.find(A.class, i);
                         setCommonFields(o, i);
                     }
+                    commitTransaction();
                 }
             });
 
         ops.add(
             new JpaOp("setB0ByPK") {
                 public void run(int countA, int countB) {
+                    beginTransaction();
                     for (int i = 0; i < countB; i++) {
                         final B0 o = em.find(B0.class, i);
                         setCommonFields(o, i);
                     }
+                    commitTransaction();
                 }
             });
 
         ops.add(
             new JpaOp("getAByPK") {
                 public void run(int countA, int countB) {
+                    beginTransaction();
                     for (int i = 0; i < countA; i++) {
                         final A o = em.find(A.class, i);
                         verifyCommonFields(o, i);
                     }
+                    commitTransaction();
                 }
             });
 
         ops.add(
             new JpaOp("getB0ByPK") {
                 public void run(int countA, int countB) {
+                    beginTransaction();
                     for (int i = 0; i < countB; i++) {
                         final B0 o = em.find(B0.class, i);
                         verifyCommonFields(o, i);
                     }
+                    commitTransaction();
                 }
             });
 
@@ -299,39 +325,45 @@ public class JpaLoad extends Driver {
             ops.add(
                 new JpaOp("setVarbinary" + l) {
                     public void run(int countA, int countB) {
+                        beginTransaction();
                         for (int i = 0; i < countB; i++) {
                             final B0 o = em.find(B0.class, i);
                             assert o != null;
                             //o.cvarbinary_def = b; // not detected by OpenJPA
                             o.setCvarbinary_def(b);
                         }
+                        commitTransaction();
                     }
                 });
 
             ops.add(
                 new JpaOp("getVarbinary" + l) {
                     public void run(int countA, int countB) {
+                        beginTransaction();
                         for (int i = 0; i < countB; i++) {
                             final B0 o = em.find(B0.class, i);
                             assert o != null;
                             verify(Arrays.equals(b, o.getCvarbinary_def()));
                         }
+                        commitTransaction();
                     }
                 });
 
             ops.add(
                 new JpaOp("clearVarbinary" + l) {
                     public void run(int countA, int countB) {
+                        beginTransaction();
                         for (int i = 0; i < countB; i++) {
                             final B0 o = em.find(B0.class, i);
                             assert o != null;
                             //o.cvarbinary_def = null; // not detected by OpenJPA
                             o.setCvarbinary_def(null);
                         }
+                        commitTransaction();
                     }
                 });
         }
-        
+
         for (int i = 0, l = 1; l <= maxVarcharChars; l *= 10, i++) {
             final String s = strings[i];
             assert l == s.length();
@@ -339,42 +371,49 @@ public class JpaLoad extends Driver {
             ops.add(
                 new JpaOp("setVarchar" + l) {
                     public void run(int countA, int countB) {
+                        beginTransaction();
                         for (int i = 0; i < countB; i++) {
                             final B0 o = em.find(B0.class, i);
                             assert o != null;
                             //o.cvarchar_def = s; // not detected by OpenJPA
                             o.setCvarchar_def(s);
                         }
+                        commitTransaction();
                     }
                 });
 
             ops.add(
                 new JpaOp("getVarchar" + l) {
                     public void run(int countA, int countB) {
+                        beginTransaction();
                         for (int i = 0; i < countB; i++) {
                             final B0 o = em.find(B0.class, i);
                             assert o != null;
                             verify(s.equals(o.getCvarchar_def()));
                         }
+                        commitTransaction();
                     }
                 });
 
             ops.add(
                 new JpaOp("clearVarchar" + l) {
                     public void run(int countA, int countB) {
+                        beginTransaction();
                         for (int i = 0; i < countB; i++) {
                             final B0 o = em.find(B0.class, i);
                             assert o != null;
                             //o.cvarchar_def = null; // not detected by OpenJPA
                             o.setCvarchar_def(null);
                         }
+                        commitTransaction();
                     }
                 });
         }
-        
+
         ops.add(
             new JpaOp("setB0->A") {
                 public void run(int countA, int countB) {
+                    beginTransaction();
                     for (int i = 0; i < countB; i++) {
                         final B0 b0 = em.find(B0.class, i);
                         assert b0 != null;
@@ -383,24 +422,28 @@ public class JpaLoad extends Driver {
                         assert a != null;
                         b0.setA(a);
                     }
+                    commitTransaction();
                 }
             });
 
         ops.add(
             new JpaOp("navB0->A") {
                 public void run(int countA, int countB) {
+                    beginTransaction();
                     for (int i = 0; i < countB; i++) {
                         final B0 b0 = em.find(B0.class, i);
                         assert b0 != null;
                         final A a = b0.getA();
                         verifyCommonFields(a, i % countA);
                     }
+                    commitTransaction();
                 }
             });
 
         ops.add(
             new JpaOp("navA->B0") {
                 public void run(int countA, int countB) {
+                    beginTransaction();
                     for (int i = 0; i < countA; i++) {
                         final A a = em.find(A.class, i);
                         assert a != null;
@@ -411,17 +454,20 @@ public class JpaLoad extends Driver {
                             verifyCommonFields(b0, i % countA);
                         }
                     }
+                    commitTransaction();
                 }
             });
 
         ops.add(
             new JpaOp("nullB0->A") {
                 public void run(int countA, int countB) {
+                    beginTransaction();
                     for (int i = 0; i < countB; i++) {
                         final B0 b0 = em.find(B0.class, i);
                         assert b0 != null;
                         b0.setA(null);
                     }
+                    commitTransaction();
                 }
             });
 
@@ -442,79 +488,93 @@ public class JpaLoad extends Driver {
         ops.add(
             new JpaOp("nullB0->A_bulk") {
                 public void run(int countA, int countB) {
+                    beginTransaction();
                     // OpenJPA 1.2.1 fails to parse a unary '-' operator
                     final int upd = em.createQuery("UPDATE B0 o SET o.a = NULL").executeUpdate();
                     assert upd == countB;
+                    commitTransaction();
                 }
             });
 
         ops.add(
             new JpaOp("delB0ByPK") {
                 public void run(int countA, int countB) {
+                    beginTransaction();
                     for (int i = 0; i < countB; i++) {
                         final B0 o = em.find(B0.class, i);
                         assert o != null;
                         em.remove(o);
                     }
+                    commitTransaction();
                 }
             });
 
         ops.add(
             new JpaOp("delAByPK") {
                 public void run(int countA, int countB) {
+                    beginTransaction();
                     for (int i = 0; i < countA; i++) {
                         final A o = em.find(A.class, i);
                         assert o != null;
                         em.remove(o);
                     }
+                    commitTransaction();
                 }
             });
 
         ops.add(
             new JpaOp("insA_attr") {
                 public void run(int countA, int countB) {
+                    beginTransaction();
                     for (int i = 0; i < countA; i++) {
                         final A o = new A();
                         o.setId(i);
                         setCommonFields(o, -i);
                         em.persist(o);
                     }
+                    commitTransaction();
                 }
             });
 
         ops.add(
             new JpaOp("insB0_attr") {
                 public void run(int countA, int countB) {
+                    beginTransaction();
                     for (int i = 0; i < countB; i++) {
                         final B0 o = new B0();
                         o.setId(i);
                         setCommonFields(o, -i);
                         em.persist(o);
                     }
+                    commitTransaction();
                 }
             });
 
         ops.add(
             new JpaOp("delAllB0") {
                 public void run(int countA, int countB) {
+                    beginTransaction();
                     int del = em.createQuery("DELETE FROM B0").executeUpdate();
                     assert del == countB;
+                    commitTransaction();
                 }
             });
 
         ops.add(
             new JpaOp("delAllA") {
                 public void run(int countA, int countB) {
+                    beginTransaction();
                     int del = em.createQuery("DELETE FROM A").executeUpdate();
                     assert del == countA;
+                    commitTransaction();
                 }
             });
 
         // prepare queries
-        for (Iterator<Driver.Op> i = ops.iterator(); i.hasNext();) {
+        for (Iterator<CrundDriver.Op> i = ops.iterator(); i.hasNext();) {
             ((JpaOp)i.next()).init();
         }
-        out.println(" [JpaOp: " + ops.size() + "]");
+        out.println("     [JpaOp: " + ops.size() + "]");
     }
 
     protected void closeOperations() {
@@ -522,12 +582,12 @@ public class JpaLoad extends Driver {
         out.flush();
 
         // close all queries
-        for (Iterator<Driver.Op> i = ops.iterator(); i.hasNext();) {
+        for (Iterator<CrundDriver.Op> i = ops.iterator(); i.hasNext();) {
             ((JpaOp)i.next()).close();
         }
         ops.clear();
 
-        out.println("      [ok]");
+        out.println("          [ok]");
     }
 
     protected void beginTransaction() {
@@ -538,8 +598,40 @@ public class JpaLoad extends Driver {
         em.getTransaction().commit();
     }
 
-    protected void rollbackTransaction() {
-        em.getTransaction().rollback();
+    // ----------------------------------------------------------------------
+    // JPA datastore operations
+    // ----------------------------------------------------------------------
+
+    protected void initConnection() {
+        out.print("creating EntityManager ...");
+        out.flush();
+        // See: clearPersistenceContext() for !allowExtendedPC
+        // Tx-scope EM supported by JPA only by container injection:
+        //   em = emf.createEntityManager(PersistenceContextType.TRANSACTION);
+        em = emf.createEntityManager();
+        // XXX check query.setHint(...) for standardized optimizations, e.g.:
+        //import org.eclipse.persistence.config.QueryHints;
+        //import org.eclipse.persistence.config.QueryType;
+        //import org.eclipse.persistence.config.PessimisticLock;
+        //import org.eclipse.persistence.config.HintValues;
+        //query.setHint(QueryHints.QUERY_TYPE, QueryType.ReadObject);
+        //query.setHint(QueryHints.PESSIMISTIC_LOCK, PessimisticLock.LockNoWait);
+        //query.setHint("eclipselink.batch", "e.address");
+        //query.setHint("eclipselink.join-fetch", "e.address");
+        delAllA = em.createQuery("DELETE FROM A");
+        delAllB0 = em.createQuery("DELETE FROM B0");
+        out.println("      [EM: 1]");
+    }
+
+    protected void closeConnection() {
+        out.print("closing EntityManager ...");
+        out.flush();
+        delAllB0 = null;
+        delAllA = null;
+        if (em != null)
+            em.close();
+        em = null;
+        out.println("       [ok]");
     }
 
     protected void clearPersistenceContext() {
@@ -557,7 +649,7 @@ public class JpaLoad extends Driver {
 
         em.getTransaction().begin();
         int delB0 = delAllB0.executeUpdate();
-        out.print("    [B0: " + delB0);
+        out.print("        [B0: " + delB0);
         out.flush();
         int delA = delAllA.executeUpdate();
         out.print(", A: " + delA);

=== modified file 'storage/ndb/test/crund/src/com/mysql/cluster/crund/NdbApiLoad.java'
--- a/storage/ndb/test/crund/src/com/mysql/cluster/crund/NdbApiLoad.java	2010-10-01 04:10:21 +0000
+++ b/storage/ndb/test/crund/src/com/mysql/cluster/crund/NdbApiLoad.java	2010-10-08 11:17:35 +0000
@@ -22,24 +22,19 @@ package com.mysql.cluster.crund;
 
 public class NdbApiLoad extends NdbBase {
 
+    // ----------------------------------------------------------------------
+    // NDB API intializers/finalizers
+    // ----------------------------------------------------------------------
+
     protected void initProperties() {
         super.initProperties();
-        descr = "->NDBAPI(" + mgmdConnect + ")";
+        descr = "->ndbapi(" + mgmdConnect + ")";
     }
 
-    /**
-     * Initializes the NDB benchmark class.
-     *
-     * @return a non-zero value in case of an error, and zero otherwise.
-     */
-    static public native int ndbinit(String mgmd_host_portno);
-
-    /**
-     * Finalizes the NDB benchmark class.
-     *
-     * @return a non-zero value in case of an error, and zero otherwise.
-     */
-    static public native int ndbclose();
+    // initializes/finalizes the NDB benchmark class
+    // a non-zero value in case of an error, and zero otherwise
+    static protected native int ndbinit(String mgmd_host_portno);
+    static protected native int ndbclose();
 
     protected void init() throws Exception {
         super.init();
@@ -72,16 +67,9 @@ public class NdbApiLoad extends NdbBase 
     }
 
     // ----------------------------------------------------------------------
+    // NDB API operations
+    // ----------------------------------------------------------------------
 
-    // native connection handling methods
-    protected native void initConnection(String catalog, String schema);
-    protected void initConnection() {
-        initConnection(catalog, schema);
-    }
-    protected native void closeConnection();
-
-    // native benchmark operations
-    protected native void clearData();
     protected native void delAllA(int countA, int countB,
                                   boolean batch);
     protected native void delAllB0(int countA, int countB,
@@ -217,7 +205,7 @@ public class NdbApiLoad extends NdbBase 
                         }
                     });
             }
-            
+
             for (int i = 1; i <= maxVarcharChars; i *= 10) {
                 final int length = i;
 
@@ -330,17 +318,34 @@ public class NdbApiLoad extends NdbBase 
 
         }
 
-        out.println(" [Op: " + ops.size() + "]");
+        out.println("     [Op: " + ops.size() + "]");
     }
 
     protected void closeOperations() {
         out.print("closing operations ...");
         out.flush();
         ops.clear();
-        out.println("      [ok]");
+        out.println("          [ok]");
     }
 
     // ----------------------------------------------------------------------
+    // NDB API datastore operations
+    // ----------------------------------------------------------------------
+
+    protected native void initConnection(String catalog,
+                                         String schema,
+                                         int defaultLockMode);
+    protected void initConnection() {
+        // XXX add lockMode property to CrundDriver, switch then here
+        final int LM_Read = 0;
+        final int LM_Exclusive = 1;
+        final int LM_CommittedRead = 2;
+        initConnection(catalog, schema, LM_CommittedRead);
+    }
+    protected native void closeConnection();
+    protected native void clearData();
+
+    // ----------------------------------------------------------------------
 
     static public void main(String[] args) {
         System.out.println("NdbApiLoad.main()");

=== modified file 'storage/ndb/test/crund/src/com/mysql/cluster/crund/NdbBase.java'
--- a/storage/ndb/test/crund/src/com/mysql/cluster/crund/NdbBase.java	2010-10-01 04:10:21 +0000
+++ b/storage/ndb/test/crund/src/com/mysql/cluster/crund/NdbBase.java	2010-10-19 22:56:45 +0000
@@ -20,9 +20,9 @@
 
 package com.mysql.cluster.crund;
 
-abstract public class NdbBase extends Driver {
+abstract public class NdbBase extends CrundDriver {
 
-    // the NDB database connection
+    // NDB settings
     protected String mgmdConnect;
     protected String catalog;
     protected String schema;
@@ -30,31 +30,45 @@ abstract public class NdbBase extends Dr
     // so far, there's no NDB support for caching data beyond Tx scope
     protected void clearPersistenceContext() throws Exception {}
 
-    // NDB operations must demarcate transactions themselves
-    final protected void beginTransaction() throws Exception {}
-    final protected void commitTransaction() throws Exception {}
-    final protected void rollbackTransaction() throws Exception {}
+    // ----------------------------------------------------------------------
+    // NDB Base intializers/finalizers
+    // ----------------------------------------------------------------------
 
-    protected void initProperties() {
+   protected void initProperties() {
         super.initProperties();
 
+        out.print("setting ndb properties ...");
+
+        final StringBuilder msg = new StringBuilder();
+        final String eol = System.getProperty("line.separator");
+
         // the hostname and port number of NDB mgmd
         mgmdConnect = props.getProperty("ndb.mgmdConnect", "localhost");
         assert mgmdConnect != null;
 
         // the database
-        catalog = props.getProperty("ndb.catalog", "");
+        catalog = props.getProperty("ndb.catalog", "crunddb");
         assert catalog != null;
 
         // the schema
-        schema = props.getProperty("ndb.schema", "");
+        schema = props.getProperty("ndb.schema", "def");
         assert schema != null;
+
+        if (msg.length() == 0) {
+            out.println("      [ok]");
+        } else {
+            out.println();
+            out.print(msg.toString());
+        }
     }
 
     protected void printProperties() {
         super.printProperties();
-        out.println("ndb.mgmdConnect             \"" + mgmdConnect + "\"");
-        out.println("ndb.catalog                 \"" + catalog + "\"");
-        out.println("ndb.schema                  \"" + schema + "\"");
+
+        out.println();
+        out.println("ndb settings ...");
+        out.println("ndb.mgmdConnect:                \"" + mgmdConnect + "\"");
+        out.println("ndb.catalog:                    \"" + catalog + "\"");
+        out.println("ndb.schema:                     \"" + schema + "\"");
     }
 }

=== modified file 'storage/ndb/test/crund/src/com/mysql/cluster/crund/NdbJTieLoad.java'
--- a/storage/ndb/test/crund/src/com/mysql/cluster/crund/NdbJTieLoad.java	2010-10-01 04:10:21 +0000
+++ b/storage/ndb/test/crund/src/com/mysql/cluster/crund/NdbJTieLoad.java	2010-10-19 22:56:45 +0000
@@ -54,6 +54,10 @@ import com.mysql.ndbjtie.ndbapi.NdbIndex
  */
 public class NdbJTieLoad extends NdbBase {
 
+    // ----------------------------------------------------------------------
+    // NDB JTie resources
+    // ----------------------------------------------------------------------
+
     // singleton object representing the NDB cluster (one per process)
     protected Ndb_cluster_connection mgmd;
 
@@ -61,22 +65,72 @@ public class NdbJTieLoad extends NdbBase
     protected Ndb ndb;
 
     // the benchmark's metadata shortcuts
-    protected Meta meta;
+    protected Model model;
 
     // object representing an NDB database transaction
     protected NdbTransaction tx;
 
-    /**
-     * Returns a string representation of an NdbError.
-     */
-    static public String toStr(NdbErrorConst e) {
+    // ----------------------------------------------------------------------
+    // NDB JTie intializers/finalizers
+    // ----------------------------------------------------------------------
+
+    protected void initProperties() {
+        super.initProperties();
+        descr = "->ndbjtie(" + mgmdConnect + ")";
+    }
+
+    protected void init() throws Exception {
+        super.init();
+
+        // load native library (better diagnostics doing it explicitely)
+        out.println();
+        loadSystemLibrary("ndbclient");
+
+        // instantiate NDB cluster singleton
+        out.print("creating cluster connection ...");
+        out.flush();
+        mgmd = Ndb_cluster_connection.create(mgmdConnect);
+        assert mgmd != null;
+        out.println(" [ok]");
+
+        // connect to cluster management node (ndb_mgmd)
+        out.print("connecting to mgmd ...");
+        out.flush();
+        final int retries = 0;        // retries (< 0 = indefinitely)
+        final int delay = 0;          // seconds to wait after retry
+        final int verbose = 1;        // print report of progess
+        // 0 = success, 1 = recoverable error, -1 = non-recoverable error
+        if (mgmd.connect(retries, delay, verbose) != 0) {
+            final String msg = ("mgmd@" + mgmdConnect
+                                + " was not ready within "
+                                + (retries * delay) + "s.");
+            out.println(msg);
+            throw new RuntimeException("!!! " + msg);
+        }
+        out.println("          [ok: " + mgmdConnect + "]");
+    }
+
+    protected void close() throws Exception {
+        out.print("closing mgmd conn ...");
+        out.flush();
+        if (mgmd != null)
+            Ndb_cluster_connection.delete(mgmd);
+        mgmd = null;
+        out.println("           [ok]");
+        super.close();
+    }
+
+    // ----------------------------------------------------------------------
+    // NDB JTie operations
+    // ----------------------------------------------------------------------
+
+    // returns a string representation of an NdbError
+    static protected String toStr(NdbErrorConst e) {
         return "NdbError[" + e.code() + "]: " + e.message();
     }
 
-    /**
-     * Holds shortcuts to the benchmark's schema information.
-     */
-    static protected class Meta {
+    // holds shortcuts to the benchmark's schema information
+    static protected class Model {
         public final TableConst table_A;
         public final TableConst table_B0;
         public final ColumnConst column_A_id;
@@ -103,7 +157,7 @@ public class NdbJTieLoad extends NdbBase
         public final int attr_B0_cvarchar_def;
 
         // initialize this instance from the dictionary
-        public Meta(Ndb ndb) {
+        public Model(Ndb ndb) {
             final Dictionary dict = ndb.getDictionary();
 
             // get columns of table A
@@ -168,93 +222,6 @@ public class NdbJTieLoad extends NdbBase
         }
     };
 
-    protected void initProperties() {
-        super.initProperties();
-        descr = "->NDBJTIE->NDBAPI(" + mgmdConnect + ")";
-    }
-
-    protected void init() throws Exception {
-        super.init();
-
-        // load native library (better diagnostics doing it explicitely)
-        out.println();
-        loadSystemLibrary("ndbclient");
-
-        // instantiate NDB cluster singleton
-        out.println();
-        out.print("creating cluster conn ...");
-        out.flush();
-        mgmd = Ndb_cluster_connection.create(mgmdConnect);
-        assert mgmd != null;
-        out.println("   [ok, mgmd=" + mgmd + "]");
-
-        // connect to cluster management node (ndb_mgmd)
-        out.print("connecting to mgmd ...");
-        out.flush();
-        final int retries = 0;        // retries (< 0 = indefinitely)
-        final int delay = 0;          // seconds to wait after retry
-        final int verbose = 1;        // print report of progess
-        // 0 = success, 1 = recoverable error, -1 = non-recoverable error
-        if (mgmd.connect(retries, delay, verbose) != 0) {
-            final String msg = ("mgmd@" + mgmdConnect
-                                + " was not ready within "
-                                + (retries * delay) + "s.");
-            out.println(msg);
-            throw new RuntimeException("!!! " + msg);
-        }
-        out.println("      [ok: " + mgmdConnect + "]");
-    }
-
-    protected void close() throws Exception {
-        out.print("closing mgmd conn ...");
-        out.flush();
-        if (mgmd != null)
-            Ndb_cluster_connection.delete(mgmd);
-        mgmd = null;
-        out.println("       [ok]");
-        super.close();
-    }
-
-    protected void initConnection() {
-        // optionally, connect and wait for reaching the data nodes (ndbds)
-        out.print("waiting for data nodes...");
-        out.flush();
-        final int initial_wait = 10; // secs to wait until first node detected
-        final int final_wait = 0;    // secs 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) {
-            final String msg = ("data nodes were not ready within "
-                                + (initial_wait + final_wait) + "s.");
-            out.println(msg);
-            throw new RuntimeException(msg);
-        }
-        out.println("   [ok]");
-
-        // connect to database
-        out.print("connecting to database...");
-        out.flush();
-        ndb = Ndb.create(mgmd, catalog, schema);
-        final 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(max_no_tx) != 0) {
-            String msg = "Error caught: " + ndb.getNdbError().message();
-            throw new RuntimeException(msg);
-        }
-        out.println("   [ok]");
-
-        // initialize the schema shortcuts
-        meta = new Meta(ndb);
-    }
-
-    protected void closeConnection() {
-        out.print("closing database conn ...");
-        out.flush();
-        meta = null;
-        Ndb.delete(ndb);
-        ndb = null;
-        out.println("   [ok]");
-    }
-
     protected void initOperations() {
         out.print("initializing operations ...");
         out.flush();
@@ -271,56 +238,56 @@ public class NdbJTieLoad extends NdbBase
             ops.add(
                 new Op("insA" + (batch ? "_batch" : "")) {
                     public void run(int countA, int countB) {
-                        ins(meta.table_A, 1, countA, !setAttrs, batch);
+                        ins(model.table_A, 1, countA, !setAttrs, batch);
                     }
                 });
 
             ops.add(
                 new Op("insB0" + (batch ? "_batch" : "")) {
                     public void run(int countA, int countB) {
-                        ins(meta.table_B0, 1, countB, !setAttrs, batch);
+                        ins(model.table_B0, 1, countB, !setAttrs, batch);
                     }
                 });
 
             ops.add(
                 new Op("setAByPK" + (batch ? "_batch" : "")) {
                     public void run(int countA, int countB) {
-                        setByPK(meta.table_A, 1, countA, batch);
+                        setByPK(model.table_A, 1, countA, batch);
                     }
                 });
 
             ops.add(
                 new Op("setB0ByPK" + (batch ? "_batch" : "")) {
                     public void run(int countA, int countB) {
-                        setByPK(meta.table_B0, 1, countB, batch);
+                        setByPK(model.table_B0, 1, countB, batch);
                     }
                 });
 
             ops.add(
                 new Op("getAByPK_bb" + (batch ? "_batch" : "")) {
                     public void run(int countA, int countB) {
-                        getByPK_bb(meta.table_A, 1, countA, batch);
+                        getByPK_bb(model.table_A, 1, countA, batch);
                     }
                 });
 
             ops.add(
                 new Op("getAByPK_ar" + (batch ? "_batch" : "")) {
                     public void run(int countA, int countB) {
-                        getByPK_ar(meta.table_A, 1, countA, batch);
+                        getByPK_ar(model.table_A, 1, countA, batch);
                     }
                 });
 
             ops.add(
                 new Op("getB0ByPK_bb" + (batch ? "_batch" : "")) {
                     public void run(int countA, int countB) {
-                        getByPK_bb(meta.table_B0, 1, countB, batch);
+                        getByPK_bb(model.table_B0, 1, countB, batch);
                     }
                 });
 
             ops.add(
                 new Op("getB0ByPK_ar" + (batch ? "_batch" : "")) {
                     public void run(int countA, int countB) {
-                        getByPK_ar(meta.table_B0, 1, countB, batch);
+                        getByPK_ar(model.table_B0, 1, countB, batch);
                     }
                 });
 
@@ -331,21 +298,21 @@ public class NdbJTieLoad extends NdbBase
                 ops.add(
                     new Op("setVarbinary" + l + (batch ? "_batch" : "")) {
                         public void run(int countA, int countB) {
-                            setVarbinary(meta.table_B0, 1, countB, batch, b);
+                            setVarbinary(model.table_B0, 1, countB, batch, b);
                         }
                     });
 
                 ops.add(
                     new Op("getVarbinary" + l + (batch ? "_batch" : "")) {
                         public void run(int countA, int countB) {
-                            getVarbinary(meta.table_B0, 1, countB, batch, b);
+                            getVarbinary(model.table_B0, 1, countB, batch, b);
                         }
                     });
 
                 ops.add(
                     new Op("clearVarbinary" + l + (batch ? "_batch" : "")) {
                         public void run(int countA, int countB) {
-                            setVarbinary(meta.table_B0, 1, countB, batch, null);
+                            setVarbinary(model.table_B0, 1, countB, batch, null);
                         }
                     });
             }
@@ -357,21 +324,21 @@ public class NdbJTieLoad extends NdbBase
                 ops.add(
                     new Op("setVarchar" + l + (batch ? "_batch" : "")) {
                         public void run(int countA, int countB) {
-                            setVarchar(meta.table_B0, 1, countB, batch, s);
+                            setVarchar(model.table_B0, 1, countB, batch, s);
                         }
                     });
 
                 ops.add(
                     new Op("getVarchar" + l + (batch ? "_batch" : "")) {
                         public void run(int countA, int countB) {
-                            getVarchar(meta.table_B0, 1, countB, batch, s);
+                            getVarchar(model.table_B0, 1, countB, batch, s);
                         }
                     });
 
                 ops.add(
                     new Op("clearVarchar" + l + (batch ? "_batch" : "")) {
                         public void run(int countA, int countB) {
-                            setVarchar(meta.table_B0, 1, countB, batch, null);
+                            setVarchar(model.table_B0, 1, countB, batch, null);
                         }
                     });
             }
@@ -421,35 +388,35 @@ public class NdbJTieLoad extends NdbBase
             ops.add(
                 new Op("delB0ByPK" + (batch ? "_batch" : "")) {
                     public void run(int countA, int countB) {
-                        delByPK(meta.table_B0, 1, countB, batch);
+                        delByPK(model.table_B0, 1, countB, batch);
                     }
                 });
 
             ops.add(
                 new Op("delAByPK" + (batch ? "_batch" : "")) {
                     public void run(int countA, int countB) {
-                        delByPK(meta.table_A, 1, countA, batch);
+                        delByPK(model.table_A, 1, countA, batch);
                     }
                 });
 
             ops.add(
                 new Op("insA_attr" + (batch ? "_batch" : "")) {
                     public void run(int countA, int countB) {
-                        ins(meta.table_A, 1, countA, setAttrs, batch);
+                        ins(model.table_A, 1, countA, setAttrs, batch);
                     }
                 });
 
             ops.add(
                 new Op("insB0_attr" + (batch ? "_batch" : "")) {
                     public void run(int countA, int countB) {
-                        ins(meta.table_B0, 1, countB, setAttrs, batch);
+                        ins(model.table_B0, 1, countB, setAttrs, batch);
                     }
                 });
 
             ops.add(
                 new Op("delAllB0" + (batch ? "_batch" : "")) {
                     public void run(int countA, int countB) {
-                        final int count = delByScan(meta.table_B0, batch);
+                        final int count = delByScan(model.table_B0, batch);
                         assert count == countB;
                     }
                 });
@@ -457,23 +424,23 @@ public class NdbJTieLoad extends NdbBase
             ops.add(
                 new Op("delAllA" + (batch ? "_batch" : "")) {
                     public void run(int countA, int countB) {
-                        final int count = delByScan(meta.table_A, batch);
+                        final int count = delByScan(model.table_A, batch);
                         assert count == countA;
                     }
                 });
         }
 
-        out.println(" [Op: " + ops.size() + "]");
+        out.println("     [Op: " + ops.size() + "]");
     }
 
     protected void closeOperations() {
         out.print("closing operations ...");
         out.flush();
         ops.clear();
-        out.println("      [ok]");
+        out.println("          [ok]");
     }
 
-    protected void beginTransaction1() {
+    protected void beginTransaction() {
         // start a transaction
         // must be closed with NdbTransaction.close
         final TableConst table  = null;
@@ -483,7 +450,7 @@ public class NdbJTieLoad extends NdbBase
             throw new RuntimeException(toStr(ndb.getNdbError()));
     }
 
-    protected void executeOperations1() {
+    protected void executeOperations() {
         // execute but don't commit the current transaction
         final int execType = NdbTransaction.ExecType.NoCommit;
         final int abortOption = NdbOperation.AbortOption.AbortOnError;
@@ -493,7 +460,7 @@ public class NdbJTieLoad extends NdbBase
             throw new RuntimeException(toStr(tx.getNdbError()));
     }
 
-    protected void commitTransaction1() {
+    protected void commitTransaction() {
         // commit the current transaction
         final int execType = NdbTransaction.ExecType.Commit;
         final int abortOption = NdbOperation.AbortOption.AbortOnError;
@@ -503,7 +470,7 @@ public class NdbJTieLoad extends NdbBase
             throw new RuntimeException(toStr(tx.getNdbError()));
     }
 
-    protected void rollbackTransaction1() {
+    protected void rollbackTransaction() {
         // abort the current transaction
         final int execType = NdbTransaction.ExecType.Rollback;
         final int abortOption = NdbOperation.AbortOption.DefaultAbortOption;
@@ -513,7 +480,7 @@ public class NdbJTieLoad extends NdbBase
             throw new RuntimeException(toStr(tx.getNdbError()));
     }
 
-    protected void closeTransaction1() {
+    protected void closeTransaction() {
         // close the current transaction
         // to be called irrespectively of success or failure
         // equivalent to tx.close()
@@ -521,18 +488,6 @@ public class NdbJTieLoad extends NdbBase
         tx = null;
     }
 
-    protected void clearData() {
-        out.print("deleting all rows ...");
-        out.flush();
-        final int delB0 = delByScan(meta.table_B0, true);
-        out.print("       [B0: " + delB0);
-        out.flush();
-        final int delA = delByScan(meta.table_A, true);
-        out.print(", A: " + delA);
-        out.flush();
-        out.println("]");
-    }
-
     // ----------------------------------------------------------------------
 
     static protected class CommonAB_RA {
@@ -545,15 +500,15 @@ public class NdbJTieLoad extends NdbBase
 
     protected void fetchCommonAttributes(CommonAB_RA cab, NdbOperation op) {
         final ByteBuffer val = null;
-        if ((cab.id = op.getValue(meta.attr_id, val)) == null)
+        if ((cab.id = op.getValue(model.attr_id, val)) == null)
             throw new RuntimeException(toStr(tx.getNdbError()));
-        if ((cab.cint = op.getValue(meta.attr_cint, val)) == null)
+        if ((cab.cint = op.getValue(model.attr_cint, val)) == null)
             throw new RuntimeException(toStr(tx.getNdbError()));
-        if ((cab.clong = op.getValue(meta.attr_clong, val)) == null)
+        if ((cab.clong = op.getValue(model.attr_clong, val)) == null)
             throw new RuntimeException(toStr(tx.getNdbError()));
-        if ((cab.cfloat = op.getValue(meta.attr_cfloat, val)) == null)
+        if ((cab.cfloat = op.getValue(model.attr_cfloat, val)) == null)
             throw new RuntimeException(toStr(tx.getNdbError()));
-        if ((cab.cdouble = op.getValue(meta.attr_cdouble, val)) == null)
+        if ((cab.cdouble = op.getValue(model.attr_cdouble, val)) == null)
             throw new RuntimeException(toStr(tx.getNdbError()));
     }
 
@@ -572,7 +527,7 @@ public class NdbJTieLoad extends NdbBase
 
     protected void ins(TableConst table, int from, int to,
                        boolean setAttrs, boolean batch) {
-        beginTransaction1();
+        beginTransaction();
         for (int i = from; i <= to; i++) {
             // get an insert operation for the table
             NdbOperation op = tx.getNdbOperation(table);
@@ -582,30 +537,30 @@ public class NdbJTieLoad extends NdbBase
                 throw new RuntimeException(toStr(tx.getNdbError()));
 
             // set values; key attribute needs to be set first
-            if (op.equal(meta.attr_id, i) != 0)
+            if (op.equal(model.attr_id, i) != 0)
                 throw new RuntimeException(toStr(tx.getNdbError()));
             if (setAttrs) {
-                if (op.setValue(meta.attr_cint, -i) != 0)
+                if (op.setValue(model.attr_cint, -i) != 0)
                     throw new RuntimeException(toStr(tx.getNdbError()));
-                if (op.setValue(meta.attr_clong, (long)-i) != 0)
+                if (op.setValue(model.attr_clong, (long)-i) != 0)
                     throw new RuntimeException(toStr(tx.getNdbError()));
-                if (op.setValue(meta.attr_cfloat, (float)-i) != 0)
+                if (op.setValue(model.attr_cfloat, (float)-i) != 0)
                     throw new RuntimeException(toStr(tx.getNdbError()));
-                if (op.setValue(meta.attr_cdouble, (double)-i) != 0)
+                if (op.setValue(model.attr_cdouble, (double)-i) != 0)
                     throw new RuntimeException(toStr(tx.getNdbError()));
             }
 
             // execute the operation now if in non-batching mode
             if (!batch)
-                executeOperations1();
+                executeOperations();
         }
-        commitTransaction1();
-        closeTransaction1();
+        commitTransaction();
+        closeTransaction();
     }
 
     protected void delByPK(TableConst table, int from, int to,
                            boolean batch) {
-        beginTransaction1();
+        beginTransaction();
         for (int i = from; i <= to; i++) {
             // get a delete operation for the table
             NdbOperation op = tx.getNdbOperation(table);
@@ -615,25 +570,25 @@ public class NdbJTieLoad extends NdbBase
                 throw new RuntimeException(toStr(tx.getNdbError()));
 
             // set key attribute
-            if (op.equal(meta.attr_id, i) != 0)
+            if (op.equal(model.attr_id, i) != 0)
                 throw new RuntimeException(toStr(tx.getNdbError()));
 
             // execute the operation now if in non-batching mode
             if (!batch)
-                executeOperations1();
+                executeOperations();
         }
-        commitTransaction1();
-        closeTransaction1();
+        commitTransaction();
+        closeTransaction();
     }
 
     protected int delByScan(TableConst table, boolean batch) {
-        beginTransaction1();
+        beginTransaction();
 
         // get a full table scan operation (no scan filter defined)
         final NdbScanOperation op = tx.getNdbScanOperation(table);
         if (op == null)
             throw new RuntimeException(toStr(tx.getNdbError()));
-        
+
         // define a read scan with exclusive locks
         final int lock_mode = NdbOperation.LockMode.LM_Exclusive;
         final int scan_flags = 0;
@@ -643,7 +598,7 @@ public class NdbJTieLoad extends NdbBase
             throw new RuntimeException(toStr(tx.getNdbError()));
 
         // start the scan; don't commit yet
-        executeOperations1();
+        executeOperations();
 
         // delete all rows in a given scan
         int count = 0;
@@ -656,10 +611,10 @@ public class NdbJTieLoad extends NdbBase
                 if (op.deleteCurrentTuple() != 0)
                     throw new RuntimeException(toStr(tx.getNdbError()));
                 count++;
-                
+
                 // execute the operation now if in non-batching mode
                 if (!batch)
-                    executeOperations1();
+                    executeOperations();
             } while ((stat = op.nextResult(!allowFetch, forceSend)) == 0);
 
             if (stat == 1) {
@@ -686,14 +641,14 @@ public class NdbJTieLoad extends NdbBase
         final boolean releaseOp = false;
         op.close(forceSend_, releaseOp);
 
-        commitTransaction1();
-        closeTransaction1();
+        commitTransaction();
+        closeTransaction();
         return count;
     }
 
     protected void setByPK(TableConst table, int from, int to,
                            boolean batch) {
-        beginTransaction1();
+        beginTransaction();
         for (int i = from; i <= to; i++) {
             // get an update operation for the table
             NdbOperation op = tx.getNdbOperation(table);
@@ -703,43 +658,43 @@ public class NdbJTieLoad extends NdbBase
                 throw new RuntimeException(toStr(tx.getNdbError()));
 
             // set key attribute
-            if (op.equal(meta.attr_id, i) != 0)
+            if (op.equal(model.attr_id, i) != 0)
                 throw new RuntimeException(toStr(tx.getNdbError()));
 
             // set values
-            if (op.setValue(meta.attr_cint, i) != 0)
+            if (op.setValue(model.attr_cint, i) != 0)
                 throw new RuntimeException(toStr(tx.getNdbError()));
-            if (op.setValue(meta.attr_clong, (long)i) != 0)
+            if (op.setValue(model.attr_clong, (long)i) != 0)
                 throw new RuntimeException(toStr(tx.getNdbError()));
-            if (op.setValue(meta.attr_cfloat, (float)i) != 0)
+            if (op.setValue(model.attr_cfloat, (float)i) != 0)
                 throw new RuntimeException(toStr(tx.getNdbError()));
-            if (op.setValue(meta.attr_cdouble, (double)i) != 0)
+            if (op.setValue(model.attr_cdouble, (double)i) != 0)
                 throw new RuntimeException(toStr(tx.getNdbError()));
 
             // execute the operation now if in non-batching mode
             if (!batch)
-                executeOperations1();
+                executeOperations();
         }
-        commitTransaction1();
-        closeTransaction1();
+        commitTransaction();
+        closeTransaction();
     }
 
     protected void fetchCommonAttributes(ByteBuffer cab, NdbOperation op) {
-        if (op.getValue(meta.attr_id, cab) == null)
+        if (op.getValue(model.attr_id, cab) == null)
             throw new RuntimeException(toStr(tx.getNdbError()));
         int p = cab.position();
         //out.println("cab.position() == " + p);
         cab.position(p += 4);
-        if (op.getValue(meta.attr_cint, cab) == null)
+        if (op.getValue(model.attr_cint, cab) == null)
             throw new RuntimeException(toStr(tx.getNdbError()));
         cab.position(p += 4);
-        if (op.getValue(meta.attr_clong, cab) == null)
+        if (op.getValue(model.attr_clong, cab) == null)
             throw new RuntimeException(toStr(tx.getNdbError()));
         cab.position(p += 8);
-        if (op.getValue(meta.attr_cfloat, cab) == null)
+        if (op.getValue(model.attr_cfloat, cab) == null)
             throw new RuntimeException(toStr(tx.getNdbError()));
         cab.position(p += 4);
-        if (op.getValue(meta.attr_cdouble, cab) == null)
+        if (op.getValue(model.attr_cdouble, cab) == null)
             throw new RuntimeException(toStr(tx.getNdbError()));
         cab.position(p += 8);
     }
@@ -774,7 +729,7 @@ public class NdbJTieLoad extends NdbBase
         final ByteBuffer cab = ByteBuffer.allocateDirect(count * 28);
         cab.order(ByteOrder.nativeOrder());
 
-        beginTransaction1();
+        beginTransaction();
         for (int i = 0, j = from; i < count; i++, j++) {
             // get a read operation for the table
             NdbOperation op = tx.getNdbOperation(table);
@@ -784,17 +739,17 @@ public class NdbJTieLoad extends NdbBase
                 throw new RuntimeException(toStr(tx.getNdbError()));
 
             // set key attribute
-            if (op.equal(meta.attr_id, j) != 0)
+            if (op.equal(model.attr_id, j) != 0)
                 throw new RuntimeException(toStr(tx.getNdbError()));
 
             // get attributes (not readable until after commit)
             fetchCommonAttributes(cab, op);
-            
+
             // execute the operation now if in non-batching mode
             if (!batch)
-                executeOperations1();
+                executeOperations();
         }
-        commitTransaction1();
+        commitTransaction();
 
         // check fetched values
         cab.rewind();
@@ -804,7 +759,7 @@ public class NdbJTieLoad extends NdbBase
             final int id1 = verifyCommonAttributes(cab);
             verify(id1 == j);
         }
-        closeTransaction1();
+        closeTransaction();
     }
 
     protected void getByPK_ar(TableConst table, int from, int to,
@@ -813,7 +768,7 @@ public class NdbJTieLoad extends NdbBase
         final int count = (to - from) + 1;
         final CommonAB_RA[] cab_ra = new CommonAB_RA[count];
 
-        beginTransaction1();
+        beginTransaction();
         for (int i = 0, j = from; i < count; i++, j++) {
             // get a read operation for the table
             NdbOperation op = tx.getNdbOperation(table);
@@ -823,32 +778,32 @@ public class NdbJTieLoad extends NdbBase
                 throw new RuntimeException(toStr(tx.getNdbError()));
 
             // set key attribute
-            if (op.equal(meta.attr_id, j) != 0)
+            if (op.equal(model.attr_id, j) != 0)
                 throw new RuntimeException(toStr(tx.getNdbError()));
 
             // get attributes (not readable until after commit)
             final CommonAB_RA c = new CommonAB_RA();
-            //if ((c.id = op.getValue(meta.attr_id, null)) == null)
+            //if ((c.id = op.getValue(model.attr_id, null)) == null)
             //    throw new RuntimeException(toStr(tx.getNdbError()));
             fetchCommonAttributes(c, op);
             cab_ra[i] = c;
-            
+
             // execute the operation now if in non-batching mode
             if (!batch)
-                executeOperations1();
+                executeOperations();
         }
-        commitTransaction1();
+        commitTransaction();
 
         // check fetched values
         for (int i = 0, j = from; i < count; i++, j++) {
             //check key attribute
             verify(cab_ra[i].id.int32_value() == j);
-            
+
             // check other attributes
             final int id1 = verifyCommonAttributes(cab_ra[i]);
             verify(id1 == j);
         }
-        closeTransaction1();
+        closeTransaction();
     }
 
     protected void setVarbinary(TableConst table, int from, int to,
@@ -871,7 +826,7 @@ public class NdbJTieLoad extends NdbBase
             buf.flip();
         }
 
-        beginTransaction1();
+        beginTransaction();
         for (int i = from; i <= to; i++) {
             // get an insert operation for the table
             NdbOperation op = tx.getNdbOperation(table);
@@ -881,19 +836,19 @@ public class NdbJTieLoad extends NdbBase
                 throw new RuntimeException(toStr(tx.getNdbError()));
 
             // set key attribute
-            if (op.equal(meta.attr_id, i) != 0)
+            if (op.equal(model.attr_id, i) != 0)
                 throw new RuntimeException(toStr(tx.getNdbError()));
 
             // set values
-            if (op.setValue(meta.attr_B0_cvarbinary_def, buf) != 0)
+            if (op.setValue(model.attr_B0_cvarbinary_def, buf) != 0)
                 throw new RuntimeException(toStr(tx.getNdbError()));
 
             // execute the operation now if in non-batching mode
             if (!batch)
-                executeOperations1();
+                executeOperations();
         }
-        commitTransaction1();
-        closeTransaction1();
+        commitTransaction();
+        closeTransaction();
 */
     }
 
@@ -901,24 +856,24 @@ public class NdbJTieLoad extends NdbBase
                               boolean batch, String string) {
 // XXX not implemented yet
 /*
-        beginTransaction1();
+        beginTransaction();
         for (int i = from; i <= to; i++) {
             // get an update operation for the table
             final NdbOperation op = tx.getUpdateOperation(table);
             assert op != null;
 
             // set key attribute
-            op.equalInt(meta.attr_id, i);
+            op.equalInt(model.attr_id, i);
 
             // set varchar
-            op.setString(meta.attr_B0_cvarchar_def, string);
+            op.setString(model.attr_B0_cvarchar_def, string);
 
             // execute the operation now if in non-batching mode
             if (!batch)
-                executeOperations1();
+                executeOperations();
         }
-        commitTransaction1();
-        closeTransaction1();
+        commitTransaction();
+        closeTransaction();
 */
     }
 
@@ -932,8 +887,8 @@ public class NdbJTieLoad extends NdbBase
         final int sbuf = count * sline;
         final ByteBuffer buf = ByteBuffer.allocateDirect(sbuf);
         //buf.order(ByteOrder.nativeOrder());
-        
-        beginTransaction1();
+
+        beginTransaction();
         for (int i = 0, j = from; i < count; i++, j++) {
             // get a read operation for the table
             NdbOperation op = tx.getNdbOperation(table);
@@ -943,7 +898,7 @@ public class NdbJTieLoad extends NdbBase
                 throw new RuntimeException(toStr(tx.getNdbError()));
 
             // set key attribute
-            if (op.equal(meta.attr_id, j) != 0)
+            if (op.equal(model.attr_id, j) != 0)
                 throw new RuntimeException(toStr(tx.getNdbError()));
 
             // get attributes (not readable until after commit)
@@ -952,12 +907,12 @@ public class NdbJTieLoad extends NdbBase
                 throw new RuntimeException(toStr(tx.getNdbError()));
             //out.println("buf.position() == " + p);
             buf.position(p += sline);
-            
+
             // execute the operation now if in non-batching mode
             if (!batch)
-                executeOperations1();
+                executeOperations();
         }
-        commitTransaction1();
+        commitTransaction();
 
         // check fetched values
         buf.rewind();
@@ -970,16 +925,16 @@ public class NdbJTieLoad extends NdbBase
 
             const size_t n = s[0];
             VERIFY(n < sline);
-            
+
             // move and 0-terminated string
             memmove(s, s + 1, n);
             s[n] = 0;
-            
+
             // check fetched values
             //CDBG << "!!! s=" << (void*)s << ", '" << s << "'" << endl;
             VERIFY(strcmp(s, str) == 0);
         }
-        closeTransaction1();
+        closeTransaction();
 */
     }
 
@@ -991,27 +946,27 @@ public class NdbJTieLoad extends NdbBase
         final int count = (to - from) + 1;
         final NdbResultSet[] rss = new NdbResultSet[count];
 
-        beginTransaction1();
+        beginTransaction();
         for (int i = 0, j = from; i < count; i++, j++) {
             // get a read operation for the table
             NdbOperation op = tx.getSelectOperation(table);
             assert op != null;
 
             // set key attribute
-            op.equalInt(meta.attr_id, j);
+            op.equalInt(model.attr_id, j);
 
             // define fetched attributes
-            op.getValue(meta.attr_B0_cvarchar_def);
+            op.getValue(model.attr_B0_cvarchar_def);
 
             // get attributes (not readable until after commit)
             rss[i] = op.resultData();
 
             // execute the operation now if in non-batching mode
             if (!batch)
-                executeOperations1();
+                executeOperations();
         }
-        //executeOperations1();
-        commitTransaction1();
+        //executeOperations();
+        commitTransaction();
 
         // check fetched values
         for (int i = 0, j = from; i < count; i++, j++) {
@@ -1022,18 +977,18 @@ public class NdbJTieLoad extends NdbBase
             // check varchar
             if (true) {
                 final String cvarchar_def
-                    = rs.getString(meta.attr_B0_cvarchar_def);
+                    = rs.getString(model.attr_B0_cvarchar_def);
                 verify(string.equals(cvarchar_def));
             } else {
                 // verification imposes a string->bytes conversion penalty
                 final byte[] cvarchar_def
-                    = rs.getStringBytes(meta.attr_B0_cvarchar_def);
+                    = rs.getStringBytes(model.attr_B0_cvarchar_def);
                 verify(Arrays.equals(string.getBytes(), cvarchar_def));
             }
 
             assert !rs.next();
         }
-        closeTransaction1();
+        closeTransaction();
 */
     }
 
@@ -1041,25 +996,25 @@ public class NdbJTieLoad extends NdbBase
                             boolean batch) {
 // XXX not implemented yet
 /*
-        beginTransaction1();
+        beginTransaction();
         for (int i = 1; i <= count_B; i++) {
             // get an update operation for the table
-            final NdbOperation op = tx.getUpdateOperation(meta.table_B0);
+            final NdbOperation op = tx.getUpdateOperation(model.table_B0);
             assert op != null;
 
             // set key attribute
-            op.equalInt(meta.attr_id, i);
+            op.equalInt(model.attr_id, i);
 
             // set a_id attribute
             int a_id = ((i - 1) % count_A) + 1;
-            op.setInt(meta.attr_B0_a_id, a_id);
+            op.setInt(model.attr_B0_a_id, a_id);
 
             // execute the operation now if in non-batching mode
             if (!batch)
-                executeOperations1();
+                executeOperations();
         }
-        commitTransaction1();
-        closeTransaction1();
+        commitTransaction();
+        closeTransaction();
 */
     }
 
@@ -1067,25 +1022,25 @@ public class NdbJTieLoad extends NdbBase
                              boolean batch) {
 // XXX not implemented yet
 /*
-        beginTransaction1();
+        beginTransaction();
         for (int i = 1; i <= count_B; i++) {
             // get an update operation for the table
-            final NdbOperation op = tx.getUpdateOperation(meta.table_B0);
+            final NdbOperation op = tx.getUpdateOperation(model.table_B0);
             assert op != null;
 
             // set key attribute
-            op.equalInt(meta.attr_id, i);
+            op.equalInt(model.attr_id, i);
 
             // set a_id attribute
             int a_id = ((i - 1) % count_A) + 1;
-            op.setNull(meta.attr_B0_a_id);
+            op.setNull(model.attr_B0_a_id);
 
             // execute the operation now if in non-batching mode
             if (!batch)
-                executeOperations1();
+                executeOperations();
         }
-        commitTransaction1();
-        closeTransaction1();
+        commitTransaction();
+        closeTransaction();
 */
     }
 
@@ -1093,7 +1048,7 @@ public class NdbJTieLoad extends NdbBase
                             boolean batch) {
 // XXX not implemented yet
 /*
-        beginTransaction1();
+        beginTransaction();
 
         // fetch the foreign keys from B0 and read attributes from A
         final NdbResultSet[] abs = new NdbResultSet[count_B];
@@ -1102,33 +1057,33 @@ public class NdbJTieLoad extends NdbBase
             NdbResultSet rs;
             {
                 // get a read operation for the table
-                NdbOperation op = tx.getSelectOperation(meta.table_B0);
+                NdbOperation op = tx.getSelectOperation(model.table_B0);
                 assert op != null;
 
                 // set key attribute
-                op.equalInt(meta.attr_id, i);
+                op.equalInt(model.attr_id, i);
 
                 // define fetched attributes
-                op.getValue(meta.attr_B0_a_id);
+                op.getValue(model.attr_B0_a_id);
 
                 // get attributes (not readable until after commit)
                 rs = op.resultData();
             }
-            executeOperations1(); // start the scan; don't commit yet
+            executeOperations(); // start the scan; don't commit yet
 
             // fetch the attributes from A
             {
                 // get a read operation for the table
-                NdbOperation op = tx.getSelectOperation(meta.table_A);
+                NdbOperation op = tx.getSelectOperation(model.table_A);
                 assert op != null;
 
                 // set key attribute
-                final int a_id = rs.getInt(meta.attr_B0_a_id);
+                final int a_id = rs.getInt(model.attr_B0_a_id);
                 assert a_id == ((i - 1) % count_A) + 1;
-                op.equalInt(meta.attr_id, a_id);
+                op.equalInt(model.attr_id, a_id);
 
                 // define fetched attributes
-                op.getValue(meta.attr_id);
+                op.getValue(model.attr_id);
                 fetchCommonAttributes(op);
 
                 // get attributes (not readable until after commit)
@@ -1137,9 +1092,9 @@ public class NdbJTieLoad extends NdbBase
 
             // execute the operation now if in non-batching mode
             if (!batch)
-                executeOperations1();
+                executeOperations();
         }
-        commitTransaction1();
+        commitTransaction();
 
         // check fetched values
         for (int i = 1, j = 0; i <= count_B; i++, j++) {
@@ -1148,7 +1103,7 @@ public class NdbJTieLoad extends NdbBase
             assert hasNext;
 
             // check key attribute
-            final int id = ab.getInt(meta.attr_id);
+            final int id = ab.getInt(model.attr_id);
             //out.println("id = " + id + ", i = " + i);
             verify(id == ((i - 1) % count_A) + 1);
 
@@ -1158,7 +1113,7 @@ public class NdbJTieLoad extends NdbBase
 
             assert !ab.next();
         }
-        closeTransaction1();
+        closeTransaction();
 */
     }
 
@@ -1166,40 +1121,40 @@ public class NdbJTieLoad extends NdbBase
                                boolean batch) {
 // XXX not implemented yet
 /*
-        beginTransaction1();
+        beginTransaction();
 
         // fetch the foreign key value from B0
         final NdbResultSet[] a_ids = new NdbResultSet[count_B];
         for (int i = 1, j = 0; i <= count_B; i++, j++) {
                 // get a read operation for the table
-                NdbOperation op = tx.getSelectOperation(meta.table_B0);
+                NdbOperation op = tx.getSelectOperation(model.table_B0);
                 assert op != null;
 
                 // set key attribute
-                op.equalInt(meta.attr_id, i);
+                op.equalInt(model.attr_id, i);
 
                 // define fetched attributes
-                op.getValue(meta.attr_B0_a_id);
+                op.getValue(model.attr_B0_a_id);
 
                 // get attributes (not readable until after commit)
                 a_ids[j] = op.resultData();
         }
-        executeOperations1(); // start the scan; don't commit yet
+        executeOperations(); // start the scan; don't commit yet
 
         // fetch the attributes from A
         final NdbResultSet[] abs = new NdbResultSet[count_B];
         for (int i = 1, j = 0; i <= count_B; i++, j++) {
             // get a read operation for the table
-            NdbOperation op = tx.getSelectOperation(meta.table_A);
+            NdbOperation op = tx.getSelectOperation(model.table_A);
             assert op != null;
 
             // set key attribute
-            final int a_id = a_ids[j].getInt(meta.attr_B0_a_id);
+            final int a_id = a_ids[j].getInt(model.attr_B0_a_id);
             assert a_id == ((i - 1) % count_A) + 1;
-            op.equalInt(meta.attr_id, a_id);
+            op.equalInt(model.attr_id, a_id);
 
             // define fetched attributes
-            op.getValue(meta.attr_id);
+            op.getValue(model.attr_id);
             fetchCommonAttributes(op);
 
             // get attributes (not readable until after commit)
@@ -1207,9 +1162,9 @@ public class NdbJTieLoad extends NdbBase
 
             // execute the operation now if in non-batching mode
             if (!batch)
-                executeOperations1();
+                executeOperations();
         }
-        commitTransaction1();
+        commitTransaction();
 
         // check fetched values
         for (int i = 1, j = 0; i <= count_B; i++, j++) {
@@ -1218,7 +1173,7 @@ public class NdbJTieLoad extends NdbBase
             assert hasNext;
 
             // check key attribute
-            final int id = ab.getInt(meta.attr_id);
+            final int id = ab.getInt(model.attr_id);
             //out.println("id = " + id + ", i = " + i);
             verify(id == ((i - 1) % count_A) + 1);
 
@@ -1228,7 +1183,7 @@ public class NdbJTieLoad extends NdbBase
 
             assert !ab.next();
         }
-        closeTransaction1();
+        closeTransaction();
 */
     }
 
@@ -1236,7 +1191,7 @@ public class NdbJTieLoad extends NdbBase
                             boolean forceSend) {
 // XXX not implemented yet
 /*
-        beginTransaction1();
+        beginTransaction();
 
         // fetch attributes from B0 by foreign key scan
         final NdbResultSet[] abs = new NdbResultSet[count_B];
@@ -1245,8 +1200,8 @@ public class NdbJTieLoad extends NdbBase
             // get an index scan operation for the table
             // XXX ? no locks (LM_CommittedRead) or shared locks (LM_Read)
             final NdbIndexScanOperation op
-                = tx.getSelectIndexScanOperation(meta.idx_B0_a_id,
-                                                 meta.table_B0,
+                = tx.getSelectIndexScanOperation(model.idx_B0_a_id,
+                                                 model.table_B0,
                                                  LockMode.LM_CommittedRead);
             assert op != null;
 
@@ -1258,10 +1213,10 @@ public class NdbJTieLoad extends NdbBase
             //
             // which translates into
             //out.println("idx_B0_a_id.getNoOfColumns() = "
-            //            + meta.idx_B0_a_id.getNoOfColumns());
+            //            + model.idx_B0_a_id.getNoOfColumns());
             //out.println("idx_B0_a_id.getColumn(0).getColumnNo() = "
-            //            + meta.idx_B0_a_id.getColumn(0).getColumnNo());
-            //op.setBoundInt(meta.idx_B0_a_id.getColumn(0).getColumnNo(),
+            //            + model.idx_B0_a_id.getColumn(0).getColumnNo());
+            //op.setBoundInt(model.idx_B0_a_id.getColumn(0).getColumnNo(),
             //               BoundType.BoundEQ, i);
             // except that we get the usual error with NDBJ:
             //[java] idx_B0_a_id.getColumn(0).getColumnNo() = 0
@@ -1270,18 +1225,18 @@ public class NdbJTieLoad extends NdbBase
             //
             // so we go by column name
             //out.println("idx_B0_a_id.getColumn(0).getName() = "
-            //            + meta.idx_B0_a_id.getColumn(0).getName());
-            //op.setBoundInt(meta.idx_B0_a_id.getColumn(0).getName(),
+            //            + model.idx_B0_a_id.getColumn(0).getName());
+            //op.setBoundInt(model.idx_B0_a_id.getColumn(0).getName(),
             //               BoundType.BoundEQ, i);
             // which is actually "a_id", so, for now, we call
             op.setBoundInt("a_id", BoundType.BoundEQ, i);
 
             // define fetched attributes
-            op.getValue(meta.attr_id);
+            op.getValue(model.attr_id);
             fetchCommonAttributes(op);
 
             // start the scan; don't commit yet
-            executeOperations1();
+            executeOperations();
 
             int stat;
             final boolean allowFetch = true; // request new batches when exhausted
@@ -1292,7 +1247,7 @@ public class NdbJTieLoad extends NdbBase
             if (stat != 1)
                 throw new RuntimeException("stat == " + stat);
         }
-        commitTransaction1();
+        commitTransaction();
         assert (j++ == count_B);
 
         // check fetched values
@@ -1305,13 +1260,13 @@ public class NdbJTieLoad extends NdbBase
             //[java] j = 1, ab = com.mysql.ndbjtie.ndbapi.NdbResultSetImpl@6f144c
             //    [java] caught com.mysql.ndbjtie.ndbapi.NdbApiException: Unknown error code
             //    [java] com.mysql.ndbjtie.ndbapi.NdbApiException: Unknown error code
-            //    [java] at com.mysql.ndbjtie.ndbapi.NdbJTieJNI.NdbScanOperationImpl_nextResult__SWIG_1(Native Method)
+            //    [java] at com.mysql.ndbjtie.ndbapi.NdbJTieJNI.NdbScanOperationImpl_nextResult__SWIG_(Native Method)
             //    [java] at com.mysql.ndbjtie.ndbapi.NdbScanOperationImpl.nextResult(NdbScanOperationImpl.java:93)
             //    [java] at com.mysql.ndbjtie.ndbapi.NdbResultSetImpl.next(NdbResultSetImpl.java:362)
             //    [java] at com.mysql.cluster.crund.NdbJTieLoad.navAToB0(NdbJTieLoad.java:1205)
             //
             // YYY Frazer: check tx object for error (could be node failure)
-            // Martin: doesn't help much; after ab.next(): 
+            // Martin: doesn't help much; after ab.next():
             //out.println("tx.getNdbError() = " + tx.getNdbError().getCode());
             // returns -1 and
             //out.println("tx.getNdbError() = " + tx.getNdbError().getMessage());
@@ -1328,7 +1283,7 @@ public class NdbJTieLoad extends NdbBase
             assert hasNext;
 
             // check key attribute
-            final int id = ab.getInt(meta.attr_id);
+            final int id = ab.getInt(model.attr_id);
             verify(id == i);
 
             // check other attributes
@@ -1337,7 +1292,7 @@ public class NdbJTieLoad extends NdbBase
 
             assert !ab.next();
         }
-        closeTransaction1();
+        closeTransaction();
 */
     }
 
@@ -1349,6 +1304,63 @@ public class NdbJTieLoad extends NdbBase
 */
     }
 
+
+    // ----------------------------------------------------------------------
+    // NDB JTie datastore operations
+    // ----------------------------------------------------------------------
+
+    protected void initConnection() {
+        // optionally, connect and wait for reaching the data nodes (ndbds)
+        out.print("waiting for data nodes...");
+        out.flush();
+        final int initial_wait = 10; // secs to wait until first node detected
+        final int final_wait = 0;    // secs 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) {
+            final String msg = ("data nodes were not ready within "
+                                + (initial_wait + final_wait) + "s.");
+            out.println(msg);
+            throw new RuntimeException(msg);
+        }
+        out.println("       [ok]");
+
+        // connect to database
+        out.print("connecting to database...");
+        out.flush();
+        ndb = Ndb.create(mgmd, catalog, schema);
+        final 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(max_no_tx) != 0) {
+            String msg = "Error caught: " + ndb.getNdbError().message();
+            throw new RuntimeException(msg);
+        }
+        out.println("       [ok]");
+
+        // initialize the schema shortcuts
+        model = new Model(ndb);
+    }
+
+    protected void closeConnection() {
+        out.print("closing database conn ...");
+        out.flush();
+        model = null;
+        Ndb.delete(ndb);
+        ndb = null;
+        out.println("       [ok]");
+    }
+
+    protected void clearData() {
+        out.print("deleting all rows ...");
+        out.flush();
+        final int delB0 = delByScan(model.table_B0, true);
+        out.print("           [B0: " + delB0);
+        out.flush();
+        final int delA = delByScan(model.table_A, true);
+        out.print(", A: " + delA);
+        out.flush();
+        out.println("]");
+    }
+
     // ----------------------------------------------------------------------
 
     static public void main(String[] args) {

=== modified file 'storage/ndb/test/crund/src/com/mysql/cluster/crund/NdbjLoad.java'
--- a/storage/ndb/test/crund/src/com/mysql/cluster/crund/NdbjLoad.java	2010-02-14 05:05:31 +0000
+++ b/storage/ndb/test/crund/src/com/mysql/cluster/crund/NdbjLoad.java	2010-10-05 08:48:30 +0000
@@ -49,6 +49,10 @@ import com.mysql.cluster.ndbj.NdbResultS
  */
 public class NdbjLoad extends NdbBase {
 
+    // ----------------------------------------------------------------------
+    // NDBJ resources
+    // ----------------------------------------------------------------------
+
     // singleton object representing the NDB cluster (one per process)
     protected NdbClusterConnection mgmd;
 
@@ -61,17 +65,68 @@ public class NdbjLoad extends NdbBase {
     // object representing an NDB database transaction
     protected NdbTransaction tx;
 
-    /**
-     * Returns a string representation of an NdbError.
-     */
-    static public String toStr(NdbError e) {
+    // ----------------------------------------------------------------------
+    // NDBJ intializers/finalizers
+    // ----------------------------------------------------------------------
+
+    protected void initProperties() {
+        super.initProperties();
+        descr = "->ndbj->ndbapi(" + mgmdConnect + ")";
+    }
+
+    protected void init() throws Exception {
+        super.init();
+
+        // load native library (better diagnostics doing it explicitely)
+        out.println();
+        loadSystemLibrary("ndbj");
+
+        // instantiate NDB cluster singleton
+        out.println();
+        out.print("creating cluster conn...");
+        out.flush();
+        mgmd = NdbClusterConnection.create(mgmdConnect);
+        assert mgmd != null;
+        out.println("    [ok]");
+
+        // connect to cluster management node (ndb_mgmd)
+        out.print("connecting to mgmd ...");
+        out.flush();
+        final int retries = 0;        // retries (< 0 = indefinitely)
+        final int delay = 0;          // seconds to wait after retry
+        final boolean verbose = true; // print report of progess
+        // 0 = success, 1 = recoverable error, -1 = non-recoverable error
+        if (mgmd.connect(retries, delay, verbose) != 0) {
+            final String msg = ("mgmd@" + mgmdConnect
+                                + " was not ready within "
+                                + (retries * delay) + "s.");
+            out.println(msg);
+            throw new RuntimeException("!!! " + msg);
+        }
+        out.println("      [ok: " + mgmdConnect + "]");
+    }
+
+    protected void close() throws Exception {
+        out.print("closing mgmd conn ...");
+        out.flush();
+        if (mgmd != null)
+            mgmd.close();
+        mgmd = null;
+        out.println("       [ok]");
+        super.close();
+    }
+
+    // ----------------------------------------------------------------------
+    // NDBJ operations
+    // ----------------------------------------------------------------------
+
+    // returns a string representation of an NdbError
+    static protected String toStr(NdbError e) {
         return "NdbError[" + e.getCode() + "]: " + e.getMessage();
     }
 
-    /**
-     * Holds shortcuts to the benchmark's schema information.
-     */
-    static protected class Meta {
+    // holds shortcuts to the benchmark's schema information
+    static protected class Model {
         public final NdbTable table_A;
         public final NdbTable table_B0;
         public final NdbColumn column_A_id;
@@ -109,7 +164,7 @@ public class NdbjLoad extends NdbBase {
         public final String name_B0_cvarchar_def;
 
         // initialize this instance from the dictionary
-        public Meta(Ndb ndb) throws NdbApiException {
+        public Model(Ndb ndb) throws NdbApiException {
             final NdbDictionary dict = ndb.getDictionary();
 
             // get columns of table A
@@ -207,103 +262,6 @@ public class NdbjLoad extends NdbBase {
     final String[] strings = { string1, string10, string100 };
     final byte[][] bytes = { bytes1, bytes10, bytes100 };
 
-    protected void initProperties() {
-        super.initProperties();
-        descr = "->NDBJ->NDBAPI(" + mgmdConnect + ")";
-    }
-
-    protected void init() throws Exception {
-        super.init();
-
-        // load native library (better diagnostics doing it explicitely)
-        out.println();
-        loadSystemLibrary("ndbj");
-
-        // instantiate NDB cluster singleton
-        out.println();
-        out.print("creating cluster conn...");
-        out.flush();
-        mgmd = NdbClusterConnection.create(mgmdConnect);
-        assert mgmd != null;
-        out.println("    [ok]");
-
-        // connect to cluster management node (ndb_mgmd)
-        out.print("connecting to mgmd ...");
-        out.flush();
-        final int retries = 0;        // retries (< 0 = indefinitely)
-        final int delay = 0;          // seconds to wait after retry
-        final boolean verbose = true; // print report of progess
-        // 0 = success, 1 = recoverable error, -1 = non-recoverable error
-        if (mgmd.connect(retries, delay, verbose) != 0) {
-            final String msg = ("mgmd@" + mgmdConnect
-                                + " was not ready within "
-                                + (retries * delay) + "s.");
-            out.println(msg);
-            throw new RuntimeException("!!! " + msg);
-        }
-        out.println("      [ok: " + mgmdConnect + "]");
-    }
-
-    protected void close() throws Exception {
-        out.print("closing mgmd conn ...");
-        out.flush();
-        if (mgmd != null)
-            mgmd.close();
-        mgmd = null;
-        out.println("       [ok]");
-        super.close();
-    }
-
-    protected void initConnection() throws NdbApiException {
-        // optionally, connect and wait for reaching the data nodes (ndbds)
-        out.print("waiting for data nodes...");
-        out.flush();
-        final int initial_wait = 10; // secs to wait until first node detected
-        final int final_wait = 0;    // secs to wait after first node detected
-
-        // XXX return: 0 all nodes live, > 0 at least one node live, < 0 error
-        try {
-            mgmd.waitUntilReady(initial_wait, final_wait);
-        } catch (NdbApiException e) {
-            out.println();
-            out.println("!!! data nodes were not ready within "
-                        + (initial_wait + final_wait) + "s.");
-            throw e;
-        }
-        out.println("   [ok]");
-
-        // connect to database
-        out.print("connecting to database...");
-        out.flush();
-        try {
-            // XXX where to set schema?
-            // YYY Frazer: schema not too useful in NDB at the moment
-            // XXX unclear if maxThreads ^= maxNumberOfTransactions
-            //     since ndb.init(maxNumberOfTransactions) is deprecated
-            //final int maxThreads = 4;
-            //ndb = mgmd.createNdb(catalog, maxThreads);
-            // YYY Frazer: yes, maxThreads == maxNumber(concurrent)OfTransactions
-            ndb = mgmd.createNdb(catalog);
-        } catch (NdbApiException e) {
-            out.println();
-            out.println("!!! failed to connect: " + e);
-            throw e;
-        }
-        out.println("   [ok]");
-
-        // initialize the schema shortcuts
-        meta = new Meta(ndb);
-    }
-
-    protected void closeConnection() {
-        out.print("closing database conn ...");
-        out.flush();
-        meta = null;
-        ndb.close();
-        ndb = null;
-        out.println("   [ok]");
-    }
-
     protected void initOperations() throws NdbApiException {
         out.print("initializing operations ...");
         out.flush();
@@ -321,7 +279,7 @@ public class NdbjLoad extends NdbBase {
                 new Op("insA" + (batch ? "_batch" : "")) {
                     public void run(int countA, int countB)
                         throws NdbApiException {
-                        ins(meta.table_A, 1, countA, !setAttrs, batch);
+                        ins(model.table_A, 1, countA, !setAttrs, batch);
                     }
                 });
 
@@ -329,7 +287,7 @@ public class NdbjLoad extends NdbBase {
                 new Op("insB0" + (batch ? "_batch" : "")) {
                     public void run(int countA, int countB)
                         throws NdbApiException {
-                        ins(meta.table_B0, 1, countB, !setAttrs, batch);
+                        ins(model.table_B0, 1, countB, !setAttrs, batch);
                     }
                 });
 
@@ -337,7 +295,7 @@ public class NdbjLoad extends NdbBase {
                 new Op("setAByPK" + (batch ? "_batch" : "")) {
                     public void run(int countA, int countB)
                         throws NdbApiException {
-                        setByPK(meta.table_A, 1, countA, batch);
+                        setByPK(model.table_A, 1, countA, batch);
                     }
                 });
 
@@ -345,7 +303,7 @@ public class NdbjLoad extends NdbBase {
                 new Op("setB0ByPK" + (batch ? "_batch" : "")) {
                     public void run(int countA, int countB)
                         throws NdbApiException {
-                        setByPK(meta.table_B0, 1, countB, batch);
+                        setByPK(model.table_B0, 1, countB, batch);
                     }
                 });
 
@@ -353,7 +311,7 @@ public class NdbjLoad extends NdbBase {
                 new Op("getAByPK" + (batch ? "_batch" : "")) {
                     public void run(int countA, int countB)
                         throws NdbApiException {
-                        getByPK(meta.table_A, 1, countA, batch);
+                        getByPK(model.table_A, 1, countA, batch);
                     }
                 });
 
@@ -361,7 +319,7 @@ public class NdbjLoad extends NdbBase {
                 new Op("getB0ByPK" + (batch ? "_batch" : "")) {
                     public void run(int countA, int countB)
                         throws NdbApiException {
-                        getByPK(meta.table_B0, 1, countB, batch);
+                        getByPK(model.table_B0, 1, countB, batch);
                     }
                 });
 
@@ -373,7 +331,7 @@ public class NdbjLoad extends NdbBase {
                     new Op("setVarbinary" + l + (batch ? "_batch" : "")) {
                         public void run(int countA, int countB)
                             throws NdbApiException {
-                            setVarbinary(meta.table_B0, 1, countB, batch, b);
+                            setVarbinary(model.table_B0, 1, countB, batch, b);
                         }
                     });
 
@@ -381,11 +339,11 @@ public class NdbjLoad extends NdbBase {
                     new Op("getVarbinary" + l + (batch ? "_batch" : "")) {
                         public void run(int countA, int countB)
                             throws NdbApiException {
-                            getVarbinary(meta.table_B0, 1, countB, batch, b);
+                            getVarbinary(model.table_B0, 1, countB, batch, b);
                         }
                     });
             }
-            
+
             for (int i = 0, l = 1; l <= maxVarcharChars; l *= 10, i++) {
                 final String s = strings[i];
                 assert l == s.length();
@@ -394,7 +352,7 @@ public class NdbjLoad extends NdbBase {
                     new Op("setVarchar" + l + (batch ? "_batch" : "")) {
                         public void run(int countA, int countB)
                             throws NdbApiException {
-                            setVarchar(meta.table_B0, 1, countB, batch, s);
+                            setVarchar(model.table_B0, 1, countB, batch, s);
                         }
                     });
 
@@ -402,7 +360,7 @@ public class NdbjLoad extends NdbBase {
                     new Op("getVarchar" + l + (batch ? "_batch" : "")) {
                         public void run(int countA, int countB)
                             throws NdbApiException {
-                            getVarchar(meta.table_B0, 1, countB, batch, s);
+                            getVarchar(model.table_B0, 1, countB, batch, s);
                         }
                     });
             }
@@ -461,7 +419,7 @@ public class NdbjLoad extends NdbBase {
                 new Op("delB0ByPK" + (batch ? "_batch" : "")) {
                     public void run(int countA, int countB)
                         throws NdbApiException {
-                        delByPK(meta.table_B0, 1, countB, batch);
+                        delByPK(model.table_B0, 1, countB, batch);
                     }
                 });
 
@@ -469,7 +427,7 @@ public class NdbjLoad extends NdbBase {
                 new Op("delAByPK" + (batch ? "_batch" : "")) {
                     public void run(int countA, int countB)
                         throws NdbApiException {
-                        delByPK(meta.table_A, 1, countA, batch);
+                        delByPK(model.table_A, 1, countA, batch);
                     }
                 });
 
@@ -477,7 +435,7 @@ public class NdbjLoad extends NdbBase {
                 new Op("insA_attr" + (batch ? "_batch" : "")) {
                     public void run(int countA, int countB)
                         throws NdbApiException {
-                        ins(meta.table_A, 1, countA, setAttrs, batch);
+                        ins(model.table_A, 1, countA, setAttrs, batch);
                     }
                 });
 
@@ -485,7 +443,7 @@ public class NdbjLoad extends NdbBase {
                 new Op("insB0_attr" + (batch ? "_batch" : "")) {
                     public void run(int countA, int countB)
                         throws NdbApiException {
-                        ins(meta.table_B0, 1, countB, setAttrs, batch);
+                        ins(model.table_B0, 1, countB, setAttrs, batch);
                     }
                 });
 
@@ -493,7 +451,7 @@ public class NdbjLoad extends NdbBase {
                 new Op("delAllB0") {
                     public void run(int countA, int countB)
                         throws NdbApiException {
-                        final int count = delByScan(meta.table_B0);
+                        final int count = delByScan(model.table_B0);
                         assert count == countB;
                     }
                 });
@@ -502,7 +460,7 @@ public class NdbjLoad extends NdbBase {
                 new Op("delAllA") {
                     public void run(int countA, int countB)
                         throws NdbApiException {
-                        final int count = delByScan(meta.table_A);
+                        final int count = delByScan(model.table_A);
                         assert count == countA;
                     }
                 });
@@ -518,14 +476,14 @@ public class NdbjLoad extends NdbBase {
         out.println("      [ok]");
     }
 
-    protected void beginTransaction1() throws NdbApiException {
+    protected void beginTransaction() throws NdbApiException {
         // start a transaction
         // must be closed with NdbTransaction.close
         tx = ndb.startTransaction();
         assert tx != null;
     }
 
-    protected void executeOperations1() throws NdbApiException {
+    protected void executeOperations() throws NdbApiException {
         // execute but don't commit the current transaction
         // XXX not documented: return value != 0 v throwing exception
         // YYY Monty: should always throw exception -> void method
@@ -534,7 +492,7 @@ public class NdbjLoad extends NdbBase {
             throw new RuntimeException("stat == " + stat);
     }
 
-    protected void commitTransaction1() throws NdbApiException {
+    protected void commitTransaction() throws NdbApiException {
         // commit the current transaction
         // XXX not documented: return value != 0 v throwing exception
         // YYY Monty: should always throw exception -> void method
@@ -544,7 +502,7 @@ public class NdbjLoad extends NdbBase {
             throw new RuntimeException("stat == " + stat);
     }
 
-    protected void rollbackTransaction1() throws NdbApiException {
+    protected void rollbackTransaction() throws NdbApiException {
         // abort the current transaction
         // XXX not documented: return value != 0 v throwing exception
         // YYY Monty: should always throw exception -> void method
@@ -553,43 +511,31 @@ public class NdbjLoad extends NdbBase {
             throw new RuntimeException("stat == " + stat);
     }
 
-    protected void closeTransaction1() {
+    protected void closeTransaction() {
         // close the current transaction
         // to be called irrespectively of success or failure
         tx.close();
         tx = null;
     }
 
-    protected void clearData() throws NdbApiException {
-        out.print("deleting all rows ...");
-        out.flush();
-        final int delB0 = delByScan(meta.table_B0);
-        out.print("       [B0: " + delB0);
-        out.flush();
-        final int delA = delByScan(meta.table_A);
-        out.print(", A: " + delA);
-        out.flush();
-        out.println("]");
-    }
-
     // ----------------------------------------------------------------------
 
     protected void fetchCommonAttributes(NdbOperation op)
         throws NdbApiException {
-        op.getValue(meta.name_cint);
-        op.getValue(meta.name_clong);
-        op.getValue(meta.name_cfloat);
-        op.getValue(meta.name_cdouble);
+        op.getValue(model.name_cint);
+        op.getValue(model.name_clong);
+        op.getValue(model.name_cfloat);
+        op.getValue(model.name_cdouble);
     }
 
     protected int getCommonAttributes(NdbResultSet rs)
         throws NdbApiException {
-        final int cint = rs.getInt(meta.name_cint);
-        final long clong = rs.getLong(meta.name_clong);
+        final int cint = rs.getInt(model.name_cint);
+        final long clong = rs.getLong(model.name_clong);
         verify(clong == cint);
-        final float cfloat = rs.getFloat(meta.name_cfloat);
+        final float cfloat = rs.getFloat(model.name_cfloat);
         verify(cfloat == cint);
-        final double cdouble = rs.getDouble(meta.name_cdouble);
+        final double cdouble = rs.getDouble(model.name_cdouble);
         verify(cdouble == cint);
         return cint;
     }
@@ -597,53 +543,53 @@ public class NdbjLoad extends NdbBase {
     protected void ins(NdbTable table, int from, int to,
                        boolean setAttrs, boolean batch)
         throws NdbApiException {
-        beginTransaction1();
+        beginTransaction();
         for (int i = from; i <= to; i++) {
             // get an insert operation for the table
             final NdbOperation op = tx.getInsertOperation(table);
             assert op != null;
 
             // set key attribute
-            op.equalInt(meta.name_id, i);
+            op.equalInt(model.name_id, i);
 
             // set other attributes
             if (setAttrs) {
-                op.setInt(meta.name_cint, -i);
-                op.setLong(meta.name_clong, -i);
-                op.setFloat(meta.name_cfloat, -i);
-                op.setDouble(meta.name_cdouble, -i);
+                op.setInt(model.name_cint, -i);
+                op.setLong(model.name_clong, -i);
+                op.setFloat(model.name_cfloat, -i);
+                op.setDouble(model.name_cdouble, -i);
             }
 
             // execute the operation now if in non-batching mode
             if (!batch)
-                executeOperations1();
+                executeOperations();
         }
-        commitTransaction1();
-        closeTransaction1();
+        commitTransaction();
+        closeTransaction();
     }
 
     protected void delByPK(NdbTable table, int from, int to,
                            boolean batch)
         throws NdbApiException {
-        beginTransaction1();
+        beginTransaction();
         for (int i = from; i <= to; i++) {
             // get a delete operation for the table
             final NdbOperation op = tx.getDeleteOperation(table);
             assert op != null;
 
             // set key attribute
-            op.equalInt(meta.name_id, i);
+            op.equalInt(model.name_id, i);
 
             // execute the operation now if in non-batching mode
             if (!batch)
-                executeOperations1();
+                executeOperations();
         }
-        commitTransaction1();
-        closeTransaction1();
+        commitTransaction();
+        closeTransaction();
     }
 
     protected int delByScan(NdbTable table) throws NdbApiException {
-        beginTransaction1();
+        beginTransaction();
 
         // get a full table scan operation with exclusive locks
         final NdbScanOperation op
@@ -651,7 +597,7 @@ public class NdbjLoad extends NdbBase {
         assert op != null;
 
         // start the scan; don't commit yet
-        executeOperations1();
+        executeOperations();
 
         // delete all rows in a given scan
         int count = 0;
@@ -689,35 +635,35 @@ public class NdbjLoad extends NdbBase {
         // close the scan
         op.close();
 
-        commitTransaction1();
-        closeTransaction1();
+        commitTransaction();
+        closeTransaction();
         return count;
     }
 
     protected void setByPK(NdbTable table, int from, int to,
                            boolean batch)
         throws NdbApiException {
-        beginTransaction1();
+        beginTransaction();
         for (int i = from; i <= to; i++) {
             // get an insert operation for the table
             final NdbOperation op = tx.getUpdateOperation(table);
             assert op != null;
 
             // set key attribute
-            op.equalInt(meta.name_id, i);
+            op.equalInt(model.name_id, i);
 
             // set other attributes
-            op.setInt(meta.name_cint, i);
-            op.setLong(meta.name_clong, i);
-            op.setFloat(meta.name_cfloat, i);
-            op.setDouble(meta.name_cdouble, i);
+            op.setInt(model.name_cint, i);
+            op.setLong(model.name_clong, i);
+            op.setFloat(model.name_cfloat, i);
+            op.setDouble(model.name_cdouble, i);
 
             // execute the operation now if in non-batching mode
             if (!batch)
-                executeOperations1();
+                executeOperations();
         }
-        commitTransaction1();
-        closeTransaction1();
+        commitTransaction();
+        closeTransaction();
     }
 
     // XXX need to use names instead of ids due to broken
@@ -727,7 +673,7 @@ public class NdbjLoad extends NdbBase {
         assert tx == null;
         tx = ndb.startTransaction();
         assert tx != null;
-        NdbOperation op = tx.getSelectOperation(meta.table_A);
+        NdbOperation op = tx.getSelectOperation(model.table_A);
         assert op != null;
         final int int_val = 1;
         op.equalInt("id", int_val);
@@ -749,17 +695,17 @@ public class NdbjLoad extends NdbBase {
         final int count = (to - from) + 1;
         final NdbResultSet[] rss = new NdbResultSet[count];
 
-        beginTransaction1();
+        beginTransaction();
         for (int i = 0, j = from; i < count; i++, j++) {
             // get a read operation for the table
             NdbOperation op = tx.getSelectOperation(table);
             assert op != null;
 
             // set key attribute
-            op.equalInt(meta.name_id, j);
+            op.equalInt(model.name_id, j);
 
             // define fetched attributes
-            op.getValue(meta.name_id);
+            op.getValue(model.name_id);
             fetchCommonAttributes(op);
 
             // get attributes (not readable until after commit)
@@ -767,9 +713,9 @@ public class NdbjLoad extends NdbBase {
 
             // execute the operation now if in non-batching mode
             if (!batch)
-                executeOperations1();
+                executeOperations();
         }
-        commitTransaction1();
+        commitTransaction();
 
         // check fetched values
         for (int i = 0, j = from; i < count; i++, j++) {
@@ -778,7 +724,7 @@ public class NdbjLoad extends NdbBase {
             assert hasNext;
 
             // check key attribute
-            final int id = rs.getInt(meta.name_id);
+            final int id = rs.getInt(model.name_id);
             verify(id == j);
 
             // check other attributes
@@ -787,53 +733,53 @@ public class NdbjLoad extends NdbBase {
 
             assert !rs.next();
         }
-        closeTransaction1();
+        closeTransaction();
     }
 
     protected void setVarbinary(NdbTable table, int from, int to,
                                 boolean batch, byte[] bytes)
         throws NdbApiException {
-        beginTransaction1();
+        beginTransaction();
         for (int i = from; i <= to; i++) {
             // get an update operation for the table
             final NdbOperation op = tx.getUpdateOperation(table);
             assert op != null;
 
             // set key attribute
-            op.equalInt(meta.name_id, i);
+            op.equalInt(model.name_id, i);
 
             // set varbinary
-            op.setBytes(meta.name_B0_cvarbinary_def, bytes);
+            op.setBytes(model.name_B0_cvarbinary_def, bytes);
 
             // execute the operation now if in non-batching mode
             if (!batch)
-                executeOperations1();
+                executeOperations();
         }
-        commitTransaction1();
-        closeTransaction1();
+        commitTransaction();
+        closeTransaction();
     }
 
     protected void setVarchar(NdbTable table, int from, int to,
                               boolean batch, String string)
         throws NdbApiException {
-        beginTransaction1();
+        beginTransaction();
         for (int i = from; i <= to; i++) {
             // get an update operation for the table
             final NdbOperation op = tx.getUpdateOperation(table);
             assert op != null;
 
             // set key attribute
-            op.equalInt(meta.name_id, i);
+            op.equalInt(model.name_id, i);
 
             // set varchar
-            op.setString(meta.name_B0_cvarchar_def, string);
+            op.setString(model.name_B0_cvarchar_def, string);
 
             // execute the operation now if in non-batching mode
             if (!batch)
-                executeOperations1();
+                executeOperations();
         }
-        commitTransaction1();
-        closeTransaction1();
+        commitTransaction();
+        closeTransaction();
     }
 
     protected void getVarbinary(NdbTable table, int from, int to,
@@ -843,27 +789,27 @@ public class NdbjLoad extends NdbBase {
         final int count = (to - from) + 1;
         final NdbResultSet[] rss = new NdbResultSet[count];
 
-        beginTransaction1();
+        beginTransaction();
         for (int i = 0, j = from; i < count; i++, j++) {
             // get a read operation for the table
             NdbOperation op = tx.getSelectOperation(table);
             assert op != null;
 
             // set key attribute
-            op.equalInt(meta.name_id, j);
+            op.equalInt(model.name_id, j);
 
             // define fetched attributes
-            op.getValue(meta.name_B0_cvarbinary_def);
+            op.getValue(model.name_B0_cvarbinary_def);
 
             // get attributes (not readable until after commit)
             rss[i] = op.resultData();
 
             // execute the operation now if in non-batching mode
             if (!batch)
-                executeOperations1();
+                executeOperations();
         }
-        //executeOperations1();
-        commitTransaction1();
+        //executeOperations();
+        commitTransaction();
 
         // check fetched values
         for (int i = 0, j = from; i < count; i++, j++) {
@@ -873,12 +819,12 @@ public class NdbjLoad extends NdbBase {
 
             // check varbinary
             final byte[] cvarbinary_def
-                = rs.getBytes(meta.name_B0_cvarbinary_def);
+                = rs.getBytes(model.name_B0_cvarbinary_def);
             verify(Arrays.equals(bytes, cvarbinary_def));
 
             assert !rs.next();
         }
-        closeTransaction1();
+        closeTransaction();
     }
 
     protected void getVarchar(NdbTable table, int from, int to,
@@ -888,27 +834,27 @@ public class NdbjLoad extends NdbBase {
         final int count = (to - from) + 1;
         final NdbResultSet[] rss = new NdbResultSet[count];
 
-        beginTransaction1();
+        beginTransaction();
         for (int i = 0, j = from; i < count; i++, j++) {
             // get a read operation for the table
             NdbOperation op = tx.getSelectOperation(table);
             assert op != null;
 
             // set key attribute
-            op.equalInt(meta.name_id, j);
+            op.equalInt(model.name_id, j);
 
             // define fetched attributes
-            op.getValue(meta.name_B0_cvarchar_def);
+            op.getValue(model.name_B0_cvarchar_def);
 
             // get attributes (not readable until after commit)
             rss[i] = op.resultData();
 
             // execute the operation now if in non-batching mode
             if (!batch)
-                executeOperations1();
+                executeOperations();
         }
-        //executeOperations1();
-        commitTransaction1();
+        //executeOperations();
+        commitTransaction();
 
         // check fetched values
         for (int i = 0, j = from; i < count; i++, j++) {
@@ -919,72 +865,72 @@ public class NdbjLoad extends NdbBase {
             // check varchar
             if (true) {
                 final String cvarchar_def
-                    = rs.getString(meta.name_B0_cvarchar_def);
+                    = rs.getString(model.name_B0_cvarchar_def);
                 verify(string.equals(cvarchar_def));
             } else {
                 // verification imposes a string->bytes conversion penalty
                 final byte[] cvarchar_def
-                    = rs.getStringBytes(meta.name_B0_cvarchar_def);
+                    = rs.getStringBytes(model.name_B0_cvarchar_def);
                 verify(Arrays.equals(string.getBytes(), cvarchar_def));
             }
 
             assert !rs.next();
         }
-        closeTransaction1();
+        closeTransaction();
     }
 
     protected void setB0ToA(int count_A, int count_B,
                             boolean batch)
         throws NdbApiException {
-        beginTransaction1();
+        beginTransaction();
         for (int i = 1; i <= count_B; i++) {
             // get an update operation for the table
-            final NdbOperation op = tx.getUpdateOperation(meta.table_B0);
+            final NdbOperation op = tx.getUpdateOperation(model.table_B0);
             assert op != null;
 
             // set key attribute
-            op.equalInt(meta.name_id, i);
+            op.equalInt(model.name_id, i);
 
             // set a_id attribute
             int a_id = ((i - 1) % count_A) + 1;
-            op.setInt(meta.name_B0_a_id, a_id);
+            op.setInt(model.name_B0_a_id, a_id);
 
             // execute the operation now if in non-batching mode
             if (!batch)
-                executeOperations1();
+                executeOperations();
         }
-        commitTransaction1();
-        closeTransaction1();
+        commitTransaction();
+        closeTransaction();
     }
 
     protected void nullB0ToA(int count_A, int count_B,
                              boolean batch)
         throws NdbApiException {
-        beginTransaction1();
+        beginTransaction();
         for (int i = 1; i <= count_B; i++) {
             // get an update operation for the table
-            final NdbOperation op = tx.getUpdateOperation(meta.table_B0);
+            final NdbOperation op = tx.getUpdateOperation(model.table_B0);
             assert op != null;
 
             // set key attribute
-            op.equalInt(meta.name_id, i);
+            op.equalInt(model.name_id, i);
 
             // set a_id attribute
             int a_id = ((i - 1) % count_A) + 1;
-            op.setNull(meta.name_B0_a_id);
+            op.setNull(model.name_B0_a_id);
 
             // execute the operation now if in non-batching mode
             if (!batch)
-                executeOperations1();
+                executeOperations();
         }
-        commitTransaction1();
-        closeTransaction1();
+        commitTransaction();
+        closeTransaction();
     }
 
     protected void navB0ToA(int count_A, int count_B,
                             boolean batch)
         throws NdbApiException {
-        beginTransaction1();
+        beginTransaction();
 
         // fetch the foreign keys from B0 and read attributes from A
         final NdbResultSet[] abs = new NdbResultSet[count_B];
@@ -993,33 +939,33 @@ public class NdbjLoad extends NdbBase {
             NdbResultSet rs;
             {
                 // get a read operation for the table
-                NdbOperation op = tx.getSelectOperation(meta.table_B0);
+                NdbOperation op = tx.getSelectOperation(model.table_B0);
                 assert op != null;
 
                 // set key attribute
-                op.equalInt(meta.name_id, i);
+                op.equalInt(model.name_id, i);
 
                 // define fetched attributes
-                op.getValue(meta.name_B0_a_id);
+                op.getValue(model.name_B0_a_id);
 
                 // get attributes (not readable until after commit)
                 rs = op.resultData();
             }
-            executeOperations1(); // start the scan; don't commit yet
+            executeOperations(); // start the scan; don't commit yet
 
             // fetch the attributes from A
             {
                 // get a read operation for the table
-                NdbOperation op = tx.getSelectOperation(meta.table_A);
+                NdbOperation op = tx.getSelectOperation(model.table_A);
                 assert op != null;
 
                 // set key attribute
-                final int a_id = rs.getInt(meta.name_B0_a_id);
+                final int a_id = rs.getInt(model.name_B0_a_id);
                 assert a_id == ((i - 1) % count_A) + 1;
-                op.equalInt(meta.name_id, a_id);
+                op.equalInt(model.name_id, a_id);
 
                 // define fetched attributes
-                op.getValue(meta.name_id);
+                op.getValue(model.name_id);
                 fetchCommonAttributes(op);
 
                 // get attributes (not readable until after commit)
@@ -1028,9 +974,9 @@ public class NdbjLoad extends NdbBase {
 
             // execute the operation now if in non-batching mode
             if (!batch)
-                executeOperations1();
+                executeOperations();
         }
-        commitTransaction1();
+        commitTransaction();
 
         // check fetched values
         for (int i = 1, j = 0; i <= count_B; i++, j++) {
@@ -1039,7 +985,7 @@ public class NdbjLoad extends NdbBase {
             assert hasNext;
 
             // check key attribute
-            final int id = ab.getInt(meta.name_id);
+            final int id = ab.getInt(model.name_id);
             //out.println("id = " + id + ", i = " + i);
             verify(id == ((i - 1) % count_A) + 1);
 
@@ -1049,46 +995,46 @@ public class NdbjLoad extends NdbBase {
 
             assert !ab.next();
         }
-        closeTransaction1();
+        closeTransaction();
     }
 
     protected void navB0ToAalt(int count_A, int count_B,
                                boolean batch)
         throws NdbApiException {
-        beginTransaction1();
+        beginTransaction();
 
         // fetch the foreign key value from B0
         final NdbResultSet[] a_ids = new NdbResultSet[count_B];
         for (int i = 1, j = 0; i <= count_B; i++, j++) {
                 // get a read operation for the table
-                NdbOperation op = tx.getSelectOperation(meta.table_B0);
+                NdbOperation op = tx.getSelectOperation(model.table_B0);
                 assert op != null;
 
                 // set key attribute
-                op.equalInt(meta.name_id, i);
+                op.equalInt(model.name_id, i);
 
                 // define fetched attributes
-                op.getValue(meta.name_B0_a_id);
+                op.getValue(model.name_B0_a_id);
 
                 // get attributes (not readable until after commit)
                 a_ids[j] = op.resultData();
         }
-        executeOperations1(); // start the scan; don't commit yet
+        executeOperations(); // start the scan; don't commit yet
 
         // fetch the attributes from A
         final NdbResultSet[] abs = new NdbResultSet[count_B];
         for (int i = 1, j = 0; i <= count_B; i++, j++) {
             // get a read operation for the table
-            NdbOperation op = tx.getSelectOperation(meta.table_A);
+            NdbOperation op = tx.getSelectOperation(model.table_A);
             assert op != null;
 
             // set key attribute
-            final int a_id = a_ids[j].getInt(meta.name_B0_a_id);
+            final int a_id = a_ids[j].getInt(model.name_B0_a_id);
             assert a_id == ((i - 1) % count_A) + 1;
-            op.equalInt(meta.name_id, a_id);
+            op.equalInt(model.name_id, a_id);
 
             // define fetched attributes
-            op.getValue(meta.name_id);
+            op.getValue(model.name_id);
             fetchCommonAttributes(op);
 
             // get attributes (not readable until after commit)
@@ -1096,9 +1042,9 @@ public class NdbjLoad extends NdbBase {
 
             // execute the operation now if in non-batching mode
             if (!batch)
-                executeOperations1();
+                executeOperations();
         }
-        commitTransaction1();
+        commitTransaction();
 
         // check fetched values
         for (int i = 1, j = 0; i <= count_B; i++, j++) {
@@ -1107,7 +1053,7 @@ public class NdbjLoad extends NdbBase {
             assert hasNext;
 
             // check key attribute
-            final int id = ab.getInt(meta.name_id);
+            final int id = ab.getInt(model.name_id);
             //out.println("id = " + id + ", i = " + i);
             verify(id == ((i - 1) % count_A) + 1);
 
@@ -1117,7 +1063,7 @@ public class NdbjLoad extends NdbBase {
 
             assert !ab.next();
         }
-        closeTransaction1();
+        closeTransaction();
     }
 
     protected void navAToB0(int count_A, int count_B,
@@ -1125,7 +1071,7 @@ public class NdbjLoad extends NdbBase {
         throws NdbApiException {
 // throws exceptions, see below:
 /*
-        beginTransaction1();
+        beginTransaction();
 
         // fetch attributes from B0 by foreign key scan
         final NdbResultSet[] abs = new NdbResultSet[count_B];
@@ -1134,8 +1080,8 @@ public class NdbjLoad extends NdbBase {
             // get an index scan operation for the table
             // XXX ? no locks (LM_CommittedRead) or shared locks (LM_Read)
             final NdbIndexScanOperation op
-                = tx.getSelectIndexScanOperation(meta.idx_B0_a_id,
-                                                 meta.table_B0,
+                = tx.getSelectIndexScanOperation(model.idx_B0_a_id,
+                                                 model.table_B0,
                                                  LockMode.LM_CommittedRead);
             assert op != null;
 
@@ -1147,10 +1093,10 @@ public class NdbjLoad extends NdbBase {
             //
             // which translates into
             //out.println("idx_B0_a_id.getNoOfColumns() = "
-            //            + meta.idx_B0_a_id.getNoOfColumns());
+            //            + model.idx_B0_a_id.getNoOfColumns());
             //out.println("idx_B0_a_id.getColumn(0).getColumnNo() = "
-            //            + meta.idx_B0_a_id.getColumn(0).getColumnNo());
-            //op.setBoundInt(meta.idx_B0_a_id.getColumn(0).getColumnNo(),
+            //            + model.idx_B0_a_id.getColumn(0).getColumnNo());
+            //op.setBoundInt(model.idx_B0_a_id.getColumn(0).getColumnNo(),
             //               BoundType.BoundEQ, i);
             // except that we get the usual error with NDBJ:
             //[java] idx_B0_a_id.getColumn(0).getColumnNo() = 0
@@ -1159,18 +1105,18 @@ public class NdbjLoad extends NdbBase {
             //
             // so we go by column name
             //out.println("idx_B0_a_id.getColumn(0).getName() = "
-            //            + meta.idx_B0_a_id.getColumn(0).getName());
-            //op.setBoundInt(meta.idx_B0_a_id.getColumn(0).getName(),
+            //            + model.idx_B0_a_id.getColumn(0).getName());
+            //op.setBoundInt(model.idx_B0_a_id.getColumn(0).getName(),
             //               BoundType.BoundEQ, i);
             // which is actually "a_id", so, for now, we call
             op.setBoundInt("a_id", BoundType.BoundEQ, i);
 
             // define fetched attributes
-            op.getValue(meta.name_id);
+            op.getValue(model.name_id);
             fetchCommonAttributes(op);
 
             // start the scan; don't commit yet
-            executeOperations1();
+            executeOperations();
 
             int stat;
             final boolean allowFetch = true; // request new batches when exhausted
@@ -1181,7 +1127,7 @@ public class NdbjLoad extends NdbBase {
             if (stat != 1)
                 throw new RuntimeException("stat == " + stat);
         }
-        commitTransaction1();
+        commitTransaction();
         assert (j++ == count_B);
 
         // check fetched values
@@ -1194,13 +1140,13 @@ public class NdbjLoad extends NdbBase {
             //[java] j = 1, ab = com.mysql.cluster.ndbj.NdbResultSetImpl@6f144c
             //    [java] caught com.mysql.cluster.ndbj.NdbApiException: Unknown error code
             //    [java] com.mysql.cluster.ndbj.NdbApiException: Unknown error code
-            //    [java] at com.mysql.cluster.ndbj.NdbjJNI.NdbScanOperationImpl_nextResult__SWIG_1(Native Method)
+            //    [java] at com.mysql.cluster.ndbj.NdbjJNI.NdbScanOperationImpl_nextResult__SWIG_(Native Method)
             //    [java] at com.mysql.cluster.ndbj.NdbScanOperationImpl.nextResult(NdbScanOperationImpl.java:93)
             //    [java] at com.mysql.cluster.ndbj.NdbResultSetImpl.next(NdbResultSetImpl.java:362)
             //    [java] at com.mysql.cluster.crund.NdbjLoad.navAToB0(NdbjLoad.java:1205)
             //
             // YYY Frazer: check tx object for error (could be node failure)
-            // Martin: doesn't help much; after ab.next(): 
+            // Martin: doesn't help much; after ab.next():
             //out.println("tx.getNdbError() = " + tx.getNdbError().getCode());
             // returns -1 and
             //out.println("tx.getNdbError() = " + tx.getNdbError().getMessage());
@@ -1217,7 +1163,7 @@ public class NdbjLoad extends NdbBase {
             assert hasNext;
 
             // check key attribute
-            final int id = ab.getInt(meta.name_id);
+            final int id = ab.getInt(model.name_id);
             verify(id == i);
 
             // check other attributes
@@ -1226,7 +1172,7 @@ public class NdbjLoad extends NdbBase {
 
             assert !ab.next();
         }
-        closeTransaction1();
+        closeTransaction();
 */
     }
 
@@ -1240,6 +1186,72 @@ public class NdbjLoad extends NdbBase {
     }
 
     // ----------------------------------------------------------------------
+    // NDBJ datastore operations
+    // ----------------------------------------------------------------------
+
+    protected void initConnection() throws NdbApiException {
+        // optionally, connect and wait for reaching the data nodes (ndbds)
+        out.print("waiting for data nodes...");
+        out.flush();
+        final int initial_wait = 10; // secs to wait until first node detected
+        final int final_wait = 0;    // secs to wait after first node detected
+
+        // XXX return: 0 all nodes live, > 0 at least one node live, < 0 error
+        try {
+            mgmd.waitUntilReady(initial_wait, final_wait);
+        } catch (NdbApiException e) {
+            out.println();
+            out.println("!!! data nodes were not ready within "
+                        + (initial_wait + final_wait) + "s.");
+            throw e;
+        }
+        out.println("   [ok]");
+
+        // connect to database
+        out.print("connecting to database...");
+        out.flush();
+        try {
+            // XXX where to set schema?
+            // YYY Frazer: schema not too useful in NDB at the moment
+            // XXX unclear if maxThreads ^= maxNumberOfTransactions
+            //     since ndb.init(maxNumberOfTransactions) is deprecated
+            //final int maxThreads = 4;
+            //ndb = mgmd.createNdb(catalog, maxThreads);
+            // YYY Frazer: yes, maxThreads == maxNumber(concurrent)OfTransactions
+            ndb = mgmd.createNdb(catalog);
+        } catch (NdbApiException e) {
+            out.println();
+            out.println("!!! failed to connect: " + e);
+            throw e;
+        }
+        out.println("   [ok]");
+
+        // initialize the schema shortcuts
+        model = new Model(ndb);
+    }
+
+    protected void closeConnection() {
+        out.print("closing database conn ...");
+        out.flush();
+        model = null;
+        ndb.close();
+        ndb = null;
+        out.println("   [ok]");
+    }
+
+    protected void clearData() throws NdbApiException {
+        out.print("deleting all rows ...");
+        out.flush();
+        final int delB0 = delByScan(model.table_B0);
+        out.print("       [B0: " + delB0);
+        out.flush();
+        final int delA = delByScan(model.table_A);
+        out.print(", A: " + delA);
+        out.flush();
+        out.println("]");
+    }
+
+    // ----------------------------------------------------------------------
 
     static public void main(String[] args) {
         System.out.println("NdbjLoad.main()");

=== added file 'storage/ndb/test/crund/src/crundndb/CrundDriver.cpp'
--- a/storage/ndb/test/crund/src/crundndb/CrundDriver.cpp	1970-01-01 00:00:00 +0000
+++ b/storage/ndb/test/crund/src/crundndb/CrundDriver.cpp	2010-10-19 22:56:45 +0000
@@ -0,0 +1,357 @@
+/* -*- mode: java; c-basic-offset: 4; indent-tabs-mode: nil; -*-
+ *  vim:expandtab:shiftwidth=4:tabstop=4:smarttab:
+ *
+ *  Copyright (C) 2009 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 <iostream>
+#include <sstream>
+#include <string>
+#include <cassert>
+
+#include "helpers.hpp"
+#include "string_helpers.hpp"
+
+#include "CrundDriver.hpp"
+
+using std::cout;
+using std::flush;
+using std::endl;
+using std::ios_base;
+using std::ostringstream;
+using std::string;
+using std::wstring;
+
+using utils::toBool;
+using utils::toInt;
+using utils::toString;
+
+// ----------------------------------------------------------------------
+
+void
+CrundDriver::init() {
+    Driver::init();
+    // do work here
+}
+
+void
+CrundDriver::close() {
+    // do work here
+    Driver::close();
+}
+
+void
+CrundDriver::initProperties() {
+    Driver::initProperties();
+
+    cout << "setting crund properties ..." << flush;
+
+    ostringstream msg;
+
+    renewConnection = toBool(props[L"renewConnection"], false);
+    renewOperations = toBool(props[L"renewOperations"], false);
+
+    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;
+    }
+
+    logSumOfOps = toBool(props[L"logSumOfOps"], true);
+    //allowExtendedPC = toBool(props[L"allowExtendedPC"], false); // not used
+
+    aStart = toInt(props[L"aStart"], 256, 0);
+    if (aStart < 1) {
+        msg << "[ignored] aStart:            '"
+            << toString(props[L"aStart"]) << "'" << endl;
+        aStart = 256;
+    }
+    aEnd = toInt(props[L"aEnd"], aStart, 0);
+    if (aEnd < aStart) {
+        msg << "[ignored] aEnd:              '"
+            << toString(props[L"aEnd"]) << "'" << endl;
+        aEnd = aStart;
+    }
+    aScale = toInt(props[L"aScale"], 2, 0);
+    if (aScale < 2) {
+        msg << "[ignored] aScale:            '"
+            << toString(props[L"aScale"]) << "'" << endl;
+        aScale = 2;
+    }
+
+    bStart = toInt(props[L"bStart"], aStart, 0);
+    if (bStart < 1) {
+        msg << "[ignored] bStart:            '"
+            << toString(props[L"bStart"]) << "'" << endl;
+        bStart = aStart;
+    }
+    bEnd = toInt(props[L"bEnd"], bStart, 0);
+    if (bEnd < bStart) {
+        msg << "[ignored] bEnd:              '"
+            << toString(props[L"bEnd"]) << "'" << endl;
+        bEnd = bStart;
+    }
+    bScale = toInt(props[L"bScale"], 2, 0);
+    if (bScale < 2) {
+        msg << "[ignored] bScale:            '"
+            << toString(props[L"bScale"]) << "'" << endl;
+        bScale = 2;
+    }
+
+    maxVarbinaryBytes = toInt(props[L"maxVarbinaryBytes"], 100, 0);
+    if (maxVarbinaryBytes < 1) {
+        msg << "[ignored] maxVarbinaryBytes: '"
+            << toString(props[L"maxVarbinaryBytes"]) << "'" << endl;
+        maxVarbinaryBytes = 100;
+    }
+    maxVarcharChars = toInt(props[L"maxVarcharChars"], 100, 0);
+    if (maxVarcharChars < 1) {
+        msg << "[ignored] maxVarcharChars:   '"
+            << toString(props[L"maxVarcharChars"]) << "'" << endl;
+        maxVarcharChars = 100;
+    }
+
+    maxBlobBytes = toInt(props[L"maxBlobBytes"], 1000, 0);
+    if (maxBlobBytes < 1) {
+        msg << "[ignored] maxBlobBytes:      '"
+            << toString(props[L"maxBlobBytes"]) << "'" << endl;
+        maxBlobBytes = 1000;
+    }
+    maxTextChars = toInt(props[L"maxTextChars"], 1000, 0);
+    if (maxTextChars < 1) {
+        msg << "[ignored] maxTextChars:      '"
+            << toString(props[L"maxTextChars"]) << "'" << endl;
+        maxTextChars = 1000;
+    }
+
+    // initialize exclude set
+    const wstring& estr = props[L"exclude"];
+    //cout << "estr='" << toString(estr) << "'" << endl;
+    const size_t len = estr.length();
+    size_t beg = 0, next;
+    while (beg < len
+           && ((next = estr.find_first_of(L",", beg)) != wstring::npos)) {
+        // add substring if not empty
+        if (beg < next) {
+            const wstring& s = estr.substr(beg, next - beg);
+            exclude.insert(toString(s));
+        }
+        beg = next + 1;
+    }
+    // add last substring if any
+    if (beg < len) {
+        const wstring& s = estr.substr(beg, len - beg);
+        exclude.insert(toString(s));
+    }
+
+    if (msg.tellp() == 0) {
+        cout << "    [ok: "
+             << "A=" << aStart << ".." << aEnd
+             << ", B=" << bStart << ".." << bEnd << "]" << endl;
+    } else {
+        cout << endl << msg.str() << endl;
+    }
+}
+
+void
+CrundDriver::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 << "crund settings ..." << endl;
+    cout << "renewConnection:                " << renewConnection << endl;
+    cout << "renewOperations:                " << renewOperations << endl;
+    cout << "lockMode:                       " << toStr(lockMode) << endl;
+    cout << "logSumOfOps:                    " << logSumOfOps << endl;
+    //cout << "allowExtendedPC:                " << allowExtendedPC << endl;
+    cout << "aStart:                         " << aStart << endl;
+    cout << "bStart:                         " << bStart << endl;
+    cout << "aEnd:                           " << aEnd << endl;
+    cout << "bEnd:                           " << bEnd << endl;
+    cout << "aScale:                         " << aScale << endl;
+    cout << "bScale:                         " << bScale << endl;
+    cout << "maxVarbinaryBytes:              " << maxVarbinaryBytes << endl;
+    cout << "maxVarcharChars:                " << maxVarcharChars << endl;
+    cout << "maxBlobBytes:                   " << maxBlobBytes << endl;
+    cout << "maxTextChars:                   " << maxTextChars << endl;
+    cout << "exclude:                        " << toString(exclude) << endl;
+
+    cout.flags(f);
+}
+
+// ----------------------------------------------------------------------
+
+void
+CrundDriver::runTests() {
+    cout << endl;
+    initConnection();
+    initOperations();
+
+    assert(aStart <= aEnd && aScale > 1);
+    assert(bStart <= bEnd && bScale > 1);
+    for (int i = aStart; i <= aEnd; i *= aScale) {
+        for (int j = bStart; j <= bEnd; j *= bScale) {
+            runLoads(i, j);
+        }
+    }
+
+    cout << endl
+         << "------------------------------------------------------------" << endl
+         << endl;
+    clearData();
+    closeOperations();
+    closeConnection();
+}
+
+void
+CrundDriver::runLoads(int countA, int countB) {
+    cout << endl
+         << "------------------------------------------------------------" << endl;
+
+    if (countA > countB) {
+        cout << "skipping operations ..."
+             << "         [A=" << countA << ", B=" << countB << "]" << endl;
+        return;
+    }
+    cout << "running operations ..."
+         << "          [A=" << countA << ", B=" << countB << "]" << endl;
+
+    // log buffers
+    if (logRealTime) {
+        rtimes << "A=" << countA << ", B=" << countB;
+        rta = 0L;
+    }
+    if (logCpuTime) {
+        ctimes << "A=" << countA << ", B=" << countB;
+        cta = 0L;
+    }
+
+    // pre-run cleanup
+    if (renewConnection) {
+        closeOperations();
+        closeConnection();
+        initConnection();
+        initOperations();
+    } else if (renewOperations) {
+        closeOperations();
+        initOperations();
+    }
+    clearData();
+
+    runOperations(countA, countB);
+
+    if (logSumOfOps) {
+        cout << endl
+             << "total" << endl;
+        if (logRealTime) {
+            cout << "tx real time                    " << rta
+                 << "\tms" << endl;
+        }
+        if (logSumOfOps) {
+            cout << "tx cpu time                     " << cta
+                 << "\tms" << endl;
+        }
+    }
+
+    // log buffers
+    if (logHeader) {
+        if (logSumOfOps) {
+            header << "\ttotal";
+        }
+        logHeader = false;
+    }
+    if (logRealTime) {
+        if (logSumOfOps) {
+            rtimes << "\t" << rta;
+        }
+        rtimes << endl;
+    }
+    if (logCpuTime) {
+        if (logSumOfOps) {
+            ctimes << "\t" << cta;
+        }
+        ctimes << endl;
+    }
+}
+
+void
+CrundDriver::runOperations(int countA, int countB) {
+    for (Operations::const_iterator i = operations.begin();
+         i != operations.end(); ++i) {
+        // no need for pre-tx cleanup with NDBAPI-based loads
+        //if (!allowExtendedPC) {
+        //    // effectively prevent caching beyond Tx scope by clearing
+        //    // any data/result caches before the next transaction
+        //    clearPersistenceContext();
+        //}
+        runOp(**i, countA, countB);
+    }
+}
+
+void
+CrundDriver::runOp(const Op& op, int countA, int countB) {
+    const string& name = op.name;
+    if (exclude.find(name) == exclude.end()) {
+        begin(name);
+        op.run(countA, countB);
+        commit(name);
+    }
+}
+
+const char*
+CrundDriver::toStr(XMode mode) {
+    switch (mode) {
+    case SINGLE:
+        return "single";
+    case BULK:
+        return "bulk";
+    case BATCH:
+        return "batch";
+    default:
+        assert(false);
+        return "<invalid value>";
+    };
+}
+
+const char*
+CrundDriver::toStr(LockMode mode) {
+    switch (mode) {
+    case SINGLE:
+        return "read_committed";
+    case SHARED:
+        return "shared";
+    case EXCLUSIVE:
+        return "exclusive";
+    default:
+        assert(false);
+        return "<invalid value>";
+    };
+}
+
+//---------------------------------------------------------------------------

=== added file 'storage/ndb/test/crund/src/crundndb/CrundDriver.hpp'
--- a/storage/ndb/test/crund/src/crundndb/CrundDriver.hpp	1970-01-01 00:00:00 +0000
+++ b/storage/ndb/test/crund/src/crundndb/CrundDriver.hpp	2010-10-19 22:56:45 +0000
@@ -0,0 +1,95 @@
+/* -*- mode: java; c-basic-offset: 4; indent-tabs-mode: nil; -*-
+ *  vim:expandtab:shiftwidth=4:tabstop=4:smarttab:
+ *
+ *  Copyright (C) 2009 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
+ */
+
+#ifndef CrundDriver_hpp
+#define CrundDriver_hpp
+
+#include <string>
+#include <vector>
+#include <set>
+
+#include "hrt_utils.h"
+
+#include "Driver.hpp"
+
+using std::string;
+using std::vector;
+using std::set;
+
+class CrundDriver : public Driver {
+protected:
+
+    // benchmark settings
+    enum LockMode { READ_COMMITTED, SHARED, EXCLUSIVE };
+    static const char* toStr(LockMode mode);
+    enum XMode { SINGLE, BULK, BATCH }; // XXX not used yet
+    static const char* toStr(XMode mode); // XXX not used yet
+    bool renewConnection;
+    bool renewOperations;
+    LockMode lockMode;
+    bool logSumOfOps;
+    //bool allowExtendedPC; // not used
+    int aStart;
+    int bStart;
+    int aEnd;
+    int bEnd;
+    int aScale;
+    int bScale;
+    int maxVarbinaryBytes;
+    int maxVarcharChars;
+    int maxBlobBytes;
+    int maxTextChars;
+    set< string > exclude;
+
+    // benchmark intializers/finalizers
+    virtual void init();
+    virtual void close();
+    virtual void initProperties();
+    virtual void printProperties();
+
+    // measured units of work
+    struct Op {
+        const string name;
+
+        virtual void run(int countA, int countB) const = 0;
+
+        Op(const string& name) : name(name) {}
+
+        virtual ~Op() {}
+    };
+    typedef vector< const Op* > Operations;
+    Operations operations;
+
+    // benchmark operations
+    virtual void initOperations() = 0;
+    virtual void closeOperations() = 0;
+    virtual void runTests();
+    virtual void runLoads(int countA, int countB);
+    virtual void runOperations(int countA, int countB);
+    virtual void runOp(const Op& op, int countA, int countB);
+
+    // datastore operations
+    virtual void initConnection() = 0;
+    virtual void closeConnection() = 0;
+    //virtual void clearPersistenceContext() = 0; // not used
+    virtual void clearData() = 0;
+};
+
+#endif // CrundDriver_hpp

=== renamed file 'storage/ndb/test/crund/src/crundndb/Operations.cpp' => 'storage/ndb/test/crund/src/crundndb/CrundNdbApiOperations.cpp'
--- a/storage/ndb/test/crund/src/crundndb/Operations.cpp	2010-10-01 08:58:08 +0000
+++ b/storage/ndb/test/crund/src/crundndb/CrundNdbApiOperations.cpp	2010-10-08 11:17:35 +0000
@@ -1,31 +1,44 @@
-/*
- * com_mysql_cluster_crund_NdbApiLoad.cpp
+/* -*- mode: java; c-basic-offset: 4; indent-tabs-mode: nil; -*-
+ *  vim:expandtab:shiftwidth=4:tabstop=4:smarttab:
+ *
+ *  Copyright (C) 2009 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 <iostream>
-#include <sstream>
-#include <cassert>
 #include <vector>
 #include <algorithm>
+#include <string>
 #include <cstring>
-#include <cstdio>
+#include <cassert>
 
 #include <NdbApi.hpp>
 #include <NdbError.hpp>
 
 #include "helpers.hpp"
 #include "string_helpers.hpp"
-#include "Operations.hpp"
+
+#include "CrundNdbApiOperations.hpp"
 
 //using namespace std;
-using std::vector;
 using std::cout;
+using std::flush;
 using std::endl;
-
-//using namespace crund_ndb;
-using crund_ndb::Meta;
-using crund_ndb::Operations;
+using std::string;
+using std::vector;
 
 // JNI crashes with gcc & operator<<(ostream &, long/int)
 using utils::toString;
@@ -64,11 +77,11 @@ using utils::toString;
     if (cond); else ABORT_ERROR("wrong data; verification failed")
 
 /************************************************************
- * Member Functions of Class Meta
+ * Member Functions of Class CrundModel
  ************************************************************/
 
 void
-Meta::init(Ndb* ndb)
+CrundModel::init(Ndb* ndb)
 {
     const NdbDictionary::Dictionary* dict = ndb->getDictionary();
 
@@ -159,9 +172,10 @@ Meta::init(Ndb* ndb)
 */
 
 void
-Operations::init(const char* mgmd_conn_str)
+CrundNdbApiOperations::init(const char* mgmd_conn_str)
 {
-    assert (mgmd_conn_str);
+    assert(mgmd == NULL);
+    assert(mgmd_conn_str);
 
     // ndb_init must be called first
     cout << endl
@@ -169,12 +183,13 @@ Operations::init(const char* mgmd_conn_s
     int stat = ndb_init();
     if (stat != 0)
         ABORT_ERROR("ndb_init() returned: " << stat);
-    cout << "     [ok]" << endl;
+    cout << "         [ok]" << endl;
 
     // instantiate NDB cluster singleton
-    cout << "creating cluster conn ..." << flush;
+    cout << "creating cluster connection ..." << flush;
+    assert(mgmd_conn_str);
     mgmd = new Ndb_cluster_connection(mgmd_conn_str);
-    cout << "   [ok]" << endl; // no useful mgmd->string conversion
+    cout << " [ok]" << endl; // no useful mgmd->string conversion
 
     // connect to cluster management node (ndb_mgmd)
     cout << "connecting to mgmd ..." << flush;
@@ -185,67 +200,106 @@ Operations::init(const char* mgmd_conn_s
     if (mgmd->connect(retries, delay, verbose) != 0)
         ABORT_ERROR("mgmd@" << mgmd_conn_str << " was not ready within "
                      << (retries * delay) << "s.");
-    cout << "      [ok: " << mgmd_conn_str << "]" << endl;
+    cout << "          [ok: " << mgmd_conn_str << "]" << endl;
 }
 
 void
-Operations::close()
+CrundNdbApiOperations::close()
 {
-    cout << "closing mgmd conn ..." << flush;
+    assert(mgmd != NULL);
+
+    cout << "closing cluster connection ..." << flush;
     delete mgmd;
     mgmd = NULL;
-    cout << "       [ok]" << endl;
+    cout << "  [ok]" << endl;
 
     // ndb_close must be called last
     cout << "closing NDBAPI ...   " << flush;
     ndb_end(0);
-    cout << "       [ok]" << endl;
+    cout << "           [ok]" << endl;
 }
 
 void
-Operations::initConnection(const char* catalog, const char* schema)
+CrundNdbApiOperations::initConnection(const char* catalog, const char* schema,
+                                      NdbOperation::LockMode defaultLockMode)
 {
+    assert(mgmd != NULL);
+    assert(ndb == NULL);
+    assert(tx == NULL);
+    assert(model == NULL);
+
     // optionally, connect and wait for reaching the data nodes (ndbds)
-    cout << "waiting for data nodes..." << flush;
+    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;
+    cout << "      [ok]" << endl;
 
     // connect to database
-    cout << "connecting to database..." << flush;
+    cout << "connecting to database ..." << flush;
     ndb = new Ndb(mgmd, catalog, schema);
     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]" << endl;
+    cout << "      [ok: " << catalog << "." << schema << "]" << endl;
 
-    // initialize the schema shortcuts
-    Meta* m = new Meta();
+    cout << "caching metadata ..." << flush;
+    CrundModel* m = new CrundModel();
     m->init(ndb);
-    meta = m;
+    model = m;
+    cout << "            [ok]" << endl;
+
+    cout << "using lock mode for reads ..." << flush;
+    ndbOpLockMode = defaultLockMode;
+    string lm;
+    switch (defaultLockMode) {
+    case NdbOperation::LM_CommittedRead:
+        lm = "LM_CommittedRead";
+        break;
+    case NdbOperation::LM_Read:
+        lm = "LM_Read";
+        break;
+    case NdbOperation::LM_Exclusive:
+        lm = "LM_Exclusive";
+        break;
+    default:
+        ndbOpLockMode = NdbOperation::LM_CommittedRead;
+        lm = "LM_CommittedRead";
+        assert(false);
+    }
+    cout << "   [ok: " + lm + "]" << endl;
 }
 
 void
-Operations::closeConnection()
+CrundNdbApiOperations::closeConnection()
 {
-    cout << "closing database conn ..." << flush;
-    delete meta;
-    meta = NULL;
+    assert(mgmd != NULL);
+    assert(ndb != NULL);
+    assert(tx == NULL);
+    assert(model != NULL);
+
+    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 << " [ok]" << endl;
 }
 
 void
-Operations::beginTransaction()
+CrundNdbApiOperations::beginTransaction()
 {
+    assert(tx == NULL);
+
     // start a transaction
     // must be closed with Ndb::closeTransaction or NdbTransaction::close
     if ((tx = ndb->startTransaction()) == NULL)
@@ -253,8 +307,10 @@ Operations::beginTransaction()
 }
 
 void
-Operations::executeOperations()
+CrundNdbApiOperations::executeOperations()
 {
+    assert(tx != NULL);
+
     // execute but don't commit the current transaction
     if (tx->execute(NdbTransaction::NoCommit) != 0
         || tx->getNdbError().status != NdbError::Success)
@@ -262,8 +318,10 @@ Operations::executeOperations()
 }
 
 void
-Operations::commitTransaction()
+CrundNdbApiOperations::commitTransaction()
 {
+    assert(tx != NULL);
+
     // commit the current transaction
     if (tx->execute(NdbTransaction::Commit) != 0
         || tx->getNdbError().status != NdbError::Success)
@@ -271,17 +329,10 @@ Operations::commitTransaction()
 }
 
 void
-Operations::rollbackTransaction()
+CrundNdbApiOperations::closeTransaction()
 {
-    // abort the current transaction
-    if (tx->execute(NdbTransaction::Rollback) != 0
-        || tx->getNdbError().status != NdbError::Success)
-        ABORT_NDB_ERROR(tx->getNdbError());
-}
+    assert(tx != NULL);
 
-void
-Operations::closeTransaction()
-{
     // close the current transaction
     // to be called irrespectively of success or failure
     ndb->closeTransaction(tx);
@@ -291,15 +342,15 @@ Operations::closeTransaction()
 // ----------------------------------------------------------------------
 
 void
-Operations::clearData()
+CrundNdbApiOperations::clearData()
 {
     cout << "deleting all rows ..." << flush;
     const bool batch = true;
     int delB0 = -1;
-    delByScan(meta->table_B0, delB0, batch);
-    cout << "       [B0: " << toString(delB0) << flush;
+    delByScan(model->table_B0, delB0, batch);
+    cout << "           [B0: " << toString(delB0) << flush;
     int delA = -1;
-    delByScan(meta->table_A, delA, batch);
+    delByScan(model->table_A, delA, batch);
     cout << ", A: " << toString(delA) << "]" << endl;
 }
 
@@ -346,15 +397,15 @@ selectString(int length)
     case 100: return astring100;
     case 1000: return astring1000;
     default:
-        assert (false);
+        assert(false);
         return "";
     }
 }
 
 void
-Operations::ins(const NdbDictionary::Table* table,
-                int from, int to,
-                bool setAttrs, bool batch)
+CrundNdbApiOperations::ins(const NdbDictionary::Table* table,
+                           int from, int to,
+                           bool setAttrs, bool batch)
 {
     beginTransaction();
     for (int i = from; i <= to; i++) {
@@ -366,16 +417,16 @@ Operations::ins(const NdbDictionary::Tab
             ABORT_NDB_ERROR(tx->getNdbError());
 
         // set values; key attribute needs to be set first
-        if (op->equal(meta->attr_id, (Int32)i) != 0)
+        if (op->equal(model->attr_id, (Int32)i) != 0)
             ABORT_NDB_ERROR(tx->getNdbError());
         if (setAttrs) {
-            if (op->setValue(meta->attr_cint, (Int32)-i) != 0)
+            if (op->setValue(model->attr_cint, (Int32)-i) != 0)
                 ABORT_NDB_ERROR(tx->getNdbError());
-            if (op->setValue(meta->attr_clong, (Int64)-i) != 0)
+            if (op->setValue(model->attr_clong, (Int64)-i) != 0)
                 ABORT_NDB_ERROR(tx->getNdbError());
-            if (op->setValue(meta->attr_cfloat, (float)-i) != 0)
+            if (op->setValue(model->attr_cfloat, (float)-i) != 0)
                 ABORT_NDB_ERROR(tx->getNdbError());
-            if (op->setValue(meta->attr_cdouble, (double)-i) != 0)
+            if (op->setValue(model->attr_cdouble, (double)-i) != 0)
                 ABORT_NDB_ERROR(tx->getNdbError());
         }
 
@@ -388,8 +439,8 @@ Operations::ins(const NdbDictionary::Tab
 }
 
 void
-Operations::delByScan(const NdbDictionary::Table* table, int& count,
-                      bool batch)
+CrundNdbApiOperations::delByScan(const NdbDictionary::Table* table, int& count,
+                                 bool batch)
 {
     beginTransaction();
 
@@ -406,11 +457,6 @@ Operations::delByScan(const NdbDictionar
     if (op->readTuples(lock_mode, scan_flags, parallel, batch_) != 0)
         ABORT_NDB_ERROR(tx->getNdbError());
 
-    // define a read scan with exclusive locks
-    // XXX deprecated: readTuplesExclusive(int parallell = 0);
-    //if (op->readTuplesExclusive() != 0)
-    //    ABORT_NDB_ERROR(tx->getNdbError());
-
     // start the scan; don't commit yet
     executeOperations();
 
@@ -458,9 +504,9 @@ Operations::delByScan(const NdbDictionar
 }
 
 void
-Operations::delByPK(const NdbDictionary::Table* table,
-                    int from, int to,
-                    bool batch)
+CrundNdbApiOperations::delByPK(const NdbDictionary::Table* table,
+                               int from, int to,
+                               bool batch)
 {
     beginTransaction();
     for (int i = from; i <= to; i++) {
@@ -472,7 +518,7 @@ Operations::delByPK(const NdbDictionary:
             ABORT_NDB_ERROR(tx->getNdbError());
 
         // set key attribute
-        if (op->equal(meta->attr_id, (Int32)i) != 0)
+        if (op->equal(model->attr_id, (Int32)i) != 0)
             ABORT_NDB_ERROR(tx->getNdbError());
 
         // execute the operation now if in non-batching mode
@@ -484,13 +530,13 @@ Operations::delByPK(const NdbDictionary:
 }
 
 void
-Operations::setByPK(const NdbDictionary::Table* table,
+CrundNdbApiOperations::setByPK(const NdbDictionary::Table* table,
                     int from, int to,
                     bool batch)
 {
     beginTransaction();
     for (int i = from; i <= to; i++) {
-        // get an insert operation for the table
+        // get an update operation for the table
         NdbOperation* op = tx->getNdbOperation(table);
         if (op == NULL)
             ABORT_NDB_ERROR(tx->getNdbError());
@@ -498,15 +544,15 @@ Operations::setByPK(const NdbDictionary:
             ABORT_NDB_ERROR(tx->getNdbError());
 
         // set values; key attribute needs to be set first
-        if (op->equal(meta->attr_id, (Int32)i) != 0)
+        if (op->equal(model->attr_id, (Int32)i) != 0)
             ABORT_NDB_ERROR(tx->getNdbError());
-        if (op->setValue(meta->attr_cint, (Int32)i) != 0)
+        if (op->setValue(model->attr_cint, (Int32)i) != 0)
             ABORT_NDB_ERROR(tx->getNdbError());
-        if (op->setValue(meta->attr_clong, (Int64)i) != 0)
+        if (op->setValue(model->attr_clong, (Int64)i) != 0)
             ABORT_NDB_ERROR(tx->getNdbError());
-        if (op->setValue(meta->attr_cfloat, (float)i) != 0)
+        if (op->setValue(model->attr_cfloat, (float)i) != 0)
             ABORT_NDB_ERROR(tx->getNdbError());
-        if (op->setValue(meta->attr_cdouble, (double)i) != 0)
+        if (op->setValue(model->attr_cdouble, (double)i) != 0)
             ABORT_NDB_ERROR(tx->getNdbError());
 
         // execute the operation now if in non-batching mode
@@ -518,7 +564,7 @@ Operations::setByPK(const NdbDictionary:
 }
 
 void
-Operations::getByPK_bb(const NdbDictionary::Table* table,
+CrundNdbApiOperations::getByPK_bb(const NdbDictionary::Table* table,
                        int from, int to,
                        bool batch)
 {
@@ -534,23 +580,23 @@ Operations::getByPK_bb(const NdbDictiona
         NdbOperation* op = tx->getNdbOperation(table);
         if (op == NULL)
             ABORT_NDB_ERROR(tx->getNdbError());
-        if (op->readTuple(NdbOperation::LM_CommittedRead) != 0)
+        if (op->readTuple(ndbOpLockMode) != 0)
             ABORT_NDB_ERROR(tx->getNdbError());
 
         // set key attribute
-        if (op->equal(meta->attr_id, (Int32)i) != 0)
+        if (op->equal(model->attr_id, (Int32)i) != 0)
             ABORT_NDB_ERROR(tx->getNdbError());
 
         // get attributes (not readable until after commit)
-        if (op->getValue(meta->attr_id, (char*)&pab->id) == NULL)
+        if (op->getValue(model->attr_id, (char*)&pab->id) == NULL)
             ABORT_NDB_ERROR(tx->getNdbError());
-        if (op->getValue(meta->attr_cint, (char*)&pab->cint) == NULL)
+        if (op->getValue(model->attr_cint, (char*)&pab->cint) == NULL)
             ABORT_NDB_ERROR(tx->getNdbError());
-        if (op->getValue(meta->attr_clong, (char*)&pab->clong) == NULL)
+        if (op->getValue(model->attr_clong, (char*)&pab->clong) == NULL)
             ABORT_NDB_ERROR(tx->getNdbError());
-        if (op->getValue(meta->attr_cfloat, (char*)&pab->cfloat) == NULL)
+        if (op->getValue(model->attr_cfloat, (char*)&pab->cfloat) == NULL)
             ABORT_NDB_ERROR(tx->getNdbError());
-        if (op->getValue(meta->attr_cdouble, (char*)&pab->cdouble) == NULL)
+        if (op->getValue(model->attr_cdouble, (char*)&pab->cdouble) == NULL)
             ABORT_NDB_ERROR(tx->getNdbError());
 
         // execute the operation now if in non-batching mode
@@ -598,7 +644,7 @@ getCommonAB(const CommonAB_AR* const ab)
 }
 
 void
-Operations::getByPK_ar(const NdbDictionary::Table* table,
+CrundNdbApiOperations::getByPK_ar(const NdbDictionary::Table* table,
                        int from, int to,
                        bool batch)
 {
@@ -614,23 +660,23 @@ Operations::getByPK_ar(const NdbDictiona
         NdbOperation* op = tx->getNdbOperation(table);
         if (op == NULL)
             ABORT_NDB_ERROR(tx->getNdbError());
-        if (op->readTuple(NdbOperation::LM_CommittedRead) != 0)
+        if (op->readTuple(ndbOpLockMode) != 0)
             ABORT_NDB_ERROR(tx->getNdbError());
 
         // set key attribute
-        if (op->equal(meta->attr_id, (Int32)i) != 0)
+        if (op->equal(model->attr_id, (Int32)i) != 0)
             ABORT_NDB_ERROR(tx->getNdbError());
 
         // get attributes (not readable until after commit)
-        if ((pab->id = op->getValue(meta->attr_id, NULL)) == NULL)
+        if ((pab->id = op->getValue(model->attr_id, NULL)) == NULL)
             ABORT_NDB_ERROR(tx->getNdbError());
-        if ((pab->cint = op->getValue(meta->attr_cint, NULL)) == NULL)
+        if ((pab->cint = op->getValue(model->attr_cint, NULL)) == NULL)
             ABORT_NDB_ERROR(tx->getNdbError());
-        if ((pab->clong = op->getValue(meta->attr_clong, NULL)) == NULL)
+        if ((pab->clong = op->getValue(model->attr_clong, NULL)) == NULL)
             ABORT_NDB_ERROR(tx->getNdbError());
-        if ((pab->cfloat = op->getValue(meta->attr_cfloat, NULL)) == NULL)
+        if ((pab->cfloat = op->getValue(model->attr_cfloat, NULL)) == NULL)
             ABORT_NDB_ERROR(tx->getNdbError());
-        if ((pab->cdouble = op->getValue(meta->attr_cdouble, NULL)) == NULL)
+        if ((pab->cdouble = op->getValue(model->attr_cdouble, NULL)) == NULL)
             ABORT_NDB_ERROR(tx->getNdbError());
 
         // execute the operation now if in non-batching mode
@@ -657,39 +703,39 @@ Operations::getByPK_ar(const NdbDictiona
 }
 
 void
-Operations::setVarbinary(const NdbDictionary::Table* table,
+CrundNdbApiOperations::setVarbinary(const NdbDictionary::Table* table,
                          int from, int to, bool batch, int length)
 {
-    setVar(table, meta->attr_B0_cvarbinary_def,
+    setVar(table, model->attr_B0_cvarbinary_def,
            from, to, batch, selectString(length));
 }
 
 void
-Operations::setVarchar(const NdbDictionary::Table* table,
+CrundNdbApiOperations::setVarchar(const NdbDictionary::Table* table,
                        int from, int to, bool batch, int length)
 {
-    setVar(table, meta->attr_B0_cvarchar_def,
+    setVar(table, model->attr_B0_cvarchar_def,
            from, to, batch, selectString(length));
 }
 
 void
-Operations::getVarbinary(const NdbDictionary::Table* table,
+CrundNdbApiOperations::getVarbinary(const NdbDictionary::Table* table,
                          int from, int to, bool batch, int length)
 {
-    getVar(table, meta->attr_B0_cvarbinary_def,
+    getVar(table, model->attr_B0_cvarbinary_def,
            from, to, batch, selectString(length));
 }
 
 void
-Operations::getVarchar(const NdbDictionary::Table* table,
+CrundNdbApiOperations::getVarchar(const NdbDictionary::Table* table,
                        int from, int to, bool batch, int length)
 {
-    getVar(table, meta->attr_B0_cvarchar_def,
+    getVar(table, model->attr_B0_cvarchar_def,
            from, to, batch, selectString(length));
 }
 
 void
-Operations::setVar(const NdbDictionary::Table* table, int attr_cvar,
+CrundNdbApiOperations::setVar(const NdbDictionary::Table* table, int attr_cvar,
                    int from, int to,
                    bool batch, const char* str)
 {
@@ -700,7 +746,7 @@ Operations::setVar(const NdbDictionary::
         // XXX assumes column declared as VARBINARY/CHAR(<255)
         size_t sbuf = 1 + slen;
         // XXX buffer overflow if slen >255!!!
-        assert (slen < 255);
+        assert(slen < 255);
         buf = new char[sbuf];
         buf[0] = (char)slen;
         memcpy(buf + 1, str, slen);
@@ -711,7 +757,7 @@ Operations::setVar(const NdbDictionary::
 
     beginTransaction();
     for (int i = from; i <= to; i++) {
-        // get an insert operation for the table
+        // get an update operation for the table
         NdbOperation* op = tx->getNdbOperation(table);
         if (op == NULL)
             ABORT_NDB_ERROR(tx->getNdbError());
@@ -719,7 +765,7 @@ Operations::setVar(const NdbDictionary::
             ABORT_NDB_ERROR(tx->getNdbError());
 
         // set values; key attribute needs to be set first
-        if (op->equal(meta->attr_id, (Int32)i) != 0)
+        if (op->equal(model->attr_id, (Int32)i) != 0)
             ABORT_NDB_ERROR(tx->getNdbError());
         if (op->setValue(attr_cvar, buf) != 0)
             ABORT_NDB_ERROR(tx->getNdbError());
@@ -738,11 +784,11 @@ Operations::setVar(const NdbDictionary::
 }
 
 void
-Operations::getVar(const NdbDictionary::Table* table, int attr_cvar,
+CrundNdbApiOperations::getVar(const NdbDictionary::Table* table, int attr_cvar,
                    int from, int to,
                    bool batch, const char* str)
 {
-    assert (str);
+    assert(str);
 
     // allocate attributes holder
     const int count = (to - from) + 1;
@@ -764,11 +810,11 @@ Operations::getVar(const NdbDictionary::
         NdbOperation* op = tx->getNdbOperation(table);
         if (op == NULL)
             ABORT_NDB_ERROR(tx->getNdbError());
-        if (op->readTuple(NdbOperation::LM_CommittedRead) != 0)
+        if (op->readTuple(ndbOpLockMode) != 0)
             ABORT_NDB_ERROR(tx->getNdbError());
 
         // set key attribute
-        if (op->equal(meta->attr_id, (Int32)1) != 0)
+        if (op->equal(model->attr_id, (Int32)1) != 0)
             ABORT_NDB_ERROR(tx->getNdbError());
 
         // get attributes (not readable until after commit)
@@ -781,7 +827,7 @@ Operations::getVar(const NdbDictionary::
     }
     commitTransaction();
     closeTransaction();
-    assert (s == buf + sbuf);
+    assert(s == buf + sbuf);
 
     // copy (move) the strings to make them aligned and 0-terminated
     s = buf;
@@ -801,32 +847,32 @@ Operations::getVar(const NdbDictionary::
         // check fetched values
         VERIFY(strcmp(s, str) == 0);
     }
-    assert (s == buf + sbuf);
+    assert(s == buf + sbuf);
 
     // release attributes holder
     delete[] buf;
 }
 
 void
-Operations::setB0ToA(int count_A, int count_B,
+CrundNdbApiOperations::setB0ToA(int count_A, int count_B,
                      bool batch)
 {
     beginTransaction();
     for (int i = 1; i <= count_B; i++) {
         // get an update operation for the table
-        NdbOperation* op = tx->getNdbOperation(meta->table_B0);
+        NdbOperation* op = tx->getNdbOperation(model->table_B0);
         if (op == NULL)
             ABORT_NDB_ERROR(tx->getNdbError());
         if (op->updateTuple() != 0)
             ABORT_NDB_ERROR(tx->getNdbError());
 
         // set key attribute
-        if (op->equal(meta->attr_id, (Int32)i) != 0)
+        if (op->equal(model->attr_id, (Int32)i) != 0)
             ABORT_NDB_ERROR(tx->getNdbError());
 
         // set a_id attribute
         int a_id = ((i - 1) % count_A) + 1;
-        if (op->setValue(meta->attr_B0_a_id, (Int32)a_id) != 0)
+        if (op->setValue(model->attr_B0_a_id, (Int32)a_id) != 0)
             ABORT_NDB_ERROR(tx->getNdbError());
 
         // execute the operation now if in non-batching mode
@@ -838,24 +884,24 @@ Operations::setB0ToA(int count_A, int co
 }
 
 void
-Operations::nullB0ToA(int count_A, int count_B,
+CrundNdbApiOperations::nullB0ToA(int count_A, int count_B,
                       bool batch)
 {
     beginTransaction();
     for (int i = 1; i <= count_B; i++) {
         // get an update operation for the table
-        NdbOperation* op = tx->getNdbOperation(meta->table_B0);
+        NdbOperation* op = tx->getNdbOperation(model->table_B0);
         if (op == NULL)
             ABORT_NDB_ERROR(tx->getNdbError());
         if (op->updateTuple() != 0)
             ABORT_NDB_ERROR(tx->getNdbError());
 
         // set key attribute
-        if (op->equal(meta->attr_id, (Int32)i) != 0)
+        if (op->equal(model->attr_id, (Int32)i) != 0)
             ABORT_NDB_ERROR(tx->getNdbError());
 
         // clear a_id attribute
-        if (op->setValue(meta->attr_B0_a_id, (char*)NULL) != 0)
+        if (op->setValue(model->attr_B0_a_id, (char*)NULL) != 0)
             ABORT_NDB_ERROR(tx->getNdbError());
 
         // execute the operation now if in non-batching mode
@@ -867,7 +913,7 @@ Operations::nullB0ToA(int count_A, int c
 }
 
 void
-Operations::navB0ToA(int count_A, int count_B,
+CrundNdbApiOperations::navB0ToA(int count_A, int count_B,
                      bool batch)
 {
     // allocate attributes holder
@@ -881,18 +927,18 @@ Operations::navB0ToA(int count_A, int co
         Int32 a_id;
         {
             // get a read operation for the table
-            NdbOperation* op = tx->getNdbOperation(meta->table_B0);
+            NdbOperation* op = tx->getNdbOperation(model->table_B0);
             if (op == NULL)
                 ABORT_NDB_ERROR(tx->getNdbError());
-            if (op->readTuple(NdbOperation::LM_CommittedRead) != 0)
+            if (op->readTuple(ndbOpLockMode) != 0)
                 ABORT_NDB_ERROR(tx->getNdbError());
 
             // set key attribute
-            if (op->equal(meta->attr_id, (Int32)i) != 0)
+            if (op->equal(model->attr_id, (Int32)i) != 0)
                 ABORT_NDB_ERROR(tx->getNdbError());
 
             // get attribute (not readable until after commit)
-            if (op->getValue(meta->attr_B0_a_id, (char*)&a_id) == NULL)
+            if (op->getValue(model->attr_B0_a_id, (char*)&a_id) == NULL)
                 ABORT_NDB_ERROR(tx->getNdbError());
         }
         executeOperations(); // start the scan; don't commit yet
@@ -900,27 +946,27 @@ Operations::navB0ToA(int count_A, int co
         // fetch the attributes from A
         {
             // get a read operation for the table
-            NdbOperation* op = tx->getNdbOperation(meta->table_A);
+            NdbOperation* op = tx->getNdbOperation(model->table_A);
             if (op == NULL)
                 ABORT_NDB_ERROR(tx->getNdbError());
-            if (op->readTuple(NdbOperation::LM_CommittedRead) != 0)
+            if (op->readTuple(ndbOpLockMode) != 0)
                 ABORT_NDB_ERROR(tx->getNdbError());
 
             // set key attribute
-            assert (a_id == ((i - 1) % count_A) + 1);
-            if (op->equal(meta->attr_id, a_id) != 0)
+            assert(a_id == ((i - 1) % count_A) + 1);
+            if (op->equal(model->attr_id, a_id) != 0)
                 ABORT_NDB_ERROR(tx->getNdbError());
 
             // get attributes (not readable until after commit)
-            if (op->getValue(meta->attr_id, (char*)&pab->id) == NULL)
+            if (op->getValue(model->attr_id, (char*)&pab->id) == NULL)
                 ABORT_NDB_ERROR(tx->getNdbError());
-            if (op->getValue(meta->attr_cint, (char*)&pab->cint) == NULL)
+            if (op->getValue(model->attr_cint, (char*)&pab->cint) == NULL)
                 ABORT_NDB_ERROR(tx->getNdbError());
-            if (op->getValue(meta->attr_clong, (char*)&pab->clong) == NULL)
+            if (op->getValue(model->attr_clong, (char*)&pab->clong) == NULL)
                 ABORT_NDB_ERROR(tx->getNdbError());
-            if (op->getValue(meta->attr_cfloat, (char*)&pab->cfloat) == NULL)
+            if (op->getValue(model->attr_cfloat, (char*)&pab->cfloat) == NULL)
                 ABORT_NDB_ERROR(tx->getNdbError());
-            if (op->getValue(meta->attr_cdouble, (char*)&pab->cdouble) == NULL)
+            if (op->getValue(model->attr_cdouble, (char*)&pab->cdouble) == NULL)
                 ABORT_NDB_ERROR(tx->getNdbError());
         }
 
@@ -948,7 +994,7 @@ Operations::navB0ToA(int count_A, int co
 }
 
 void
-Operations::navB0ToAalt(int count_A, int count_B,
+CrundNdbApiOperations::navB0ToAalt(int count_A, int count_B,
                         bool batch)
 {
     // allocate foreign key values holder
@@ -959,18 +1005,18 @@ Operations::navB0ToAalt(int count_A, int
     Int32* pa_id = a_id;
     for (int i = 1; i <= count_B; i++) {
         // get a read operation for the table
-        NdbOperation* op = tx->getNdbOperation(meta->table_B0);
+        NdbOperation* op = tx->getNdbOperation(model->table_B0);
         if (op == NULL)
             ABORT_NDB_ERROR(tx->getNdbError());
-        if (op->readTuple(NdbOperation::LM_CommittedRead) != 0)
+        if (op->readTuple(ndbOpLockMode) != 0)
             ABORT_NDB_ERROR(tx->getNdbError());
 
         // set key attribute
-        if (op->equal(meta->attr_id, (Int32)i) != 0)
+        if (op->equal(model->attr_id, (Int32)i) != 0)
             ABORT_NDB_ERROR(tx->getNdbError());
 
         // get attribute (not readable until after commit)
-        if (op->getValue(meta->attr_B0_a_id, (char*)pa_id++) == NULL)
+        if (op->getValue(model->attr_B0_a_id, (char*)pa_id++) == NULL)
             ABORT_NDB_ERROR(tx->getNdbError());
 
         // execute the operation now if in non-batching mode
@@ -987,27 +1033,27 @@ Operations::navB0ToAalt(int count_A, int
     CommonAB* pab = ab;
     for (int i = 1; i <= count_B; i++, pa_id++, pab++) {
         // get a read operation for the table
-        NdbOperation* op = tx->getNdbOperation(meta->table_A);
+        NdbOperation* op = tx->getNdbOperation(model->table_A);
         if (op == NULL)
             ABORT_NDB_ERROR(tx->getNdbError());
-        if (op->readTuple(NdbOperation::LM_CommittedRead) != 0)
+        if (op->readTuple(ndbOpLockMode) != 0)
             ABORT_NDB_ERROR(tx->getNdbError());
 
         // set key attribute
-        assert (*pa_id == ((i - 1) % count_A) + 1);
-        if (op->equal(meta->attr_id, (Int32)*pa_id) != 0)
+        assert(*pa_id == ((i - 1) % count_A) + 1);
+        if (op->equal(model->attr_id, (Int32)*pa_id) != 0)
             ABORT_NDB_ERROR(tx->getNdbError());
 
         // get attributes (not readable until after commit)
-        if (op->getValue(meta->attr_id, (char*)&pab->id) == NULL)
+        if (op->getValue(model->attr_id, (char*)&pab->id) == NULL)
             ABORT_NDB_ERROR(tx->getNdbError());
-        if (op->getValue(meta->attr_cint, (char*)&pab->cint) == NULL)
+        if (op->getValue(model->attr_cint, (char*)&pab->cint) == NULL)
             ABORT_NDB_ERROR(tx->getNdbError());
-        if (op->getValue(meta->attr_clong, (char*)&pab->clong) == NULL)
+        if (op->getValue(model->attr_clong, (char*)&pab->clong) == NULL)
             ABORT_NDB_ERROR(tx->getNdbError());
-        if (op->getValue(meta->attr_cfloat, (char*)&pab->cfloat) == NULL)
+        if (op->getValue(model->attr_cfloat, (char*)&pab->cfloat) == NULL)
             ABORT_NDB_ERROR(tx->getNdbError());
-        if (op->getValue(meta->attr_cdouble, (char*)&pab->cdouble) == NULL)
+        if (op->getValue(model->attr_cdouble, (char*)&pab->cdouble) == NULL)
             ABORT_NDB_ERROR(tx->getNdbError());
 
         // execute the operation now if in non-batching mode
@@ -1037,7 +1083,7 @@ Operations::navB0ToAalt(int count_A, int
 }
 
 void
-Operations::navAToB0(int count_A, int count_B,
+CrundNdbApiOperations::navAToB0(int count_A, int count_B,
                      bool forceSend)
 {
     // attributes holder
@@ -1052,36 +1098,35 @@ Operations::navAToB0(int count_A, int co
     for (int i = 1; i <= count_A; i++) {
         // get an index scan operation for the table
         NdbIndexScanOperation* op
-            = tx->getNdbIndexScanOperation(meta->idx_B0_a_id);
+            = tx->getNdbIndexScanOperation(model->idx_B0_a_id);
         if (op == NULL)
             ABORT_NDB_ERROR(tx->getNdbError());
 
-        // define a read scan without locks (LM_CommittedRead)
-        if (op->readTuples(NdbOperation::LM_CommittedRead) != 0)
+        if (op->readTuples(ndbOpLockMode) != 0)
             ABORT_NDB_ERROR(tx->getNdbError());
 
         // define the scan's bounds (more efficient than using a scan filter)
         // the argument to setBound() is not the column's attribute id
-        //    if (op->setBound(meta->attr_B0_a_id, ...
+        //    if (op->setBound(model->attr_B0_a_id, ...
         // or column name
         //    if (op->setBound("a_id", ...
         // but the attribute id of the column *in the index*.
         //    if (op->setBound(idx_B0_a_id->getColumn(0)->getAttrId()...
         // for which we introduced a shortcut.
-        if (op->setBound(meta->attr_idx_B0_a_id,
+        if (op->setBound(model->attr_idx_B0_a_id,
                          NdbIndexScanOperation::BoundEQ, &i) != 0)
             ABORT_NDB_ERROR(tx->getNdbError());
 
         // get attributes (not readable until after commit)
-        if (op->getValue(meta->attr_id, (char*)&h.id) == NULL)
+        if (op->getValue(model->attr_id, (char*)&h.id) == NULL)
             ABORT_NDB_ERROR(tx->getNdbError());
-        if (op->getValue(meta->attr_cint, (char*)&h.cint) == NULL)
+        if (op->getValue(model->attr_cint, (char*)&h.cint) == NULL)
             ABORT_NDB_ERROR(tx->getNdbError());
-        if (op->getValue(meta->attr_clong, (char*)&h.clong) == NULL)
+        if (op->getValue(model->attr_clong, (char*)&h.clong) == NULL)
             ABORT_NDB_ERROR(tx->getNdbError());
-        if (op->getValue(meta->attr_cfloat, (char*)&h.cfloat) == NULL)
+        if (op->getValue(model->attr_cfloat, (char*)&h.cfloat) == NULL)
             ABORT_NDB_ERROR(tx->getNdbError());
-        if (op->getValue(meta->attr_cdouble, (char*)&h.cdouble) == NULL)
+        if (op->getValue(model->attr_cdouble, (char*)&h.cdouble) == NULL)
             ABORT_NDB_ERROR(tx->getNdbError());
 
         // start the scan; don't commit yet
@@ -1091,7 +1136,7 @@ Operations::navAToB0(int count_A, int co
         int stat;
         const bool allowFetch = true; // request new batches when exhausted
         while ((stat = op->nextResult(allowFetch, forceSend)) == 0) {
-            assert (ab <= pab && pab < ab + count_B);
+            assert(ab <= pab && pab < ab + count_B);
             *pab++ = h;
         }
         if (stat != 1)
@@ -1102,7 +1147,7 @@ Operations::navAToB0(int count_A, int co
     commitTransaction();
     closeTransaction();
     //CDBG << "!!! pab - ab =" << toString(pab-ab) << endl;
-    assert (pab == ab + count_B);
+    assert(pab == ab + count_B);
 
     // check fetched values
     // XXX this is not the most efficient way of testing...
@@ -1120,7 +1165,7 @@ Operations::navAToB0(int count_A, int co
 }
 
 void
-Operations::navAToB0alt(int count_A, int count_B,
+CrundNdbApiOperations::navAToB0alt(int count_A, int count_B,
                         bool forceSend)
 {
     // number of operations in a multi-scan batch
@@ -1142,37 +1187,36 @@ Operations::navAToB0alt(int count_A, int
 
         for (int i = 0; i < nmscans; i++) {
             // get an index scan operation for the table
-            op[i] = tx->getNdbIndexScanOperation(meta->idx_B0_a_id);
+            op[i] = tx->getNdbIndexScanOperation(model->idx_B0_a_id);
             if (op[i] == NULL)
                 ABORT_NDB_ERROR(tx->getNdbError());
 
             // XXX ? no locks (LM_CommittedRead) or shared locks (LM_Read)
-            // define a read scan without locks
-            if (op[i]->readTuples(NdbOperation::LM_CommittedRead) != 0)
+            if (op[i]->readTuples(ndbOpLockMode) != 0)
                 ABORT_NDB_ERROR(tx->getNdbError());
 
             // define the scan's bounds (more efficient than using a scan filter)
             // the argument to setBound() is not the column's attribute id
-            //    if (op[i]->setBound(meta->attr_B0_a_id, ...
+            //    if (op[i]->setBound(model->attr_B0_a_id, ...
             // or column name
             //    if (op[i]->setBound("a_id", ...
             // but the attribute id of the column *in the index*.
             //    if (op[i]->setBound(idx_B0_a_id->getColumn(0)->getAttrId()...
             // for which we introduced a shortcut.
-            if (op[i]->setBound(meta->attr_idx_B0_a_id,
+            if (op[i]->setBound(model->attr_idx_B0_a_id,
                                 NdbIndexScanOperation::BoundEQ, &a_id) != 0)
                 ABORT_NDB_ERROR(tx->getNdbError());
 
             // get attributes (not readable until after commit)
-            if (op[i]->getValue(meta->attr_id, (char*)&h.id) == NULL)
+            if (op[i]->getValue(model->attr_id, (char*)&h.id) == NULL)
                 ABORT_NDB_ERROR(tx->getNdbError());
-            if (op[i]->getValue(meta->attr_cint, (char*)&h.cint) == NULL)
+            if (op[i]->getValue(model->attr_cint, (char*)&h.cint) == NULL)
                 ABORT_NDB_ERROR(tx->getNdbError());
-            if (op[i]->getValue(meta->attr_clong, (char*)&h.clong) == NULL)
+            if (op[i]->getValue(model->attr_clong, (char*)&h.clong) == NULL)
                 ABORT_NDB_ERROR(tx->getNdbError());
-            if (op[i]->getValue(meta->attr_cfloat, (char*)&h.cfloat) == NULL)
+            if (op[i]->getValue(model->attr_cfloat, (char*)&h.cfloat) == NULL)
                 ABORT_NDB_ERROR(tx->getNdbError());
-            if (op[i]->getValue(meta->attr_cdouble, (char*)&h.cdouble) == NULL)
+            if (op[i]->getValue(model->attr_cdouble, (char*)&h.cdouble) == NULL)
                 ABORT_NDB_ERROR(tx->getNdbError());
 
             // next a
@@ -1186,7 +1230,7 @@ Operations::navAToB0alt(int count_A, int
             int stat;
             const bool allowFetch = true; // request new batches when exhausted
             while ((stat = op[i]->nextResult(allowFetch, forceSend)) == 0) {
-                assert (ab <= pab && pab < ab + count_B);
+                assert(ab <= pab && pab < ab + count_B);
                 *pab++ = h;
             }
             if (stat != 1)
@@ -1201,8 +1245,8 @@ Operations::navAToB0alt(int count_A, int
     commitTransaction();
     closeTransaction();
     //CDBG << "!!! pab - ab =" << toString(pab-ab) << endl;
-    assert (a_id == count_A + 1);
-    assert (pab == ab + count_B);
+    assert(a_id == count_A + 1);
+    assert(pab == ab + count_B);
 
     // check fetched values
     // XXX this is not the most efficient way of testing...

=== renamed file 'storage/ndb/test/crund/src/crundndb/Operations.hpp' => 'storage/ndb/test/crund/src/crundndb/CrundNdbApiOperations.hpp'
--- a/storage/ndb/test/crund/src/crundndb/Operations.hpp	2010-10-01 08:58:08 +0000
+++ b/storage/ndb/test/crund/src/crundndb/CrundNdbApiOperations.hpp	2010-10-08 11:17:35 +0000
@@ -1,20 +1,33 @@
-/*
- * Operations.hpp
+/* -*- mode: java; c-basic-offset: 4; indent-tabs-mode: nil; -*-
+ *  vim:expandtab:shiftwidth=4:tabstop=4:smarttab:
  *
+ *  Copyright (C) 2009 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
  */
 
-#ifndef crundndb_Operations_hpp
-#define crundndb_Operations_hpp
+#ifndef CrundNdbApiOperations_hpp
+#define CrundNdbApiOperations_hpp
 
 #include <NdbApi.hpp>
 #include <NdbError.hpp>
 
-namespace crund_ndb {
-
 /**
  * Holds shortcuts to the benchmark's schema information.
  */
-struct Meta
+struct CrundModel
 {
     const NdbDictionary::Table* table_A;
     const NdbDictionary::Table* table_B0;
@@ -50,7 +63,7 @@ struct Meta
 /**
  * Implements the benchmark's basic database operations.
  */
-class Operations
+class CrundNdbApiOperations
 {
 // For a better locality of information, consider refactorizing this
 // class into separate classes: Cluster, Db, Tx, and Operations by
@@ -60,34 +73,50 @@ class Operations
 // But for now, having all in one class is good enough.
 
 public:
-    // the benchmark's metadata shortcuts
-    const Meta* meta;
 
-//protected:
-    // singleton object representing the NDB cluster (one per process)
-    Ndb_cluster_connection* mgmd;
+    CrundNdbApiOperations()
+        : model(NULL), mgmd(NULL), ndb(NULL), tx(NULL) {
+    }
+
+    ~CrundNdbApiOperations() {
+        assert(model == NULL);
+        assert(mgmd == NULL); assert(ndb == NULL); assert(tx == NULL);
+    }
 
-    // object representing a connection to an NDB database
-    Ndb* ndb;
+    // NDB Api metadata resources
+    const CrundModel* model;
 
-    // object representing an NDB database transaction
+protected:
+
+    // NDB API resources
+    Ndb_cluster_connection* mgmd;
+    Ndb* ndb;
     NdbTransaction* tx;
+    NdbOperation::LockMode ndbOpLockMode;
+
+    // NDB Api data resources
+    // XXX not used yet, see TwsDriver
+    //char* bb;
+    //char* bb_pos;
+    //NdbRecAttr** ra;
+    //NdbRecAttr** ra_pos;
+
+private:
+
+    CrundNdbApiOperations(const CrundNdbApiOperations&);
+    CrundNdbApiOperations& operator=(const CrundNdbApiOperations&);
 
 public:
+
     void init(const char* mgmd_conn_str);
 
     void close();
 
-    void initConnection(const char* catalog, const char* schema);
+    void initConnection(const char* catalog, const char* schema,
+                        NdbOperation::LockMode defaultLockMode);
 
     void closeConnection();
 
-    void beginTransaction();
-
-    void commitTransaction();
-
-    void rollbackTransaction();
-
     void clearData();
 
     void delByScan(const NdbDictionary::Table* table, int& count,
@@ -139,10 +168,15 @@ public:
                    bool batch);
 
 protected:
-    // executes the operations in the current transaction
-    void executeOperations();
 
-    // closes the current transaction
+    // XXX not used yet, see TwsDriver
+    //void ndbapiBeginTransaction();
+    //void ndbapiExecuteTransaction();
+    //void ndbapiCommitTransaction();
+    //void ndbapiCloseTransaction();
+    void beginTransaction();
+    void executeOperations();
+    void commitTransaction();
     void closeTransaction();
 
     void setVar(const NdbDictionary::Table* table, int attr_cvar,
@@ -150,8 +184,10 @@ protected:
 
     void getVar(const NdbDictionary::Table* table, int attr_cvar,
                 int from, int to, bool batch, const char* str);
-};
 
-} // crund_ndb
+    // XXX not used yet, see TwsDriver
+    //static void ndbapiToBuffer1blp(void* to, const char* from, size_t width);
+    //static void ndbapiToString1blp(char* to, const void* from, size_t width);
+};
 
-#endif // crundndb_Operations_hpp
+#endif // CrundNdbApiOperations_hpp

=== modified file 'storage/ndb/test/crund/src/crundndb/Driver.cpp'
--- a/storage/ndb/test/crund/src/crundndb/Driver.cpp	2010-10-01 08:58:08 +0000
+++ b/storage/ndb/test/crund/src/crundndb/Driver.cpp	2010-10-19 22:56:45 +0000
@@ -1,6 +1,21 @@
-/*
- * Driver.cpp
+/* -*- mode: java; c-basic-offset: 4; indent-tabs-mode: nil; -*-
+ *  vim:expandtab:shiftwidth=4:tabstop=4:smarttab:
  *
+ *  Copyright (C) 2009 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 <iostream>
@@ -10,298 +25,136 @@
 #include <vector>
 #include <cassert>
 #include <ctime>
-#include <set>
 
 #include "helpers.hpp"
 #include "string_helpers.hpp"
-#include "Properties.hpp"
-#include "hrt_utils.h"
-#include "Operations.hpp"
 
-// global type aliases
-typedef const NdbDictionary::Table* NdbTable;
+#include "Driver.hpp"
 
-namespace crund_ndb {
-
-//using namespace std;
+using std::cout;
+using std::flush;
+using std::endl;
+using std::ios_base;
+using std::ofstream;
+using std::ostringstream;
 using std::string;
 using std::wstring;
 using std::vector;
-using std::ofstream;
-using std::ostringstream;
-using std::set;
 
 using utils::Properties;
+using utils::toBool;
+using utils::toInt;
+using utils::toString;
 
-class Driver {
-
-public:
-    /**
-     * Creates a Driver instance.
-     */
-    Driver();
-
-    /**
-     * Parses the benchmark's command-line arguments.
-     */
-    void parseArguments(int argc, const char* argv[]);
-
-    /**
-     * Runs the entire benchmark.
-     */
-    void run();
-
-protected:
-    // command-line arguments
-    vector< string > propFileNames;
-    string logFileName;
-
-    // the data output stream
-    ofstream log;
-
-    // benchmark settings
-    Properties props;
-    string descr;
-    bool logRealTime;
-    bool logCpuTime;
-    bool logSumOfOps;
-    bool renewConnection;
-    bool renewOperations;
-    int aStart, aEnd, aScale;
-    int bStart, bEnd, bScale;
-    int maxVarbinaryBytes;
-    int maxVarcharChars;
-    int maxBlobBytes;
-    int maxTextChars;
-    int warmupRuns;
-    int hotRuns;
-    set< string > exclude;
-
-    // the NDB database connection
-    string mgmdConnect;
-    string catalog;
-    string schema;
-
-    // the benchmark's basic database operations.
-    static crund_ndb::Operations* ops;
-
-    /**
-     * A database operation to be benchmarked.
-     */
-    struct Op {
-        const string name;
+//---------------------------------------------------------------------------
 
-        virtual void run(int countA, int countB) const = 0;
-        //void (*run)(int countA, int countB);
+vector< string > Driver::propFileNames;
+string Driver::logFileName;
 
-        Op(const string& name)
-            : name(name) {
-        }
+void
+Driver::exitUsage()
+{
+    cout << "usage: [options]" << endl
+         << "    [-p <file name>]...    properties file name" << endl
+         << "    [-l <file name>]       log file name for data output" << endl
+         << "    [-h|--help]            print usage message and exit" << endl
+         << endl;
+    exit(1); // return an error code
+}
 
-        virtual ~Op() {
+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();
         }
-    };
-
-    /**
-     * The list of database operations to be benchmarked.
-     * Managed by methods initOperations() and closeOperations().
-     */
-    typedef vector< const Op* > Operations;
-    Operations operations;
-
-private:
-    // buffers collecting the header and data lines written to log
-    bool logHeader;
-    ostringstream header;
-    ostringstream rtimes;
-    ostringstream ctimes;
-
-    // benchmark data fields
-    int s0, s1;
-    hrt_tstamp t0, t1;
-    long rta, cta;
-
-protected:
-
-    /**
-     * Loads the benchmark's properties from properties files.
-     */
-    void loadProperties();
-
-    /**
-     * Reads and initializes the benchmark's properties from a file.
-     */
-    void initProperties();
-
-    /**
-     * Prints the benchmark's properties.
-     */
-    void printProperties();
-
-    /**
-     * Opens the benchmark's data log file.
-     */
-    void openLogFile();
-
-    /**
-     * Closes the benchmark's data log file.
-     */
-    void closeLogFile();
-
-    /**
-     * Initializes the benchmark's resources.
-     */
-    void init();
-
-    /**
-     * Releases the benchmark's resources.
-     */
-    void close();
-
-    /**
-     * Prints a command-line usage message and exits.
-     */
-    void exitUsage();
-
-    /**
-     * Runs a series of benchmark operations on scaled-up data.
-     */
-    void runTests();
-
-    /**
-     * Runs a series of benchmark operations.
-     */
-    void runOperations(int countA, int countB);
-
-    /**
-     * Runs a benchmark operation.
-     */
-    void runOp(const Op& op, int countA, int countB);
-
-    /**
-     * Begins a benchmarked transaction.
-     */
-    void begin(const string& name);
-
-    /**
-     * Closes a benchmarked transaction.
-     */
-    void commit(const string& name);
-
-    // ----------------------------------------------------------------------
-
-    void initConnection();
-
-    void closeConnection();
-
-    void initOperations();
-
-    template< bool feat > void initOperationsFeat();
-
-    void closeOperations();
-
-    void clearData();
-
-    // operation invocation templates
-    template< bool > struct ADelAllOp;
-
-    template< bool > struct B0DelAllOp;
-
-    template< bool, bool > struct AInsOp;
-
-    template< bool, bool > struct B0InsOp;
-
-    template< const char**,
-              void (crund_ndb::Operations::*)(NdbTable,int,int,bool),
-              bool >
-    struct AByPKOp;
-
-    template< const char**,
-              void (crund_ndb::Operations::*)(NdbTable,int,int,bool),
-              bool >
-    struct B0ByPKOp;
-
-    template< const char**,
-              void (crund_ndb::Operations::*)(NdbTable,int,int,bool,int),
-              bool >
-    struct LengthOp;
-
-    template< const char**,
-              void (crund_ndb::Operations::*)(NdbTable,int,int,bool,int),
-              bool >
-    struct ZeroLengthOp;
-
-    template< const char**,
-              void (crund_ndb::Operations::*)(int,int,bool),
-              bool >
-    struct RelOp;
-};
+    }
 
-} // crund_ndb
+    if (propFileNames.size() == 0) {
+        propFileNames.push_back("run.properties");
+    }
 
-// ----------------------------------------------------------------------
+    if (logFileName.empty()) {
+        logFileName = "log_";
 
-//using namespace std;
-using std::wistringstream;
-using std::ios_base;
-using std::cout;
-using std::flush;
-using std::endl;
-using std::string;
-using std::wstring;
+        // format, destination strings (static size)
+        const char format[] = "%Y%m%d_%H%M%S";
+        const int size = sizeof("yyyymmdd_HHMMSS");
+        char dest[size];
 
-using utils::toBool;
-using utils::toInt;
-using utils::toString;
-using crund_ndb::Driver;
+        // 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;
 
-Driver::Driver() {
+        logFileName += dest;
+        logFileName += ".txt";
+    }
+    //cout << "logFileName='" << logFileName << "'" << endl;
 }
 
-#include <algorithm>
-#include <cctype>
-
 // ----------------------------------------------------------------------
 
-crund_ndb::Operations* Driver::ops = NULL;
-
 void
 Driver::run() {
     init();
 
-    // warmup runs
-    for (int i = 0; i < warmupRuns; i++) {
-        runTests();
-    }
+    if (warmupRuns > 0) {
+        cout << endl
+             << "++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++" << endl
+             << "warmup runs ..." << endl
+             << "++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++" << endl;
 
-    // truncate log file, reset log buffers
-    cout << endl
-         << "++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++" << endl
-         << "start logging results ..." << endl
-         << "++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++" << endl
-         << endl;
-    header.rdbuf()->str("");
-    rtimes.rdbuf()->str("");
-    closeLogFile();
-    openLogFile();
+        for (int i = 0; i < warmupRuns; i++) {
+            runTests();
+        }
 
-    // hot runs
-    for (int i = 0; i < hotRuns; i++) {
-        runTests();
-    }
+        // truncate log file, reset log buffers
+        closeLogFile();
+        openLogFile();
+        header.rdbuf()->str("");
+        rtimes.rdbuf()->str("");
+        ctimes.rdbuf()->str("");
+        logHeader = true;
+    }
+
+    if (hotRuns > 0) {
+        cout << endl
+             << "++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++" << endl
+             << "hot runs ..." << endl
+             << "++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++" << endl;
 
-    // write log buffers
-    if (logRealTime) {
-        // doesn't work: ostream << ostringstream->rdbuf()
-        log << descr << ", rtime[ms]"
-            << header.rdbuf()->str() << endl
-            << rtimes.rdbuf()->str() << endl << endl << endl;
-    }
-    if (logCpuTime) {
-        // doesn't work: ostream << ostringstream->rdbuf()
-        log << descr << ", ctime[ms]"
-            << header.rdbuf()->str() << endl
-            << ctimes.rdbuf()->str() << endl << endl << endl;
+        for (int i = 0; i < hotRuns; i++) {
+            runTests();
+        }
+
+        // write log buffers
+        if (logRealTime) {
+            log << descr << ", rtime[ms]"
+                << header.rdbuf()->str() << endl
+                << rtimes.rdbuf()->str() << endl << endl << endl;
+        }        
+        if (logCpuTime) {
+            log << descr << ", ctime[ms]"
+                << header.rdbuf()->str() << endl
+                << ctimes.rdbuf()->str() << endl << endl << endl;
+        }
     }
 
     close();
@@ -318,11 +171,6 @@ Driver::init() {
     logHeader = true;
     header.rdbuf()->str("");
     rtimes.rdbuf()->str("");
-
-    // initialize the benchmark's resources
-    ops = new crund_ndb::Operations();
-    assert (!mgmdConnect.empty());
-    ops->init(mgmdConnect.c_str());
 }
 
 void
@@ -331,108 +179,28 @@ Driver::close() {
     header.rdbuf()->str("");
     rtimes.rdbuf()->str("");
 
-    // release the benchmark's resources
-    assert (!mgmdConnect.empty());
-    ops->close();
-    delete ops;
-    ops = NULL;
-
     closeLogFile();
 }
 
 void
 Driver::loadProperties() {
-    if (propFileNames.size() == 0) {
-        propFileNames.push_back("crund.properties");
-    }
-
     cout << endl;
     for (vector<string>::const_iterator i = propFileNames.begin();
          i != propFileNames.end(); ++i) {
-        cout << "reading properties file:    " << *i << endl;
+        cout << "reading properties file:        " << *i << endl;
         props.load(i->c_str());
-        props.load(i->c_str());
-        //wcout << props << endl;
+        //cout << "props = {" << endl << props << "}" << endl;
     }
 }
 
 void
 Driver::initProperties() {
-    cout << "initializing properties ... " << flush;
+    cout << "setting driver properties ..." << flush;
 
     ostringstream msg;
 
-    logRealTime = toBool(props[L"logRealTime"]);
-    logCpuTime = toBool(props[L"logCpuTime"]);
-    logSumOfOps = toBool(props[L"logSumOfOps"]);
-    renewOperations = toBool(props[L"renewOperations"]);
-    renewConnection = toBool(props[L"renewConnection"]);
-
-    aStart = toInt(props[L"aStart"], 256, 0);
-    if (aStart < 1) {
-        msg << "[ignored] aStart:            '"
-            << toString(props[L"aStart"]) << "'" << endl;
-        aStart = 256;
-    }
-    aEnd = toInt(props[L"aEnd"], aStart, 0);
-    if (aEnd < aStart) {
-        msg << "[ignored] aEnd:              '"
-            << toString(props[L"aEnd"]) << "'" << endl;
-        aEnd = aStart;
-    }
-    aScale = toInt(props[L"aScale"], 2, 0);
-    if (aScale < 2) {
-        msg << "[ignored] aScale:            '"
-            << toString(props[L"aScale"]) << "'" << endl;
-        aScale = 2;
-    }
-
-    bStart = toInt(props[L"bStart"], aStart, 0);
-    if (bStart < 1) {
-        msg << "[ignored] bStart:            '"
-            << toString(props[L"bStart"]) << "'" << endl;
-        bStart = aStart;
-    }
-    bEnd = toInt(props[L"bEnd"], bStart, 0);
-    if (bEnd < bStart) {
-        msg << "[ignored] bEnd:              '"
-            << toString(props[L"bEnd"]) << "'" << endl;
-        bEnd = bStart;
-    }
-    bScale = toInt(props[L"bScale"], 2, 0);
-    if (bScale < 2) {
-        msg << "[ignored] bScale:            '"
-            << toString(props[L"bScale"]) << "'" << endl;
-        bScale = 2;
-    }
-
-    maxVarbinaryBytes = toInt(props[L"maxVarbinaryBytes"], 100, 0);
-    if (maxVarbinaryBytes < 1) {
-        msg << "[ignored] maxVarbinaryBytes: '"
-            << toString(props[L"maxVarbinaryBytes"]) << "'" << endl;
-        maxVarbinaryBytes = 100;
-    }
-
-    maxVarcharChars = toInt(props[L"maxVarcharChars"], 100, 0);
-    if (maxVarcharChars < 1) {
-        msg << "[ignored] maxVarcharChars:   '"
-            << toString(props[L"maxVarcharChars"]) << "'" << endl;
-        maxVarcharChars = 100;
-    }
-
-    maxBlobBytes = toInt(props[L"maxBlobBytes"], 1000, 0);
-    if (maxBlobBytes < 1) {
-        msg << "[ignored] maxBlobBytes:      '"
-            << toString(props[L"maxBlobBytes"]) << "'" << endl;
-        maxBlobBytes = 1000;
-    }
-
-    maxTextChars = toInt(props[L"maxTextChars"], 1000, 0);
-    if (maxTextChars < 1) {
-        msg << "[ignored] maxTextChars:      '"
-            << toString(props[L"maxTextChars"]) << "'" << endl;
-        maxTextChars = 1000;
-    }
+    logRealTime = toBool(props[L"logRealTime"], true);
+    logCpuTime = toBool(props[L"logCpuTime"], false);
 
     warmupRuns = toInt(props[L"warmupRuns"], 0, -1);
     if (warmupRuns < 0) {
@@ -448,42 +216,12 @@ Driver::initProperties() {
         hotRuns = 1;
     }
 
-    // initialize exclude set
-    const wstring& estr = props[L"exclude"];
-    //cout << "estr='" << toString(estr) << "'" << endl;
-    const size_t len = estr.length();
-    size_t beg = 0, next;
-    while (beg < len
-           && ((next = estr.find_first_of(L",", beg)) != wstring::npos)) {
-        // add substring if not empty
-        if (beg < next) {
-            const wstring& s = estr.substr(beg, next - beg);
-            exclude.insert(toString(s));
-        }
-        beg = next + 1;
-    }
-    // add last substring if any
-    if (beg < len) {
-        const wstring& s = estr.substr(beg, len - beg);
-        exclude.insert(toString(s));
-    }
-
-    // string properties
-    mgmdConnect = toString(props[L"ndb.mgmdConnect"]);
-    catalog = toString(props[L"ndb.catalog"]);
-    schema = toString(props[L"ndb.schema"]);
-
-    descr = "C++->NDBAPI(" + mgmdConnect + ")";
-
-    if (msg.tellp() == 0) {
-        cout << "[ok]" << endl;
+    //if (msg.tellp() == 0) // netbeans reports amibuities
+    if (msg.str().empty()) {
+        cout << "   [ok]" << endl;
     } else {
         cout << endl << msg.str() << endl;
     }
-
-    cout << "data set:                   "
-         << "[A=" << aStart << ".." << aEnd
-         << ", B=" << bStart << ".." << bEnd << "]" << endl;
 }
 
 void
@@ -493,28 +231,11 @@ Driver::printProperties() {
     //cout << ios_base::boolalpha;
     cout.flags(ios_base::boolalpha);
 
-    cout << endl << "main settings:" << endl;
-    cout << "logRealTime:                " << logRealTime << endl;
-    cout << "logCpuTime:                 " << logCpuTime << endl;
-    cout << "logSumOfOps:                " << logSumOfOps << endl;
-    cout << "renewOperations:            " << renewOperations << endl;
-    cout << "renewConnection:            " << renewConnection << endl;
-    cout << "aStart:                     " << aStart << endl;
-    cout << "bStart:                     " << bStart << endl;
-    cout << "aEnd:                       " << aEnd << endl;
-    cout << "bEnd:                       " << bEnd << endl;
-    cout << "aScale:                     " << aScale << endl;
-    cout << "bScale:                     " << bScale << endl;
-    cout << "maxVarbinaryBytes:          " << maxVarbinaryBytes << endl;
-    cout << "maxVarcharChars:            " << maxVarcharChars << endl;
-    cout << "maxBlobBytes:               " << maxBlobBytes << endl;
-    cout << "maxTextChars:               " << maxTextChars << endl;
-    cout << "warmupRuns:                 " << warmupRuns << endl;
-    cout << "hotRuns:                    " << hotRuns << endl;
-    cout << "exclude:                    " << toString(exclude) << endl;
-    cout << "ndb.mgmdConnect             \"" << mgmdConnect << "\"" << endl;
-    cout << "ndb.catalog                 \"" << catalog << "\"" << endl;
-    cout << "ndb.schema                  \"" << schema << "\"" << endl;
+    cout << endl << "driver settings ..." << endl;
+    cout << "logRealTime:                    " << logRealTime << endl;
+    cout << "logCpuTime:                     " << logCpuTime << endl;
+    cout << "warmupRuns:                     " << warmupRuns << endl;
+    cout << "hotRuns:                        " << hotRuns << endl;
 
     cout.flags(f);
 }
@@ -522,129 +243,23 @@ Driver::printProperties() {
 void
 Driver::openLogFile() {
     cout << endl
-         << "writing results to file:    " << logFileName << endl;
-    //log.open(logFileName.c_str());
+         << "opening results file:" << flush;
     log.open(logFileName.c_str(), ios_base::out | ios_base::trunc);
-    assert (log.good());
+    assert(log.good());
+    cout << "           [ok: " << logFileName << "]" << endl;
 }
 
 void
 Driver::closeLogFile() {
-    cout << "closing files ...    " << flush;
+    cout << endl
+         << "closing results file:" << flush;
     log.close();
-    cout << "       [ok]" << endl;
+    cout << "           [ok: " << logFileName << "]" << endl;
 }
 
 // ----------------------------------------------------------------------
 
 void
-Driver::runTests() {
-    initConnection();
-    initOperations();
-
-    assert(aStart <= aEnd && aScale > 1);
-    assert(bStart <= bEnd && bScale > 1);
-    for (int i = aStart; i <= aEnd; i *= aScale) {
-        for (int j = bStart; j <= bEnd; j *= bScale) {
-            runOperations(i, j);
-        }
-    }
-
-    cout << endl
-         << "------------------------------------------------------------" << endl
-         << endl;
-
-    clearData();
-    closeOperations();
-    closeConnection();
-}
-
-void
-Driver::runOperations(int countA, int countB) {
-    cout << endl
-         << "------------------------------------------------------------" << endl;
-
-    if (countA > countB) {
-        cout << "skipping operations ...     "
-             << "[A=" << countA << ", B=" << countB << "]" << endl;
-        return;
-    }
-    cout << "running operations ...      "
-         << "[A=" << countA << ", B=" << countB << "]" << endl;
-
-    // log buffers
-    if (logRealTime) {
-        rtimes << "A=" << countA << ", B=" << countB;
-        rta = 0L;
-    }
-    if (logCpuTime) {
-        ctimes << "A=" << countA << ", B=" << countB;
-        cta = 0L;
-    }
-
-    // pre-run cleanup
-    if (renewConnection) {
-        closeOperations();
-        closeConnection();
-        initConnection();
-        initOperations();
-    } else if (renewOperations) {
-        closeOperations();
-        initOperations();
-    }
-    clearData();
-
-    // run operations
-    for (Operations::const_iterator i = operations.begin();
-         i != operations.end(); ++i) {
-        // no need for pre-tx cleanup with NDBAPI-based loads
-        //if (!allowExtendedPC) {
-        //    // effectively prevent caching beyond Tx scope by clearing
-        //    // any data/result caches before the next transaction
-        //    clearPersistenceContext();
-        //}
-        runOp(**i, countA, countB);
-    }
-    if (logHeader) {
-        if (logSumOfOps)
-            header << "\ttotal";
-    }
-
-    // log buffers
-    logHeader = false;
-    if (logRealTime) {
-        if (logSumOfOps) {
-            rtimes << "\t" << rta;
-            cout << endl
-                 << "total" << endl
-                 << "tx real time\t\t= " << rta
-                 << "\tms [begin..commit]" << endl;
-        }
-        rtimes << endl;
-    }
-    if (logCpuTime) {
-        if (logSumOfOps) {
-            ctimes << "\t" << cta;
-            cout << endl
-                 << "total" << endl
-                 << "tx cpu time\t\t= " << cta
-                 << "\tms [begin..commit]" << endl;
-        }
-        ctimes << endl;
-    }
-}
-
-void
-Driver::runOp(const Op& op, int countA, int countB) {
-    const string& name = op.name;
-    if (exclude.find(name) == exclude.end()) {
-        begin(name);
-        op.run(countA, countB);
-        commit(name);
-    }
-}
-
-void
 Driver::begin(const string& name) {
     cout << endl;
     cout << name << endl;
@@ -656,16 +271,10 @@ Driver::begin(const string& name) {
     } else if (logCpuTime) {
         s0 = hrt_ctnow(&t0.ctstamp);
     }
-
-    // NDB Operations manages transactions boundaries itself
-    //beginTransaction();
 }
 
 void
 Driver::commit(const string& name) {
-    // NDB Operations manages transactions boundaries itself
-    //commitTransaction();
-
     if (logRealTime && logCpuTime) {
         s1 = hrt_tnow(&t1);
     } else if (logRealTime) {
@@ -680,8 +289,8 @@ Driver::commit(const string& name) {
             rtimes << "\tERROR";
         } else {
             long t = long(hrt_rtmicros(&t1.rtstamp, &t0.rtstamp)/1000);
-            cout << "tx real time\t\t= " << t
-                 << "\tms [begin..commit]" << endl;
+            cout << "tx real time:                   " << t
+                 << "\tms" << endl;
             rtimes << "\t" << t;
             rta += t;
         }
@@ -693,8 +302,8 @@ Driver::commit(const string& name) {
             ctimes << "\tERROR";
         } else {
             long t = long(hrt_ctmicros(&t1.ctstamp, &t0.ctstamp)/1000);
-            cout << "tx cpu time\t\t= " << t
-                 << "\tms [begin..commit]" << endl;
+            cout << "tx cpu time:                    " << t
+                 << "\tms" << endl;
             ctimes << "\t" << t;
             cta += t;
         }
@@ -705,350 +314,3 @@ Driver::commit(const string& name) {
 }
 
 //---------------------------------------------------------------------------
-
-void
-Driver::initConnection() {
-    ops->initConnection(catalog.c_str(), schema.c_str());
-}
-
-void
-Driver::closeConnection() {
-    ops->closeConnection();
-}
-
-void
-Driver::initOperations() {
-    cout << "initializing operations ..." << flush;
-
-    const bool feat = true;
-    initOperationsFeat< !feat >();
-    initOperationsFeat< feat >();
-
-    cout << " [Op: " << operations.size() << "]" << endl;
-}
-
-// the operation invocation templates look a bit complex, but they help
-// a lot to factorize code over the operations' parameter signatures
-
-template< bool OB >
-struct Driver::ADelAllOp : Op {
-    ADelAllOp() : Op(string("delAllA")
-                     + (OB ? "_batch" : "")) {
-    }
-
-    virtual void run(int countA, int countB) const {
-        int count;
-        ops->delByScan(ops->meta->table_A, count, OB);
-        assert (count == countA);
-    }
-};
-
-template< bool OB >
-struct Driver::B0DelAllOp : Op {
-    B0DelAllOp() : Op(string("delAllB0")
-                      + (OB ? "_batch" : "")) {
-    }
-
-    virtual void run(int countA, int countB) const {
-        int count;
-        ops->delByScan(ops->meta->table_B0, count, OB);
-        assert (count == countB);
-    }
-};
-
-template< bool OSA, bool OB >
-struct Driver::AInsOp : Op {
-    AInsOp() : Op(string("insA")
-                  + (OSA ? "_attr" : "")
-                  + (OB ? "_batch" : "")) {
-    }
-
-    virtual void run(int countA, int countB) const {
-        ops->ins(ops->meta->table_A, 1, countA, OSA, OB);
-    }
-};
-
-template< bool OSA, bool OB >
-struct Driver::B0InsOp : Op {
-    B0InsOp() : Op(string("insB0")
-                   + (OSA ? "_attr" : "")
-                   + (OB ? "_batch" : "")) {
-    }
-
-    virtual void run(int countA, int countB) const {
-        ops->ins(ops->meta->table_B0, 1, countB, OSA, OB);
-    }
-};
-
-template< const char** ON,
-          void (crund_ndb::Operations::*OF)(NdbTable,int,int,bool),
-          bool OB >
-struct Driver::AByPKOp : Op {
-    AByPKOp() : Op(string(*ON)
-                   + (OB ? "_batch" : "")) {
-    }
-
-    virtual void run(int countA, int countB) const {
-        (ops->*OF)(ops->meta->table_A, 1, countA, OB);
-    }
-};
-
-template< const char** ON,
-          void (crund_ndb::Operations::*OF)(NdbTable,int,int,bool),
-          bool OB >
-struct Driver::B0ByPKOp : Op {
-    B0ByPKOp() : Op(string(*ON)
-                    + (OB ? "_batch" : "")) {
-    }
-
-    virtual void run(int countA, int countB) const {
-        (ops->*OF)(ops->meta->table_B0, 1, countB, OB);
-    }
-};
-
-template< const char** ON,
-          void (crund_ndb::Operations::*OF)(NdbTable,int,int,bool,int),
-          bool OB >
-struct Driver::LengthOp : Op {
-    const int length;
-
-    LengthOp(int length) : Op(string(*ON)
-                              + toString(length)
-                              + (OB ? "_batch" : "")),
-                           length(length) {
-    }
-
-    virtual void run(int countA, int countB) const {
-        (ops->*OF)(ops->meta->table_B0, 1, countB, OB, length);
-    }
-};
-
-template< const char** ON,
-          void (crund_ndb::Operations::*OF)(NdbTable,int,int,bool,int),
-          bool OB >
-struct Driver::ZeroLengthOp : LengthOp< ON, OF, OB > {
-    ZeroLengthOp(int length) : LengthOp< ON, OF, OB >(length) {
-    }
-
-    virtual void run(int countA, int countB) const {
-        (ops->*OF)(ops->meta->table_B0, 1, countB, OB, 0);
-    }
-};
-
-template< const char** ON,
-          void (crund_ndb::Operations::*OF)(int,int,bool),
-          bool OFS >
-struct Driver::RelOp : Op {
-    RelOp() : Op(string(*ON)
-                 + (OFS ? "_forceSend" : "")) {
-    }
-
-    virtual void run(int countA, int countB) const {
-        (ops->*OF)(countA, countB, OFS);
-    }
-};
-
-// ISO C++ 98 does not allow for a string literal as a template argument
-// for a non-type template parameter, because string literals are objects
-// with internal linkage.  This restriction maybe lifted in C++0x.
-//
-// Until then, we have to allocate the operation names as variables
-// (which are external at file scope by default).
-const char* delAByPK_s = "delAByPK";
-const char* delB0ByPK_s = "delB0ByPK";
-const char* setAByPK_s = "setAByPK";
-const char* setB0ByPK_s = "setB0ByPK";
-const char* getAByPK_bb_s = "getAByPK_bb";
-const char* getB0ByPK_bb_s = "getB0ByPK_bb";
-const char* getAByPK_ar_s = "getAByPK_ar";
-const char* getB0ByPK_ar_s = "getB0ByPK_ar";
-
-const char* setVarbinary_s = "setVarbinary";
-const char* getVarbinary_s = "getVarbinary";
-const char* clearVarbinary_s = "clearVarbinary";
-const char* setVarchar_s = "setVarchar";
-const char* getVarchar_s = "getVarchar";
-const char* clearVarchar_s = "clearVarchar";
-
-const char* setB0ToA_s = "setB0->A";
-const char* navB0ToA_s = "navB0->A";
-const char* navB0ToAalt_s = "navB0->A_alt";
-const char* navAToB0_s = "navA->B0";
-const char* navAToB0alt_s = "navA->B0_alt";
-const char* nullB0ToA_s = "nullB0->A";
-
-template< bool feat > void
-Driver::initOperationsFeat() {
-
-    const bool setAttr = true;
-    operations.push_back(
-        new AInsOp< !setAttr, feat >());
-
-    operations.push_back(
-        new B0InsOp< !setAttr, feat >());
-
-    operations.push_back(
-        new AByPKOp< &setAByPK_s, &crund_ndb::Operations::setByPK, feat >());
-
-    operations.push_back(
-        new B0ByPKOp< &setB0ByPK_s, &crund_ndb::Operations::setByPK, feat >());
-
-    operations.push_back(
-        new AByPKOp< &getAByPK_bb_s, &crund_ndb::Operations::getByPK_bb, feat >());
-
-    operations.push_back(
-        new AByPKOp< &getAByPK_ar_s, &crund_ndb::Operations::getByPK_ar, feat >());
-
-    operations.push_back(
-        new B0ByPKOp< &getB0ByPK_bb_s, &crund_ndb::Operations::getByPK_bb, feat >());
-
-    operations.push_back(
-        new B0ByPKOp< &getB0ByPK_ar_s, &crund_ndb::Operations::getByPK_ar, feat >());
-
-    for (int i = 1; i <= maxVarbinaryBytes; i *= 10) {
-        const int length = i;
-
-        operations.push_back(
-            new LengthOp< &setVarbinary_s, &crund_ndb::Operations::setVarbinary, feat >(length));
-
-        operations.push_back(
-            new LengthOp< &getVarbinary_s, &crund_ndb::Operations::getVarbinary, feat >(length));
-
-        operations.push_back(
-            new ZeroLengthOp< &clearVarbinary_s, &crund_ndb::Operations::setVarbinary, feat >(length));
-    }
-
-    for (int i = 1; i <= maxVarcharChars; i *= 10) {
-        const int length = i;
-
-        operations.push_back(
-            new LengthOp< &setVarchar_s, &crund_ndb::Operations::setVarchar, feat >(length));
-
-        operations.push_back(
-            new LengthOp< &getVarchar_s, &crund_ndb::Operations::getVarchar, feat >(length));
-
-        operations.push_back(
-            new ZeroLengthOp< &clearVarchar_s, &crund_ndb::Operations::setVarchar, feat >(length));
-    }
-
-    operations.push_back(
-        new RelOp< &setB0ToA_s, &crund_ndb::Operations::setB0ToA, feat >());
-
-    operations.push_back(
-        new RelOp< &navB0ToA_s, &crund_ndb::Operations::navB0ToA, feat >());
-
-    operations.push_back(
-        new RelOp< &navB0ToAalt_s, &crund_ndb::Operations::navB0ToAalt, feat >());
-
-    operations.push_back(
-        new RelOp< &navAToB0_s, &crund_ndb::Operations::navAToB0, feat >());
-
-    operations.push_back(
-        new RelOp< &navAToB0alt_s, &crund_ndb::Operations::navAToB0alt, feat >());
-
-    operations.push_back(
-        new RelOp< &nullB0ToA_s, &crund_ndb::Operations::nullB0ToA, feat >());
-
-    operations.push_back(
-        new B0ByPKOp< &setAByPK_s, &crund_ndb::Operations::delByPK, feat >());
-
-    operations.push_back(
-        new AByPKOp< &setB0ByPK_s, &crund_ndb::Operations::delByPK, feat >());
-
-    operations.push_back(
-        new AInsOp< setAttr, feat >());
-
-    operations.push_back(
-        new B0InsOp< setAttr, feat >());
-
-    operations.push_back(
-        new ADelAllOp< feat >());
-
-    operations.push_back(
-        new B0DelAllOp< feat >());
-}
-
-void
-Driver::closeOperations() {
-    cout << "closing operations ..." << flush;
-    for (Operations::const_iterator i = operations.begin();
-         i != operations.end(); ++i) {
-        delete *i;
-    }
-    operations.clear();
-    cout << "      [ok]" << endl;
-}
-
-void
-Driver::clearData()
-{
-    ops->clearData();
-}
-
-//---------------------------------------------------------------------------
-
-void
-Driver::exitUsage()
-{
-    cout << "usage: [options]" << endl
-         << "    [-p <file name>]...    properties file name" << endl
-         << "    [-l <file name>]       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 (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;
-    }
-}
-
-int
-main(int argc, const char* argv[])
-{
-    TRACE("main()");
-
-    Driver d;
-    d.parseArguments(argc, argv);
-    d.run();
-
-    return 0;
-}

=== added file 'storage/ndb/test/crund/src/crundndb/Driver.hpp'
--- a/storage/ndb/test/crund/src/crundndb/Driver.hpp	1970-01-01 00:00:00 +0000
+++ b/storage/ndb/test/crund/src/crundndb/Driver.hpp	2010-10-19 22:56:45 +0000
@@ -0,0 +1,104 @@
+/* -*- mode: java; c-basic-offset: 4; indent-tabs-mode: nil; -*-
+ *  vim:expandtab:shiftwidth=4:tabstop=4:smarttab:
+ *
+ *  Copyright (C) 2009 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
+ */
+
+#ifndef Driver_hpp
+#define Driver_hpp
+
+#include <iostream>
+#include <sstream>
+#include <fstream>
+#include <string>
+#include <vector>
+
+#include "Properties.hpp"
+#include "hrt_utils.h"
+
+using std::ofstream;
+using std::ostringstream;
+using std::string;
+using std::vector;
+
+using utils::Properties;
+
+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 logRealTime;
+    bool logCpuTime;
+    int warmupRuns;
+    int hotRuns;
+
+    // driver resources
+    ofstream log;
+    string descr;
+    bool logHeader;
+    ostringstream header;
+    ostringstream rtimes;
+    ostringstream ctimes;
+    int s0, s1;
+    hrt_tstamp t0, t1;
+    long rta, cta;
+
+    // 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);
+};
+
+#endif // Driver_hpp

=== modified file 'storage/ndb/test/crund/src/crundndb/Makefile'
--- a/storage/ndb/test/crund/src/crundndb/Makefile	2010-10-01 08:58:08 +0000
+++ b/storage/ndb/test/crund/src/crundndb/Makefile	2010-10-19 22:56:45 +0000
@@ -10,7 +10,7 @@ include	../../env.properties
 
   DDEFINES 	=
 
-  DELIVERABLES	= libcrundndb.a libcrundndb.$(DLL_SUFFIX) Driver 
+  DELIVERABLES	= libcrundndb.a libcrundndb.$(DLL_SUFFIX) NdbApiDriver 
 
   GENERATED_H	= com_mysql_cluster_crund_NdbApiLoad.h
 
@@ -54,43 +54,47 @@ com_mysql_cluster_crund_NdbApiLoad.h:
 #		$(API_PKG_PATH)/NdbApiLoad.java
 #	$(COMPILE.java) $<
 
-run.driver:	Driver
-	LD_LIBRARY_PATH=${NDB_LIBDIR} ./Driver \
+# not sure if needed:
+#	LD_LIBRARY_PATH=${NDB_LIBDIR}:./Driver
+run.driver:	NdbApiDriver
+	./NdbApiDriver \
 	-p ../../crundRun.properties -p ../../crundNdbapi.properties
 
 # for JVM processes, try running valgrind with
 # --smc-check=all --trace-children=yes --leak-check=full --show-reachable=yes
-valgrind.driver:	Driver
-	LD_LIBRARY_PATH=${NDB_LIBDIR} valgrind \
+# not sure if needed:
+#	LD_LIBRARY_PATH=${NDB_LIBDIR}:./Driver
+valgrind.driver:	NdbApiDriver
+	valgrind \
 	--leak-check=full --show-reachable=yes --trace-children=yes \
-	./Driver \
+	./NdbApiDriver \
 	-p ../../crundRun.properties -p ../../crundNdbapi.properties
 
-Driver:	libcrundndb.a
+NdbApiDriver:	Driver.o CrundDriver.o libcrundndb.a
 
 # can list multiple archive members: lib.a(a.o b.o ...) lib.a(c.o)...
-libcrundndb.a:	libcrundndb.a(Operations.o)	\
+libcrundndb.a:	libcrundndb.a(CrundNdbApiOperations.o)	\
 		libcrundndb.a(com_mysql_cluster_crund_NdbApiLoad.o)
 
 # XXX cleanup & refactorize this rule!
 # LINK.o
-#libcrundndb.so:	Operations.o com_mysql_cluster_crund_NdbApiLoad.o
+#libcrundndb.so:	CrundNdbApiOperations.o com_mysql_cluster_crund_NdbApiLoad.o
 #libcrundndb.so:	libcrundndb.a
-libcrundndb.so:	Operations.cpp
+libcrundndb.so:	CrundNdbApiOperations.cpp
 	$(LINK.cpp) \
 	-fPIC -shared \
 	-L${NDB_LIBDIR} \
 	-lndbclient \
 	-o libcrundndb.so \
-	Operations.cpp com_mysql_cluster_crund_NdbApiLoad.cpp
+	CrundNdbApiOperations.cpp com_mysql_cluster_crund_NdbApiLoad.cpp
 
-libcrundndb.dylib:	Operations.cpp
+libcrundndb.dylib:	CrundNdbApiOperations.cpp
 	$(LINK.cpp) \
 	-fPIC -shared -dynamiclib \
 	-L${NDB_LIBDIR} \
 	-lndbclient \
 	-o libcrundndb.dylib \
-	Operations.cpp com_mysql_cluster_crund_NdbApiLoad.cpp
+	CrundNdbApiOperations.cpp com_mysql_cluster_crund_NdbApiLoad.cpp
 
 # Solaris cc?
 # -#          <!-- verbose mode -->

=== added file 'storage/ndb/test/crund/src/crundndb/NdbApiDriver.cpp'
--- a/storage/ndb/test/crund/src/crundndb/NdbApiDriver.cpp	1970-01-01 00:00:00 +0000
+++ b/storage/ndb/test/crund/src/crundndb/NdbApiDriver.cpp	2010-10-19 22:56:45 +0000
@@ -0,0 +1,437 @@
+/* -*- mode: java; c-basic-offset: 4; indent-tabs-mode: nil; -*-
+ *  vim:expandtab:shiftwidth=4:tabstop=4:smarttab:
+ *
+ *  Copyright (C) 2009 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 <iostream>
+#include <sstream>
+#include <string>
+#include <cassert>
+
+#include "helpers.hpp"
+#include "string_helpers.hpp"
+
+#include "NdbApiDriver.hpp"
+#include "CrundNdbApiOperations.hpp"
+
+using std::cout;
+using std::flush;
+using std::endl;
+using std::ios_base;
+using std::ostringstream;
+using std::string;
+using std::wstring;
+
+using utils::toString;
+
+// ----------------------------------------------------------------------
+
+CrundNdbApiOperations* NdbApiDriver::ops = NULL;
+
+// ISO C++ 98 does not allow for a string literal as a template argument
+// for a non-type template parameter, because string literals are objects
+// with internal linkage.  This restriction maybe lifted in C++0x.
+//
+// Until then, we have to allocate the operation names as variables
+// (which are external at file scope by default).
+const char* delAByPK_s = "delAByPK";
+const char* delB0ByPK_s = "delB0ByPK";
+const char* setAByPK_s = "setAByPK";
+const char* setB0ByPK_s = "setB0ByPK";
+const char* getAByPK_bb_s = "getAByPK_bb";
+const char* getB0ByPK_bb_s = "getB0ByPK_bb";
+const char* getAByPK_ar_s = "getAByPK_ar";
+const char* getB0ByPK_ar_s = "getB0ByPK_ar";
+
+const char* setVarbinary_s = "setVarbinary";
+const char* getVarbinary_s = "getVarbinary";
+const char* clearVarbinary_s = "clearVarbinary";
+const char* setVarchar_s = "setVarchar";
+const char* getVarchar_s = "getVarchar";
+const char* clearVarchar_s = "clearVarchar";
+
+const char* setB0ToA_s = "setB0->A";
+const char* navB0ToA_s = "navB0->A";
+const char* navB0ToAalt_s = "navB0->A_alt";
+const char* navAToB0_s = "navA->B0";
+const char* navAToB0alt_s = "navA->B0_alt";
+const char* nullB0ToA_s = "nullB0->A";
+
+//---------------------------------------------------------------------------
+
+void
+NdbApiDriver::init() {
+    CrundDriver::init();
+
+    // initialize the benchmark's resources
+    ops = new CrundNdbApiOperations();
+    assert(!mgmdConnect.empty());
+    ops->init(mgmdConnect.c_str());
+}
+
+void
+NdbApiDriver::close() {
+    // release the benchmark's resources
+    assert(ops);
+    ops->close();
+    delete ops;
+    ops = NULL;
+
+    CrundDriver::close();
+}
+
+void
+NdbApiDriver::initProperties() {
+    CrundDriver::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("crunddb");
+    }
+
+    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
+NdbApiDriver::printProperties() {
+    CrundDriver::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
+NdbApiDriver::initOperations() {
+    cout << "initializing operations ..." << flush;
+
+    const bool feat = true;
+    initOperationsFeat< !feat >();
+    initOperationsFeat< feat >();
+
+    cout << "     [Op: " << operations.size() << "]" << endl;
+}
+
+// the operation invocation templates look a bit complex, but they help
+// a lot to factorize code over the operations' parameter signatures
+
+template< bool OB >
+struct NdbApiDriver::ADelAllOp : Op {
+    ADelAllOp() : Op(string("delAllA")
+                     + (OB ? "_batch" : "")) {
+    }
+
+    virtual void run(int countA, int countB) const {
+        int count;
+        ops->delByScan(ops->model->table_A, count, OB);
+        assert(count == countA);
+    }
+};
+
+template< bool OB >
+struct NdbApiDriver::B0DelAllOp : Op {
+    B0DelAllOp() : Op(string("delAllB0")
+                      + (OB ? "_batch" : "")) {
+    }
+
+    virtual void run(int countA, int countB) const {
+        int count;
+        ops->delByScan(ops->model->table_B0, count, OB);
+        assert(count == countB);
+    }
+};
+
+template< bool OSA, bool OB >
+struct NdbApiDriver::AInsOp : Op {
+    AInsOp() : Op(string("insA")
+                  + (OSA ? "_attr" : "")
+                  + (OB ? "_batch" : "")) {
+    }
+
+    virtual void run(int countA, int countB) const {
+        ops->ins(ops->model->table_A, 1, countA, OSA, OB);
+    }
+};
+
+template< bool OSA, bool OB >
+struct NdbApiDriver::B0InsOp : Op {
+    B0InsOp() : Op(string("insB0")
+                   + (OSA ? "_attr" : "")
+                   + (OB ? "_batch" : "")) {
+    }
+
+    virtual void run(int countA, int countB) const {
+        ops->ins(ops->model->table_B0, 1, countB, OSA, OB);
+    }
+};
+
+template< const char** ON,
+          void (CrundNdbApiOperations::*OF)(NdbTable,int,int,bool),
+          bool OB >
+struct NdbApiDriver::AByPKOp : Op {
+    AByPKOp() : Op(string(*ON)
+                   + (OB ? "_batch" : "")) {
+    }
+
+    virtual void run(int countA, int countB) const {
+        (ops->*OF)(ops->model->table_A, 1, countA, OB);
+    }
+};
+
+template< const char** ON,
+          void (CrundNdbApiOperations::*OF)(NdbTable,int,int,bool),
+          bool OB >
+struct NdbApiDriver::B0ByPKOp : Op {
+    B0ByPKOp() : Op(string(*ON)
+                    + (OB ? "_batch" : "")) {
+    }
+
+    virtual void run(int countA, int countB) const {
+        (ops->*OF)(ops->model->table_B0, 1, countB, OB);
+    }
+};
+
+template< const char** ON,
+          void (CrundNdbApiOperations::*OF)(NdbTable,int,int,bool,int),
+          bool OB >
+struct NdbApiDriver::LengthOp : Op {
+    const int length;
+
+    LengthOp(int length) : Op(string(*ON)
+                              + toString(length)
+                              + (OB ? "_batch" : "")),
+                           length(length) {
+    }
+
+    virtual void run(int countA, int countB) const {
+        (ops->*OF)(ops->model->table_B0, 1, countB, OB, length);
+    }
+};
+
+template< const char** ON,
+          void (CrundNdbApiOperations::*OF)(NdbTable,int,int,bool,int),
+          bool OB >
+struct NdbApiDriver::ZeroLengthOp : LengthOp< ON, OF, OB > {
+    ZeroLengthOp(int length) : LengthOp< ON, OF, OB >(length) {
+    }
+
+    virtual void run(int countA, int countB) const {
+        (ops->*OF)(ops->model->table_B0, 1, countB, OB, 0);
+    }
+};
+
+template< const char** ON,
+          void (CrundNdbApiOperations::*OF)(int,int,bool),
+          bool OFS >
+struct NdbApiDriver::RelOp : Op {
+    RelOp() : Op(string(*ON)
+                 + (OFS ? "_forceSend" : "")) {
+    }
+
+    virtual void run(int countA, int countB) const {
+        (ops->*OF)(countA, countB, OFS);
+    }
+};
+
+template< bool feat > void
+NdbApiDriver::initOperationsFeat() {
+
+    const bool setAttr = true;
+    operations.push_back(
+        new AInsOp< !setAttr, feat >());
+
+    operations.push_back(
+        new B0InsOp< !setAttr, feat >());
+
+    operations.push_back(
+        new AByPKOp< &setAByPK_s, &CrundNdbApiOperations::setByPK, feat >());
+
+    operations.push_back(
+        new B0ByPKOp< &setB0ByPK_s, &CrundNdbApiOperations::setByPK, feat >());
+
+    operations.push_back(
+        new AByPKOp< &getAByPK_bb_s, &CrundNdbApiOperations::getByPK_bb, feat >());
+
+    operations.push_back(
+        new AByPKOp< &getAByPK_ar_s, &CrundNdbApiOperations::getByPK_ar, feat >());
+
+    operations.push_back(
+        new B0ByPKOp< &getB0ByPK_bb_s, &CrundNdbApiOperations::getByPK_bb, feat >());
+
+    operations.push_back(
+        new B0ByPKOp< &getB0ByPK_ar_s, &CrundNdbApiOperations::getByPK_ar, feat >());
+
+    for (int i = 1; i <= maxVarbinaryBytes; i *= 10) {
+        const int length = i;
+
+        operations.push_back(
+            new LengthOp< &setVarbinary_s, &CrundNdbApiOperations::setVarbinary, feat >(length));
+
+        operations.push_back(
+            new LengthOp< &getVarbinary_s, &CrundNdbApiOperations::getVarbinary, feat >(length));
+
+        operations.push_back(
+            new ZeroLengthOp< &clearVarbinary_s, &CrundNdbApiOperations::setVarbinary, feat >(length));
+    }
+
+    for (int i = 1; i <= maxVarcharChars; i *= 10) {
+        const int length = i;
+
+        operations.push_back(
+            new LengthOp< &setVarchar_s, &CrundNdbApiOperations::setVarchar, feat >(length));
+
+        operations.push_back(
+            new LengthOp< &getVarchar_s, &CrundNdbApiOperations::getVarchar, feat >(length));
+
+        operations.push_back(
+            new ZeroLengthOp< &clearVarchar_s, &CrundNdbApiOperations::setVarchar, feat >(length));
+    }
+
+    operations.push_back(
+        new RelOp< &setB0ToA_s, &CrundNdbApiOperations::setB0ToA, feat >());
+
+    operations.push_back(
+        new RelOp< &navB0ToA_s, &CrundNdbApiOperations::navB0ToA, feat >());
+
+    operations.push_back(
+        new RelOp< &navB0ToAalt_s, &CrundNdbApiOperations::navB0ToAalt, feat >());
+
+    operations.push_back(
+        new RelOp< &navAToB0_s, &CrundNdbApiOperations::navAToB0, feat >());
+
+    operations.push_back(
+        new RelOp< &navAToB0alt_s, &CrundNdbApiOperations::navAToB0alt, feat >());
+
+    operations.push_back(
+        new RelOp< &nullB0ToA_s, &CrundNdbApiOperations::nullB0ToA, feat >());
+
+    operations.push_back(
+        new B0ByPKOp< &setAByPK_s, &CrundNdbApiOperations::delByPK, feat >());
+
+    operations.push_back(
+        new AByPKOp< &setB0ByPK_s, &CrundNdbApiOperations::delByPK, feat >());
+
+    operations.push_back(
+        new AInsOp< setAttr, feat >());
+
+    operations.push_back(
+        new B0InsOp< setAttr, feat >());
+
+    operations.push_back(
+        new ADelAllOp< feat >());
+
+    operations.push_back(
+        new B0DelAllOp< feat >());
+}
+
+void
+NdbApiDriver::closeOperations() {
+    cout << "closing operations ..." << flush;
+    for (Operations::const_iterator i = operations.begin();
+         i != operations.end(); ++i) {
+        delete *i;
+    }
+    operations.clear();
+    cout << "          [ok]" << endl;
+}
+
+//---------------------------------------------------------------------------
+
+void
+NdbApiDriver::initConnection() {
+    NdbOperation::LockMode ndbOpLockMode;
+    switch (lockMode) {
+    case READ_COMMITTED:
+        ndbOpLockMode = NdbOperation::LM_CommittedRead;
+        break;
+    case SHARED:
+        ndbOpLockMode = NdbOperation::LM_Read;
+        break;
+    case EXCLUSIVE:
+        ndbOpLockMode = NdbOperation::LM_Exclusive;
+        break;
+    default:
+        ndbOpLockMode = NdbOperation::LM_CommittedRead;
+        assert(false);
+    }
+
+    ops->initConnection(catalog.c_str(), schema.c_str(), ndbOpLockMode);
+}
+
+void
+NdbApiDriver::closeConnection() {
+    ops->closeConnection();
+}
+
+void
+NdbApiDriver::clearPersistenceContext() {
+    assert(false); // XXX not implemented yet
+}
+
+void
+NdbApiDriver::clearData()
+{
+    ops->clearData();
+}
+
+//---------------------------------------------------------------------------
+
+int
+main(int argc, const char* argv[])
+{
+    TRACE("main()");
+
+    NdbApiDriver::parseArguments(argc, argv);
+    NdbApiDriver d;
+    d.run();
+
+    return 0;
+}
+
+//---------------------------------------------------------------------------

=== added file 'storage/ndb/test/crund/src/crundndb/NdbApiDriver.hpp'
--- a/storage/ndb/test/crund/src/crundndb/NdbApiDriver.hpp	1970-01-01 00:00:00 +0000
+++ b/storage/ndb/test/crund/src/crundndb/NdbApiDriver.hpp	2010-10-08 11:17:35 +0000
@@ -0,0 +1,95 @@
+/* -*- mode: java; c-basic-offset: 4; indent-tabs-mode: nil; -*-
+ *  vim:expandtab:shiftwidth=4:tabstop=4:smarttab:
+ *
+ *  Copyright (C) 2009 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
+ */
+
+#ifndef NdbApiDriver_hpp
+#define NdbApiDriver_hpp
+
+#include <string>
+
+#include "CrundDriver.hpp"
+#include "CrundNdbApiOperations.hpp"
+
+using std::string;
+
+// global type aliases
+typedef const NdbDictionary::Table* NdbTable;
+
+class NdbApiDriver : public CrundDriver {
+public:
+
+    // the generated features are OK
+    //NdbApiDriver() {}
+    //virtual ~NdbApsDriver() {}
+    //NdbApiDriver(const NdbApiDriver&) {}
+    //NdbApiDriver& operator=(const NdbApiDriver&) {}
+
+protected:
+
+    // NDB API resources
+    string mgmdConnect;
+    string catalog;
+    string schema;
+
+    // the benchmark's basic database operations
+    static CrundNdbApiOperations* ops;
+
+    // NDB API intializers/finalizers
+    virtual void initProperties();
+    virtual void printProperties();
+    virtual void init();
+    virtual void close();
+
+    // NDB API operations
+    template< bool feat > void initOperationsFeat();
+    template< bool > struct ADelAllOp;
+    template< bool > struct B0DelAllOp;
+    template< bool, bool > struct AInsOp;
+    template< bool, bool > struct B0InsOp;
+    template< const char**,
+              void (CrundNdbApiOperations::*)(NdbTable,int,int,bool),
+              bool >
+    struct AByPKOp;
+    template< const char**,
+              void (CrundNdbApiOperations::*)(NdbTable,int,int,bool),
+              bool >
+    struct B0ByPKOp;
+    template< const char**,
+              void (CrundNdbApiOperations::*)(NdbTable,int,int,bool,int),
+              bool >
+    struct LengthOp;
+    template< const char**,
+              void (CrundNdbApiOperations::*)(NdbTable,int,int,bool,int),
+              bool >
+    struct ZeroLengthOp;
+    template< const char**,
+              void (CrundNdbApiOperations::*)(int,int,bool),
+              bool >
+    struct RelOp;
+    virtual void initOperations();
+    virtual void closeOperations();
+
+    // NDB API datastore operations
+    virtual void initConnection();
+    virtual void closeConnection();
+    virtual void clearPersistenceContext();
+    virtual void clearData();
+};
+
+#endif // Driver_hpp

=== modified file 'storage/ndb/test/crund/src/crundndb/com_mysql_cluster_crund_NdbApiLoad.cpp'
--- a/storage/ndb/test/crund/src/crundndb/com_mysql_cluster_crund_NdbApiLoad.cpp	2010-10-01 08:58:08 +0000
+++ b/storage/ndb/test/crund/src/crundndb/com_mysql_cluster_crund_NdbApiLoad.cpp	2010-10-19 22:56:45 +0000
@@ -1,27 +1,38 @@
-/*
- * com_mysql_cluster_crund_NdbApiLoad.cpp
+/* -*- mode: java; c-basic-offset: 4; indent-tabs-mode: nil; -*-
+ *  vim:expandtab:shiftwidth=4:tabstop=4:smarttab:
  *
+ *  Copyright (C) 2009 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 <jni.h>
 #include <cassert>
 
-#include "com_mysql_cluster_crund_NdbApiLoad.h"
 #include "helpers.hpp"
-#include "Operations.hpp"
 
-//using namespace crund_ndb;
-using crund_ndb::Meta;
-using crund_ndb::Operations;
-
-/************************************************************
- * Native JNI Functions
- ************************************************************/
+#include "com_mysql_cluster_crund_NdbApiLoad.h"
 
-/**
- * Provides the benchmark's basic database operations.
- */
-static Operations* ops = NULL;
+#include "CrundNdbApiOperations.hpp"
+
+// ----------------------------------------------------------------------
+
+// provides the benchmark's basic database operations
+static CrundNdbApiOperations* ops = NULL;
+
+// ----------------------------------------------------------------------
 
 JNIEXPORT jint JNICALL
 Java_com_mysql_cluster_crund_NdbApiLoad_ndbinit(JNIEnv* env,
@@ -29,14 +40,14 @@ Java_com_mysql_cluster_crund_NdbApiLoad_
                                                 jstring mgmd_jstr)
 {
     TRACE("ndbinit()");
-    assert (mgmd_jstr);
+    assert(mgmd_jstr);
 
     // location of cluster management server (ndb_mgmd)
     // get a native string from the Java string
     const char* mgmd_cstr = env->GetStringUTFChars(mgmd_jstr, NULL);
 
     // initialize the benchmark's resources
-    ops = new Operations();
+    ops = new CrundNdbApiOperations();
     ops->init(mgmd_cstr);
 
     // release the native and Java strings
@@ -62,17 +73,19 @@ JNIEXPORT void JNICALL
 Java_com_mysql_cluster_crund_NdbApiLoad_initConnection(JNIEnv* env,
                                                        jobject obj,
                                                        jstring catalog_jstr,
-                                                       jstring schema_jstr)
+                                                       jstring schema_jstr,
+                                                       jint defaultLockMode)
 {
     TRACE("initConnection()");
-    assert (catalog_jstr);
-    assert (schema_jstr);
+    assert(catalog_jstr);
+    assert(schema_jstr);
 
     // get native strings from the Java strings
     const char* catalog_cstr = env->GetStringUTFChars(catalog_jstr, NULL);
     const char* schema_cstr = env->GetStringUTFChars(schema_jstr, NULL);
+    NdbOperation::LockMode dlm = (NdbOperation::LockMode)defaultLockMode;
 
-    ops->initConnection(catalog_cstr, schema_cstr);
+    ops->initConnection(catalog_cstr, schema_cstr, dlm);
 
     // release the native and Java strings
     env->ReleaseStringUTFChars(schema_jstr, schema_cstr);
@@ -96,30 +109,6 @@ Java_com_mysql_cluster_crund_NdbApiLoad_
 }
 
 JNIEXPORT void JNICALL
-Java_com_mysql_cluster_crund_NdbApiLoad_beginTransaction(JNIEnv* env,
-                                                         jobject obj)
-{
-    TRACE("beginTransaction()");
-    ops->beginTransaction();
-}
-
-JNIEXPORT void JNICALL
-Java_com_mysql_cluster_crund_NdbApiLoad_commitTransaction(JNIEnv* env,
-                                                          jobject obj)
-{
-    TRACE("commitTransaction()");
-    ops->commitTransaction();
-}
-
-JNIEXPORT void JNICALL
-Java_com_mysql_cluster_crund_NdbApiLoad_rollbackTransaction(JNIEnv* env,
-                                                            jobject obj)
-{
-    TRACE("rollbackTransaction()");
-    ops->rollbackTransaction();
-}
-
-JNIEXPORT void JNICALL
 Java_com_mysql_cluster_crund_NdbApiLoad_delAllA(JNIEnv* env,
                                                 jobject obj,
                                                 jint count_A,
@@ -128,8 +117,8 @@ Java_com_mysql_cluster_crund_NdbApiLoad_
 {
     TRACE("delAllA()");
     int count;
-    ops->delByScan(ops->meta->table_A, count, batch == JNI_TRUE);
-    assert (count == count_A);
+    ops->delByScan(ops->model->table_A, count, batch == JNI_TRUE);
+    assert(count == count_A);
 }
 
 JNIEXPORT void JNICALL
@@ -141,8 +130,8 @@ Java_com_mysql_cluster_crund_NdbApiLoad_
 {
     TRACE("delAllB0()");
     int count;
-    ops->delByScan(ops->meta->table_B0, count, batch == JNI_TRUE);
-    assert (count == count_B);
+    ops->delByScan(ops->model->table_B0, count, batch == JNI_TRUE);
+    assert(count == count_B);
 }
 
 JNIEXPORT void JNICALL
@@ -154,7 +143,7 @@ Java_com_mysql_cluster_crund_NdbApiLoad_
                                              jboolean batch)
 {
     TRACE("insA()");
-    ops->ins(ops->meta->table_A, 1, count_A,
+    ops->ins(ops->model->table_A, 1, count_A,
              setAttrs == JNI_TRUE, batch == JNI_TRUE);
 }
 
@@ -167,7 +156,7 @@ Java_com_mysql_cluster_crund_NdbApiLoad_
                                               jboolean batch)
 {
     TRACE("insB0()");
-    ops->ins(ops->meta->table_B0, 1, count_B,
+    ops->ins(ops->model->table_B0, 1, count_B,
              setAttrs == JNI_TRUE, batch == JNI_TRUE);
 }
 
@@ -179,7 +168,7 @@ Java_com_mysql_cluster_crund_NdbApiLoad_
                                                  jboolean batch)
 {
     TRACE("delAByPK()");
-    ops->delByPK(ops->meta->table_A, 1, count_A, batch == JNI_TRUE);
+    ops->delByPK(ops->model->table_A, 1, count_A, batch == JNI_TRUE);
 }
 
 JNIEXPORT void JNICALL
@@ -190,7 +179,7 @@ Java_com_mysql_cluster_crund_NdbApiLoad_
                                                   jboolean batch)
 {
     TRACE("delB0ByPK()");
-    ops->delByPK(ops->meta->table_B0, 1, count_B, batch == JNI_TRUE);
+    ops->delByPK(ops->model->table_B0, 1, count_B, batch == JNI_TRUE);
 }
 
 JNIEXPORT void JNICALL
@@ -201,7 +190,7 @@ Java_com_mysql_cluster_crund_NdbApiLoad_
                                                  jboolean batch)
 {
     TRACE("setAByPK()");
-    ops->setByPK(ops->meta->table_A, 1, count_A, batch == JNI_TRUE);
+    ops->setByPK(ops->model->table_A, 1, count_A, batch == JNI_TRUE);
 }
 
 JNIEXPORT void JNICALL
@@ -212,7 +201,7 @@ Java_com_mysql_cluster_crund_NdbApiLoad_
                                                   jboolean batch)
 {
     TRACE("setB0ByPK()");
-    ops->setByPK(ops->meta->table_B0, 1, count_B, batch == JNI_TRUE);
+    ops->setByPK(ops->model->table_B0, 1, count_B, batch == JNI_TRUE);
 }
 
 JNIEXPORT void JNICALL
@@ -223,7 +212,7 @@ Java_com_mysql_cluster_crund_NdbApiLoad_
                                                      jboolean batch)
 {
     TRACE("getAByPK_bb()");
-    ops->getByPK_bb(ops->meta->table_A, 1, count_A, batch == JNI_TRUE);
+    ops->getByPK_bb(ops->model->table_A, 1, count_A, batch == JNI_TRUE);
 }
 
 JNIEXPORT void JNICALL
@@ -234,7 +223,7 @@ Java_com_mysql_cluster_crund_NdbApiLoad_
                                                       jboolean batch)
 {
     TRACE("getB0ByPK_bb()");
-    ops->getByPK_bb(ops->meta->table_B0, 1, count_B, batch == JNI_TRUE);
+    ops->getByPK_bb(ops->model->table_B0, 1, count_B, batch == JNI_TRUE);
 }
 
 JNIEXPORT void JNICALL
@@ -245,7 +234,7 @@ Java_com_mysql_cluster_crund_NdbApiLoad_
                                                      jboolean batch)
 {
     TRACE("getAByPK_ar()");
-    ops->getByPK_ar(ops->meta->table_A, 1, count_A, batch == JNI_TRUE);
+    ops->getByPK_ar(ops->model->table_A, 1, count_A, batch == JNI_TRUE);
 }
 
 JNIEXPORT void JNICALL
@@ -256,7 +245,7 @@ Java_com_mysql_cluster_crund_NdbApiLoad_
                                                       jboolean batch)
 {
     TRACE("getB0ByPK_ar()");
-    ops->getByPK_ar(ops->meta->table_B0, 1, count_B, batch == JNI_TRUE);
+    ops->getByPK_ar(ops->model->table_B0, 1, count_B, batch == JNI_TRUE);
 }
 
 JNIEXPORT void JNICALL
@@ -268,7 +257,7 @@ Java_com_mysql_cluster_crund_NdbApiLoad_
                                                      jint length)
 {
     TRACE("setVarbinary()");
-    ops->setVarbinary(ops->meta->table_B0,
+    ops->setVarbinary(ops->model->table_B0,
                       1, count_B, batch == JNI_TRUE, length);
 }
 
@@ -281,7 +270,7 @@ Java_com_mysql_cluster_crund_NdbApiLoad_
                                                      jint length)
 {
     TRACE("getVarbinary()");
-    ops->getVarbinary(ops->meta->table_B0,
+    ops->getVarbinary(ops->model->table_B0,
                       1, count_B, batch == JNI_TRUE, length);
 }
 
@@ -294,7 +283,7 @@ Java_com_mysql_cluster_crund_NdbApiLoad_
                                                    jint length)
 {
     TRACE("setVarchar()");
-    ops->setVarchar(ops->meta->table_B0,
+    ops->setVarchar(ops->model->table_B0,
                     1, count_B, batch == JNI_TRUE, length);
 }
 
@@ -307,7 +296,7 @@ Java_com_mysql_cluster_crund_NdbApiLoad_
                                                    jint length)
 {
     TRACE("getVarchar()");
-    ops->getVarchar(ops->meta->table_B0,
+    ops->getVarchar(ops->model->table_B0,
                     1, count_B, batch == JNI_TRUE, length);
 }
 
@@ -376,3 +365,5 @@ Java_com_mysql_cluster_crund_NdbApiLoad_
     TRACE("nullB0ToA()");
     ops->nullB0ToA(count_A, count_B, batch == JNI_TRUE);
 }
+
+// ----------------------------------------------------------------------

=== added directory 'storage/ndb/test/crund/tws'
=== added file 'storage/ndb/test/crund/tws/README.txt'
--- a/storage/ndb/test/crund/tws/README.txt	1970-01-01 00:00:00 +0000
+++ b/storage/ndb/test/crund/tws/README.txt	2010-10-08 11:14:56 +0000
@@ -0,0 +1,19 @@
+
+TWS (Table With Strings)
+------------------------
+
+A benchmark that measures the round-trip latency (and a few other metrics)
+of basic lookup/insert/update/delete operations with MySQL Cluster APIs
+on a predominantly string/varchar-based table.
+
+Currently supported APIs: NDB API, NDB JTie, ClusterJ, and JDBC.
+
+This benchmark code is mostly self-contained (and prepared but not yet
+integrated with CRUND).
+
+Please, see
+-> tws_java/README.txt
+-> tws_c++/README.txt
+on how to build and run the client code.
+
+Questions or comments appreciated: martin.zaun@stripped

=== 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-19 22:53:39 +0000
@@ -0,0 +1,94 @@
+######################################################################
+# driver settings
+######################################################################
+
+logRealTime=true
+logCpuTime=true
+logMemUsage=false
+includeFullGC=false
+
+#warmupRuns=10
+#warmupRuns=1
+warmupRuns=0
+
+######################################################################
+# TWS workload settings
+######################################################################
+
+renewConnection=false
+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
+
+#nRuns=100
+#nRuns=10
+nRuns=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

=== added file 'storage/ndb/test/crund/tws/schema.sql'
--- a/storage/ndb/test/crund/tws/schema.sql	1970-01-01 00:00:00 +0000
+++ b/storage/ndb/test/crund/tws/schema.sql	2010-10-08 11:14:56 +0000
@@ -0,0 +1,33 @@
+SET storage_engine=NDB;
+
+DROP DATABASE IF EXISTS testdb;
+CREATE DATABASE testdb;
+-- USE testdb;
+
+DROP TABLE IF EXISTS testdb.mytable;
+
+CREATE  TABLE IF NOT EXISTS testdb.mytable (
+        c0 VARCHAR(9)   NOT NULL,
+        c1 VARCHAR(10)  NOT NULL,
+        c2 INT          NOT NULL,
+        c3 INT          NOT NULL,
+        c4 INT          NULL,
+        c5 VARCHAR(39)  NULL,
+        c6 VARCHAR(39)  NULL,
+        c7 VARCHAR(9)   NOT NULL,
+        c8 VARCHAR(11)  NOT NULL,
+        c9 CHAR         NULL,
+        c10 CHAR        NULL,
+        c11 VARCHAR(7)  NULL,
+        c12 VARCHAR(7)  NULL,
+        c13 CHAR        NULL,
+        c14 VARCHAR(34) NULL,
+        PRIMARY KEY (c0),
+        UNIQUE INDEX c0_UNIQUE USING BTREE (c0 ASC)
+-- "Job buffer congestion" crashes with node failure with unique indexes
+-- http://bugs.mysql.com/bug.php?id=56552
+--        UNIQUE INDEX c1_UNIQUE USING BTREE (c1 ASC),
+--        UNIQUE INDEX c2_UNIQUE (c2 ASC),
+--        UNIQUE INDEX c7_UNIQUE (c7 ASC),
+--        UNIQUE INDEX c8_UNIQUE (c8 ASC)
+);

=== added directory 'storage/ndb/test/crund/tws/tws_cpp'
=== added file 'storage/ndb/test/crund/tws/tws_cpp/Driver.cpp'
--- a/storage/ndb/test/crund/tws/tws_cpp/Driver.cpp	1970-01-01 00:00:00 +0000
+++ b/storage/ndb/test/crund/tws/tws_cpp/Driver.cpp	2010-10-19 22:52:04 +0000
@@ -0,0 +1,268 @@
+/* -*- 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 "Driver.hpp"
+
+#include <cassert>
+
+#include "helpers.hpp"
+#include "string_helpers.hpp"
+
+using std::cout;
+using std::flush;
+using std::endl;
+using std::ios_base;
+using std::string;
+using std::vector;
+
+using utils::Properties;
+using utils::toBool;
+using utils::toInt;
+using utils::toString;
+
+// ---------------------------------------------------------------------------
+// Helper Macros & Functions
+// ---------------------------------------------------------------------------
+
+#define ABORT_GETTIMEOFDAY_ERROR()                                      \
+    do { cout << "!!! error in " << __FILE__ << ", line: " << __LINE__  \
+              << ", gettimeofday() returned an error code." << endl;    \
+        exit(-1);                                                       \
+    } while (0)
+
+// ---------------------------------------------------------------------------
+// Driver Implementation
+// ---------------------------------------------------------------------------
+
+vector< string > Driver::propFileNames;
+string Driver::logFileName;
+
+void
+Driver::exitUsage()
+{
+    cout << "usage: [options]" << endl
+         << "    [-p <file name>]...    properties file name" << endl
+         << "    [-l <file name>]       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();
+        clearLogBuffers();
+    }
+
+    cout << endl
+         << "++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++" << endl
+         << "hot runs ..." << endl
+         << "++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++" << endl;
+    runTests();
+
+    cout << endl
+         << "++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++" << endl;
+    close();
+}
+
+void
+Driver::init() {
+    loadProperties();
+    initProperties();
+    printProperties();
+    openLogFile();
+    clearLogBuffers();
+}
+
+void
+Driver::close() {
+    clearLogBuffers();
+    closeLogFile();
+}
+
+void
+Driver::loadProperties() {
+    cout << endl;
+    for (vector<string>::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;
+
+    warmupRuns = toInt(props[L"warmupRuns"], 0, -1);
+    if (warmupRuns < 0) {
+        msg << "[ignored] warmupRuns:        '"
+            << toString(props[L"warmupRuns"]) << "'" << endl;
+        warmupRuns = 0;
+    }
+
+    //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 << "warmupRuns:                     " << warmupRuns << 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::clearLogBuffers() {
+    logHeader = true;
+    header.rdbuf()->str("");
+    rtimes.rdbuf()->str("");
+}
+
+void
+Driver::writeLogBuffers() {
+    log << descr << ", rtime[ms]"
+        << header.rdbuf()->str() << endl
+        << rtimes.rdbuf()->str() << endl;
+}
+
+void
+Driver::begin(const string& name) {
+    cout << endl;
+    cout << name << endl;
+
+    if (gettimeofday(&t0, NULL) != 0)
+        ABORT_GETTIMEOFDAY_ERROR();
+}
+
+void
+Driver::finish(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;
+}
+
+//---------------------------------------------------------------------------

=== added file 'storage/ndb/test/crund/tws/tws_cpp/Driver.hpp'
--- a/storage/ndb/test/crund/tws/tws_cpp/Driver.hpp	1970-01-01 00:00:00 +0000
+++ b/storage/ndb/test/crund/tws/tws_cpp/Driver.hpp	2010-10-19 22:52:04 +0000
@@ -0,0 +1,102 @@
+/* -*- 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
+ */
+
+#ifndef Driver_hpp
+#define Driver_hpp
+
+#include <iostream>
+#include <sstream>
+#include <fstream>
+#include <string>
+#include <vector>
+
+#include <sys/time.h>
+
+#include "Properties.hpp"
+
+using std::string;
+using std::vector;
+using std::ofstream;
+using std::ostringstream;
+
+using utils::Properties;
+
+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;
+    int warmupRuns;
+
+    // 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 clearLogBuffers();
+    virtual void writeLogBuffers();
+    virtual void begin(const string& name);
+    virtual void finish(const string& name);
+};
+
+#endif // Driver_hpp

=== added file 'storage/ndb/test/crund/tws/tws_cpp/NdbApiTwsDriver.cpp'
--- a/storage/ndb/test/crund/tws/tws_cpp/NdbApiTwsDriver.cpp	1970-01-01 00:00:00 +0000
+++ b/storage/ndb/test/crund/tws/tws_cpp/NdbApiTwsDriver.cpp	2010-10-19 22:52:04 +0000
@@ -0,0 +1,941 @@
+/* -*- 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 "NdbApiTwsDriver.hpp"
+
+#include <iostream>
+#include <string>
+#include <cassert>
+
+#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 utils::Properties;
+using utils::toBool;
+using utils::toInt;
+using utils::toString;
+
+// ---------------------------------------------------------------------------
+// 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)
+
+// ---------------------------------------------------------------------------
+// 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::runLoadOperations() {
+    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();
+    }
+
+    finish(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();
+    }
+
+    finish(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();
+    }
+
+    finish(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();
+    }
+
+    finish(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 connection ..." << 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;
+}
+
+//---------------------------------------------------------------------------

=== added file 'storage/ndb/test/crund/tws/tws_cpp/NdbApiTwsDriver.hpp'
--- a/storage/ndb/test/crund/tws/tws_cpp/NdbApiTwsDriver.hpp	1970-01-01 00:00:00 +0000
+++ b/storage/ndb/test/crund/tws/tws_cpp/NdbApiTwsDriver.hpp	2010-10-19 22:52:04 +0000
@@ -0,0 +1,172 @@
+/* -*- 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
+ */
+
+#ifndef NdbApiTwsDriver_hpp
+#define NdbApiTwsDriver_hpp
+
+#include "TwsDriver.hpp"
+
+#include <NdbApi.hpp>
+#include <NdbError.hpp>
+
+using std::string;
+
+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) {
+    }
+
+    virtual ~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 init();
+    virtual void close();
+    virtual void initProperties();
+    virtual void printProperties();
+    void initNdbapiBuffers();
+    void closeNdbapiBuffers();
+
+    // NDB API operations
+    virtual void runLoadOperations();
+    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 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
+};
+
+#endif // NdbApiTwsDriver_hpp

=== 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 11:14:56 +0000
@@ -0,0 +1,52 @@
+
+How to Build and Run the C++ TWS Benchmark
+------------------------------------------
+
+This benchmark is being built with
+-> Gnu 'make' (using generic, hand-coded Makefiles)
+-> Gnu g++    (or Solaris Studio CC as compilers)
+
+0)  Configure external dependencies paths
+
+    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-19 22:52:04 +0000
@@ -0,0 +1,285 @@
+/* -*- 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 "TwsDriver.hpp"
+
+#include <iostream>
+#include <sstream>
+#include <fstream>
+#include <string>
+#include <cassert>
+
+#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::ostringstream;
+
+using utils::Properties;
+using utils::toBool;
+using utils::toInt;
+using utils::toString;
+
+// ---------------------------------------------------------------------------
+// Helper Macros & Functions
+// ---------------------------------------------------------------------------
+
+#define ABORT_VERIFICATION_ERROR()                                      \
+    do { cout << "!!! error in " << __FILE__ << ", line: " << __LINE__  \
+              << ", failed data verification." << endl;                 \
+        exit(-1);                                                       \
+    } while (0)
+
+// ---------------------------------------------------------------------------
+// TwsDriver Implementation
+// ---------------------------------------------------------------------------
+
+void
+TwsDriver::init() {
+    Driver::init();
+}
+
+void
+TwsDriver::close() {
+    Driver::close();
+}
+
+void
+TwsDriver::initProperties() {
+    Driver::initProperties();
+
+    cout << "setting tws properties ..." << flush;
+
+    ostringstream msg;
+
+    renewConnection = toBool(props[L"renewConnection"], false);
+    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;
+    }
+
+    nRuns = toInt(props[L"nRuns"], 1, -1);
+    if (nRuns < 0) {
+        msg << "[ignored] nRuns:             '"
+            << toString(props[L"nRuns"]) << "'" << endl;
+        nRuns = 1;
+    }
+
+    //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 << "renewConnection:                " << renewConnection << 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 << "nRuns:                          " << nRuns << 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() {
+    // anticipating multiple loads to be run here
+    runSeries();
+}
+
+void
+TwsDriver::runSeries() {
+    if (nRuns == 0)
+        return; // nothing to do
+
+    cout << endl
+         << "------------------------------------------------------------" << endl;
+    cout << "running " << nRuns << " iterations on load: " << descr;
+
+    for (int i = 0; i < nRuns; i++) {
+        cout << endl
+             << "------------------------------------------------------------" << endl;
+        runOperations();
+    }
+
+    writeLogBuffers();
+    clearLogBuffers();
+}
+
+void
+TwsDriver::runOperations() {
+    // log buffers
+    rtimes << "nRows=" << nRows;
+    rta = 0L;
+
+    // pre-run cleanup
+    if (renewConnection) {
+        closeConnection();
+        initConnection();
+    }
+    //clearData(); // not used
+
+    runLoadOperations();
+
+    cout << endl
+         << "total" << endl;
+    cout << "tx real time                    " << rta
+         << "\tms" << endl;
+
+    // log buffers
+    if (logHeader) {
+        header << "\ttotal";
+        logHeader = false;
+    }
+    rtimes << "\t" << rta << endl;
+}
+
+void
+TwsDriver::verify(int exp, int act) {
+    if (doVerify) {
+        //cout << "XXX exp=" << exp << ", act=" << act << endl;
+        if (exp != act) {
+            ABORT_VERIFICATION_ERROR();
+        }
+    }
+}
+
+void
+TwsDriver::verify(long exp, long act) {
+    if (doVerify) {
+        //cout << "XXX exp=" << exp << ", act=" << act << endl;
+        if (exp != act) {
+            ABORT_VERIFICATION_ERROR();
+        }
+    }
+}
+
+void
+TwsDriver::verify(long long exp, long long 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 "<invalid value>";
+    };
+}
+
+const char*
+TwsDriver::toStr(LockMode mode) {
+    switch (mode) {
+    case SINGLE:
+        return "read_committed";
+    case SHARED:
+        return "shared";
+    case EXCLUSIVE:
+        return "exclusive";
+    default:
+        assert(false);
+        return "<invalid value>";
+    };
+}
+
+//---------------------------------------------------------------------------

=== added file 'storage/ndb/test/crund/tws/tws_cpp/TwsDriver.hpp'
--- a/storage/ndb/test/crund/tws/tws_cpp/TwsDriver.hpp	1970-01-01 00:00:00 +0000
+++ b/storage/ndb/test/crund/tws/tws_cpp/TwsDriver.hpp	2010-10-19 22:52:04 +0000
@@ -0,0 +1,71 @@
+/* -*- 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
+ */
+
+#ifndef TwsDriver_hpp
+#define TwsDriver_hpp
+
+#include "Driver.hpp"
+
+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 renewConnection;
+    bool doInsert;
+    bool doLookup;
+    bool doUpdate;
+    bool doDelete;
+    bool doSingle;
+    bool doBulk;
+    bool doBatch;
+    bool doVerify;
+    LockMode lockMode;
+    int nRows;
+    int nRuns;
+
+    // benchmark intializers/finalizers
+    virtual void init();
+    virtual void close();
+    virtual void initProperties();
+    virtual void printProperties();
+
+    // benchmark operations
+    virtual void runTests();
+    virtual void runLoads();
+    virtual void runSeries();
+    virtual void runOperations();
+    virtual void runLoadOperations() = 0;
+    void verify(int exp, int act);
+    void verify(long exp, long act);
+    void verify(long long exp, long long act);
+    void verify(const char* exp, const char* act);
+
+    // datastore operations
+    virtual void initConnection() = 0;
+    virtual void closeConnection() = 0;
+    //virtual void clearPersistenceContext() = 0; // not used
+    //virtual void clearData() = 0; // not used
+};
+
+#endif // TwsDriver_hpp

=== renamed directory 'storage/ndb/test/crund/tws_benchmark' => 'storage/ndb/test/crund/tws/tws_java'
=== modified file 'storage/ndb/test/crund/tws/tws_java/README.txt'
--- a/storage/ndb/test/crund/tws_benchmark/README.txt	2010-09-29 10:02:15 +0000
+++ b/storage/ndb/test/crund/tws/tws_java/README.txt	2010-10-08 11:14:56 +0000
@@ -1,24 +1,12 @@
 
-TWS (Table With Strings)
-------------------------
+How to Build, Run, and Profile the Java TWS Benchmark
+-----------------------------------------------------
 
-A self-contained benchmark that measures the performance of selected MySQL
-Server/Cluster APIs for basic operations on a string/varchar-based schema.
+The benchmark is being built and run with
+-> Ant >= 1.7 (project scripts generated by Netbeans)
+-> JDK >= 1.5
 
-This benchmark is standalone and not yet integrated into CRUND.
-
-Questions or comments appreciated: martin.zaun@stripped
-
-
-How to Build, Run, and Profile TWS
-----------------------------------
-
-The benchmark is built and run by Ant scripts (generated from Netbeans).
-
-0) Configure TWS Properties
-
-    The benchmark is built and run by Ant scripts (originally, generated
-    from Netbeans).
+0)  Configure external dependencies paths
 
     Copy the configuration sample files
         $ cd ./nbproject
@@ -30,10 +18,7 @@ The benchmark is built and run by Ant sc
 
         $ cp -vr private_sample private
         private_sample -> private
-        private_sample/config.properties -> private/config.properties
-        private_sample/private.xml -> private/private.xml
-        private_sample/profiler -> private/profiler
-        private_sample/profiler/configurations.xml -> private/profiler/configurations.xml
+	...
         private_sample/private.properties -> private/private.properties
 
     Edit the files
@@ -46,8 +31,10 @@ The benchmark is built and run by Ant sc
         ./private/config.properties
     to select the JVM run configuration (debug/optimized settings).
 
+    Important: the JVM's -d32/-d64/default machine type settings must match
+    the architecture type of the NDB libraries.
 
-1) Build TWS
+1)  Build the classfiles
 
     Standard project targets:
         $ ant default
@@ -58,20 +45,17 @@ The benchmark is built and run by Ant sc
         $ ant deps-jar
         $ ant deps-clean
 
+2) Run the benchmark
 
-2) Run TWS
-
-    Start the Cluster and load the schema (see ../scripts/)
-        ./schema.sql
+    Edit the benchmark's settings (copy from ../run.properties.sample)
+        ../run.properties
 
-    Copy the run configuration sample file
-        $ cp -v run.properties.sample run.properties
-        run.properties.sample -> run.properties
-
-    Edit the file for the benchmark settings
-        ./run.properties
+    Have a running NDB Cluster with loaded schema file: ../schema.sql.
 
     Run (and Profiling?) targets:
         $ ant run
 
-    All the benchmark's data output is to stdout, at this time.
+    The benchmark's result data is written to a generated log_XXX file.
+
+Comments or questions appreciated.
+martin.zaun@stripped

=== modified file 'storage/ndb/test/crund/tws/tws_java/nbproject/configs_sample/server-dbg.properties'
--- a/storage/ndb/test/crund/tws_benchmark/nbproject/configs_sample/server-dbg.properties	2010-10-03 04:32:37 +0000
+++ b/storage/ndb/test/crund/tws/tws_java/nbproject/configs_sample/server-dbg.properties	2010-10-19 22:50:53 +0000
@@ -1,2 +1,3 @@
-run.jvmargs=-server -Xms512m -Xmx512m -ea -Djava.library.path="/Users/mz/mysql/bin-7.1-dbg64/lib/mysql"
+main.class=com.mysql.cluster.benchmark.tws.TwsDriver
+run.jvmargs=-server -Xms512m -Xmx512m -da -Djava.library.path="/Users/mz/mysql/bin-7.1-dbg64/lib/mysql"
 #run.jvmargs=-server -Xms512m -Xmx512m -ea -Djava.library.path="/home/md/mysql/bin-7.1-dbg32/lib/mysql"

=== modified file 'storage/ndb/test/crund/tws/tws_java/nbproject/configs_sample/server-opt.properties'
--- a/storage/ndb/test/crund/tws_benchmark/nbproject/configs_sample/server-opt.properties	2010-09-29 09:09:26 +0000
+++ b/storage/ndb/test/crund/tws/tws_java/nbproject/configs_sample/server-opt.properties	2010-10-19 22:50:53 +0000
@@ -1,2 +1,3 @@
+main.class=com.mysql.cluster.benchmark.tws.TwsDriver
 run.jvmargs=-server -Xms512m -Xmx512m -da -Djava.library.path="/Users/mz/mysql/bin-7.1-opt64/lib/mysql"
 #run.jvmargs=-server -Xms512m -Xmx512m -da -Djava.library.path="/home/md/mysql/bin-7.1-opt32/lib/mysql"

=== modified file 'storage/ndb/test/crund/tws/tws_java/nbproject/private_sample/config.properties'
--- a/storage/ndb/test/crund/tws_benchmark/nbproject/private_sample/config.properties	2010-09-29 09:09:26 +0000
+++ b/storage/ndb/test/crund/tws/tws_java/nbproject/private_sample/config.properties	2010-10-19 22:50:53 +0000
@@ -1,2 +1,2 @@
-config=server-opt
+config=server-dbg
 #config=server-dbg

=== added directory 'storage/ndb/test/crund/tws/tws_java/nbproject/private_sample/configs'
=== added file 'storage/ndb/test/crund/tws/tws_java/nbproject/private_sample/configs/server-dbg.properties'
--- a/storage/ndb/test/crund/tws/tws_java/nbproject/private_sample/configs/server-dbg.properties	1970-01-01 00:00:00 +0000
+++ b/storage/ndb/test/crund/tws/tws_java/nbproject/private_sample/configs/server-dbg.properties	2010-10-19 22:50:53 +0000
@@ -0,0 +1 @@
+application.args=-p ../run.properties

=== added file 'storage/ndb/test/crund/tws/tws_java/nbproject/private_sample/configs/server-opt.properties'
--- a/storage/ndb/test/crund/tws/tws_java/nbproject/private_sample/configs/server-opt.properties	1970-01-01 00:00:00 +0000
+++ b/storage/ndb/test/crund/tws/tws_java/nbproject/private_sample/configs/server-opt.properties	2010-10-19 22:50:53 +0000
@@ -0,0 +1 @@
+application.args=-p ../run.properties

=== added directory 'storage/ndb/test/crund/tws/tws_java/src/com'
=== added directory 'storage/ndb/test/crund/tws/tws_java/src/com/mysql'
=== added directory 'storage/ndb/test/crund/tws/tws_java/src/com/mysql/cluster'
=== added directory 'storage/ndb/test/crund/tws/tws_java/src/com/mysql/cluster/benchmark'
=== added directory 'storage/ndb/test/crund/tws/tws_java/src/com/mysql/cluster/benchmark/tws'
=== added file 'storage/ndb/test/crund/tws/tws_java/src/com/mysql/cluster/benchmark/tws/ClusterjLoad.java'
--- a/storage/ndb/test/crund/tws/tws_java/src/com/mysql/cluster/benchmark/tws/ClusterjLoad.java	1970-01-01 00:00:00 +0000
+++ b/storage/ndb/test/crund/tws/tws_java/src/com/mysql/cluster/benchmark/tws/ClusterjLoad.java	2010-10-19 22:50:53 +0000
@@ -0,0 +1,386 @@
+/* -*- mode: java; 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
+ */
+
+package com.mysql.cluster.benchmark.tws;
+
+import com.mysql.clusterj.ClusterJHelper;
+import com.mysql.clusterj.SessionFactory;
+import com.mysql.clusterj.Session;
+import com.mysql.clusterj.LockMode;
+import com.mysql.clusterj.Constants;
+import com.mysql.clusterj.annotation.Index;
+import com.mysql.clusterj.annotation.PersistenceCapable;
+import com.mysql.clusterj.annotation.PrimaryKey;
+
+import java.util.Map;
+import java.util.Iterator;
+
+
+class ClusterjLoad extends TwsLoad {
+
+    // ClusterJ resources
+    protected SessionFactory sessionFactory;
+    protected Session session;
+
+    public ClusterjLoad(TwsDriver driver) {
+        super(driver);
+    }
+
+    // ----------------------------------------------------------------------
+    // ClusterJ intializers/finalizers
+    // ----------------------------------------------------------------------
+
+    protected void initProperties() {
+        out.println();
+        out.print("setting clusterj properties ...");
+
+        final StringBuilder msg = new StringBuilder();
+        final String eol = System.getProperty("line.separator");
+
+        // check required properties
+        String mgmdConnect
+            = driver.props.getProperty(Constants.PROPERTY_CLUSTER_CONNECTSTRING);
+
+        if (msg.length() == 0) {
+            out.println(" [ok]");
+        } else {
+            out.println();
+            out.print(msg.toString());
+        }
+
+        // have mgmdConnect initialized first
+        descr = "clusterj(" + mgmdConnect + ")";
+    }
+
+    protected void printProperties() {
+        for (Iterator<Map.Entry<Object,Object>> i
+                 = driver.props.entrySet().iterator(); i.hasNext();) {
+            Map.Entry<Object,Object> e = i.next();
+            final String k = (String)e.getKey();
+            if (k.startsWith("com.mysql.clusterj")) {
+                final StringBuilder s = new StringBuilder("..");
+                s.append(k, 18, k.length());
+                while (s.length() < 31) s.append(' ');
+                out.println(s + " " + e.getValue());
+            }
+        }
+    }
+
+    public void init() throws Exception {
+        super.init();
+        assert (sessionFactory == null);
+
+        // load native library (better diagnostics doing it explicitely)
+        //loadSystemLibrary("ndbclient");
+
+        out.print("creating SessionFactory ...");
+        out.flush();
+        sessionFactory = ClusterJHelper.getSessionFactory(driver.props);
+        out.println("     [ok]");
+    }
+
+    public void close() throws Exception {
+        assert (sessionFactory != null);
+
+        out.println();
+        out.print("closing SessionFactory ...");
+        out.flush();
+        sessionFactory.close();
+        sessionFactory = null;
+        out.println("      [ok]");
+
+        super.close();
+    }
+
+    // ----------------------------------------------------------------------
+    // ClusterJ datastore operations
+    // ----------------------------------------------------------------------
+
+    public void initConnection() {
+        assert (sessionFactory != null);
+        assert (session == null);
+
+        out.println();
+        out.println("initializing clusterj resources ...");
+
+        out.print("starting clusterj session ...");
+        out.flush();
+        session = sessionFactory.getSession();
+        out.println("   [ok]");
+
+        out.print("setting session lock mode ...");
+        session.setLockMode(driver.lockMode);
+        out.println("   [ok: " + driver.lockMode + "]");
+    }
+
+    public void closeConnection() {
+        assert (session != null);
+
+        out.println();
+        out.println("releasing clusterj resources ...");
+
+        out.print("closing clusterj session ...");
+        out.flush();
+        session.close();
+        session = null;
+        out.println("    [ok]");
+    }
+
+    // ----------------------------------------------------------------------
+
+    public void runOperations() {
+        out.println();
+        out.println("running ClusterJ operations ..."
+                    + " [nRows=" + driver.nRows + "]");
+
+        if (driver.doSingle) {
+            if (driver.doInsert) runClusterjInsert(TwsDriver.XMode.SINGLE);
+            if (driver.doLookup) runClusterjLookup(TwsDriver.XMode.SINGLE);
+            if (driver.doUpdate) runClusterjUpdate(TwsDriver.XMode.SINGLE);
+            if (driver.doDelete) runClusterjDelete(TwsDriver.XMode.SINGLE);
+        }
+        if (driver.doBulk) {
+            if (driver.doInsert) runClusterjInsert(TwsDriver.XMode.BULK);
+            if (driver.doLookup) runClusterjLookup(TwsDriver.XMode.BULK);
+            if (driver.doUpdate) runClusterjUpdate(TwsDriver.XMode.BULK);
+            if (driver.doDelete) runClusterjDelete(TwsDriver.XMode.BULK);
+        }
+        if (driver.doBatch) {
+            if (driver.doInsert) runClusterjInsert(TwsDriver.XMode.BATCH);
+            //if (driver.doLookup) runClusterjLookup(TwsDriver.XMode.BATCH);
+            if (driver.doUpdate) runClusterjUpdate(TwsDriver.XMode.BATCH);
+            if (driver.doDelete) runClusterjDelete(TwsDriver.XMode.BATCH);
+        }
+    }
+
+    // ----------------------------------------------------------------------
+
+    protected void runClusterjInsert(TwsDriver.XMode mode) {
+        final String name = "insert_" + mode.toString().toLowerCase();
+        driver.begin(name);
+
+        if (mode != TwsDriver.XMode.SINGLE)
+            session.currentTransaction().begin();
+        for(int i = 0; i < driver.nRows; i++) {
+            clusterjInsert(i);
+            if (mode == TwsDriver.XMode.BULK)
+                session.flush();
+        }
+        if (mode != TwsDriver.XMode.SINGLE)
+            session.currentTransaction().commit();
+
+        driver.finish(name);
+    }
+
+    protected void clusterjInsert(int c0) {
+        final CJSubscriber o = session.newInstance(CJSubscriber.class);
+        final int i = c0;
+        final String str = Integer.toString(i);
+        //final String oneChar = Integer.toString(1);
+        o.setC0(str);
+        o.setC1(str);
+        o.setC2(i);
+        o.setC3(i);
+        //o.setC4(i);
+        o.setC5(str);
+        o.setC6(str);
+        o.setC7(str);
+        o.setC8(str);
+        //o.setC9(oneChar);
+        //o.setC10(oneChar);
+        //o.setC11(str);
+        //o.setC12(str);
+        //o.setC13(oneChar);
+        //o.setC14(str);
+        session.persist(o);
+    }
+
+    // ----------------------------------------------------------------------
+
+    protected void runClusterjLookup(TwsDriver.XMode mode) {
+        assert(mode != TwsDriver.XMode.BATCH);
+
+        final String name = "lookup_" + mode.toString().toLowerCase();
+        driver.begin(name);
+
+        if (mode != TwsDriver.XMode.SINGLE)
+            session.currentTransaction().begin();
+        for(int i = 0; i < driver.nRows; i++) {
+            clusterjLookup(i);
+        }
+        if (mode != TwsDriver.XMode.SINGLE)
+            session.currentTransaction().commit();
+
+        driver.finish(name);
+    }
+
+    protected void clusterjLookup(int c0) {
+        final CJSubscriber o
+            = session.find(CJSubscriber.class, Integer.toString(c0));
+        if (o != null) {
+            // not verifying at this time
+            String ac0 = o.getC0();
+            String c1 = o.getC1();
+            int c2 = o.getC2();
+            int c3 = o.getC3();
+            int c4 = o.getC4();
+            String c5 = o.getC5();
+            String c6 = o.getC6();
+            String c7 = o.getC7();
+            String c8 = o.getC8();
+            String c9 = o.getC9();
+            String c10 = o.getC10();
+            String c11 = o.getC11();
+            String c12 = o.getC12();
+            String c13 = o.getC13();
+            String c14 = o.getC14();
+        }
+    }
+
+    // ----------------------------------------------------------------------
+
+    protected void runClusterjUpdate(TwsDriver.XMode mode) {
+        final String name = "update_" + mode.toString().toLowerCase();
+        driver.begin(name);
+
+        if (mode != TwsDriver.XMode.SINGLE)
+            session.currentTransaction().begin();
+        for(int i = 0; i < driver.nRows; i++) {
+            clusterjUpdate(i);
+            if (mode == TwsDriver.XMode.BULK)
+                session.flush();
+        }
+        if (mode != TwsDriver.XMode.SINGLE)
+            session.currentTransaction().commit();
+
+        driver.finish(name);
+    }
+
+    protected void clusterjUpdate(int c0) {
+        final String str0 = Integer.toString(c0);
+        final int r = -c0;
+        final String str1 = Integer.toString(r);
+
+        // blind update
+        final CJSubscriber o = session.newInstance(CJSubscriber.class);
+        o.setC0(str0);
+        //final CJSubscriber o = session.find(CJSubscriber.class, str0);
+        //String oneChar = Integer.toString(2);
+        o.setC1(str1);
+        o.setC2(r);
+        o.setC3(r);
+        //o.setC4(r);
+        o.setC5(str1);
+        o.setC6(str1);
+        o.setC7(str1);
+        o.setC8(str1);
+        //o.setC9(oneChar);
+        //o.setC10(oneChar);
+        //o.setC11(str);
+        //o.setC12(str);
+        //o.setC13(oneChar);
+        //o.setC14(str);
+        session.updatePersistent(o);
+    }
+
+    // ----------------------------------------------------------------------
+
+    protected void runClusterjDelete(TwsDriver.XMode mode) {
+        final String name = "delete_" + mode.toString().toLowerCase();
+        driver.begin(name);
+
+        if (mode != TwsDriver.XMode.SINGLE)
+            session.currentTransaction().begin();
+        for(int i = 0; i < driver.nRows; i++) {
+            clusterjDelete(i);
+            if (mode == TwsDriver.XMode.BULK)
+                session.flush();
+        }
+        if (mode != TwsDriver.XMode.SINGLE)
+            session.currentTransaction().commit();
+
+        driver.finish(name);
+    }
+
+    protected void clusterjDelete(int c0) {
+        // XXX use new API for blind delete
+        final CJSubscriber o = session.newInstance(CJSubscriber.class);
+        o.setC0(Integer.toString(c0));
+        assert o != null;
+        session.remove(o);
+    }
+
+    // ----------------------------------------------------------------------
+
+    @PersistenceCapable(table="mytable")
+    //@Index(name="c0_UNIQUE")
+    static public interface CJSubscriber {
+        @PrimaryKey
+        String getC0();
+        void setC0(String c0);
+
+        @Index(name="c1_UNIQUE")
+        String getC1();
+        void setC1(String c1);
+
+        @Index(name="c2_UNIQUE")
+        int getC2();
+        void setC2(int c2);
+
+        int getC3();
+        void setC3(int c3);
+
+        int getC4();
+        void setC4(int c4);
+
+        String getC5();
+        void setC5(String c5);
+
+        String getC6();
+        void setC6(String c6);
+
+        @Index(name="c7_UNIQUE")
+        String getC7();
+        void setC7(String c7);
+
+        @Index(name="c8_UNIQUE")
+        String getC8();
+        void setC8(String c8);
+
+        String getC9();
+        void setC9(String c9);
+
+        String getC10();
+        void setC10(String c10);
+
+        String getC11();
+        void setC11(String c11);
+
+        String getC12();
+        void setC12(String c12);
+
+        String getC13();
+        void setC13(String c13);
+
+        String getC14();
+        void setC14(String c14);
+    }
+
+}

=== added file 'storage/ndb/test/crund/tws/tws_java/src/com/mysql/cluster/benchmark/tws/Driver.java'
--- a/storage/ndb/test/crund/tws/tws_java/src/com/mysql/cluster/benchmark/tws/Driver.java	1970-01-01 00:00:00 +0000
+++ b/storage/ndb/test/crund/tws/tws_java/src/com/mysql/cluster/benchmark/tws/Driver.java	2010-10-19 22:50:53 +0000
@@ -0,0 +1,405 @@
+/* -*- mode: java; 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
+ */
+
+package com.mysql.cluster.benchmark.tws;
+
+import java.io.PrintWriter;
+import java.io.FileInputStream;
+import java.io.InputStream;
+import java.io.IOException;
+import java.io.FileWriter;
+
+import java.util.Properties;
+import java.util.List;
+import java.util.ArrayList;
+import java.util.Date;
+import java.text.SimpleDateFormat;
+
+
+public abstract class Driver {
+
+    // console
+    static protected final PrintWriter out = new PrintWriter(System.out, true);
+    static protected final PrintWriter err = new PrintWriter(System.err, true);
+
+    // shortcuts
+    static protected final String endl = System.getProperty("line.separator");
+    static protected final Runtime rt = Runtime.getRuntime();
+
+    // driver command-line arguments
+    static private final List<String> propFileNames = new ArrayList<String>();
+    static private String logFileName;
+
+    // driver settings
+    protected final Properties props = new Properties();
+    protected boolean logRealTime;
+    protected boolean logMemUsage;
+    protected boolean includeFullGC;
+    protected int warmupRuns;
+
+    // driver resources
+    protected PrintWriter log;
+    protected boolean logHeader;
+    protected StringBuilder header;
+    protected StringBuilder rtimes;
+    protected StringBuilder musage;
+    protected long t0 = 0, t1 = 0, ta = 0;
+    protected long m0 = 0, m1 = 0, ma = 0;
+
+    // ----------------------------------------------------------------------
+    // driver usage
+    // ----------------------------------------------------------------------
+
+    /**
+     * Prints a command-line usage message and exits.
+     */
+    static protected void exitUsage() {
+        out.println("usage: [options]");
+        out.println("    [-p <file name>]...    a properties file name");
+        out.println("    [-l <file name>]       log file name for data output");
+        out.println("    [-h|--help]            print usage message and exit");
+        out.println();
+        System.exit(1); // return an error code
+    }
+
+    /**
+     * Parses the benchmark's command-line arguments.
+     */
+    static public void parseArguments(String[] args) {
+        for (int i = 0; i < args.length; i++) {
+            final String arg = args[i];
+            if (arg.equals("-p")) {
+                if (i >= args.length) {
+                    exitUsage();
+                }
+                propFileNames.add(args[++i]);
+            } else if (arg.equals("-l")) {
+                if (i >= args.length) {
+                    exitUsage();
+                }
+                logFileName = args[++i];
+            } else if (arg.equals("-h") || arg.equals("--help")) {
+                exitUsage();
+            } else {
+                out.println("unknown option: " + arg);
+                exitUsage();
+            }
+        }
+
+        if (propFileNames.size() == 0) {
+            propFileNames.add("run.properties");
+        }
+
+        if (logFileName == null) {
+            SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd_HHMMss");
+            logFileName = ("log_" + sdf.format(new Date()) + ".txt");
+        }
+    }
+
+    /**
+     * Creates an instance.
+     */
+    public Driver() {}
+
+    /**
+     * Runs the benchmark.
+     */
+    public void run() {
+        try {
+            init();
+
+            if (warmupRuns > 0) {
+                out.println();
+                out.println("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++");
+                out.println("warmup runs ...");
+                out.println("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++");
+
+                for (int i = 0; i < warmupRuns; i++) {
+                    runTests();
+                }
+
+                // truncate log file, reset log buffers
+                closeLogFile();
+                openLogFile();
+                clearLogBuffers();
+            }
+
+            out.println();
+            out.println("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++");
+            out.println("hot runs ...");
+            out.println("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++");
+            runTests();
+
+            out.println();
+            out.println("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++");
+            close();
+        } catch (Exception ex) {
+            // end the program regardless of threads
+            out.println("caught " + ex);
+            ex.printStackTrace();
+            System.exit(2); // return an error code
+        }
+    }
+
+    // ----------------------------------------------------------------------
+    // driver intializers/finalizers
+    // ----------------------------------------------------------------------
+
+    // loads a dynamically linked system library and reports any failures
+    static protected void loadSystemLibrary(String name) {
+        out.print("loading libary ...");
+        out.flush();
+        try {
+            System.loadLibrary(name);
+        } catch (UnsatisfiedLinkError e) {
+            String path;
+            try {
+                path = System.getProperty("java.library.path");
+            } catch (Exception ex) {
+                path = "<exception caught: " + ex.getMessage() + ">";
+            }
+            err.println("NdbBase: failed loading library '"
+                        + name + "'; java.library.path='" + path + "'");
+            throw e;
+        } catch (SecurityException e) {
+            err.println("NdbBase: failed loading library '"
+                        + name + "'; caught exception: " + e);
+            throw e;
+        }
+        out.println("              [" + name + "]");
+    }
+
+    // attempts to run the JVM's Garbage Collector
+    static private void gc() {
+        // empirically determined limit after which no further
+        // reduction in memory usage has been observed
+        //final int nFullGCs = 5;
+        final int nFullGCs = 10;
+        for (int i = 0; i < nFullGCs; i++) {
+            //out.print("gc: ");
+            long oldfree;
+            long newfree = rt.freeMemory();
+            do {
+                oldfree = newfree;
+                rt.runFinalization();
+                rt.gc();
+                newfree = rt.freeMemory();
+                //out.print('.');
+            } while (newfree > oldfree);
+            //out.println();
+        }
+    }
+
+    // initializes the driver's resources.
+    protected void init() throws Exception {
+        loadProperties();
+        initProperties();
+        printProperties();
+        openLogFile();
+        clearLogBuffers();
+    }
+
+    // releases the driver's resources.
+    protected void close() throws Exception {
+        out.println();
+
+        // release log buffers
+        logHeader = false;
+        header = null;
+        rtimes = null;
+        musage = null;
+
+        closeLogFile();
+        props.clear();
+    }
+
+    // loads the benchmark's properties from properties files
+    private void loadProperties() throws IOException {
+        out.println();
+        for (String fn : propFileNames) {
+            out.println("reading properties file:        " + fn);
+            InputStream is = null;
+            try {
+                is = new FileInputStream(fn);
+                props.load(is);
+            } finally {
+                if (is != null)
+                    is.close();
+            }
+        }
+    }
+
+    // retrieves a property's value and parses it as a boolean
+    protected boolean parseBoolean(String k, boolean vdefault) {
+        final String v = props.getProperty(k);
+        return (v == null ? vdefault : Boolean.parseBoolean(v));
+    }
+
+    // retrieves a property's value and parses it as a signed decimal integer
+    protected int parseInt(String k, int vdefault) {
+        final String v = props.getProperty(k);
+        try {
+            return (v == null ? vdefault : Integer.parseInt(v));
+        } catch (NumberFormatException e) {
+            final NumberFormatException nfe = new NumberFormatException(
+                "invalid value of benchmark property ('" + k + "', '"
+                + v + "').");
+            nfe.initCause(e);
+            throw nfe;
+        }
+    }
+
+    // initializes the benchmark properties
+    protected void initProperties() {
+        //props.list(out);
+        out.print("setting driver properties ...");
+        out.flush();
+
+        final StringBuilder msg = new StringBuilder();
+        final String eol = System.getProperty("line.separator");
+
+        logRealTime = parseBoolean("logRealTime", true);
+        logMemUsage = parseBoolean("logMemUsage", false);
+        includeFullGC = parseBoolean("includeFullGC", false);
+
+        warmupRuns = parseInt("warmupRuns", 0);
+        if (warmupRuns < 0) {
+            msg.append("[ignored] warmupRuns:           " + warmupRuns + eol);
+            warmupRuns = 0;
+        }
+
+        if (msg.length() == 0) {
+            out.println("   [ok]");
+        } else {
+            out.println();
+            out.print(msg.toString());
+        }
+    }
+
+    // prints the benchmark's properties
+    protected void printProperties() {
+        out.println();
+        out.println("driver settings ...");
+        out.println("logRealTime:                    " + logRealTime);
+        out.println("logMemUsage:                    " + logMemUsage);
+        out.println("includeFullGC:                  " + includeFullGC);
+        out.println("warmupRuns:                     " + warmupRuns);
+    }
+
+    // opens the benchmark's data log file
+    private void openLogFile() throws IOException {
+        out.println();
+        out.println("writing results to file:        " + logFileName);
+        log = new PrintWriter(new FileWriter(logFileName, false));
+    }
+
+    // closes the benchmark's data log file
+    private void closeLogFile() throws IOException {
+        out.print("closing files ...");
+        out.flush();
+        if (log != null) {
+            log.close();
+            log = null;
+        }
+        out.println("               [ok]");
+    }
+
+    // ----------------------------------------------------------------------
+    // benchmark operations
+    // ----------------------------------------------------------------------
+
+    abstract protected void runTests() throws Exception;
+
+    protected void clearLogBuffers() {
+        logHeader = true;
+        header = new StringBuilder();
+        if (logRealTime) {
+            rtimes = new StringBuilder();
+        }
+        if (logMemUsage) {
+            musage = new StringBuilder();
+        }
+    }
+    
+    protected void writeLogBuffers(String descr) {
+        if (logRealTime) {
+            log.println(descr + ", rtime[ms]"
+                        + header.toString() + endl
+                        + rtimes.toString() + endl);
+        }
+        if (logMemUsage) {
+            log.println(descr + ", net musage[KiB]"
+                        + header.toString() + endl
+                        + musage.toString() + endl);
+        }
+    }
+    
+    protected void begin(String name) {
+        out.println();
+        out.println(name);
+
+        // attempt max GC, before tx
+        gc();
+
+        if (logMemUsage) {
+            m0 = rt.totalMemory() - rt.freeMemory();
+        }
+
+        if (logRealTime) {
+            //t0 = System.currentTimeMillis();
+            t0 = System.nanoTime() / 1000000;
+        }
+    }
+
+    protected void finish(String name) {
+        // attempt one full GC, before timing tx end
+        if (includeFullGC) {
+            rt.gc();
+        }
+
+        if (logRealTime) {
+            //t1 = System.currentTimeMillis();
+            t1 = System.nanoTime() / 1000000;
+            final long t = t1 - t0;
+            out.println("tx real time                    " + t
+                        + "\tms");
+            //rtimes.append("\t" + (Math.round(t / 100.0) / 10.0));
+            rtimes.append("\t" + t);
+            ta += t;
+        }
+
+        if (logMemUsage) {
+            // attempt max GC, after tx
+            gc();
+            m1 = rt.totalMemory() - rt.freeMemory();
+            final long m0K = (m0 / 1024);
+            final long m1K = (m1 / 1024);
+            final long mK = m1K - m0K;
+            out.println("net mem usage                   "
+                        + (mK >= 0 ? "+" : "") + mK
+                        + "\tKiB [" + m0K + "K->" + m1K + "K]");
+            musage.append("\t" + mK);
+            ma += mK;
+        }
+
+        if (logHeader)
+            header.append("\t" + name);
+    }
+}

=== added file 'storage/ndb/test/crund/tws/tws_java/src/com/mysql/cluster/benchmark/tws/JdbcLoad.java'
--- a/storage/ndb/test/crund/tws/tws_java/src/com/mysql/cluster/benchmark/tws/JdbcLoad.java	1970-01-01 00:00:00 +0000
+++ b/storage/ndb/test/crund/tws/tws_java/src/com/mysql/cluster/benchmark/tws/JdbcLoad.java	2010-10-19 22:50:53 +0000
@@ -0,0 +1,462 @@
+/* -*- mode: java; 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
+ */
+
+package com.mysql.cluster.benchmark.tws;
+
+import java.sql.Connection;
+import java.sql.DriverManager;
+import java.sql.SQLException;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+
+class JdbcLoad extends TwsLoad {
+
+    // JDBC settings
+    protected String jdbcDriver;
+    protected String url;
+    protected String username;
+    protected String password;
+
+    // JDBC resources
+    protected Class jdbcDriverClass;
+    protected Connection connection;
+    protected PreparedStatement ins0;
+    protected PreparedStatement sel0;
+    protected PreparedStatement upd0;
+    protected PreparedStatement del0;
+    protected PreparedStatement delAll;
+
+    public JdbcLoad(TwsDriver driver) {
+        super(driver);
+    }
+
+    // ----------------------------------------------------------------------
+    // JDBC intializers/finalizers
+    // ----------------------------------------------------------------------
+
+    protected void initProperties() {
+        out.println();
+        out.print("setting jdbc properties ...");
+
+        final StringBuilder msg = new StringBuilder();
+        final String eol = System.getProperty("line.separator");
+
+        // load the JDBC driver class
+        jdbcDriver = driver.props.getProperty("jdbc.driver");
+        if (jdbcDriver == null) {
+            throw new RuntimeException("Missing property: jdbc.driver");
+        }
+        try {
+            Class.forName(jdbcDriver);
+        } catch (ClassNotFoundException e) {
+            out.println("Cannot load JDBC driver '" + jdbcDriver
+                        + "' from classpath '"
+                        + System.getProperty("java.class.path") + "'");
+            throw new RuntimeException(e);
+        }
+
+        url = driver.props.getProperty("jdbc.url");
+        if (url == null) {
+            throw new RuntimeException("Missing property: jdbc.url");
+        }
+
+        username = driver.props.getProperty("jdbc.user");
+        password = driver.props.getProperty("jdbc.password");
+
+        if (msg.length() == 0) {
+            out.println("     [ok]");
+        } else {
+            out.println();
+            out.print(msg.toString());
+        }
+
+        // have url initialized first
+        descr = "jdbc(" + url + ")";
+     }
+
+    protected void printProperties() {
+        out.println("jdbc.driver:                    " + jdbcDriver);
+        out.println("jdbc.url:                       " + url);
+        out.println("jdbc.user:                      \"" + username + "\"");
+        out.println("jdbc.password:                  \"" + password + "\"");
+    }
+
+    public void init() throws Exception {
+        super.init();
+        assert (jdbcDriverClass == null);
+
+        // load the JDBC driver class
+        out.print("loading jdbc driver ...");
+        out.flush();
+        try {
+            jdbcDriverClass = Class.forName(jdbcDriver);
+        } catch (ClassNotFoundException e) {
+            out.println("Cannot load JDBC driver '" + jdbcDriver
+                        + "' from classpath '"
+                        + System.getProperty("java.class.path") + "'");
+            throw new RuntimeException(e);
+        }
+        out.println("         [ok: " + jdbcDriverClass.getName() + "]");
+    }
+
+    public void close() throws Exception {
+        assert (jdbcDriverClass != null);
+
+        //out.println();
+        jdbcDriverClass = null;
+
+        super.close();
+    }
+
+    // ----------------------------------------------------------------------
+    // JDBC datastore operations
+    // ----------------------------------------------------------------------
+
+    public void initConnection() throws SQLException {
+        assert (jdbcDriverClass != null);
+        assert (connection == null);
+
+        out.println();
+        out.println("initializing jdbc resources ...");
+
+        // create a connection to the database
+        out.print("starting jdbc connection ...");
+        out.flush();
+        try {
+            connection = DriverManager.getConnection(url, username, password);
+        } catch (SQLException e) {
+            out.println("Cannot connect to database '" + url + "'");
+            throw new RuntimeException(e);
+        }
+        out.println("    [ok: " + url + "]");
+
+        out.print("setting isolation level ...");
+        out.flush();
+        // ndb storage engine only supports READ_COMMITTED
+        final int il = Connection.TRANSACTION_READ_COMMITTED;
+        connection.setTransactionIsolation(il);
+        out.print("     [ok: ");
+        switch (connection.getTransactionIsolation()) {
+        case Connection.TRANSACTION_READ_UNCOMMITTED:
+            out.print("READ_UNCOMMITTED");
+            break;
+        case Connection.TRANSACTION_READ_COMMITTED:
+            out.print("READ_COMMITTED");
+            break;
+        case Connection.TRANSACTION_REPEATABLE_READ:
+            out.print("REPEATABLE_READ");
+            break;
+        case Connection.TRANSACTION_SERIALIZABLE:
+            out.print("SERIALIZABLE");
+            break;
+        default:
+            assert false;
+        }
+        out.println("]");
+
+        initPreparedStatements();
+    }
+
+    public void closeConnection() throws SQLException {
+        assert (connection != null);
+
+        out.println();
+        out.println("releasing jdbc resources ...");
+
+        closePreparedStatements();
+
+        out.print("closing jdbc connection ...");
+        out.flush();
+        connection.close();
+        connection = null;
+        out.println("     [ok]");
+    }
+
+    public void initPreparedStatements() throws SQLException {
+        assert (connection != null);
+        assert (ins0 == null);
+        assert (sel0 == null);
+        assert (upd0 == null);
+        assert (del0 == null);
+
+        out.print("using lock mode for reads ...");
+        out.flush();
+        final String lm;
+        switch (driver.lockMode) {
+        case READ_COMMITTED:
+            lm = "";
+            break;
+        case SHARED:
+            lm = " LOCK IN share mode";
+            break;
+        case EXCLUSIVE:
+            lm = " FOR UPDATE";
+            break;
+        default:
+            lm = "";
+            assert false;
+        }
+        out.println("   [ok: " + "SELECT" + lm + ";]");
+
+        out.print("compiling jdbc statements ...");
+        out.flush();
+
+        final String sqlIns0 = "INSERT INTO mytable (c0, c1, c2, c3, c5, c6, c7, c8) VALUES (?, ?, ?, ?, ?, ?, ?, ?)";
+        ins0 = connection.prepareStatement(sqlIns0);
+
+        final String sqlSel0 = ("SELECT * FROM mytable where c0=?" + lm);
+        sel0 = connection.prepareStatement(sqlSel0);
+
+        final String sqlUpd0 = "UPDATE mytable SET c1 = ?, c2 = ?, c3 = ?, c5 = ?, c6 = ?, c7 = ?, c8 = ? WHERE c0=?";
+        upd0 = connection.prepareStatement(sqlUpd0);
+
+        final String sqlDel0 = "DELETE FROM mytable WHERE c0=?";
+        del0 = connection.prepareStatement(sqlDel0);
+
+        delAll = connection.prepareStatement("DELETE FROM mytable");
+
+        out.println("   [ok]");
+    }
+
+    protected void closePreparedStatements() throws SQLException {
+        assert (ins0 != null);
+        assert (sel0 != null);
+        assert (upd0 != null);
+        assert (del0 != null);
+        assert (delAll != null);
+
+        out.print("closing jdbc statements ...");
+        out.flush();
+
+        ins0.close();
+        ins0 = null;
+
+        sel0.close();
+        sel0 = null;
+
+        upd0.close();
+        upd0 = null;
+
+        del0.close();
+        del0 = null;
+
+        delAll.close();
+        delAll = null;
+
+        out.println("     [ok]");
+    }
+
+    // ----------------------------------------------------------------------
+
+    public void runOperations() throws SQLException {
+        out.println();
+        out.println("running JDBC operations ..."
+                    + "     [nRows=" + driver.nRows + "]");
+
+        if (driver.doSingle) {
+            if (driver.doInsert) runJdbcInsert(TwsDriver.XMode.SINGLE);
+            if (driver.doLookup) runJdbcLookup(TwsDriver.XMode.SINGLE);
+            if (driver.doUpdate) runJdbcUpdate(TwsDriver.XMode.SINGLE);
+            if (driver.doDelete) runJdbcDelete(TwsDriver.XMode.SINGLE);
+        }
+        if (driver.doBulk) {
+            if (driver.doInsert) runJdbcInsert(TwsDriver.XMode.BULK);
+            if (driver.doLookup) runJdbcLookup(TwsDriver.XMode.BULK);
+            if (driver.doUpdate) runJdbcUpdate(TwsDriver.XMode.BULK);
+            if (driver.doDelete) runJdbcDelete(TwsDriver.XMode.BULK);
+        }
+        if (driver.doBatch) {
+            if (driver.doInsert) runJdbcInsert(TwsDriver.XMode.BATCH);
+            //if (driver.doLookup) runJdbcLookup(TwsDriver.XMode.BATCH);
+            if (driver.doUpdate) runJdbcUpdate(TwsDriver.XMode.BATCH);
+            if (driver.doDelete) runJdbcDelete(TwsDriver.XMode.BATCH);
+        }
+    }
+
+    // ----------------------------------------------------------------------
+
+    protected void runJdbcInsert(TwsDriver.XMode mode) throws SQLException {
+        final String name = "insert_" + mode.toString().toLowerCase();
+        driver.begin(name);
+
+        connection.setAutoCommit(mode == TwsDriver.XMode.SINGLE);
+        for(int i = 0; i < driver.nRows; i++) {
+            jdbcInsert(i, mode);
+        }
+        if (mode == TwsDriver.XMode.BATCH)
+            ins0.executeBatch();
+        if (mode != TwsDriver.XMode.SINGLE)
+            connection.commit();
+
+        driver.finish(name);
+    }
+
+    protected void jdbcInsert(int c0, TwsDriver.XMode mode) {
+        // include exception handling as part of jdbc pattern
+        try {
+            final int i = c0;
+            final String str = Integer.toString(i);
+            ins0.setString(1, str); // key
+            ins0.setString(2, str);
+            ins0.setInt(3, i);
+            ins0.setInt(4, i);
+            ins0.setString(5, str);
+            ins0.setString(6, str);
+            ins0.setString(7, str);
+            ins0.setString(8, str);
+            if (mode == TwsDriver.XMode.BATCH) {
+                ins0.addBatch();
+            } else {
+                int cnt = ins0.executeUpdate();
+                assert (cnt == 1);
+            }
+        } catch (SQLException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    // ----------------------------------------------------------------------
+
+    protected void runJdbcLookup(TwsDriver.XMode mode) throws SQLException {
+        assert(mode != TwsDriver.XMode.BATCH);
+
+        final String name = "lookup_" + mode.toString().toLowerCase();
+        driver.begin(name);
+
+        connection.setAutoCommit(mode == TwsDriver.XMode.SINGLE);
+        for(int i = 0; i < driver.nRows; i++) {
+            jdbcLookup(i);
+        }
+        if (mode != TwsDriver.XMode.SINGLE)
+            connection.commit();
+
+        driver.finish(name);
+    }
+
+    protected void jdbcLookup(int c0) {
+        // include exception handling as part of jdbc pattern
+        try {
+            sel0.setString(1, Integer.toString(c0)); // key
+            ResultSet resultSet = sel0.executeQuery();
+
+            if (resultSet.next()) {
+                // not verifying at this time
+                String ac0 = resultSet.getString(1);
+                String c1 = resultSet.getString(2);
+                int c2 = resultSet.getInt(3);
+                int c3 = resultSet.getInt(4);
+                int c4 = resultSet.getInt(5);
+                String c5 = resultSet.getString(6);
+                String c6 = resultSet.getString(7);
+                String c7 = resultSet.getString(8);
+                String c8 = resultSet.getString(9);
+                String c9 = resultSet.getString(10);
+                String c10 = resultSet.getString(11);
+                String c11 = resultSet.getString(12);
+                String c12 = resultSet.getString(13);
+                String c13 = resultSet.getString(14);
+                String c14 = resultSet.getString(15);
+            }
+            assert (!resultSet.next());
+
+            resultSet.close();
+        } catch (SQLException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    // ----------------------------------------------------------------------
+
+    protected void runJdbcUpdate(TwsDriver.XMode mode) throws SQLException {
+        final String name = "update_" + mode.toString().toLowerCase();
+        driver.begin(name);
+
+        connection.setAutoCommit(mode == TwsDriver.XMode.SINGLE);
+        for(int i = 0; i < driver.nRows; i++) {
+            jdbcUpdate(i, mode);
+        }
+        if (mode == TwsDriver.XMode.BATCH)
+            upd0.executeBatch();
+        if (mode != TwsDriver.XMode.SINGLE)
+            connection.commit();
+
+        driver.finish(name);
+    }
+
+    protected void jdbcUpdate(int c0, TwsDriver.XMode mode) {
+        final String str0 = Integer.toString(c0);
+        final int r = -c0;
+        final String str1 = Integer.toString(r);
+
+        // include exception handling as part of jdbc pattern
+        try {
+            upd0.setString(1, str1);
+            upd0.setInt(2, r);
+            upd0.setInt(3, r);
+            upd0.setString(4, str1);
+            upd0.setString(5, str1);
+            upd0.setString(6, str1);
+            upd0.setString(7, str1);
+            upd0.setString(8, str0); // key
+            if (mode == TwsDriver.XMode.BATCH) {
+                upd0.addBatch();
+            } else {
+                int cnt = upd0.executeUpdate();
+                assert (cnt == 1);
+            }
+        } catch (SQLException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    // ----------------------------------------------------------------------
+
+    protected void runJdbcDelete(TwsDriver.XMode mode) throws SQLException {
+        final String name = "delete_" + mode.toString().toLowerCase();
+        driver.begin(name);
+
+        connection.setAutoCommit(mode == TwsDriver.XMode.SINGLE);
+        for(int i = 0; i < driver.nRows; i++) {
+            jdbcDelete(i, mode);
+        }
+        if (mode == TwsDriver.XMode.BATCH)
+            del0.executeBatch();
+        if (mode != TwsDriver.XMode.SINGLE)
+            connection.commit();
+
+        driver.finish(name);
+    }
+
+    protected void jdbcDelete(int c0, TwsDriver.XMode mode) {
+        // include exception handling as part of jdbc pattern
+        try {
+            final String str = Integer.toString(c0);
+            del0.setString(1, str);
+            if (mode == TwsDriver.XMode.BATCH) {
+                del0.addBatch();
+            } else {
+                int cnt = del0.executeUpdate();
+                assert (cnt == 1);
+            }
+        } catch (SQLException e) {
+            throw new RuntimeException(e);
+        }
+    }
+}

=== added file 'storage/ndb/test/crund/tws/tws_java/src/com/mysql/cluster/benchmark/tws/NdbjtieLoad.java'
--- a/storage/ndb/test/crund/tws/tws_java/src/com/mysql/cluster/benchmark/tws/NdbjtieLoad.java	1970-01-01 00:00:00 +0000
+++ b/storage/ndb/test/crund/tws/tws_java/src/com/mysql/cluster/benchmark/tws/NdbjtieLoad.java	2010-10-19 22:50:53 +0000
@@ -0,0 +1,997 @@
+/* -*- mode: java; 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
+ */
+
+package com.mysql.cluster.benchmark.tws;
+
+import com.mysql.ndbjtie.ndbapi.Ndb_cluster_connection;
+import com.mysql.ndbjtie.ndbapi.Ndb;
+import com.mysql.ndbjtie.ndbapi.NdbDictionary.Dictionary;
+import com.mysql.ndbjtie.ndbapi.NdbDictionary.TableConst;
+import com.mysql.ndbjtie.ndbapi.NdbDictionary.Table;
+import com.mysql.ndbjtie.ndbapi.NdbDictionary.ColumnConst;
+import com.mysql.ndbjtie.ndbapi.NdbDictionary.IndexConst;
+import com.mysql.ndbjtie.ndbapi.NdbErrorConst;
+import com.mysql.ndbjtie.ndbapi.NdbError;
+import com.mysql.ndbjtie.ndbapi.NdbTransaction;
+import com.mysql.ndbjtie.ndbapi.NdbOperation;
+import com.mysql.ndbjtie.ndbapi.NdbScanOperation;
+import com.mysql.ndbjtie.ndbapi.NdbRecAttr;
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.nio.CharBuffer;
+import java.nio.IntBuffer;
+import java.nio.charset.Charset;
+import java.nio.charset.CodingErrorAction;
+import java.nio.charset.CharsetEncoder;
+import java.nio.charset.CharsetDecoder;
+import java.nio.charset.CoderResult;
+import java.nio.charset.CharacterCodingException;
+
+
+class NdbjtieLoad extends TwsLoad {
+
+    // NDB settings
+    protected String mgmdConnect;
+    protected String catalog;
+    protected String schema;
+
+    // NDB JTie resources
+    protected Ndb_cluster_connection mgmd;
+    protected Ndb ndb;
+    protected NdbTransaction tx;
+    protected int ndbOpLockMode;
+
+    // NDB JTie metadata resources
+    protected TableConst table_t0;
+    protected ColumnConst column_c0;
+    protected ColumnConst column_c1;
+    protected ColumnConst column_c2;
+    protected ColumnConst column_c3;
+    protected ColumnConst column_c4;
+    protected ColumnConst column_c5;
+    protected ColumnConst column_c6;
+    protected ColumnConst column_c7;
+    protected ColumnConst column_c8;
+    protected ColumnConst column_c9;
+    protected ColumnConst column_c10;
+    protected ColumnConst column_c11;
+    protected ColumnConst column_c12;
+    protected ColumnConst column_c13;
+    protected ColumnConst column_c14;
+    protected int attr_c0;
+    protected int attr_c1;
+    protected int attr_c2;
+    protected int attr_c3;
+    protected int attr_c4;
+    protected int attr_c5;
+    protected int attr_c6;
+    protected int attr_c7;
+    protected int attr_c8;
+    protected int attr_c9;
+    protected int attr_c10;
+    protected int attr_c11;
+    protected int attr_c12;
+    protected int attr_c13;
+    protected int attr_c14;
+    protected int width_c0;
+    protected int width_c1;
+    protected int width_c2;
+    protected int width_c3;
+    protected int width_c4;
+    protected int width_c5;
+    protected int width_c6;
+    protected int width_c7;
+    protected int width_c8;
+    protected int width_c9;
+    protected int width_c10;
+    protected int width_c11;
+    protected int width_c12;
+    protected int width_c13;
+    protected int width_c14;
+    protected int width_row; // sum of {width_c0 .. width_c14}
+
+    // NDB JTie data resources
+    protected ByteBuffer bb;
+
+    // NDB JTie static resources
+    static protected final ByteOrder bo = ByteOrder.nativeOrder();
+    static protected final Charset cs;
+    static protected final CharsetEncoder csEncoder;
+    static protected final CharsetDecoder csDecoder;
+    static {
+        // default charset for mysql is "ISO-8859-1" ("US-ASCII", "UTF-8")
+        cs = Charset.forName("ISO-8859-1");
+        csDecoder = cs.newDecoder();
+        csEncoder = cs.newEncoder();
+
+        // report any unclean transcodings
+        csEncoder
+            .onMalformedInput(CodingErrorAction.REPORT)
+            .onUnmappableCharacter(CodingErrorAction.REPORT);
+        csDecoder
+            .onMalformedInput(CodingErrorAction.REPORT)
+            .onUnmappableCharacter(CodingErrorAction.REPORT);
+    }
+
+    public NdbjtieLoad(TwsDriver driver) {
+        super(driver);
+    }
+
+    // ----------------------------------------------------------------------
+    // NDB Base intializers/finalizers
+    // ----------------------------------------------------------------------
+
+    protected void initProperties() {
+        out.println();
+        out.print("setting ndb properties ...");
+
+        final StringBuilder msg = new StringBuilder();
+        final String eol = System.getProperty("line.separator");
+
+        // the hostname and port number of NDB mgmd
+        mgmdConnect = driver.props.getProperty("ndb.mgmdConnect", "localhost");
+        assert mgmdConnect != null;
+
+        // the database
+        catalog = driver.props.getProperty("ndb.catalog", "crunddb");
+        assert catalog != null;
+
+        // the schema
+        schema = driver.props.getProperty("ndb.schema", "def");
+        assert schema != null;
+
+        if (msg.length() == 0) {
+            out.println("      [ok]");
+        } else {
+            out.println();
+            out.print(msg.toString());
+        }
+
+        // have mgmdConnect initialized first
+        descr = "ndbjtie(" + mgmdConnect + ")";
+    }
+
+    protected void printProperties() {
+        out.println("ndb.mgmdConnect:                \"" + mgmdConnect + "\"");
+        out.println("ndb.catalog:                    \"" + catalog + "\"");
+        out.println("ndb.schema:                     \"" + schema + "\"");
+    }
+
+    public void init() throws Exception {
+        super.init();
+        assert mgmd == null;
+
+        // load native library (better diagnostics doing it explicitely)
+        Driver.loadSystemLibrary("ndbclient");
+
+        // instantiate NDB cluster singleton
+        out.print("creating cluster connection ...");
+        out.flush();
+        mgmd = Ndb_cluster_connection.create(mgmdConnect);
+        assert mgmd != null;
+        out.println(" [ok: mgmd@" + mgmdConnect + "]");
+    }
+
+    public void close() throws Exception {
+        assert mgmd != null;
+
+        out.println();
+        out.print("closing cluster connection ...");
+        out.flush();
+        Ndb_cluster_connection.delete(mgmd);
+        mgmd = null;
+        out.println("  [ok]");
+
+        super.close();
+    }
+
+    // ----------------------------------------------------------------------
+    // NDB JTie datastore operations
+    // ----------------------------------------------------------------------
+
+    public void initConnection() {
+        assert (mgmd != null);
+        assert (ndb == null);
+
+        out.println();
+        out.println("initializing ndbjtie resources ...");
+
+        // connect to cluster management node (ndb_mgmd)
+        out.print("connecting to cluster ...");
+        out.flush();
+        final int retries = 0;        // retries (< 0 = indefinitely)
+        final int delay = 0;          // seconds to wait after retry
+        final int verbose = 1;        // print report of progess
+        // 0 = success, 1 = recoverable error, -1 = non-recoverable error
+        if (mgmd.connect(retries, delay, verbose) != 0) {
+            final String msg = ("mgmd@" + mgmdConnect
+                                + " was not ready within "
+                                + (retries * delay) + "s.");
+            out.println(msg);
+            throw new RuntimeException("!!! " + msg);
+        }
+        out.println("       [ok: " + mgmdConnect + "]");
+
+        // connect to data nodes (ndbds)
+        out.print("waiting for data nodes ...");
+        out.flush();
+        final int initial_wait = 10; // secs to wait until first node detected
+        final int final_wait = 0;    // secs 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) {
+            final String msg = ("data nodes were not ready within "
+                                + (initial_wait + final_wait) + "s.");
+            out.println(msg);
+            throw new RuntimeException(msg);
+        }
+        out.println("      [ok]");
+
+        // connect to database
+        out.print("connecting to database ...");
+        ndb = Ndb.create(mgmd, catalog, schema);
+        final 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(max_no_tx) != 0) {
+            String msg = "Error caught: " + ndb.getNdbError().message();
+            throw new RuntimeException(msg);
+        }
+        out.println("      [ok: " + catalog + "." + schema + "]");
+
+        initNdbjtieModel();
+
+        initNdbjtieBuffers();
+
+        out.print("using lock mode for reads ...");
+        out.flush();
+        final String lm;
+        switch (driver.lockMode) {
+        case READ_COMMITTED:
+            ndbOpLockMode = NdbOperation.LockMode.LM_CommittedRead;
+            lm = "LM_CommittedRead";
+            break;
+        case SHARED:
+            ndbOpLockMode = NdbOperation.LockMode.LM_Read;
+            lm = "LM_Read";
+            break;
+        case EXCLUSIVE:
+            ndbOpLockMode = NdbOperation.LockMode.LM_Exclusive;
+            lm = "LM_Exclusive";
+            break;
+        default:
+            ndbOpLockMode = NdbOperation.LockMode.LM_CommittedRead;
+            lm = "LM_CommittedRead";
+            assert false;
+        }
+        out.println("   [ok: " + lm + "]");
+    }
+
+    public void closeConnection() {
+        assert (ndb != null);
+
+        out.println();
+        out.println("releasing ndbjtie resources ...");
+
+        closeNdbjtieBuffers();
+
+        closeNdbjtieModel();
+
+        out.print("closing database connection ...");
+        out.flush();
+        Ndb.delete(ndb);
+        ndb = null;
+        out.println(" [ok]");
+    }
+
+    protected void initNdbjtieModel() {
+        assert (ndb != null);
+        assert (table_t0 == null);
+        assert (column_c0 == null);
+
+        out.print("caching metadata ...");
+        out.flush();
+
+        final Dictionary dict = ndb.getDictionary();
+
+        if ((table_t0 = dict.getTable("mytable")) == null)
+            throw new RuntimeException(toStr(dict.getNdbError()));
+
+        if ((column_c0 = table_t0.getColumn("c0")) == null)
+            throw new RuntimeException(toStr(dict.getNdbError()));
+        if ((column_c1 = table_t0.getColumn("c1")) == null)
+            throw new RuntimeException(toStr(dict.getNdbError()));
+        if ((column_c2 = table_t0.getColumn("c2")) == null)
+            throw new RuntimeException(toStr(dict.getNdbError()));
+        if ((column_c3 = table_t0.getColumn("c3")) == null)
+            throw new RuntimeException(toStr(dict.getNdbError()));
+        if ((column_c4 = table_t0.getColumn("c4")) == null)
+            throw new RuntimeException(toStr(dict.getNdbError()));
+        if ((column_c5 = table_t0.getColumn("c5")) == null)
+            throw new RuntimeException(toStr(dict.getNdbError()));
+        if ((column_c6 = table_t0.getColumn("c6")) == null)
+            throw new RuntimeException(toStr(dict.getNdbError()));
+        if ((column_c7 = table_t0.getColumn("c7")) == null)
+            throw new RuntimeException(toStr(dict.getNdbError()));
+        if ((column_c8 = table_t0.getColumn("c8")) == null)
+            throw new RuntimeException(toStr(dict.getNdbError()));
+        if ((column_c9 = table_t0.getColumn("c9")) == null)
+            throw new RuntimeException(toStr(dict.getNdbError()));
+        if ((column_c10 = table_t0.getColumn("c10")) == null)
+            throw new RuntimeException(toStr(dict.getNdbError()));
+        if ((column_c11 = table_t0.getColumn("c11")) == null)
+            throw new RuntimeException(toStr(dict.getNdbError()));
+        if ((column_c12 = table_t0.getColumn("c12")) == null)
+            throw new RuntimeException(toStr(dict.getNdbError()));
+        if ((column_c13 = table_t0.getColumn("c13")) == null)
+            throw new RuntimeException(toStr(dict.getNdbError()));
+        if ((column_c14 = table_t0.getColumn("c14")) == null)
+            throw new RuntimeException(toStr(dict.getNdbError()));
+
+        attr_c0 = column_c0.getColumnNo();
+        attr_c1 = column_c1.getColumnNo();
+        attr_c2 = column_c2.getColumnNo();
+        attr_c3 = column_c3.getColumnNo();
+        attr_c4 = column_c4.getColumnNo();
+        attr_c5 = column_c5.getColumnNo();
+        attr_c6 = column_c6.getColumnNo();
+        attr_c7 = column_c7.getColumnNo();
+        attr_c8 = column_c8.getColumnNo();
+        attr_c9 = column_c9.getColumnNo();
+        attr_c10 = column_c10.getColumnNo();
+        attr_c11 = column_c11.getColumnNo();
+        attr_c12 = column_c12.getColumnNo();
+        attr_c13 = column_c13.getColumnNo();
+        attr_c14 = column_c14.getColumnNo();
+
+        width_c0 = ndbjtieColumnWidth(column_c0);
+        width_c1 = ndbjtieColumnWidth(column_c1);
+        width_c2 = ndbjtieColumnWidth(column_c2);
+        width_c3 = ndbjtieColumnWidth(column_c3);
+        width_c4 = ndbjtieColumnWidth(column_c4);
+        width_c5 = ndbjtieColumnWidth(column_c5);
+        width_c6 = ndbjtieColumnWidth(column_c6);
+        width_c7 = ndbjtieColumnWidth(column_c7);
+        width_c8 = ndbjtieColumnWidth(column_c8);
+        width_c9 = ndbjtieColumnWidth(column_c9);
+        width_c10 = ndbjtieColumnWidth(column_c10);
+        width_c11 = ndbjtieColumnWidth(column_c11);
+        width_c12 = ndbjtieColumnWidth(column_c12);
+        width_c13 = ndbjtieColumnWidth(column_c13);
+        width_c14 = ndbjtieColumnWidth(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);
+
+        out.println("            [ok]");
+    }
+
+    protected void closeNdbjtieModel() {
+        assert (ndb != null);
+        assert (table_t0 != null);
+        assert (column_c0 != null);
+
+        out.print("clearing metadata cache...");
+        out.flush();
+
+        column_c14 = null;
+        column_c13 = null;
+        column_c12 = null;
+        column_c11 = null;
+        column_c10 = null;
+        column_c9 = null;
+        column_c8 = null;
+        column_c7 = null;
+        column_c6 = null;
+        column_c5 = null;
+        column_c4 = null;
+        column_c3 = null;
+        column_c2 = null;
+        column_c1 = null;
+        column_c0 = null;
+
+        table_t0 = null;
+
+        out.println("      [ok]");
+    }
+
+    public void initNdbjtieBuffers() {
+        assert (column_c0 != null);
+        assert (bb == null);
+
+        out.print("allocating buffers...");
+        out.flush();
+
+        bb = ByteBuffer.allocateDirect(width_row * driver.nRows);
+
+        // initial order of a byte buffer is always BIG_ENDIAN
+        bb.order(bo);
+
+        out.println("           [ok]");
+    }
+
+    protected void closeNdbjtieBuffers() {
+        assert (column_c0 != null);
+        assert (bb != null);
+
+        out.print("releasing buffers...");
+        out.flush();
+
+        bb = null;
+
+        out.println("            [ok]");
+    }
+
+    static protected String toStr(NdbErrorConst e) {
+        return "NdbError[" + e.code() + "]: " + e.message();
+    }
+
+    static protected int ndbjtieColumnWidth(ColumnConst 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;
+    }
+
+    // ----------------------------------------------------------------------
+
+    public void runOperations() {
+        out.println();
+        out.println("running NDB JTie operations ..."
+                    + " [nRows=" + driver.nRows + "]");
+
+        if (driver.doSingle) {
+            if (driver.doInsert) runNdbjtieInsert(TwsDriver.XMode.SINGLE);
+            if (driver.doLookup) runNdbjtieLookup(TwsDriver.XMode.SINGLE);
+            if (driver.doUpdate) runNdbjtieUpdate(TwsDriver.XMode.SINGLE);
+            if (driver.doDelete) runNdbjtieDelete(TwsDriver.XMode.SINGLE);
+        }
+        if (driver.doBulk) {
+            if (driver.doInsert) runNdbjtieInsert(TwsDriver.XMode.BULK);
+            if (driver.doLookup) runNdbjtieLookup(TwsDriver.XMode.BULK);
+            if (driver.doUpdate) runNdbjtieUpdate(TwsDriver.XMode.BULK);
+            if (driver.doDelete) runNdbjtieDelete(TwsDriver.XMode.BULK);
+        }
+        if (driver.doBatch) {
+            if (driver.doInsert) runNdbjtieInsert(TwsDriver.XMode.BATCH);
+            if (driver.doLookup) runNdbjtieLookup(TwsDriver.XMode.BATCH);
+            if (driver.doUpdate) runNdbjtieUpdate(TwsDriver.XMode.BATCH);
+            if (driver.doDelete) runNdbjtieDelete(TwsDriver.XMode.BATCH);
+        }
+    }
+
+    // ----------------------------------------------------------------------
+
+    protected void runNdbjtieInsert(TwsDriver.XMode mode) {
+        final String name = "insert_" + mode.toString().toLowerCase();
+        driver.begin(name);
+
+        if (mode == TwsDriver.XMode.SINGLE) {
+            for(int i = 0; i < driver.nRows; i++) {
+                ndbjtieBeginTransaction();
+                ndbjtieInsert(i);
+                ndbjtieCommitTransaction();
+                ndbjtieCloseTransaction();
+            }
+        } else {
+            ndbjtieBeginTransaction();
+            for(int i = 0; i < driver.nRows; i++) {
+                ndbjtieInsert(i);
+
+                if (mode == TwsDriver.XMode.BULK)
+                    ndbjtieExecuteTransaction();
+            }
+            ndbjtieCommitTransaction();
+            ndbjtieCloseTransaction();
+        }
+
+        driver.finish(name);
+    }
+
+    protected void ndbjtieInsert(int c0) {
+        // get an insert operation for the table
+        NdbOperation op = tx.getNdbOperation(table_t0);
+        if (op == null)
+            throw new RuntimeException(toStr(tx.getNdbError()));
+        if (op.insertTuple() != 0)
+            throw new RuntimeException(toStr(tx.getNdbError()));
+
+        // include exception handling as part of transcoding pattern
+        final int i = c0;
+        final CharBuffer str = CharBuffer.wrap(Integer.toString(i));
+        try {
+            // set values; key attribute needs to be set first
+            //str.rewind();
+            ndbjtieTranscode(bb, str);
+            if (op.equal(attr_c0, bb) != 0) // key
+                throw new RuntimeException(toStr(tx.getNdbError()));
+            bb.position(bb.position() + width_c0);
+
+            str.rewind();
+            ndbjtieTranscode(bb, str);
+            if (op.setValue(attr_c1, bb) != 0)
+                throw new RuntimeException(toStr(tx.getNdbError()));
+            bb.position(bb.position() + width_c1);
+
+            if (op.setValue(attr_c2, i) != 0)
+                throw new RuntimeException(toStr(tx.getNdbError()));
+
+            if (op.setValue(attr_c3, i) != 0)
+                throw new RuntimeException(toStr(tx.getNdbError()));
+
+            // XXX
+            if (op.setValue(attr_c4, null) != 0)
+                throw new RuntimeException(toStr(tx.getNdbError()));
+
+            str.rewind();
+            ndbjtieTranscode(bb, str);
+            if (op.setValue(attr_c5, bb) != 0)
+                throw new RuntimeException(toStr(tx.getNdbError()));
+            bb.position(bb.position() + width_c5);
+
+            str.rewind();
+            ndbjtieTranscode(bb, str);
+            if (op.setValue(attr_c6, bb) != 0)
+                throw new RuntimeException(toStr(tx.getNdbError()));
+            bb.position(bb.position() + width_c6);
+
+            str.rewind();
+            ndbjtieTranscode(bb, str);
+            if (op.setValue(attr_c7, bb) != 0)
+                throw new RuntimeException(toStr(tx.getNdbError()));
+            bb.position(bb.position() + width_c7);
+
+            str.rewind();
+            ndbjtieTranscode(bb, str);
+            if (op.setValue(attr_c8, bb) != 0)
+                throw new RuntimeException(toStr(tx.getNdbError()));
+            bb.position(bb.position() + width_c8);
+
+            // XXX
+            if (op.setValue(attr_c9, null) != 0)
+                throw new RuntimeException(toStr(tx.getNdbError()));
+
+            if (op.setValue(attr_c10, null) != 0)
+                throw new RuntimeException(toStr(tx.getNdbError()));
+
+            if (op.setValue(attr_c11, null) != 0)
+                throw new RuntimeException(toStr(tx.getNdbError()));
+
+            if (op.setValue(attr_c12, null) != 0)
+                throw new RuntimeException(toStr(tx.getNdbError()));
+
+            if (op.setValue(attr_c13, null) != 0)
+                throw new RuntimeException(toStr(tx.getNdbError()));
+
+            if (op.setValue(attr_c14, null) != 0)
+                throw new RuntimeException(toStr(tx.getNdbError()));
+        } catch (CharacterCodingException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    // ----------------------------------------------------------------------
+
+    protected void runNdbjtieLookup(TwsDriver.XMode mode) {
+        final String name = "lookup_" + mode.toString().toLowerCase();
+        driver.begin(name);
+
+        if (mode == TwsDriver.XMode.SINGLE) {
+            for(int i = 0; i < driver.nRows; i++) {
+                ndbjtieBeginTransaction();
+                ndbjtieLookup(i);
+                ndbjtieCommitTransaction();
+                ndbjtieRead(i);
+                ndbjtieCloseTransaction();
+            }
+        } else {
+            ndbjtieBeginTransaction();
+            for(int i = 0; i < driver.nRows; i++) {
+                ndbjtieLookup(i);
+
+                if (mode == TwsDriver.XMode.BULK)
+                    ndbjtieExecuteTransaction();
+            }
+            ndbjtieCommitTransaction();
+            for(int i = 0; i < driver.nRows; i++) {
+                ndbjtieRead(i);
+            }
+            ndbjtieCloseTransaction();
+        }
+
+        driver.finish(name);
+    }
+
+    protected void ndbjtieLookup(int c0) {
+        // get a lookup operation for the table
+        NdbOperation op = tx.getNdbOperation(table_t0);
+        if (op == null)
+            throw new RuntimeException(toStr(tx.getNdbError()));
+        if (op.readTuple(ndbOpLockMode) != 0)
+            throw new RuntimeException(toStr(tx.getNdbError()));
+
+        int p = bb.position();
+
+        // include exception handling as part of transcoding pattern
+        final CharBuffer str = CharBuffer.wrap(Integer.toString(c0));
+        try {
+            // set values; key attribute needs to be set first
+            //str.rewind();
+            ndbjtieTranscode(bb, str);
+            if (op.equal(attr_c0, bb) != 0) // key
+                throw new RuntimeException(toStr(tx.getNdbError()));
+            bb.position(p += width_c0);
+        } catch (CharacterCodingException e) {
+            throw new RuntimeException(e);
+        }
+
+        // get attributes (not readable until after commit)
+        if (op.getValue(attr_c1, bb) == null)
+            throw new RuntimeException(toStr(tx.getNdbError()));
+        bb.position(p += width_c1);
+        if (op.getValue(attr_c2, bb) == null)
+            throw new RuntimeException(toStr(tx.getNdbError()));
+        bb.position(p += width_c2);
+        if (op.getValue(attr_c3, bb) == null)
+            throw new RuntimeException(toStr(tx.getNdbError()));
+        bb.position(p += width_c3);
+        if (op.getValue(attr_c4, bb) == null)
+            throw new RuntimeException(toStr(tx.getNdbError()));
+        bb.position(p += width_c4);
+        if (op.getValue(attr_c5, bb) == null)
+            throw new RuntimeException(toStr(tx.getNdbError()));
+        bb.position(p += width_c5);
+        if (op.getValue(attr_c6, bb) == null)
+            throw new RuntimeException(toStr(tx.getNdbError()));
+        bb.position(p += width_c6);
+        if (op.getValue(attr_c7, bb) == null)
+            throw new RuntimeException(toStr(tx.getNdbError()));
+        bb.position(p += width_c7);
+        if (op.getValue(attr_c8, bb) == null)
+            throw new RuntimeException(toStr(tx.getNdbError()));
+        bb.position(p += width_c8);
+        if (op.getValue(attr_c9, bb) == null)
+            throw new RuntimeException(toStr(tx.getNdbError()));
+        bb.position(p += width_c9);
+        if (op.getValue(attr_c10, bb) == null)
+            throw new RuntimeException(toStr(tx.getNdbError()));
+        bb.position(p += width_c10);
+        if (op.getValue(attr_c11, bb) == null)
+            throw new RuntimeException(toStr(tx.getNdbError()));
+        bb.position(p += width_c11);
+        if (op.getValue(attr_c12, bb) == null)
+            throw new RuntimeException(toStr(tx.getNdbError()));
+        bb.position(p += width_c12);
+        if (op.getValue(attr_c13, bb) == null)
+            throw new RuntimeException(toStr(tx.getNdbError()));
+        bb.position(p += width_c13);
+        if (op.getValue(attr_c14, bb) == null)
+            throw new RuntimeException(toStr(tx.getNdbError()));
+        bb.position(p += width_c14);
+    }
+
+    protected void ndbjtieRead(int c0) {
+        // include exception handling as part of transcoding pattern
+        //final int i = c0;
+        //final CharBuffer str = CharBuffer.wrap(Integer.toString(i));
+        //assert (str.position() == 0);
+
+        try {
+            int p = bb.position();
+            bb.position(p += width_c0);
+
+            // not verifying at this time
+            // (str.equals(ndbjtieTranscode(bb_c1)));
+            // (i == bb_c2.asIntBuffer().get());
+            //CharBuffer y = ndbjtieTranscode(bb);
+
+            ndbjtieTranscode(bb);
+            bb.position(p += width_c1);
+
+            bb.asIntBuffer().get();
+            bb.position(p += width_c2);
+            bb.asIntBuffer().get();
+            bb.position(p += width_c3);
+            bb.asIntBuffer().get();
+            bb.position(p += width_c4);
+
+            ndbjtieTranscode(bb);
+            bb.position(p += width_c5);
+            ndbjtieTranscode(bb);
+            bb.position(p += width_c6);
+            ndbjtieTranscode(bb);
+            bb.position(p += width_c7);
+            ndbjtieTranscode(bb);
+            bb.position(p += width_c8);
+            ndbjtieTranscode(bb);
+            bb.position(p += width_c9);
+            ndbjtieTranscode(bb);
+            bb.position(p += width_c10);
+            ndbjtieTranscode(bb);
+            bb.position(p += width_c11);
+            ndbjtieTranscode(bb);
+            bb.position(p += width_c12);
+            ndbjtieTranscode(bb);
+            bb.position(p += width_c13);
+            ndbjtieTranscode(bb);
+            bb.position(p += width_c14);
+        } catch (CharacterCodingException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    // ----------------------------------------------------------------------
+
+    protected void runNdbjtieUpdate(TwsDriver.XMode mode) {
+        final String name = "update_" + mode.toString().toLowerCase();
+        driver.begin(name);
+
+        if (mode == TwsDriver.XMode.SINGLE) {
+            for(int i = 0; i < driver.nRows; i++) {
+                ndbjtieBeginTransaction();
+                ndbjtieUpdate(i);
+                ndbjtieCommitTransaction();
+                ndbjtieCloseTransaction();
+            }
+        } else {
+            ndbjtieBeginTransaction();
+            for(int i = 0; i < driver.nRows; i++) {
+                ndbjtieUpdate(i);
+
+                if (mode == TwsDriver.XMode.BULK)
+                    ndbjtieExecuteTransaction();
+            }
+            ndbjtieCommitTransaction();
+            ndbjtieCloseTransaction();
+        }
+
+        driver.finish(name);
+    }
+
+    protected void ndbjtieUpdate(int c0) {
+        final CharBuffer str0 = CharBuffer.wrap(Integer.toString(c0));
+        final int r = -c0;
+        final CharBuffer str1 = CharBuffer.wrap(Integer.toString(r));
+
+        // get an update operation for the table
+        NdbOperation op = tx.getNdbOperation(table_t0);
+        if (op == null)
+            throw new RuntimeException(toStr(tx.getNdbError()));
+        if (op.updateTuple() != 0)
+            throw new RuntimeException(toStr(tx.getNdbError()));
+
+        // include exception handling as part of transcoding pattern
+        try {
+            // set values; key attribute needs to be set first
+            //str0.rewind();
+            ndbjtieTranscode(bb, str0);
+            if (op.equal(attr_c0, bb) != 0) // key
+                throw new RuntimeException(toStr(tx.getNdbError()));
+            bb.position(bb.position() + width_c0);
+
+            //str1.rewind();
+            ndbjtieTranscode(bb, str1);
+            if (op.setValue(attr_c1, bb) != 0)
+                throw new RuntimeException(toStr(tx.getNdbError()));
+            bb.position(bb.position() + width_c1);
+
+            if (op.setValue(attr_c2, r) != 0)
+                throw new RuntimeException(toStr(tx.getNdbError()));
+
+            if (op.setValue(attr_c3, r) != 0)
+                throw new RuntimeException(toStr(tx.getNdbError()));
+
+            str1.rewind();
+            ndbjtieTranscode(bb, str1);
+            if (op.setValue(attr_c5, bb) != 0)
+                throw new RuntimeException(toStr(tx.getNdbError()));
+            bb.position(bb.position() + width_c5);
+
+            str1.rewind();
+            ndbjtieTranscode(bb, str1);
+            if (op.setValue(attr_c6, bb) != 0)
+                throw new RuntimeException(toStr(tx.getNdbError()));
+            bb.position(bb.position() + width_c6);
+
+            str1.rewind();
+            ndbjtieTranscode(bb, str1);
+            if (op.setValue(attr_c7, bb) != 0)
+                throw new RuntimeException(toStr(tx.getNdbError()));
+            bb.position(bb.position() + width_c7);
+
+            str1.rewind();
+            ndbjtieTranscode(bb, str1);
+            if (op.setValue(attr_c8, bb) != 0)
+                throw new RuntimeException(toStr(tx.getNdbError()));
+            bb.position(bb.position() + width_c8);
+        } catch (CharacterCodingException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    // ----------------------------------------------------------------------
+
+    protected void runNdbjtieDelete(TwsDriver.XMode mode) {
+        final String name = "delete_" + mode.toString().toLowerCase();
+        driver.begin(name);
+
+        if (mode == TwsDriver.XMode.SINGLE) {
+            for(int i = 0; i < driver.nRows; i++) {
+                ndbjtieBeginTransaction();
+                ndbjtieDelete(i);
+                ndbjtieCommitTransaction();
+                ndbjtieCloseTransaction();
+            }
+        } else {
+            ndbjtieBeginTransaction();
+            for(int i = 0; i < driver.nRows; i++) {
+                ndbjtieDelete(i);
+
+                if (mode == TwsDriver.XMode.BULK)
+                    ndbjtieExecuteTransaction();
+            }
+            ndbjtieCommitTransaction();
+            ndbjtieCloseTransaction();
+        }
+
+        driver.finish(name);
+    }
+
+    protected void ndbjtieDelete(int c0) {
+        // get a delete operation for the table
+        NdbOperation op = tx.getNdbOperation(table_t0);
+        if (op == null)
+            throw new RuntimeException(toStr(tx.getNdbError()));
+        if (op.deleteTuple() != 0)
+            throw new RuntimeException(toStr(tx.getNdbError()));
+
+        int p = bb.position();
+
+        // include exception handling as part of transcoding pattern
+        final int i = c0;
+        final CharBuffer str = CharBuffer.wrap(Integer.toString(c0));
+        try {
+            // set values; key attribute needs to be set first
+            //str.rewind();
+            ndbjtieTranscode(bb, str);
+            if (op.equal(attr_c0, bb) != 0) // key
+                throw new RuntimeException(toStr(tx.getNdbError()));
+            bb.position(p += width_c0);
+        } catch (CharacterCodingException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    // ----------------------------------------------------------------------
+
+    protected void ndbjtieBeginTransaction() {
+        assert (tx == null);
+
+        // prepare buffer for writing
+        bb.clear();
+
+        // start a transaction
+        // must be closed with NdbTransaction.close
+        final TableConst table  = null;
+        final ByteBuffer keyData = null;
+        final int keyLen = 0;
+        if ((tx = ndb.startTransaction(table, keyData, keyLen)) == null)
+            throw new RuntimeException(toStr(ndb.getNdbError()));
+    }
+
+    protected void ndbjtieExecuteTransaction() {
+        assert (tx != null);
+
+        // execute but don't commit the current transaction
+        final int execType = NdbTransaction.ExecType.NoCommit;
+        final int abortOption = NdbOperation.AbortOption.AbortOnError;
+        final int force = 0;
+        if (tx.execute(execType, abortOption, force) != 0
+            || tx.getNdbError().status() != NdbError.Status.Success)
+            throw new RuntimeException(toStr(tx.getNdbError()));
+    }
+
+    protected void ndbjtieCommitTransaction() {
+        assert (tx != null);
+
+        // commit the current transaction
+        final int execType = NdbTransaction.ExecType.Commit;
+        final int abortOption = NdbOperation.AbortOption.AbortOnError;
+        final int force = 0;
+        if (tx.execute(execType, abortOption, force) != 0
+            || tx.getNdbError().status() != NdbError.Status.Success)
+            throw new RuntimeException(toStr(tx.getNdbError()));
+
+        // prepare buffer for reading
+        bb.rewind();
+    }
+
+    protected void ndbjtieCloseTransaction() {
+        assert (tx != null);
+
+        // close the current transaction (required after commit, rollback)
+        ndb.closeTransaction(tx);
+        tx = null;
+    }
+
+    // ----------------------------------------------------------------------
+
+    protected CharBuffer ndbjtieTranscode(ByteBuffer from)
+        throws CharacterCodingException {
+        // mark position
+        final int p = from.position();
+
+        // read 1-byte length prefix
+        final int l = from.get();
+        assert ((0 <= l) && (l < 256)); // or (l <= 256)?
+
+        // prepare buffer for reading
+        from.limit(from.position() + l);
+
+        // decode
+        final CharBuffer to = csDecoder.decode(from);
+        assert (!from.hasRemaining());
+
+        // allow for repositioning
+        from.limit(from.capacity());
+
+        assert (to.position() == 0);
+        assert (to.limit() == to.capacity());
+        return to;
+    }
+
+    protected void ndbjtieTranscode(ByteBuffer to, CharBuffer from)
+        throws CharacterCodingException {
+        // mark position
+        final int p = to.position();
+
+        // advance 1-byte length prefix
+        to.position(p + 1);
+        //to.put((byte)0);
+
+        // encode
+        final boolean endOfInput = true;
+        final CoderResult cr = csEncoder.encode(from, to, endOfInput);
+        if (!cr.isUnderflow())
+            cr.throwException();
+        assert (!from.hasRemaining());
+
+        // write 1-byte length prefix
+        final int l = (to.position() - p) - 1;
+        assert (0 <= l && l < 256); // or (l <= 256)?
+        to.put(p, (byte)l);
+
+        // reset position
+        to.position(p);
+    }
+}
\ No newline at end of file

=== added file 'storage/ndb/test/crund/tws/tws_java/src/com/mysql/cluster/benchmark/tws/TwsDriver.java'
--- a/storage/ndb/test/crund/tws/tws_java/src/com/mysql/cluster/benchmark/tws/TwsDriver.java	1970-01-01 00:00:00 +0000
+++ b/storage/ndb/test/crund/tws/tws_java/src/com/mysql/cluster/benchmark/tws/TwsDriver.java	2010-10-19 22:50:53 +0000
@@ -0,0 +1,304 @@
+/* -*- mode: java; 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
+ */
+
+package com.mysql.cluster.benchmark.tws;
+
+// reusing this enum from ClusterJ
+import com.mysql.clusterj.LockMode;
+
+
+public class TwsDriver extends Driver {
+
+    // benchmark settings
+    protected boolean renewConnection;
+    protected boolean doJdbc;
+    protected boolean doClusterj;
+    protected boolean doNdbjtie;
+    protected boolean doInsert;
+    protected boolean doLookup;
+    protected boolean doUpdate;
+    protected boolean doDelete;
+    protected boolean doSingle;
+    protected boolean doBulk;
+    protected boolean doBatch;
+    protected LockMode lockMode;
+    protected int nRows;
+    protected int nRuns;
+
+    // benchmark resources
+    protected TwsLoad jdbcLoad;
+    protected TwsLoad clusterjLoad;
+    protected TwsLoad ndbjtieLoad;
+
+    static public void main(String[] args) throws Exception {
+        parseArguments(args);
+        TwsDriver main = new TwsDriver();
+        main.run();
+    }
+
+    // ----------------------------------------------------------------------
+    // benchmark intializers/finalizers
+    // ----------------------------------------------------------------------
+
+    protected void init() throws Exception {
+        super.init();
+
+        if (doJdbc) {
+            assert (jdbcLoad == null);
+            jdbcLoad = new JdbcLoad(this);
+            jdbcLoad.init();
+        }
+        if (doClusterj) {
+            assert (clusterjLoad == null);
+            clusterjLoad = new ClusterjLoad(this);
+            clusterjLoad.init();
+        }
+        if (doNdbjtie) {
+            assert (ndbjtieLoad == null);
+            ndbjtieLoad = new NdbjtieLoad(this);
+            ndbjtieLoad.init();
+        }
+
+        initConnections();
+    }
+
+    protected void close() throws Exception {
+        closeConnections();
+
+        if (doJdbc) {
+            assert (jdbcLoad != null);
+            jdbcLoad.close();
+            jdbcLoad = null;
+        }
+        if (doClusterj) {
+            assert (clusterjLoad != null);
+            clusterjLoad.close();
+            clusterjLoad = null;
+        }
+        if (doNdbjtie) {
+            assert (ndbjtieLoad != null);
+            ndbjtieLoad.close();
+            ndbjtieLoad = null;
+        }
+
+        super.close();
+    }
+
+    protected void initProperties() {
+        super.initProperties();
+
+        out.print("setting tws properties ...");
+
+        final StringBuilder msg = new StringBuilder();
+        final String eol = System.getProperty("line.separator");
+
+        renewConnection = parseBoolean("renewConnection", false);
+        doJdbc = parseBoolean("doJdbc", false);
+        doClusterj = parseBoolean("doClusterj", false);
+        doNdbjtie = parseBoolean("doNdbjtie", false);
+        doInsert = parseBoolean("doInsert", false);
+        doLookup = parseBoolean("doLookup", false);
+        doUpdate = parseBoolean("doUpdate", false);
+        doDelete = parseBoolean("doDelete", false);
+        doSingle = parseBoolean("doSingle", false);
+        doBulk = parseBoolean("doBulk", false);
+        doBatch = parseBoolean("doBatch", false);
+
+        final String lm = props.getProperty("lockMode");
+        try {
+            lockMode = (lm == null
+                        ? LockMode.READ_COMMITTED : LockMode.valueOf(lm));
+        } catch (IllegalArgumentException e) {
+            msg.append("[ignored] lockMode:             " + lm + eol);
+            lockMode = LockMode.READ_COMMITTED;
+        }
+
+        nRows = parseInt("nRows", 256);
+        if (nRows < 1) {
+            msg.append("[ignored] nRows:            '"
+                       + props.getProperty("nRows") + "'" + eol);
+            nRows = 256;
+        }
+
+        nRuns = parseInt("nRuns", 1);
+        if (nRuns < 0) {
+            msg.append("[ignored] nRuns:                " + nRuns + eol);
+            nRuns = 1;
+        }
+
+        if (msg.length() == 0) {
+            out.println("      [ok]");
+        } else {
+            out.println();
+            out.print(msg.toString());
+        }
+    }
+
+    protected void printProperties() {
+        super.printProperties();
+        out.println();
+        out.println("tws settings ...");
+        out.println("renewConnection:                " + renewConnection);
+        out.println("doJdbc:                         " + doJdbc);
+        out.println("doClusterj:                     " + doClusterj);
+        out.println("doNdbjtie:                      " + doNdbjtie);
+        out.println("doInsert:                       " + doInsert);
+        out.println("doLookup:                       " + doLookup);
+        out.println("doUpdate:                       " + doUpdate);
+        out.println("doDelete:                       " + doDelete);
+        out.println("doSingle:                       " + doSingle);
+        out.println("doBulk:                         " + doBulk);
+        out.println("doBatch:                        " + doBatch);
+        out.println("lockMode:                       " + lockMode);
+        out.println("nRows:                          " + nRows);
+        out.println("nRuns:                          " + nRuns);
+    }
+
+    // ----------------------------------------------------------------------
+    // benchmark operations
+    // ----------------------------------------------------------------------
+
+    protected void runTests() throws Exception {
+        //initConnection();
+
+        //assert(rStart <= rEnd && rScale > 1);
+        //for (int i = rStart; i <= rEnd; i *= rScale)
+        runLoads();
+
+        //closeConnection();
+    }
+
+    protected void runLoads() throws Exception {
+        if (doJdbc)
+            runSeries(jdbcLoad);
+        if (doClusterj)
+            runSeries(clusterjLoad);
+        if (doNdbjtie)
+            runSeries(ndbjtieLoad);
+    }
+
+    protected void runSeries(TwsLoad load) throws Exception {
+        if (nRuns == 0)
+            return; // nothing to do
+
+        out.println();
+        out.println("------------------------------------------------------------");
+        out.print("running " + nRuns + " iterations on load: "
+                  + load.getDescriptor());
+
+        for (int i = 0; i < nRuns; i++) {
+            out.println();
+            out.println("------------------------------------------------------------");
+            runOperations(load);
+        }
+
+        writeLogBuffers(load.getDescriptor());
+        clearLogBuffers();
+    }
+    
+    enum XMode { SINGLE, BULK, BATCH }
+
+    protected void runOperations(TwsLoad load) throws Exception {
+        //out.println("running operations ..."
+        //            + "          [nRows=" + nRows + "]");
+
+        // log buffers
+        if (logRealTime) {
+            rtimes.append("nRows=" + nRows);
+            ta = 0;
+        }
+        if (logMemUsage) {
+            musage.append("nRows=" + nRows);
+            ma = 0;
+        }
+
+        // pre-run cleanup
+        if (renewConnection) {
+            load.closeConnection();
+            load.initConnection();
+        }
+        //clearData(); // not used
+
+        load.runOperations();
+
+        out.println();
+        out.println("total");
+        if (logRealTime) {
+            out.println("tx real time                    " + ta
+                        + "\tms");
+        }
+        if (logMemUsage) {
+            out.println("net mem usage                   "
+                        + (ma >= 0 ? "+" : "") + ma
+                        + "\tKiB");
+        }
+
+        // log buffers
+        if (logHeader) {
+            header.append("\ttotal");
+            logHeader = false;
+        }
+        if (logRealTime) {
+            rtimes.append("\t" + ta);
+            rtimes.append(endl);
+        }
+        if (logMemUsage) {
+            musage.append("\t" + ma);
+            musage.append(endl);
+        }
+    }
+
+    // ----------------------------------------------------------------------
+    // datastore operations
+    // ----------------------------------------------------------------------
+
+    protected void initConnections() throws Exception {
+        if (doJdbc) {
+            assert (jdbcLoad != null);
+            jdbcLoad.initConnection();
+        }
+        if (doClusterj) {
+            assert (clusterjLoad != null);
+            clusterjLoad.initConnection();
+        }
+        if (doNdbjtie) {
+            assert (ndbjtieLoad != null);
+            ndbjtieLoad.initConnection();
+        }
+    }
+
+    protected void closeConnections() throws Exception {
+        if (doJdbc) {
+            assert (jdbcLoad != null);
+            jdbcLoad.closeConnection();
+        }
+        if (doClusterj) {
+            assert (clusterjLoad != null);
+            clusterjLoad.closeConnection();
+        }
+        if (doNdbjtie) {
+            assert (ndbjtieLoad != null);
+            ndbjtieLoad.closeConnection();
+        }
+    }
+
+    //abstract protected void clearPersistenceContext() throws Exception;
+    //abstract protected void clearData() throws Exception;
+}

=== added file 'storage/ndb/test/crund/tws/tws_java/src/com/mysql/cluster/benchmark/tws/TwsLoad.java'
--- a/storage/ndb/test/crund/tws/tws_java/src/com/mysql/cluster/benchmark/tws/TwsLoad.java	1970-01-01 00:00:00 +0000
+++ b/storage/ndb/test/crund/tws/tws_java/src/com/mysql/cluster/benchmark/tws/TwsLoad.java	2010-10-19 22:50:53 +0000
@@ -0,0 +1,95 @@
+/* -*- mode: java; 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
+ */
+
+package com.mysql.cluster.benchmark.tws;
+
+import java.io.PrintWriter;
+
+
+abstract class TwsLoad {
+
+    // console
+    static protected final PrintWriter out = TwsDriver.out;
+    static protected final PrintWriter err = TwsDriver.err;
+
+    // resources
+    protected final TwsDriver driver;
+    protected String descr;
+
+    public TwsLoad(TwsDriver driver) {
+        this.driver = driver;
+    }
+
+    // ----------------------------------------------------------------------
+    // intializers/finalizers
+    // ----------------------------------------------------------------------
+
+    abstract protected void initProperties();
+    abstract protected void printProperties();
+
+    public String getDescriptor() {
+        return descr;
+    }
+
+    public void init() throws Exception {
+        initProperties();
+        printProperties();
+    }
+
+    public void close() throws Exception {
+    }
+
+    // ----------------------------------------------------------------------
+    // benchmark operations
+    // ----------------------------------------------------------------------
+
+    abstract public void runOperations() throws Exception;
+
+    // reports an error if a condition is not met
+    static protected final void verify(boolean cond) {
+        //assert (cond);
+        if (!cond)
+            throw new RuntimeException("data verification failed.");
+    }
+
+    static protected final void verify(int exp, int act) {
+        if (exp != act)
+            throw new RuntimeException("data verification failed:"
+                                       + " expected = " + exp
+                                       + ", actual = " + act);
+    }
+
+    static protected final void verify(String exp, String act) {
+        if ((exp == null && act != null)
+            || (exp != null && !exp.equals(act)))
+            throw new RuntimeException("data verification failed:"
+                                       + " expected = '" + exp + "'"
+                                       + ", actual = '" + act + "'");
+    }
+
+    // ----------------------------------------------------------------------
+    // datastore operations
+    // ----------------------------------------------------------------------
+
+    abstract public void initConnection() throws Exception;
+    abstract public void closeConnection() throws Exception;
+    //abstract public void clearPersistenceContext() throws Exception;
+    //abstract public void clearData() throws Exception;
+}

=== removed file 'storage/ndb/test/crund/tws_benchmark/run.properties.sample'
--- a/storage/ndb/test/crund/tws_benchmark/run.properties.sample	2010-10-03 04:32:37 +0000
+++ b/storage/ndb/test/crund/tws_benchmark/run.properties.sample	1970-01-01 00:00:00 +0000
@@ -1,64 +0,0 @@
-# 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
-#   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
-
-#nRuns=10000
-#nRuns=1000
-#nRuns=100
-#nRuns=25
-nRuns=10
-#nRuns=5
-#nRuns=1
-
-# 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

=== removed file 'storage/ndb/test/crund/tws_benchmark/schema.sql'
--- a/storage/ndb/test/crund/tws_benchmark/schema.sql	2010-09-27 05:58:05 +0000
+++ b/storage/ndb/test/crund/tws_benchmark/schema.sql	1970-01-01 00:00:00 +0000
@@ -1,31 +0,0 @@
-SET storage_engine=NDB;
-
-DROP DATABASE IF EXISTS testdb;
-CREATE DATABASE testdb;
--- USE testdb;
-
-DROP TABLE IF EXISTS testdb.mytable;
-
-CREATE  TABLE IF NOT EXISTS testdb.mytable (
-        c0 VARCHAR(9)   NOT NULL,
-        c1 VARCHAR(10)  NOT NULL,
-        c2 INT          NOT NULL,
-        c3 INT          NOT NULL,
-        c4 INT          NULL,
-        c5 VARCHAR(39)  NULL,
-        c6 VARCHAR(39)  NULL,
-        c7 VARCHAR(9)   NOT NULL,
-        c8 VARCHAR(11)  NOT NULL,
-        c9 CHAR         NULL,
-        c10 CHAR        NULL,
-        c11 VARCHAR(7)  NULL,
-        c12 VARCHAR(7)  NULL,
-        c13 CHAR        NULL,
-        c14 VARCHAR(34) NULL,
-        PRIMARY KEY (c0),
-        UNIQUE INDEX c0_UNIQUE USING BTREE (c0 ASC),
-        UNIQUE INDEX c1_UNIQUE USING BTREE (c1 ASC),
-        UNIQUE INDEX c2_UNIQUE (c2 ASC),
-        UNIQUE INDEX c7_UNIQUE (c7 ASC),
-        UNIQUE INDEX c8_UNIQUE (c8 ASC)
-);

=== removed file 'storage/ndb/test/crund/tws_benchmark/src/Main.java'
--- a/storage/ndb/test/crund/tws_benchmark/src/Main.java	2010-10-03 04:52:07 +0000
+++ b/storage/ndb/test/crund/tws_benchmark/src/Main.java	1970-01-01 00:00:00 +0000
@@ -1,1752 +0,0 @@
-/* -*- mode: java; 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
- */
-
-//package com.mysql.cluster.crund.tws;
-
-import com.mysql.clusterj.ClusterJHelper;
-import com.mysql.clusterj.SessionFactory;
-import com.mysql.clusterj.Session;
-import com.mysql.clusterj.LockMode;
-import com.mysql.clusterj.annotation.Index;
-import com.mysql.clusterj.annotation.PersistenceCapable;
-import com.mysql.clusterj.annotation.PrimaryKey;
-
-import com.mysql.ndbjtie.ndbapi.Ndb_cluster_connection;
-import com.mysql.ndbjtie.ndbapi.Ndb;
-import com.mysql.ndbjtie.ndbapi.NdbDictionary.Dictionary;
-import com.mysql.ndbjtie.ndbapi.NdbDictionary.TableConst;
-import com.mysql.ndbjtie.ndbapi.NdbDictionary.Table;
-import com.mysql.ndbjtie.ndbapi.NdbDictionary.ColumnConst;
-import com.mysql.ndbjtie.ndbapi.NdbDictionary.IndexConst;
-import com.mysql.ndbjtie.ndbapi.NdbErrorConst;
-import com.mysql.ndbjtie.ndbapi.NdbError;
-import com.mysql.ndbjtie.ndbapi.NdbTransaction;
-import com.mysql.ndbjtie.ndbapi.NdbOperation;
-import com.mysql.ndbjtie.ndbapi.NdbScanOperation;
-import com.mysql.ndbjtie.ndbapi.NdbRecAttr;
-
-import java.io.PrintWriter;
-import java.io.FileInputStream;
-import java.io.InputStream;
-import java.io.IOException;
-
-import java.nio.ByteBuffer;
-import java.nio.ByteOrder;
-import java.nio.CharBuffer;
-import java.nio.IntBuffer;
-import java.nio.charset.Charset;
-import java.nio.charset.CodingErrorAction;
-import java.nio.charset.CharsetEncoder;
-import java.nio.charset.CharsetDecoder;
-import java.nio.charset.CoderResult;
-import java.nio.charset.CharacterCodingException;
-
-import java.sql.Connection;
-import java.sql.DriverManager;
-import java.sql.SQLException;
-import java.sql.PreparedStatement;
-import java.sql.ResultSet;
-
-import java.util.Properties;
-
-public class Main
-{
-    // console
-    static protected final PrintWriter out = new PrintWriter(System.out, true);
-    static protected final PrintWriter err = new PrintWriter(System.err, true);
-
-    // benchmark settings
-    static protected final String propsFileName  = "run.properties";
-    static protected final Properties props = new Properties();
-    static protected boolean doJdbc;
-    static protected boolean doClusterj;
-    static protected boolean doNdbjtie;
-    static protected boolean doInsert;
-    static protected boolean doLookup;
-    static protected boolean doUpdate;
-    static protected boolean doDelete;
-    static protected boolean doSingle;
-    static protected boolean doBulk;
-    static protected boolean doBatch;
-    static protected LockMode lockMode;
-    static protected int nRows;
-    static protected int nRuns;
-
-    // JDBC resources
-    protected Connection connection;
-    protected PreparedStatement ins0;
-    protected PreparedStatement sel0;
-    protected PreparedStatement upd0;
-    protected PreparedStatement del0;
-
-    // ClusterJ resources
-    protected SessionFactory sessionFactory;
-    protected Session session;
-
-    // NDB JTie resources
-    protected Ndb_cluster_connection mgmd;
-    protected Ndb ndb;
-    protected NdbTransaction tx;
-    protected int ndbOpLockMode;
-
-    // NDB JTie metadata resources
-    protected TableConst table_t0;
-    protected ColumnConst column_c0;
-    protected ColumnConst column_c1;
-    protected ColumnConst column_c2;
-    protected ColumnConst column_c3;
-    protected ColumnConst column_c4;
-    protected ColumnConst column_c5;
-    protected ColumnConst column_c6;
-    protected ColumnConst column_c7;
-    protected ColumnConst column_c8;
-    protected ColumnConst column_c9;
-    protected ColumnConst column_c10;
-    protected ColumnConst column_c11;
-    protected ColumnConst column_c12;
-    protected ColumnConst column_c13;
-    protected ColumnConst column_c14;
-    protected int attr_c0;
-    protected int attr_c1;
-    protected int attr_c2;
-    protected int attr_c3;
-    protected int attr_c4;
-    protected int attr_c5;
-    protected int attr_c6;
-    protected int attr_c7;
-    protected int attr_c8;
-    protected int attr_c9;
-    protected int attr_c10;
-    protected int attr_c11;
-    protected int attr_c12;
-    protected int attr_c13;
-    protected int attr_c14;
-    protected int width_c0;
-    protected int width_c1;
-    protected int width_c2;
-    protected int width_c3;
-    protected int width_c4;
-    protected int width_c5;
-    protected int width_c6;
-    protected int width_c7;
-    protected int width_c8;
-    protected int width_c9;
-    protected int width_c10;
-    protected int width_c11;
-    protected int width_c12;
-    protected int width_c13;
-    protected int width_c14;
-
-    // NDB JTie data resources
-    protected ByteBuffer bb_r;
-
-    // NDB JTie static resources
-    static protected final ByteOrder bo = ByteOrder.nativeOrder();
-    static protected final Charset cs;
-    static protected final CharsetEncoder csEncoder;
-    static protected final CharsetDecoder csDecoder;
-    static {
-        // default charset for mysql is "ISO-8859-1" ("US-ASCII", "UTF-8")
-        cs = Charset.forName("ISO-8859-1");
-        csDecoder = cs.newDecoder();
-        csEncoder = cs.newEncoder();
-
-        // report any unclean transcodings
-        csEncoder
-            .onMalformedInput(CodingErrorAction.REPORT)
-            .onUnmappableCharacter(CodingErrorAction.REPORT);
-        csDecoder
-            .onMalformedInput(CodingErrorAction.REPORT)
-            .onUnmappableCharacter(CodingErrorAction.REPORT);
-    }
-
-    static public void main(String[] args) throws SQLException, IOException {
-        parseProperties();
-
-        Main main = new Main();
-        main.init();
-        main.run();
-        main.close();
-    }
-
-    // ----------------------------------------------------------------------
-
-    static public void parseProperties() throws IOException {
-        out.println("reading properties file " + propsFileName + " ...");
-        InputStream is = null;
-        try {
-            is = new FileInputStream(propsFileName);
-            props.load(is);
-        } finally {
-            if (is != null)
-                is.close();
-        }
-
-        doJdbc = parseBoolean("doJdbc", false);
-        doClusterj = parseBoolean("doClusterj", false);
-        doNdbjtie = parseBoolean("doNdbjtie", false);
-        doInsert = parseBoolean("doInsert", false);
-        doLookup = parseBoolean("doLookup", false);
-        doUpdate = parseBoolean("doUpdate", false);
-        doDelete = parseBoolean("doDelete", false);
-        doSingle = parseBoolean("doSingle", false);
-        doBulk = parseBoolean("doBulk", false);
-        doBatch = parseBoolean("doBatch", false);
-        lockMode = parseLockMode("lockMode", LockMode.READ_COMMITTED);
-        nRows = parseInt("nRows", 50000);
-        nRuns = parseInt("nRuns", 5);
-
-        out.println("doJdbc     : " + doJdbc);
-        out.println("doClusterj : " + doClusterj);
-        out.println("doNdbjtie  : " + doNdbjtie);
-        out.println("doInsert   : " + doInsert);
-        out.println("doLookup   : " + doLookup);
-        out.println("doUpdate   : " + doUpdate);
-        out.println("doDelete   : " + doDelete);
-        out.println("doSingle   : " + doSingle);
-        out.println("doBulk     : " + doBulk);
-        out.println("doBatch    : " + doBatch);
-        out.println("lockMode   : " + lockMode);
-        out.println("nRows      : " + nRows);
-        out.println("nRuns      : " + nRuns);
-    }
-
-    static protected boolean parseBoolean(String k, boolean vdefault) {
-        final String v = props.getProperty(k);
-        return (v == null ? vdefault : Boolean.parseBoolean(v));
-    }
-
-    static protected int parseInt(String k, int vdefault) {
-        final String v = props.getProperty(k);
-        try {
-            return (v == null ? vdefault : Integer.parseInt(v));
-        } catch (NumberFormatException e) {
-            final NumberFormatException nfe = new NumberFormatException(
-                "invalid value of benchmark property ('" + k + "', '"
-                + v + "').");
-            nfe.initCause(e);
-            throw nfe;
-        }
-    }
-
-    static protected LockMode parseLockMode(String k, LockMode vdefault) {
-        final String v = props.getProperty(k);
-        try {
-            return (v == null ? vdefault : LockMode.valueOf(v));
-        } catch (IllegalArgumentException e) {
-            final IllegalArgumentException iae = new IllegalArgumentException(
-                "invalid value of benchmark property ('" + k + "', '"
-                + v + "').");
-            iae.initCause(e);
-            throw iae;
-        }
-    }
-
-    // ----------------------------------------------------------------------
-
-    public void init() throws SQLException {
-        if (doJdbc)
-            initJdbcConnection();
-        if (doClusterj)
-            initClusterjConnection();
-        if (doNdbjtie)
-            initNdbjtieConnection();
-    }
-
-    public void close() throws SQLException {
-        if (doJdbc)
-            closeJdbcConnection();
-        if (doClusterj)
-            closeClusterjConnection();
-        if (doNdbjtie)
-            closeNdbjtieConnection();
-    }
-
-    // ----------------------------------------------------------------------
-
-    protected void initJdbcConnection() throws SQLException {
-        assert (connection == null);
-
-        out.println();
-        out.println("initializing jdbc resources ...");
-
-        // load the JDBC driver class
-        out.print("loading jdbc driver ...");
-        out.flush();
-        final String driver
-            = props.getProperty("jdbc.driver", "com.mysql.jdbc.Driver");
-        final Class cls;
-        try {
-            cls = Class.forName(driver);
-        } catch (ClassNotFoundException e) {
-            out.println("Cannot load JDBC driver '" + driver
-                        + "' from classpath '"
-                        + System.getProperty("java.class.path") + "'");
-            throw new RuntimeException(e);
-        }
-        out.println("          [ok: " + cls.getName() + "]");
-
-        // create a connection to the database
-        out.print("starting jdbc connection ...");
-        out.flush();
-        final String url
-            = props.getProperty("jdbc.url",
-                                "jdbc:mysql://localhost/testdb");
-        final String username
-            = props.getProperty("jdbc.user", "root");
-        final String password
-            = props.getProperty("jdbc.password", "");
-        try {
-            connection = DriverManager.getConnection(url, username, password);
-        } catch (SQLException e) {
-            out.println("Cannot connect to database '" + url + "'");
-            throw new RuntimeException(e);
-        }
-        out.println("     [ok: " + url + "]");
-
-        out.print("setting isolation level ...");
-        out.flush();
-        // ndb storage engine only supports READ_COMMITTED
-        final int il = Connection.TRANSACTION_READ_COMMITTED;
-        connection.setTransactionIsolation(il);
-        out.print("      [ok: ");
-        switch (connection.getTransactionIsolation()) {
-        case Connection.TRANSACTION_READ_UNCOMMITTED:
-            out.print("READ_UNCOMMITTED");
-            break;
-        case Connection.TRANSACTION_READ_COMMITTED:
-            out.print("READ_COMMITTED");
-            break;
-        case Connection.TRANSACTION_REPEATABLE_READ:
-            out.print("REPEATABLE_READ");
-            break;
-        case Connection.TRANSACTION_SERIALIZABLE:
-            out.print("SERIALIZABLE");
-            break;
-        default:
-            assert false;
-        }
-        out.println("]");
-        
-        initJdbcPreparedStatements();
-    }
-
-    protected void closeJdbcConnection() throws SQLException {
-        assert (connection != null);
-
-        out.println();
-        out.println("releasing jdbc resources ...");
-
-        closeJdbcPreparedStatements();
-
-        out.print("closing jdbc connection ...");
-        out.flush();
-        connection.close();
-        connection = null;
-        out.println("      [ok]");
-    }
-
-    protected void initJdbcPreparedStatements() throws SQLException {
-        assert (connection != null);
-        assert (ins0 == null);
-        assert (sel0 == null);
-        assert (upd0 == null);
-        assert (del0 == null);
-
-        out.print("using lock mode for reads ...    [ok: ");
-        final String lm;
-        switch (lockMode) {
-        case READ_COMMITTED:
-            lm = "";
-            break;
-        case SHARED:
-            lm = " LOCK IN share mode";
-            break;
-        case EXCLUSIVE:
-            lm = " FOR UPDATE";
-            break;
-        default:
-            lm = "";
-            assert false;
-        }
-        out.println("SELECT" + lm + ";]");
-
-        out.print("compiling jdbc statements ...");
-        out.flush();
-
-        final String sqlIns0 = "INSERT INTO mytable (c0, c1, c2, c3, c5, c6, c7, c8) VALUES (?, ?, ?, ?, ?, ?, ?, ?)";
-        ins0 = connection.prepareStatement(sqlIns0);
-
-        final String sqlSel0 = ("SELECT * FROM mytable where c0=?" + lm);
-        sel0 = connection.prepareStatement(sqlSel0);
-
-        final String sqlUpd0 = "UPDATE mytable SET c1 = ?, c2 = ?, c3 = ?, c5 = ?, c6 = ?, c7 = ?, c8 = ? WHERE c0=?";
-        upd0 = connection.prepareStatement(sqlUpd0);
-
-        final String sqlDel0 = "DELETE FROM mytable WHERE c0=?";
-        del0 = connection.prepareStatement(sqlDel0);
-
-        out.println("    [ok]");
-    }
-
-    protected void closeJdbcPreparedStatements() throws SQLException {
-        assert (ins0 != null);
-        assert (sel0 != null);
-        assert (upd0 != null);
-        assert (del0 != null);
-
-        out.print("closing jdbc statements ...");
-        out.flush();
-
-        ins0.close();
-        ins0 = null;
-
-        sel0.close();
-        sel0 = null;
-
-        upd0.close();
-        upd0 = null;
-
-        del0.close();
-        del0 = null;
-
-        out.println("      [ok]");
-    }
-
-    // ----------------------------------------------------------------------
-
-    protected void initClusterjConnection() {
-        assert (sessionFactory == null);
-        assert (session == null);
-
-        out.println();
-        out.println("initializing clusterj resources ...");
-
-        out.print("starting clusterj session ...");
-        out.flush();
-        sessionFactory = ClusterJHelper.getSessionFactory(props);
-        session = sessionFactory.getSession();
-        out.println("    [ok]");
-
-        out.print("setting session lock mode ...");
-        session.setLockMode(lockMode);
-        out.println("    [ok: " + lockMode + "]");
-    }
-
-    protected void closeClusterjConnection() {
-        assert (session != null);
-        assert (sessionFactory != null);
-
-        out.println();
-        out.println("releasing clusterj resources ...");
-
-        out.print("closing clusterj session ...");
-        out.flush();
-        session.close();
-        session = null;
-        sessionFactory.close();
-        sessionFactory = null;
-        out.println("     [ok]");
-    }
-
-    // ----------------------------------------------------------------------
-
-    protected void initNdbjtieConnection() {
-        assert (mgmd == null);
-        assert (ndb == null);
-
-        out.println();
-        out.println("initializing ndbjtie resources ...");
-
-        // load native library (better diagnostics doing it explicitely)
-        loadSystemLibrary("ndbclient");
-
-        // read connection properties
-        final String mgmdConnect
-            = props.getProperty("com.mysql.clusterj.connectstring",
-                                "localhost:1186");
-        final String catalog
-            = props.getProperty("com.mysql.clusterj.database",
-                                "testdb");
-        final String schema
-            = "def";
-        assert (mgmdConnect != null);
-        assert (catalog != null);
-        assert (schema != null);
-
-        // instantiate NDB cluster singleton
-        out.print("creating cluster connection ...");
-        out.flush();
-        mgmd = Ndb_cluster_connection.create(mgmdConnect);
-        assert mgmd != null;
-        out.println("  [ok]");
-
-        // connect to cluster management node (ndb_mgmd)
-        out.print("connecting to cluster ...");
-        out.flush();
-        final int retries = 0;        // retries (< 0 = indefinitely)
-        final int delay = 0;          // seconds to wait after retry
-        final int verbose = 1;        // print report of progess
-        // 0 = success, 1 = recoverable error, -1 = non-recoverable error
-        if (mgmd.connect(retries, delay, verbose) != 0) {
-            final String msg = ("mgmd@" + mgmdConnect
-                                + " was not ready within "
-                                + (retries * delay) + "s.");
-            out.println(msg);
-            throw new RuntimeException("!!! " + msg);
-        }
-        out.println("        [ok: " + mgmdConnect + "]");
-
-        // connect to data nodes (ndbds)
-        out.print("waiting for data nodes ...");
-        out.flush();
-        final int initial_wait = 10; // secs to wait until first node detected
-        final int final_wait = 0;    // secs 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) {
-            final String msg = ("data nodes were not ready within "
-                                + (initial_wait + final_wait) + "s.");
-            out.println(msg);
-            throw new RuntimeException(msg);
-        }
-        out.println("       [ok]");
-
-        // connect to database
-        out.print("connecting to database ...");
-        ndb = Ndb.create(mgmd, catalog, schema);
-        final 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(max_no_tx) != 0) {
-            String msg = "Error caught: " + ndb.getNdbError().message();
-            throw new RuntimeException(msg);
-        }
-        out.println("       [ok: " + catalog + "." + schema + "]");
-
-        initNdbjtieMeta();
-
-        initNdbjtieBuffers();
-
-        out.print("using lock mode for reads ...    [ok: ");
-        switch (lockMode) {
-        case READ_COMMITTED:
-            ndbOpLockMode = NdbOperation.LockMode.LM_CommittedRead;
-            out.print("LM_CommittedRead");
-            break;
-        case SHARED:
-            ndbOpLockMode = NdbOperation.LockMode.LM_Read;
-            out.print("LM_Read");
-            break;
-        case EXCLUSIVE:
-            ndbOpLockMode = NdbOperation.LockMode.LM_Exclusive;
-            out.print("LM_Exclusive");
-            break;
-        default:
-            ndbOpLockMode = NdbOperation.LockMode.LM_CommittedRead;
-            assert false;
-        }
-        out.println("]");
-    }
-
-    protected void closeNdbjtieConnection() {
-        assert (mgmd != null);
-        assert (ndb != null);
-
-        out.println();
-        out.println("releasing ndbjtie resources ...");
-
-        closeNdbjtieBuffers();
-
-        closeNdbjtieMeta();
-
-        out.print("closing database connection ...");
-        out.flush();
-        Ndb.delete(ndb);
-        ndb = null;
-        out.println("  [ok]");
-
-        out.print("closing cluster connection ...");
-        out.flush();
-        if (mgmd != null)
-            Ndb_cluster_connection.delete(mgmd);
-        mgmd = null;
-        out.println("   [ok]");
-    }
-
-    protected void initNdbjtieMeta() {
-        assert (ndb != null);
-        assert (table_t0 == null);
-        assert (column_c0 == null);
-
-        out.print("caching metadata ...");
-        out.flush();
-
-        final Dictionary dict = ndb.getDictionary();
-
-        if ((table_t0 = dict.getTable("mytable")) == null)
-            throw new RuntimeException(toStr(dict.getNdbError()));
-
-        if ((column_c0 = table_t0.getColumn("c0")) == null)
-            throw new RuntimeException(toStr(dict.getNdbError()));
-        if ((column_c1 = table_t0.getColumn("c1")) == null)
-            throw new RuntimeException(toStr(dict.getNdbError()));
-        if ((column_c2 = table_t0.getColumn("c2")) == null)
-            throw new RuntimeException(toStr(dict.getNdbError()));
-        if ((column_c3 = table_t0.getColumn("c3")) == null)
-            throw new RuntimeException(toStr(dict.getNdbError()));
-        if ((column_c4 = table_t0.getColumn("c4")) == null)
-            throw new RuntimeException(toStr(dict.getNdbError()));
-        if ((column_c5 = table_t0.getColumn("c5")) == null)
-            throw new RuntimeException(toStr(dict.getNdbError()));
-        if ((column_c6 = table_t0.getColumn("c6")) == null)
-            throw new RuntimeException(toStr(dict.getNdbError()));
-        if ((column_c7 = table_t0.getColumn("c7")) == null)
-            throw new RuntimeException(toStr(dict.getNdbError()));
-        if ((column_c8 = table_t0.getColumn("c8")) == null)
-            throw new RuntimeException(toStr(dict.getNdbError()));
-        if ((column_c9 = table_t0.getColumn("c9")) == null)
-            throw new RuntimeException(toStr(dict.getNdbError()));
-        if ((column_c10 = table_t0.getColumn("c10")) == null)
-            throw new RuntimeException(toStr(dict.getNdbError()));
-        if ((column_c11 = table_t0.getColumn("c11")) == null)
-            throw new RuntimeException(toStr(dict.getNdbError()));
-        if ((column_c12 = table_t0.getColumn("c12")) == null)
-            throw new RuntimeException(toStr(dict.getNdbError()));
-        if ((column_c13 = table_t0.getColumn("c13")) == null)
-            throw new RuntimeException(toStr(dict.getNdbError()));
-        if ((column_c14 = table_t0.getColumn("c14")) == null)
-            throw new RuntimeException(toStr(dict.getNdbError()));
-
-        attr_c0 = column_c0.getColumnNo();
-        attr_c1 = column_c1.getColumnNo();
-        attr_c2 = column_c2.getColumnNo();
-        attr_c3 = column_c3.getColumnNo();
-        attr_c4 = column_c4.getColumnNo();
-        attr_c5 = column_c5.getColumnNo();
-        attr_c6 = column_c6.getColumnNo();
-        attr_c7 = column_c7.getColumnNo();
-        attr_c8 = column_c8.getColumnNo();
-        attr_c9 = column_c9.getColumnNo();
-        attr_c10 = column_c10.getColumnNo();
-        attr_c11 = column_c11.getColumnNo();
-        attr_c12 = column_c12.getColumnNo();
-        attr_c13 = column_c13.getColumnNo();
-        attr_c14 = column_c14.getColumnNo();
-
-        width_c0 = ndbjtieColumnWidth(column_c0);
-        width_c1 = ndbjtieColumnWidth(column_c1);
-        width_c2 = ndbjtieColumnWidth(column_c2);
-        width_c3 = ndbjtieColumnWidth(column_c3);
-        width_c4 = ndbjtieColumnWidth(column_c4);
-        width_c5 = ndbjtieColumnWidth(column_c5);
-        width_c6 = ndbjtieColumnWidth(column_c6);
-        width_c7 = ndbjtieColumnWidth(column_c7);
-        width_c8 = ndbjtieColumnWidth(column_c8);
-        width_c9 = ndbjtieColumnWidth(column_c9);
-        width_c10 = ndbjtieColumnWidth(column_c10);
-        width_c11 = ndbjtieColumnWidth(column_c11);
-        width_c12 = ndbjtieColumnWidth(column_c12);
-        width_c13 = ndbjtieColumnWidth(column_c13);
-        width_c14 = ndbjtieColumnWidth(column_c14);
-
-        out.println("             [ok]");
-    }
-
-    protected void closeNdbjtieMeta() {
-        assert (ndb != null);
-        assert (table_t0 != null);
-        assert (column_c0 != null);
-
-        out.print("clearing metadata cache...");
-        out.flush();
-
-        width_c14 = 0;
-        width_c13 = 0;
-        width_c12 = 0;
-        width_c11 = 0;
-        width_c10 = 0;
-        width_c9 = 0;
-        width_c8 = 0;
-        width_c7 = 0;
-        width_c6 = 0;
-        width_c5 = 0;
-        width_c4 = 0;
-        width_c3 = 0;
-        width_c2 = 0;
-        width_c1 = 0;
-        width_c0 = 0;
-
-        column_c14 = null;
-        column_c13 = null;
-        column_c12 = null;
-        column_c11 = null;
-        column_c10 = null;
-        column_c9 = null;
-        column_c8 = null;
-        column_c7 = null;
-        column_c6 = null;
-        column_c5 = null;
-        column_c4 = null;
-        column_c3 = null;
-        column_c2 = null;
-        column_c1 = null;
-        column_c0 = null;
-
-        table_t0 = null;
-
-        out.println("       [ok]");
-    }
-
-    protected void initNdbjtieBuffers() {
-        assert (column_c0 != null);
-        assert (bb_r == null);
-
-        out.print("allocating buffers...");
-        out.flush();
-
-        final int 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);
-
-        //bb_r = ByteBuffer.allocateDirect(width_row);
-        bb_r = ByteBuffer.allocateDirect(width_row * nRows);
-
-        // initial order of a byte buffer is always BIG_ENDIAN
-        bb_r.order(bo);
-
-        out.println("            [ok]");
-    }
-
-    protected void closeNdbjtieBuffers() {
-        assert (column_c0 != null);
-        assert (bb_r != null);
-
-        out.print("releasing buffers...");
-        out.flush();
-
-        bb_r = null;
-
-        out.println("             [ok]");
-    }
-
-    static protected void loadSystemLibrary(String name) {
-        out.print("loading native libary ...");
-        out.flush();
-        try {
-            System.loadLibrary(name);
-        } catch (UnsatisfiedLinkError e) {
-            String path;
-            try {
-                path = System.getProperty("java.library.path");
-            } catch (Exception ex) {
-                path = "<exception caught: " + ex.getMessage() + ">";
-            }
-            err.println("NdbBase: failed loading library '"
-                        + name + "'; java.library.path='" + path + "'");
-            throw e;
-        } catch (SecurityException e) {
-            err.println("NdbBase: failed loading library '"
-                        + name + "'; caught exception: " + e);
-            throw e;
-        }
-        out.println("        [ok: " + name + "]");
-    }
-
-    static protected String toStr(NdbErrorConst e) {
-        return "NdbError[" + e.code() + "]: " + e.message();
-    }
-
-    static protected int ndbjtieColumnWidth(ColumnConst c) {
-        final int s = c.getSize(); // size of type or of base type
-        final int al = c.getLength(); // length or max length, 1 for scalars
-        final int at = c.getArrayType(); // size of length prefix, practically
-        return (s * al) + at;
-    }
-
-    // ----------------------------------------------------------------------
-
-    enum XMode { SINGLE, BULK, BATCH }
-
-    public void run() throws SQLException {
-        for (int i = 0; i < nRuns; i++) {
-            if (doJdbc) {
-                out.println();
-                out.println("handle " + nRows + " rows by JDBC ...");
-                if (doSingle) {
-                    out.println();
-                    if (doInsert) runJdbcInsert(XMode.SINGLE);
-                    if (doLookup) runJdbcLookup(XMode.SINGLE);
-                    if (doUpdate) runJdbcUpdate(XMode.SINGLE);
-                    if (doDelete) runJdbcDelete(XMode.SINGLE);
-                }
-                if (doBulk) {
-                    out.println();
-                    if (doInsert) runJdbcInsert(XMode.BULK);
-                    if (doLookup) runJdbcLookup(XMode.BULK);
-                    if (doUpdate) runJdbcUpdate(XMode.BULK);
-                    if (doDelete) runJdbcDelete(XMode.BULK);
-                }
-                if (doBatch) {
-                    out.println();
-                    if (doInsert) runJdbcInsert(XMode.BATCH);
-                    if (doLookup) runJdbcLookup(XMode.BATCH);
-                    if (doUpdate) runJdbcUpdate(XMode.BATCH);
-                    if (doDelete) runJdbcDelete(XMode.BATCH);
-                }
-            }
-            if (doClusterj) {
-                out.println();
-                out.println("handle " + nRows + " rows by ClusterJ ...");
-                if (doSingle) {
-                    out.println();
-                    if (doInsert) runClusterjInsert(XMode.SINGLE);
-                    if (doLookup) runClusterjLookup(XMode.SINGLE);
-                    if (doUpdate) runClusterjUpdate(XMode.SINGLE);
-                    if (doDelete) runClusterjDelete(XMode.SINGLE);
-                }
-                if (doBulk) {
-                    out.println();
-                    if (doInsert) runClusterjInsert(XMode.BULK);
-                    if (doLookup) runClusterjLookup(XMode.BULK);
-                    if (doUpdate) runClusterjUpdate(XMode.BULK);
-                    if (doDelete) runClusterjDelete(XMode.BULK);
-                }
-            }
-            if (doNdbjtie) {
-                out.println();
-                out.println("handle " + nRows + " rows by NDB JTie ...");
-                if (doSingle) {
-                    out.println();
-                    if (doInsert) runNdbjtieInsert(XMode.SINGLE);
-                    if (doLookup) runNdbjtieLookup(XMode.SINGLE);
-                    if (doUpdate) runNdbjtieUpdate(XMode.SINGLE);
-                    if (doDelete) runNdbjtieDelete(XMode.SINGLE);
-                }
-                if (doBulk) {
-                    out.println();
-                    if (doInsert) runNdbjtieInsert(XMode.BULK);
-                    if (doLookup) runNdbjtieLookup(XMode.BULK);
-                    if (doUpdate) runNdbjtieUpdate(XMode.BULK);
-                    if (doDelete) runNdbjtieDelete(XMode.BULK);
-                }
-                if (doBatch) {
-                    out.println();
-                    if (doInsert) runNdbjtieInsert(XMode.BATCH);
-                    if (doLookup) runNdbjtieLookup(XMode.BATCH);
-                    if (doUpdate) runNdbjtieUpdate(XMode.BATCH);
-                    if (doDelete) runNdbjtieDelete(XMode.BATCH);
-                }
-            }
-        }
-    }
-
-    // ----------------------------------------------------------------------
-
-    public void runJdbcInsert(XMode mode) throws SQLException {
-        final String m = mode.toString().toLowerCase();
-        //out.println("insert " + nRows + " rows by JDBC " + m + " tx ...");
-
-        long time = -System.currentTimeMillis();
-        connection.setAutoCommit(mode == XMode.SINGLE);
-        for(int i = 0; i < nRows; i++) {
-            jdbcInsert(i, mode);
-        }
-        if (mode == XMode.BATCH)
-            ins0.executeBatch();
-        if (mode != XMode.SINGLE)
-            connection.commit();
-        time += System.currentTimeMillis();
-
-        out.println("jdbc_insert_" + m + "    \t: " + time + " ms");
-    }
-
-    public void runClusterjInsert(XMode mode) {
-        final String m = mode.toString().toLowerCase();
-        //out.println("insert " + nRows + " rows by ClusterJ " + m + " tx ...");
-
-        long time = -System.currentTimeMillis();
-        if (mode != XMode.SINGLE)
-            session.currentTransaction().begin();
-        for(int i = 0; i < nRows; i++) {
-            clusterjInsert(i);
-        }
-        if (mode != XMode.SINGLE)
-            session.currentTransaction().commit();
-        time += System.currentTimeMillis();
-
-        out.println("clusterj_insert_" + m + "  \t: " + time + " ms");
-    }
-
-    public void runNdbjtieInsert(XMode mode) {
-        final String m = mode.toString().toLowerCase();
-        //out.println("insert " + nRows + " rows by NDB JTie " + m + " tx ...");
-
-        long time = -System.currentTimeMillis();
-        if (mode == XMode.SINGLE) {
-            for(int i = 0; i < nRows; i++) {
-                ndbjtieBeginTransaction();
-                ndbjtieInsert(i);
-                ndbjtieCommitTransaction();
-                ndbjtieCloseTransaction();
-            }
-        } else {
-            ndbjtieBeginTransaction();
-            for(int i = 0; i < nRows; i++) {
-                ndbjtieInsert(i);
-
-                if (mode == XMode.BULK)
-                    ndbjtieExecuteTransaction();
-            }
-            ndbjtieCommitTransaction();
-            ndbjtieCloseTransaction();
-        }
-        time += System.currentTimeMillis();
-
-        out.println("ndbjtie_insert_" + m + "  \t: " + time + " ms");
-    }
-
-    public void jdbcInsert(int c0, XMode mode) {
-        // include exception handling as part of jdbc pattern
-        try {
-            final int i = c0;
-            final String str = Integer.toString(i);
-            ins0.setString(1, str); // key
-            ins0.setString(2, str);
-            ins0.setInt(3, i);
-            ins0.setInt(4, i);
-            ins0.setString(5, str);
-            ins0.setString(6, str);
-            ins0.setString(7, str);
-            ins0.setString(8, str);
-            if (mode == XMode.BATCH) {
-                ins0.addBatch();
-            } else {
-                int cnt = ins0.executeUpdate();
-                assert (cnt == 1);
-            }
-        } catch (SQLException e) {
-            throw new RuntimeException(e);
-        }
-    }
-
-    public void clusterjInsert(int c0) {
-        final CJSubscriber o = session.newInstance(CJSubscriber.class);
-        final int i = c0;
-        final String str = Integer.toString(i);
-        //final String oneChar = Integer.toString(1);
-        o.setC0(str);
-        o.setC1(str);
-        o.setC2(i);
-        o.setC3(i);
-        //o.setC4(i);
-        o.setC5(str);
-        o.setC6(str);
-        o.setC7(str);
-        o.setC8(str);
-        //o.setC9(oneChar);
-        //o.setC10(oneChar);
-        //o.setC11(str);
-        //o.setC12(str);
-        //o.setC13(oneChar);
-        //o.setC14(str);
-        session.persist(o);
-    }
-
-    protected void ndbjtieInsert(int c0) {
-        // get an insert operation for the table
-        NdbOperation op = tx.getNdbOperation(table_t0);
-        if (op == null)
-            throw new RuntimeException(toStr(tx.getNdbError()));
-        if (op.insertTuple() != 0)
-            throw new RuntimeException(toStr(tx.getNdbError()));
-
-        // include exception handling as part of transcoding pattern
-        final int i = c0;
-        final CharBuffer str = CharBuffer.wrap(Integer.toString(i));
-        try {
-            // set values; key attribute needs to be set first
-            //str.rewind();
-            ndbjtieTranscode(bb_r, str);
-            if (op.equal(attr_c0, bb_r) != 0) // key
-                throw new RuntimeException(toStr(tx.getNdbError()));
-            bb_r.position(bb_r.position() + width_c0);
-
-            str.rewind();
-            ndbjtieTranscode(bb_r, str);
-            if (op.setValue(attr_c1, bb_r) != 0)
-                throw new RuntimeException(toStr(tx.getNdbError()));
-            bb_r.position(bb_r.position() + width_c1);
-
-            if (op.setValue(attr_c2, i) != 0)
-                throw new RuntimeException(toStr(tx.getNdbError()));
-
-            if (op.setValue(attr_c3, i) != 0)
-                throw new RuntimeException(toStr(tx.getNdbError()));
-
-            str.rewind();
-            ndbjtieTranscode(bb_r, str);
-            if (op.setValue(attr_c5, bb_r) != 0)
-                throw new RuntimeException(toStr(tx.getNdbError()));
-            bb_r.position(bb_r.position() + width_c5);
-
-            str.rewind();
-            ndbjtieTranscode(bb_r, str);
-            if (op.setValue(attr_c6, bb_r) != 0)
-                throw new RuntimeException(toStr(tx.getNdbError()));
-            bb_r.position(bb_r.position() + width_c6);
-
-            str.rewind();
-            ndbjtieTranscode(bb_r, str);
-            if (op.setValue(attr_c7, bb_r) != 0)
-                throw new RuntimeException(toStr(tx.getNdbError()));
-            bb_r.position(bb_r.position() + width_c7);
-
-            str.rewind();
-            ndbjtieTranscode(bb_r, str);
-            if (op.setValue(attr_c8, bb_r) != 0)
-                throw new RuntimeException(toStr(tx.getNdbError()));
-            bb_r.position(bb_r.position() + width_c8);
-        } catch (CharacterCodingException e) {
-            throw new RuntimeException(e);
-        }
-    }
-
-    // ----------------------------------------------------------------------
-
-    public void runJdbcLookup(XMode mode) throws SQLException {
-        final String m = mode.toString().toLowerCase();
-        //out.println("lookup " + nRows + " rows by JDBC " + m + " tx ...");
-
-        if(mode == XMode.BATCH) {
-            out.println("jdbc_lookup_" + m + "    \t: " + 0 + " n/a");
-            return;
-        }
-        
-        long time = -System.currentTimeMillis();
-        connection.setAutoCommit(mode == XMode.SINGLE);
-        for(int i = 0; i < nRows; i++) {
-            jdbcLookup(i);
-        }
-        if (mode != XMode.SINGLE)
-            connection.commit();
-        time += System.currentTimeMillis();
-
-        out.println("jdbc_lookup_" + m + "    \t: " + time + " ms");
-    }
-
-    public void runClusterjLookup(XMode mode) {
-        final String m = mode.toString().toLowerCase();
-        //out.println("lookup " + nRows + " rows by ClusterJ " + m + " tx ...");
-
-        long time = -System.currentTimeMillis();
-        if (mode != XMode.SINGLE)
-            session.currentTransaction().begin();
-        for(int i = 0; i < nRows; i++) {
-            clusterjLookup(i);
-        }
-        if (mode != XMode.SINGLE)
-            session.currentTransaction().commit();
-        time += System.currentTimeMillis();
-
-        out.println("clusterj_lookup_" + m + "  \t: " + time + " ms");
-    }
-
-    public void runNdbjtieLookup(XMode mode) {
-        final String m = mode.toString().toLowerCase();
-        //out.println("lookup " + nRows + " rows by NDB JTie " + m + " tx ...");
-
-        long time = -System.currentTimeMillis();
-        if (mode == XMode.SINGLE) {
-            for(int i = 0; i < nRows; i++) {
-                ndbjtieBeginTransaction();
-                ndbjtieLookup(i);
-                ndbjtieCommitTransaction();
-                ndbjtieCloseTransaction();
-                ndbjtieRead(i);
-            }
-        } else {
-            ndbjtieBeginTransaction();
-            for(int i = 0; i < nRows; i++) {
-                ndbjtieLookup(i);
-
-                if (mode == XMode.BULK)
-                    ndbjtieExecuteTransaction();
-            }
-            ndbjtieCommitTransaction();
-            ndbjtieCloseTransaction();
-            for(int i = 0; i < nRows; i++) {
-                ndbjtieRead(i);
-            }
-        }
-        time += System.currentTimeMillis();
-
-        out.println("ndbjtie_lookup_" + m + "  \t: " + time + " ms");
-    }
-
-    public void jdbcLookup(int c0) {
-        // include exception handling as part of jdbc pattern
-        try {
-            sel0.setString(1, Integer.toString(c0)); // key
-            ResultSet resultSet = sel0.executeQuery();
-
-            if (resultSet.next()) {
-                // not verifying at this time
-                String ac0 = resultSet.getString(1);
-                String c1 = resultSet.getString(2);
-                int c2 = resultSet.getInt(3);
-                int c3 = resultSet.getInt(4);
-                int c4 = resultSet.getInt(5);
-                String c5 = resultSet.getString(6);
-                String c6 = resultSet.getString(7);
-                String c7 = resultSet.getString(8);
-                String c8 = resultSet.getString(9);
-                String c9 = resultSet.getString(10);
-                String c10 = resultSet.getString(11);
-                String c11 = resultSet.getString(12);
-                String c12 = resultSet.getString(13);
-                String c13 = resultSet.getString(14);
-                String c14 = resultSet.getString(15);
-            }
-            assert (!resultSet.next());
-
-            resultSet.close();
-        } catch (SQLException e) {
-            throw new RuntimeException(e);
-        }
-    }
-
-    public void clusterjLookup(int c0) {
-        final CJSubscriber o
-            = session.find(CJSubscriber.class, Integer.toString(c0));
-        if (o != null) {
-            // not verifying at this time
-            String ac0 = o.getC0();
-            String c1 = o.getC1();
-            int c2 = o.getC2();
-            int c3 = o.getC3();
-            int c4 = o.getC4();
-            String c5 = o.getC5();
-            String c6 = o.getC6();
-            String c7 = o.getC7();
-            String c8 = o.getC8();
-            String c9 = o.getC9();
-            String c10 = o.getC10();
-            String c11 = o.getC11();
-            String c12 = o.getC12();
-            String c13 = o.getC13();
-            String c14 = o.getC14();
-        }
-    }
-
-    protected void ndbjtieLookup(int c0) {
-        // get a lookup operation for the table
-        NdbOperation op = tx.getNdbOperation(table_t0);
-        if (op == null)
-            throw new RuntimeException(toStr(tx.getNdbError()));
-        if (op.readTuple(ndbOpLockMode) != 0)
-            throw new RuntimeException(toStr(tx.getNdbError()));
-
-        int p = bb_r.position();
-
-        // include exception handling as part of transcoding pattern
-        final CharBuffer str = CharBuffer.wrap(Integer.toString(c0));
-        try {
-            // set values; key attribute needs to be set first
-            //str.rewind();
-            ndbjtieTranscode(bb_r, str);
-            if (op.equal(attr_c0, bb_r) != 0) // key
-                throw new RuntimeException(toStr(tx.getNdbError()));
-            bb_r.position(p += width_c0);
-        } catch (CharacterCodingException e) {
-            throw new RuntimeException(e);
-        }
-
-        // get attributes (not readable until after commit)
-        if (op.getValue(attr_c1, bb_r) == null)
-            throw new RuntimeException(toStr(tx.getNdbError()));
-        bb_r.position(p += width_c1);
-        if (op.getValue(attr_c2, bb_r) == null)
-            throw new RuntimeException(toStr(tx.getNdbError()));
-        bb_r.position(p += width_c2);
-        if (op.getValue(attr_c3, bb_r) == null)
-            throw new RuntimeException(toStr(tx.getNdbError()));
-        bb_r.position(p += width_c3);
-        if (op.getValue(attr_c4, bb_r) == null)
-            throw new RuntimeException(toStr(tx.getNdbError()));
-        bb_r.position(p += width_c4);
-        if (op.getValue(attr_c5, bb_r) == null)
-            throw new RuntimeException(toStr(tx.getNdbError()));
-        bb_r.position(p += width_c5);
-        if (op.getValue(attr_c6, bb_r) == null)
-            throw new RuntimeException(toStr(tx.getNdbError()));
-        bb_r.position(p += width_c6);
-        if (op.getValue(attr_c7, bb_r) == null)
-            throw new RuntimeException(toStr(tx.getNdbError()));
-        bb_r.position(p += width_c7);
-        if (op.getValue(attr_c8, bb_r) == null)
-            throw new RuntimeException(toStr(tx.getNdbError()));
-        bb_r.position(p += width_c8);
-        if (op.getValue(attr_c9, bb_r) == null)
-            throw new RuntimeException(toStr(tx.getNdbError()));
-        bb_r.position(p += width_c9);
-        if (op.getValue(attr_c10, bb_r) == null)
-            throw new RuntimeException(toStr(tx.getNdbError()));
-        bb_r.position(p += width_c10);
-        if (op.getValue(attr_c11, bb_r) == null)
-            throw new RuntimeException(toStr(tx.getNdbError()));
-        bb_r.position(p += width_c11);
-        if (op.getValue(attr_c12, bb_r) == null)
-            throw new RuntimeException(toStr(tx.getNdbError()));
-        bb_r.position(p += width_c12);
-        if (op.getValue(attr_c13, bb_r) == null)
-            throw new RuntimeException(toStr(tx.getNdbError()));
-        bb_r.position(p += width_c13);
-        if (op.getValue(attr_c14, bb_r) == null)
-            throw new RuntimeException(toStr(tx.getNdbError()));
-        bb_r.position(p += width_c14);
-    }
-
-    protected void ndbjtieRead(int c0) {
-        // include exception handling as part of transcoding pattern
-        final int i = c0;
-        final CharBuffer str = CharBuffer.wrap(Integer.toString(i));
-        assert (str.position() == 0);
-
-        try {
-            int p = bb_r.position();
-            bb_r.position(p += width_c0);
-
-            // not verifying at this time
-            // (str.equals(ndbjtieTranscode(bb_c1)));
-            // (i == bb_c2.asIntBuffer().get());
-            CharBuffer y = ndbjtieTranscode(bb_r);
-            bb_r.position(p += width_c1);
-
-            bb_r.asIntBuffer().get();
-            bb_r.position(p += width_c2);
-            bb_r.asIntBuffer().get();
-            bb_r.position(p += width_c3);
-            bb_r.asIntBuffer().get();
-            bb_r.position(p += width_c4);
-
-            ndbjtieTranscode(bb_r);
-            bb_r.position(p += width_c5);
-            ndbjtieTranscode(bb_r);
-            bb_r.position(p += width_c6);
-            ndbjtieTranscode(bb_r);
-            bb_r.position(p += width_c7);
-            ndbjtieTranscode(bb_r);
-            bb_r.position(p += width_c8);
-            ndbjtieTranscode(bb_r);
-            bb_r.position(p += width_c9);
-            ndbjtieTranscode(bb_r);
-            bb_r.position(p += width_c10);
-            ndbjtieTranscode(bb_r);
-            bb_r.position(p += width_c11);
-            ndbjtieTranscode(bb_r);
-            bb_r.position(p += width_c12);
-            ndbjtieTranscode(bb_r);
-            bb_r.position(p += width_c13);
-            ndbjtieTranscode(bb_r);
-            bb_r.position(p += width_c14);
-        } catch (CharacterCodingException e) {
-            throw new RuntimeException(e);
-        }
-    }
-
-    // ----------------------------------------------------------------------
-
-    public void runJdbcUpdate(XMode mode) throws SQLException {
-        final String m = mode.toString().toLowerCase();
-        //out.println("update " + nRows + " rows by JDBC " + m + " tx ...");
-
-        long time = -System.currentTimeMillis();
-        connection.setAutoCommit(mode == XMode.SINGLE);
-        for(int i = 0; i < nRows; i++) {
-            jdbcUpdate(i, mode);
-        }
-        if (mode == XMode.BATCH)
-            upd0.executeBatch();
-        if (mode != XMode.SINGLE)
-            connection.commit();
-        time += System.currentTimeMillis();
-
-        out.println("jdbc_update_" + m + "    \t: " + time + " ms");
-    }
-
-    public void runClusterjUpdate(XMode mode) {
-        final String m = mode.toString().toLowerCase();
-        //out.println("update " + nRows + " rows by ClusterJ " + m + " tx ...");
-
-        long time = -System.currentTimeMillis();
-        if (mode != XMode.SINGLE)
-            session.currentTransaction().begin();
-        for(int i = 0; i < nRows; i++) {
-            clusterjUpdate(i);
-        }
-        if (mode != XMode.SINGLE)
-            session.currentTransaction().commit();
-        time += System.currentTimeMillis();
-
-        out.println("clusterj_update_" + m + "  \t: " + time + " ms");
-    }
-
-    public void runNdbjtieUpdate(XMode mode) {
-        final String m = mode.toString().toLowerCase();
-        //out.println("update " + nRows + " rows by NDB JTie " + m + " tx ...");
-
-        long time = -System.currentTimeMillis();
-        if (mode == XMode.SINGLE) {
-            for(int i = 0; i < nRows; i++) {
-                ndbjtieBeginTransaction();
-                ndbjtieUpdate(i);
-                ndbjtieCommitTransaction();
-                ndbjtieCloseTransaction();
-            }
-        } else {
-            ndbjtieBeginTransaction();
-            for(int i = 0; i < nRows; i++) {
-                ndbjtieUpdate(i);
-
-                if (mode == XMode.BULK)
-                    ndbjtieExecuteTransaction();
-            }
-            ndbjtieCommitTransaction();
-            ndbjtieCloseTransaction();
-        }
-        time += System.currentTimeMillis();
-
-        out.println("ndbjtie_update_" + m + "  \t: " + time + " ms");
-    }
-
-    public void jdbcUpdate(int c0, XMode mode) {
-        final String str0 = Integer.toString(c0);
-        final int r = -c0;
-        final String str1 = Integer.toString(r);
-
-        // include exception handling as part of jdbc pattern
-        try {
-            upd0.setString(1, str1);
-            upd0.setInt(2, r);
-            upd0.setInt(3, r);
-            upd0.setString(4, str1);
-            upd0.setString(5, str1);
-            upd0.setString(6, str1);
-            upd0.setString(7, str1);
-            upd0.setString(8, str0); // key
-            if (mode == XMode.BATCH) {
-                upd0.addBatch();
-            } else {
-                int cnt = upd0.executeUpdate();
-                assert (cnt == 1);
-            }
-        } catch (SQLException e) {
-            throw new RuntimeException(e);
-        }
-    }
-
-    public void clusterjUpdate(int c0) {
-        final String str0 = Integer.toString(c0);
-        final int r = -c0;
-        final String str1 = Integer.toString(r);
-
-        // blind update
-        final CJSubscriber o = session.newInstance(CJSubscriber.class);
-        o.setC0(str0);
-        //final CJSubscriber o = session.find(CJSubscriber.class, str0);
-        //String oneChar = Integer.toString(2);
-        o.setC1(str1);
-        o.setC2(r);
-        o.setC3(r);
-        //o.setC4(r);
-        o.setC5(str1);
-        o.setC6(str1);
-        o.setC7(str1);
-        o.setC8(str1);
-        //o.setC9(oneChar);
-        //o.setC10(oneChar);
-        //o.setC11(str);
-        //o.setC12(str);
-        //o.setC13(oneChar);
-        //o.setC14(str);
-        session.updatePersistent(o);
-    }
-
-    protected void ndbjtieUpdate(int c0) {
-        final CharBuffer str0 = CharBuffer.wrap(Integer.toString(c0));
-        final int r = -c0;
-        final CharBuffer str1 = CharBuffer.wrap(Integer.toString(r));
-
-        // get an update operation for the table
-        NdbOperation op = tx.getNdbOperation(table_t0);
-        if (op == null)
-            throw new RuntimeException(toStr(tx.getNdbError()));
-        if (op.updateTuple() != 0)
-            throw new RuntimeException(toStr(tx.getNdbError()));
-
-        // include exception handling as part of transcoding pattern
-        try {
-            // set values; key attribute needs to be set first
-            //str0.rewind();
-            ndbjtieTranscode(bb_r, str0);
-            if (op.equal(attr_c0, bb_r) != 0) // key
-                throw new RuntimeException(toStr(tx.getNdbError()));
-            bb_r.position(bb_r.position() + width_c0);
-
-            //str1.rewind();
-            ndbjtieTranscode(bb_r, str1);
-            if (op.setValue(attr_c1, bb_r) != 0)
-                throw new RuntimeException(toStr(tx.getNdbError()));
-            bb_r.position(bb_r.position() + width_c1);
-
-            if (op.setValue(attr_c2, r) != 0)
-                throw new RuntimeException(toStr(tx.getNdbError()));
-
-            if (op.setValue(attr_c3, r) != 0)
-                throw new RuntimeException(toStr(tx.getNdbError()));
-
-            str1.rewind();
-            ndbjtieTranscode(bb_r, str1);
-            if (op.setValue(attr_c5, bb_r) != 0)
-                throw new RuntimeException(toStr(tx.getNdbError()));
-            bb_r.position(bb_r.position() + width_c5);
-
-            str1.rewind();
-            ndbjtieTranscode(bb_r, str1);
-            if (op.setValue(attr_c6, bb_r) != 0)
-                throw new RuntimeException(toStr(tx.getNdbError()));
-            bb_r.position(bb_r.position() + width_c6);
-
-            str1.rewind();
-            ndbjtieTranscode(bb_r, str1);
-            if (op.setValue(attr_c7, bb_r) != 0)
-                throw new RuntimeException(toStr(tx.getNdbError()));
-            bb_r.position(bb_r.position() + width_c7);
-
-            str1.rewind();
-            ndbjtieTranscode(bb_r, str1);
-            if (op.setValue(attr_c8, bb_r) != 0)
-                throw new RuntimeException(toStr(tx.getNdbError()));
-            bb_r.position(bb_r.position() + width_c8);
-        } catch (CharacterCodingException e) {
-            throw new RuntimeException(e);
-        }
-    }
-
-    // ----------------------------------------------------------------------
-
-    public void runJdbcDelete(XMode mode) throws SQLException {
-        final String m = mode.toString().toLowerCase();
-        //out.println("delete " + nRows + " rows by JDBC " + m + " tx ...");
-
-        long time = -System.currentTimeMillis();
-        connection.setAutoCommit(mode == XMode.SINGLE);
-        for(int i = 0; i < nRows; i++) {
-            jdbcDelete(i, mode);
-        }
-        if (mode == XMode.BATCH)
-            del0.executeBatch();
-        if (mode != XMode.SINGLE)
-            connection.commit();
-        time += System.currentTimeMillis();
-
-        out.println("jdbc_delete_" + m + "    \t: " + time + " ms");
-    }
-
-    public void runClusterjDelete(XMode mode) {
-        final String m = mode.toString().toLowerCase();
-        //out.println("delete " + nRows + " rows by ClusterJ " + m + " tx ...");
-
-        long time = -System.currentTimeMillis();
-        if (mode != XMode.SINGLE)
-            session.currentTransaction().begin();
-        for(int i = 0; i < nRows; i++) {
-            clusterjDelete(i);
-        }
-        if (mode != XMode.SINGLE)
-            session.currentTransaction().commit();
-        time += System.currentTimeMillis();
-
-        out.println("clusterj_delete_" + m + "  \t: " + time + " ms");
-    }
-
-    public void runNdbjtieDelete(XMode mode) {
-        final String m = mode.toString().toLowerCase();
-        //out.println("delete " + nRows + " rows by NDB JTie " + m + " tx ...");
-
-        long time = -System.currentTimeMillis();
-        if (mode == XMode.SINGLE) {
-            for(int i = 0; i < nRows; i++) {
-                ndbjtieBeginTransaction();
-                ndbjtieDelete(i);
-                ndbjtieCommitTransaction();
-                ndbjtieCloseTransaction();
-            }
-        } else {
-            ndbjtieBeginTransaction();
-            for(int i = 0; i < nRows; i++) {
-                ndbjtieDelete(i);
-
-                if (mode == XMode.BULK)
-                    ndbjtieExecuteTransaction();
-            }
-            ndbjtieCommitTransaction();
-            ndbjtieCloseTransaction();
-        }
-        time += System.currentTimeMillis();
-
-        out.println("ndbjtie_delete_" + m + "  \t: " + time + " ms");
-    }
-
-    public void jdbcDelete(int c0, XMode mode) {
-        // include exception handling as part of jdbc pattern
-        try {
-            final String str = Integer.toString(c0);
-            del0.setString(1, str);
-            if (mode == XMode.BATCH) {
-                del0.addBatch();
-            } else {
-                int cnt = del0.executeUpdate();
-                assert (cnt == 1);
-            }
-        } catch (SQLException e) {
-            throw new RuntimeException(e);
-        }
-    }
-
-    public void clusterjDelete(int c0) {
-        // can do a blind delete
-        final CJSubscriber o = session.newInstance(CJSubscriber.class);
-        o.setC0(Integer.toString(c0));
-        assert o != null;
-        session.remove(o);
-    }
-
-    protected void ndbjtieDelete(int c0) {
-        // get an delete operation for the table
-        NdbOperation op = tx.getNdbOperation(table_t0);
-        if (op == null)
-            throw new RuntimeException(toStr(tx.getNdbError()));
-        if (op.deleteTuple() != 0)
-            throw new RuntimeException(toStr(tx.getNdbError()));
-
-        int p = bb_r.position();
-
-        // include exception handling as part of transcoding pattern
-        final int i = c0;
-        final CharBuffer str = CharBuffer.wrap(Integer.toString(c0));
-        try {
-            // set values; key attribute needs to be set first
-            //str.rewind();
-            ndbjtieTranscode(bb_r, str);
-            if (op.equal(attr_c0, bb_r) != 0) // key
-                throw new RuntimeException(toStr(tx.getNdbError()));
-            bb_r.position(p += width_c0);
-        } catch (CharacterCodingException e) {
-            throw new RuntimeException(e);
-        }
-    }
-
-    // ----------------------------------------------------------------------
-
-    protected void ndbjtieBeginTransaction() {
-        assert (tx == null);
-
-        // prepare buffer for writing
-        bb_r.clear();
-
-        // start a transaction
-        // must be closed with NdbTransaction.close
-        final TableConst table  = null;
-        final ByteBuffer keyData = null;
-        final int keyLen = 0;
-        if ((tx = ndb.startTransaction(table, keyData, keyLen)) == null)
-            throw new RuntimeException(toStr(ndb.getNdbError()));
-    }
-
-    protected void ndbjtieExecuteTransaction() {
-        assert (tx != null);
-
-        // execute but don't commit the current transaction
-        final int execType = NdbTransaction.ExecType.NoCommit;
-        final int abortOption = NdbOperation.AbortOption.AbortOnError;
-        final int force = 0;
-        if (tx.execute(execType, abortOption, force) != 0
-            || tx.getNdbError().status() != NdbError.Status.Success)
-            throw new RuntimeException(toStr(tx.getNdbError()));
-    }
-
-    protected void ndbjtieCommitTransaction() {
-        assert (tx != null);
-
-        // commit the current transaction
-        final int execType = NdbTransaction.ExecType.Commit;
-        final int abortOption = NdbOperation.AbortOption.AbortOnError;
-        final int force = 0;
-        if (tx.execute(execType, abortOption, force) != 0
-            || tx.getNdbError().status() != NdbError.Status.Success)
-            throw new RuntimeException(toStr(tx.getNdbError()));
-    }
-
-    protected void ndbjtieRollbackTransaction() {
-        assert (tx != null);
-
-        // abort the current transaction
-        final int execType = NdbTransaction.ExecType.Rollback;
-        final int abortOption = NdbOperation.AbortOption.DefaultAbortOption;
-        final int force = 0;
-        if (tx.execute(execType, abortOption, force) != 0
-            || tx.getNdbError().status() != NdbError.Status.Success)
-            throw new RuntimeException(toStr(tx.getNdbError()));
-    }
-
-    protected void ndbjtieCloseTransaction() {
-        assert (tx != null);
-
-        // close the current transaction (required after commit, rollback)
-        ndb.closeTransaction(tx);
-        tx = null;
-
-        // prepare buffer for reading
-        bb_r.rewind();
-    }
-
-    // ----------------------------------------------------------------------
-
-    protected CharBuffer ndbjtieTranscode(ByteBuffer from)
-        throws CharacterCodingException {
-        // mark position
-        final int p = from.position();
-
-        // read 1-byte length prefix
-        final int l = from.get();
-        assert ((0 <= l) && (l < 256)); // or (l <= 256)?
-
-        // prepare buffer for reading
-        from.limit(from.position() + l);
-
-        // decode
-        final CharBuffer to = csDecoder.decode(from);
-        assert (!from.hasRemaining());
-
-        // allow for repositioning
-        from.limit(from.capacity());
-
-        assert (to.position() == 0);
-        assert (to.limit() == to.capacity());
-        return to;
-    }
-
-    protected void ndbjtieTranscode(ByteBuffer to, CharBuffer from)
-        throws CharacterCodingException {
-        // mark position
-        final int p = to.position();
-
-        // advance 1-byte length prefix
-        to.position(p + 1);
-        //to.put((byte)0);
-
-        // encode
-        final boolean endOfInput = true;
-        final CoderResult cr = csEncoder.encode(from, to, endOfInput);
-        if (!cr.isUnderflow())
-            cr.throwException();
-        assert (!from.hasRemaining());
-
-        // write 1-byte length prefix
-        final int l = (to.position() - p) - 1;
-        assert (0 <= l && l < 256); // or (l <= 256)?
-        to.put(p, (byte)l);
-
-        // reset position
-        to.position(p);
-    }
-
-    // ----------------------------------------------------------------------
-
-    @PersistenceCapable(table="mytable")
-    //@Index(name="c0_UNIQUE")
-    static public interface CJSubscriber
-    {
-        @PrimaryKey
-        String getC0();
-        void setC0(String c0);
-
-        @Index(name="c1_UNIQUE")
-        String getC1();
-        void setC1(String c1);
-
-        @Index(name="c2_UNIQUE")
-        int getC2();
-        void setC2(int c2);
-
-        int getC3();
-        void setC3(int c3);
-
-        int getC4();
-        void setC4(int c4);
-
-        String getC5();
-        void setC5(String c5);
-
-        String getC6();
-        void setC6(String c6);
-
-        @Index(name="c7_UNIQUE")
-        String getC7();
-        void setC7(String c7);
-
-        @Index(name="c8_UNIQUE")
-        String getC8();
-        void setC8(String c8);
-
-        String getC9();
-        void setC9(String c9);
-
-        String getC10();
-        void setC10(String c10);
-
-        String getC11();
-        void setC11(String c11);
-
-        String getC12();
-        void setC12(String c12);
-
-        String getC13();
-        void setC13(String c13);
-
-        String getC14();
-        void setC14(String c14);
-    }
-
-    // ----------------------------------------------------------------------
-}
\ No newline at end of file


Attachment: [text/bzr-bundle] bzr/martin.zaun@oracle.com-20101019231444-pwpzhu4sz7x2bs97.bundle
Thread
bzr push into mysql-5.1-telco-7.1 branch (martin.zaun:3900 to 3901) Martin Zaun20 Oct