diff options
Diffstat (limited to 'ndb/test/ndbapi/testDataBuffers.cpp')
-rw-r--r-- | ndb/test/ndbapi/testDataBuffers.cpp | 616 |
1 files changed, 616 insertions, 0 deletions
diff --git a/ndb/test/ndbapi/testDataBuffers.cpp b/ndb/test/ndbapi/testDataBuffers.cpp new file mode 100644 index 00000000000..75773040113 --- /dev/null +++ b/ndb/test/ndbapi/testDataBuffers.cpp @@ -0,0 +1,616 @@ +/* Copyright (C) 2003 MySQL AB + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +/* + * testDataBuffers + * + * Test getValue() of byte arrays: + * - using application buffers of different alignments and sizes + * - using NdbApi allocated small (<32) and big (>=32) buffers + * + * Verifies fixes to tickets 189 and 206. + * + * Options: see printusage() below. + * + * Creates tables TB00 to TB15 + */ + +#include <ndb_global.h> + +#include <NdbMain.h> +#include <NdbOut.hpp> +#include <NdbApi.hpp> +#include <NdbTest.hpp> +#include <NdbSchemaCon.hpp> +// limits +static int const MaxAttr = 64; +static int const MaxOper = 1000; +static int const MaxSize = 10000; +static int const MaxOff = 64; // max offset to add to data buffer +static int const MaxData = MaxSize + MaxOff + 100; + +// options +static int attrcnt = 25; +static int existok = 0; +static bool kontinue = false; +static int loopcnt = 1; +static int opercnt = 100; // also does this many scans +static int randomizer = 171317; +static int sizelim = 500; +static int xverbose = 0; + +static void printusage() { + ndbout + << "usage: testDataBuffers options [default/max]" + << endl + << "NOTE: too large combinations result in NDB error" + << endl + << "-a N number of attributes (including the key) [25/64]" + << endl + << "-e no error if table exists (assumed to have same structure)" + << endl + << "-k on error continue with next test case" + << endl + << "-l N number of loops to run, 0 means infinite [1]" + << endl + << "-o N number of operations (rows in each table) [100/1000]" + << endl + << "-r N source of randomness (big number (prime)) [171317]" + << endl + << "-s N array size limit (rounded up in some tests) [500/10000]" + << endl + << "-x extremely verbose" + << endl + << "Tables: TB00 .. TB15" + << endl + ; +} + +static Ndb* ndb = 0; +static NdbSchemaCon* tcon = 0; +static NdbSchemaOp* top = 0; +static NdbConnection* con = 0; +static NdbOperation* op = 0; + +static int +ndberror(char const* fmt, ...) +{ + va_list ap; + char buf[200]; + va_start(ap, fmt); + vsnprintf(buf, sizeof(buf), fmt, ap); + va_end(ap); + ndbout << buf << " --" << endl; + if (ndb) + ndbout << "ndb : " << ndb->getNdbError() << endl; + if (tcon) + ndbout << "tcon: " << tcon->getNdbError() << endl; + if (top) + ndbout << "top: " << top->getNdbError() << endl; + if (con) + ndbout << "con : " << con->getNdbError() << endl; + if (op) + ndbout << "op : " << op->getNdbError() << endl; + return -1; +} + +static int +chkerror(char const* fmt, ...) +{ + va_list ap; + char buf[200]; + va_start(ap, fmt); + vsnprintf(buf, sizeof(buf), fmt, ap); + va_end(ap); + ndbout << "*** check failed: " << buf << " ***" << endl; + return -1; +} + +// alignment of addresses and data sizes + +static bool isAligned(unsigned x) +{ + return ((x & 3) == 0); +} +static bool isAligned(char* p) +{ + return isAligned(unsigned(p)); +} +static unsigned toAligned(unsigned x) +{ + while (! isAligned(x)) + x++; + return x; +} +static char* toAligned(char* p) +{ + while (! isAligned(p)) + p++; + return p; +} + +// byte value for key k column i byte j +static int byteVal(int k, int i, int j) +{ + return '0' + (k + i + j) % 10; +} + +// tables + +static char tab[20] = ""; + +static struct col { + char aAttrName[20]; + AttrType aAttrType; + int aAttrSize; + int aArraySize; + KeyType aTupleKey; + bool nullable; + NdbRecAttr* aRa; + char* buf; + int bufsiz; + char data[MaxData]; +} ccol[MaxAttr]; + +static int key = 0; + +// independent test bits +static bool alignAddr; // align our buffer addresses to 4x +static bool alignSize; // align data sizes to 4x +static bool useBuf; // use our buffers for output +static bool noRandom; // do not randomize sizes and offsets +static int testbits = 4; + +static int +makeSize(int i) +{ + int n; + if (noRandom) + n = i; + else + n = i * randomizer; + n %= sizelim; + if (n <= 0) + n = 1; + if (alignSize) + n = toAligned(n); + return n; +} + +static int +makeOff(int k) +{ + int n; + if (alignAddr) + n = 0; + else if (noRandom) + n = k; + else + n = k * randomizer; + n %= MaxOff; + if (n < 0) + n = -n; + return n; +} + +static int +testcase(int flag) +{ + ndbout << "--- case " << flag << " ---" << endl; + sprintf(tab, "TB%02d", flag); + + alignAddr = ! (flag & 1); + ndbout << (alignAddr ? "align addresses" : "mis-align addresses") << endl; + alignSize = ! (flag & 2); + ndbout << (alignSize ? "align data sizes" : "mis-align data sizes") << endl; + useBuf = ! (flag & 4); + ndbout << (useBuf ? "use our buffers" : "use ndbapi buffers") << endl; + noRandom = ! (flag & 8); + ndbout << (noRandom ? "simple sizes" : "randomize sizes") << endl; + + int smax = 0, stot = 0; + if (xverbose) + ndbout << "- define table " << tab << endl; + for (int i = 0; i < attrcnt; i++) { + col& c = ccol[i]; + memset(&c, 0, sizeof(c)); + sprintf(c.aAttrName, "C%d", i); + if (i == 0) { + c.aAttrType = UnSigned; + c.aAttrSize = 32; + c.aArraySize = 1; + c.aTupleKey = TupleKey; + c.nullable = false; + } else { + c.aAttrType = String; + c.aAttrSize = 8; + c.aArraySize = makeSize(i); + if (smax < c.aArraySize) + smax = c.aArraySize; + stot += c.aArraySize; + c.aTupleKey = NoKey; + c.nullable = true; + if (xverbose) + ndbout << "-- column " << i << " size=" << c.aArraySize << endl; + } + c.buf = toAligned(c.data); + c.bufsiz = sizeof(c.data) - (c.buf - c.data); + } + ndbout << "tab=" << tab << " cols=" << attrcnt + << " size max=" << smax << " tot=" << stot << endl; + + ndb = new Ndb("TEST_DB"); + if (ndb->init() != 0) + return ndberror("init"); + if (ndb->waitUntilReady(30) < 0) + return ndberror("waitUntilReady"); + + if ((tcon = NdbSchemaCon::startSchemaTrans(ndb)) == 0) + return ndberror("startSchemaTransaction"); + if ((top = tcon->getNdbSchemaOp()) == 0) + return ndberror("getNdbSchemaOp"); + if (top->createTable(tab) < 0) + return ndberror("createTable"); + for (int i = 0; i < attrcnt; i++) { + col& c = ccol[i]; + if (top->createAttribute( + c.aAttrName, + c.aTupleKey, + c.aAttrSize, + c.aArraySize, + c.aAttrType, + MMBased, + c.nullable + ) < 0) + return ndberror("createAttribute col=%d", i); + } + if (tcon->execute() < 0) { + if (! (tcon->getNdbError().code == 721 && existok)) + return ndberror("execute"); + ndbout << "using " << tab << endl; + } else { + ndbout << "created " << tab << endl; + } + top = 0; + tcon = 0; + + if (xverbose) + ndbout << "- delete" << endl; + int delcnt = 0; + for (key = 0; key < opercnt; key++) { + if ((con = ndb->startTransaction()) == 0) + return ndberror("startTransaction key=%d", key); + if ((op = con->getNdbOperation(tab)) == 0) + return ndberror("getNdbOperation key=%d", key); + if (op->deleteTuple() < 0) + return ndberror("deleteTuple key=%d", key); + for (int i = 0; i < attrcnt; i++) { + col& c = ccol[i]; + if (i == 0) { + if (op->equal(c.aAttrName, (char*)&key, sizeof(key)) < 0) + return ndberror("equal key=%d", key); + } else { + } + } + if (con->execute(Commit) < 0) { + if (con->getNdbError().code != 626) + return ndberror("execute key=%d", key); + } else { + delcnt++; + } + ndb->closeTransaction(con); + } + con = 0; + op = 0; + ndbout << "deleted " << delcnt << endl; + + if (xverbose) + ndbout << "- insert" << endl; + for (key = 0; key < opercnt; key++) { + int off = makeOff(key); + if ((con = ndb->startTransaction()) == 0) + return ndberror("startTransaction key=%d", key); + if ((op = con->getNdbOperation(tab)) == 0) + return ndberror("getNdbOperation key=%d", key); + if (op->insertTuple() < 0) + return ndberror("insertTuple key=%d", key); + for (int i = 0; i < attrcnt; i++) { + col& c = ccol[i]; + if (i == 0) { + if (op->equal(c.aAttrName, (char*)&key, sizeof(key)) < 0) + return ndberror("equal key=%d", key); + } else { + memset(c.buf, 'A', c.bufsiz); + for (int j = 0; j < c.aArraySize; j++) + c.buf[j + off] = byteVal(key, i, j); + if (op->setValue(c.aAttrName, c.buf + off, c.aArraySize) < 0) + return ndberror("setValue key=%d col=%d", key, i); + } + } + if (con->execute(Commit) < 0) + return ndberror("execute key=%d", key); + ndb->closeTransaction(con); + } + con = 0; + op = 0; + ndbout << "inserted " << key << endl; + + if (xverbose) + ndbout << "- select" << endl; + for (key = 0; key < opercnt; key++) { + int off = makeOff(key); + if (xverbose) + ndbout << "-- key " << key << " off=" << off << endl; + if ((con = ndb->startTransaction()) == 0) + return ndberror("startTransaction key=%d", key); + if ((op = con->getNdbOperation(tab)) == 0) + return ndberror("getNdbOperation key=%d", key); + if (op->readTuple() < 0) + return ndberror("readTuple key=%d", key); + for (int i = 0; i < attrcnt; i++) { + col& c = ccol[i]; + if (i == 0) { + if (op->equal(c.aAttrName, (char*)&key, sizeof(key)) < 0) + return ndberror("equal key=%d", key); + } else { + if (xverbose) { + char tmp[20]; + if (useBuf) + sprintf(tmp, "0x%x", int(c.buf + off)); + else + strcpy(tmp, "ndbapi"); + ndbout << "--- column " << i << " addr=" << tmp << endl; + } + memset(c.buf, 'B', c.bufsiz); + if (useBuf) { + if (op->getValue(c.aAttrName, c.buf + off) < 0) + return ndberror("getValue key=%d col=%d", key, i); + } else { + if ((c.aRa = op->getValue(c.aAttrName)) == 0) + return ndberror("getValue key=%d col=%d", key, i); + } + } + } + if (con->execute(Commit) != 0) + return ndberror("execute key=%d", key); + for (int i = 0; i < attrcnt; i++) { + col& c = ccol[i]; + if (i == 0) { + } else if (useBuf) { + for (int j = 0; j < off; j++) { + if (c.buf[j] != 'B') { + return chkerror("mismatch before key=%d col=%d pos=%d ok=%02x bad=%02x", + key, i, j, 'B', c.buf[j]); + } + } + for (int j = 0; j < c.aArraySize; j++) { + if (c.buf[j + off] != byteVal(key, i, j)) { + return chkerror("mismatch key=%d col=%d pos=%d ok=%02x bad=%02x", + key, i, j, byteVal(key, i, j), c.buf[j]); + } + } + for (int j = c.aArraySize + off; j < c.bufsiz; j++) { + if (c.buf[j] != 'B') { + return chkerror("mismatch after key=%d col=%d pos=%d ok=%02x bad=%02x", + key, i, j, 'B', c.buf[j]); + } + } + } else { + char* buf = c.aRa->aRef(); + if (buf == 0) + return ndberror("null aRef key=%d col%d", key, i); + for (int j = 0; j < c.aArraySize; j++) { + if (buf[j] != byteVal(key, i, j)) { + return chkerror("mismatch key=%d col=%d pos=%d ok=%02x bad=%02x", + key, i, j, byteVal(key, i, j), buf[j]); + } + } + } + } + ndb->closeTransaction(con); + } + con = 0; + op = 0; + ndbout << "selected " << key << endl; + + if (xverbose) + ndbout << "- scan" << endl; + char found[MaxOper]; + for (int k = 0; k < opercnt; k++) + found[k] = 0; + for (key = 0; key < opercnt; key++) { + int off = makeOff(key); + if (xverbose) + ndbout << "-- key " << key << " off=" << off << endl; + int newkey = 0; + if ((con = ndb->startTransaction()) == 0) + return ndberror("startTransaction key=%d", key); + if ((op = con->getNdbOperation(tab)) == 0) + return ndberror("getNdbOperation key=%d", key); + if (op->openScanRead(1) < 0) + return ndberror("openScanRead key=%d", key); + { + col& c = ccol[0]; + if (op->load_const_u32(1, key) < 0) + return ndberror("load_const_u32"); + if (op->read_attr(c.aAttrName, 2) < 0) + return ndberror("read_attr"); + if (op->branch_eq(1, 2, 0) < 0) + return ndberror("branch_eq"); + if (op->interpret_exit_nok() < 0) + return ndberror("interpret_exit_nok"); + if (op->def_label(0) < 0) + return ndberror("def_label"); + if (op->interpret_exit_ok() < 0) + return ndberror("interpret_exit_ok"); + } + for (int i = 0; i < attrcnt; i++) { + col& c = ccol[i]; + if (i == 0) { + if (op->getValue(c.aAttrName, (char*)&newkey) < 0) + return ndberror("getValue key=%d col=%d", key, i); + } else { + if (xverbose) { + char tmp[20]; + if (useBuf) + sprintf(tmp, "0x%x", int(c.buf + off)); + else + strcpy(tmp, "ndbapi"); + ndbout << "--- column " << i << " addr=" << tmp << endl; + } + memset(c.buf, 'C', c.bufsiz); + if (useBuf) { + if (op->getValue(c.aAttrName, c.buf + off) < 0) + return ndberror("getValue key=%d col=%d", key, i); + } else { + if ((c.aRa = op->getValue(c.aAttrName)) == 0) + return ndberror("getValue key=%d col=%d", key, i); + } + } + } + if (con->executeScan() < 0) + return ndberror("executeScan key=%d", key); + int ret, cnt = 0; + while ((ret = con->nextScanResult()) == 0) { + if (key != newkey) + return ndberror("unexpected key=%d newkey=%d", key, newkey); + for (int i = 1; i < attrcnt; i++) { + col& c = ccol[i]; + if (useBuf) { + for (int j = 0; j < off; j++) { + if (c.buf[j] != 'C') { + return chkerror("mismatch before key=%d col=%d pos=%d ok=%02x bad=%02x", + key, i, j, 'C', c.buf[j]); + } + } + for (int j = 0; j < c.aArraySize; j++) { + if (c.buf[j + off] != byteVal(key, i, j)) { + return chkerror("mismatch key=%d col=%d pos=%d ok=%02x bad=%02x", + key, i, j, byteVal(key, i, j), c.buf[j]); + } + } + for (int j = c.aArraySize + off; j < c.bufsiz; j++) { + if (c.buf[j] != 'C') { + return chkerror("mismatch after key=%d col=%d pos=%d ok=%02x bad=%02x", + key, i, j, 'C', c.buf[j]); + } + } + } else { + char* buf = c.aRa->aRef(); + if (buf == 0) + return ndberror("null aRef key=%d col%d", key, i); + for (int j = 0; j < c.aArraySize; j++) { + if (buf[j] != byteVal(key, i, j)) { + return chkerror("mismatch key=%d col=%d pos=%d ok=%02x bad=%02x", + key, i, j, byteVal(key, i, j), buf[j]); + } + } + } + } + cnt++; + } + if (ret < 0) + return ndberror("nextScanResult key=%d", key); + if (cnt != 1) + return ndberror("scan key=%d found %d", key, cnt); + found[key] = 1; + ndb->closeTransaction(con); + } + con = 0; + op = 0; + for (int k = 0; k < opercnt; k++) + if (! found[k]) + return ndberror("key %d not found", k); + ndbout << "scanned " << key << endl; + + ndb = 0; + ndbout << "done" << endl; + return 0; +} + +NDB_COMMAND(testDataBuffers, "testDataBuffers", "testDataBuffers", "testDataBuffers", 65535) +{ + while (++argv, --argc > 0) { + char const* p = argv[0]; + if (*p++ != '-' || strlen(p) != 1) + goto wrongargs; + switch (*p) { + case 'a': + if (++argv, --argc > 0) { + attrcnt = atoi(argv[0]); + if (1 <= attrcnt && attrcnt <= MaxAttr) + break; + } + goto wrongargs; + case 'e': + existok = 1; + break; + case 'k': + kontinue = true; + break; + case 'l': + if (++argv, --argc > 0) { + loopcnt = atoi(argv[0]); + if (0 <= loopcnt) + break; + } + goto wrongargs; + case 'o': + if (++argv, --argc > 0) { + opercnt = atoi(argv[0]); + if (0 <= opercnt && opercnt <= MaxOper) + break; + } + goto wrongargs; + case 'r': + if (++argv, --argc > 0) { + randomizer = atoi(argv[0]); + if (1 <= randomizer) + break; + } + goto wrongargs; + case 's': + if (++argv, --argc > 0) { + sizelim = atoi(argv[0]); + if (1 <= sizelim && sizelim <= MaxSize) + break; + } + goto wrongargs; + case 'x': + xverbose = 1; + break; + default: + wrongargs: + printusage(); + return NDBT_ProgramExit(NDBT_WRONGARGS); + } + } + unsigned ok = true; + for (int i = 1; 0 == loopcnt || i <= loopcnt; i++) { + ndbout << "=== loop " << i << " ===" << endl; + for (int flag = 0; flag < (1<<testbits); flag++) { + if (testcase(flag) < 0) { + ok = false; + if (! kontinue) + goto out; + } + } + } +out: + return NDBT_ProgramExit(ok ? NDBT_OK : NDBT_FAILED); +} + +// vim: set sw=4: |