Below is the list of changes that have just been committed into a local
5.1 repository of pekka. When pekka does a push these changes will
be propagated to the main repository and, within 24 hours after the
push, to the public repository.
For information on how to access the public repository
see http://dev.mysql.com/doc/mysql/en/installing-source-tree.html
ChangeSet@stripped, 2007-03-22 09:16:27+01:00, pekka@stripped +10 -0
ndb - wl#3717 data ops
passes testBlobs in V1 and V2
storage/ndb/include/kernel/ndb_limits.h@stripped, 2007-03-22 09:15:04+01:00, pekka@stripped +4 -1
wl#3717 data ops
storage/ndb/include/kernel/signaldata/DictTabInfo.hpp@stripped, 2007-03-22 09:15:04+01:00, pekka@stripped +8 -2
wl#3717 data ops
storage/ndb/include/ndbapi/NdbBlob.hpp@stripped, 2007-03-22 09:15:04+01:00, pekka@stripped +44 -4
wl#3717 data ops
storage/ndb/include/ndbapi/NdbDictionary.hpp@stripped, 2007-03-22 09:15:04+01:00, pekka@stripped +3 -0
wl#3717 data ops
storage/ndb/src/ndbapi/NdbBlob.cpp@stripped, 2007-03-22 09:15:04+01:00, pekka@stripped +448 -101
wl#3717 data ops
storage/ndb/src/ndbapi/NdbDictionary.cpp@stripped, 2007-03-22 09:15:04+01:00, pekka@stripped +12 -0
wl#3717 data ops
storage/ndb/src/ndbapi/NdbDictionaryImpl.cpp@stripped, 2007-03-22 09:15:04+01:00, pekka@stripped +21 -2
wl#3717 data ops
storage/ndb/src/ndbapi/NdbDictionaryImpl.hpp@stripped, 2007-03-22 09:15:04+01:00, pekka@stripped +29 -2
wl#3717 data ops
storage/ndb/src/ndbapi/NdbRecAttr.cpp@stripped, 2007-03-22 09:15:05+01:00, pekka@stripped +4 -5
wl#3717 data ops
storage/ndb/test/ndbapi/testBlobs.cpp@stripped, 2007-03-22 09:15:05+01:00, pekka@stripped +107 -40
wl#3717 data ops
# This is a BitKeeper patch. What follows are the unified diffs for the
# set of deltas contained in the patch. The rest of the patch, the part
# that BitKeeper cares about, is below these diffs.
# User: pekka
# Host: clam.(none)
# Root: /export/space/pekka/ndb/version/my51-wl3717-a
--- 1.28/storage/ndb/include/kernel/ndb_limits.h 2007-01-06 01:21:21 +01:00
+++ 1.29/storage/ndb/include/kernel/ndb_limits.h 2007-03-22 09:15:04 +01:00
@@ -121,7 +121,10 @@
/*
* Blobs.
*/
-#define NDB_BLOB_HEAD_SIZE 2 /* sizeof(NdbBlob::Head) >> 2 */
+#define NDB_BLOB_V1 1
+#define NDB_BLOB_V2 2
+#define NDB_BLOB_V1_HEAD_SIZE 2 /* sizeof(Uint64) >> 2 */
+#define NDB_BLOB_V2_HEAD_SIZE 4 /* 2 + 2 + 4 + 8 bytes, see NdbBlob.hpp */
/*
* Character sets.
--- 1.36/storage/ndb/include/kernel/signaldata/DictTabInfo.hpp 2007-02-23 12:23:42 +01:00
+++ 1.37/storage/ndb/include/kernel/signaldata/DictTabInfo.hpp 2007-03-22 09:15:04 +01:00
@@ -506,8 +506,14 @@
case DictTabInfo::ExtBlob:
case DictTabInfo::ExtText:
AttributeSize = DictTabInfo::an8Bit;
- // head + inline part (length in precision lower half)
- AttributeArraySize = (NDB_BLOB_HEAD_SIZE << 2) + (AttributeExtPrecision & 0xFFFF);
+ if (unlikely(AttributeArrayType == NDB_ARRAYTYPE_FIXED)) {
+ // head + inline part (length in precision lower half)
+ AttributeArraySize = (NDB_BLOB_V1_HEAD_SIZE << 2) +
+ (AttributeExtPrecision & 0xFFFF);
+ } else {
+ AttributeArraySize = (NDB_BLOB_V2_HEAD_SIZE << 2) +
+ (AttributeExtPrecision & 0xFFFF);
+ }
break;
case DictTabInfo::ExtBit:
AttributeSize = DictTabInfo::aBit;
--- 1.89/storage/ndb/include/ndbapi/NdbDictionary.hpp 2007-02-22 15:49:30 +01:00
+++ 1.90/storage/ndb/include/ndbapi/NdbDictionary.hpp 2007-03-22 09:15:04 +01:00
@@ -537,6 +537,9 @@
static const Column * ROW_GCI;
int getSizeInBytes() const;
+
+ int getBlobVersion() const; // NDB_BLOB_V1 or NDB_BLOB_V2
+ void setBlobVersion(int blobVersion); // default NDB_BLOB_V2
#endif
private:
--- 1.69/storage/ndb/src/ndbapi/NdbDictionary.cpp 2007-02-22 15:49:31 +01:00
+++ 1.70/storage/ndb/src/ndbapi/NdbDictionary.cpp 2007-03-22 09:15:04 +01:00
@@ -291,6 +291,18 @@
return (StorageType)m_impl.m_storageType;
}
+int
+NdbDictionary::Column::getBlobVersion() const
+{
+ return m_impl.getBlobVersion();
+}
+
+void
+NdbDictionary::Column::setBlobVersion(int blobVersion)
+{
+ m_impl.setBlobVersion(blobVersion);
+}
+
/*****************************************************************
* Table facade
*/
--- 1.164/storage/ndb/src/ndbapi/NdbDictionaryImpl.cpp 2007-03-20 16:38:18 +01:00
+++ 1.165/storage/ndb/src/ndbapi/NdbDictionaryImpl.cpp 2007-03-22 09:15:04 +01:00
@@ -114,6 +114,7 @@
m_arraySize = col.m_arraySize;
m_arrayType = col.m_arrayType;
m_storageType = col.m_storageType;
+ m_blobVersion = col.m_blobVersion;
m_keyInfoPos = col.m_keyInfoPos;
if (col.m_blobTable == NULL)
m_blobTable = NULL;
@@ -134,6 +135,7 @@
// do not use default_charset_info as it may not be initialized yet
// use binary collation until NDB tests can handle charsets
CHARSET_INFO* default_cs = &my_charset_bin;
+ m_blobVersion = 0;
m_type = t;
switch (m_type) {
case Tinyint:
@@ -205,14 +207,16 @@
m_scale = 8000;
m_length = 4;
m_cs = NULL;
- m_arrayType = NDB_ARRAYTYPE_FIXED;
+ m_arrayType = NDB_ARRAYTYPE_MEDIUM_VAR;
+ m_blobVersion = NDB_BLOB_V2;
break;
case Text:
m_precision = 256;
m_scale = 8000;
m_length = 4;
m_cs = default_cs;
- m_arrayType = NDB_ARRAYTYPE_FIXED;
+ m_arrayType = NDB_ARRAYTYPE_MEDIUM_VAR;
+ m_blobVersion = NDB_BLOB_V2;
break;
case Time:
case Year:
@@ -314,6 +318,9 @@
if (m_arrayType != col.m_arrayType || m_storageType != col.m_storageType){
DBUG_RETURN(false);
}
+ if (m_blobVersion != col.m_blobVersion) {
+ DBUG_RETURN(false);
+ }
DBUG_RETURN(true);
}
@@ -2169,6 +2176,18 @@
col->m_arraySize = (attrDesc.AttributeArraySize + 31) >> 5;
}
col->m_storageType = attrDesc.AttributeStorageType;
+
+ if (col->getBlobType()) {
+ if (unlikely(col->m_arrayType) == NDB_ARRAYTYPE_FIXED)
+ col->m_blobVersion = NDB_BLOB_V1;
+ else if (col->m_arrayType == NDB_ARRAYTYPE_MEDIUM_VAR)
+ col->m_blobVersion = NDB_BLOB_V2;
+ else {
+ delete impl;
+ NdbMem_Free((void*)tableDesc);
+ DBUG_RETURN(4263);
+ }
+ }
col->m_pk = attrDesc.AttributeKeyFlag;
col->m_distributionKey = (attrDesc.AttributeDKey != 0);
--- 1.73/storage/ndb/src/ndbapi/NdbDictionaryImpl.hpp 2007-02-22 15:49:31 +01:00
+++ 1.74/storage/ndb/src/ndbapi/NdbDictionaryImpl.hpp 2007-03-22 09:15:04 +01:00
@@ -109,6 +109,10 @@
bool getStringType() const;
bool getBlobType() const;
+ int m_blobVersion; // if blob, NDB_BLOB_V1 or NDB_BLOB_V2
+ int getBlobVersion() const;
+ void setBlobVersion(int blobVersion);
+
/**
* Equality/assign
*/
@@ -729,22 +733,45 @@
}
inline
+int
+NdbColumnImpl::getBlobVersion() const {
+ return m_blobVersion;
+}
+
+inline
+void
+NdbColumnImpl::setBlobVersion(int blobVersion) {
+ if (blobVersion == NDB_BLOB_V1) {
+ m_arrayType = NDB_ARRAYTYPE_FIXED;
+ } else if (blobVersion == NDB_BLOB_V2) {
+ // always 2 length bytes for head+inline
+ m_arrayType = NDB_ARRAYTYPE_MEDIUM_VAR;
+ }
+ // invalid value should be detected at validate
+ m_blobVersion = blobVersion;
+}
+
+inline
bool
NdbColumnImpl::get_var_length(const void* value, Uint32& len) const
{
+ DBUG_ENTER("NdbColumnImpl::get_var_length");
Uint32 max_len = m_attrSize * m_arraySize;
switch (m_arrayType) {
case NDB_ARRAYTYPE_SHORT_VAR:
len = 1 + *((Uint8*)value);
+ DBUG_PRINT("info", ("SHORT_VAR: len=%u max_len=%u", len, max_len));
break;
case NDB_ARRAYTYPE_MEDIUM_VAR:
len = 2 + uint2korr((char*)value);
+ DBUG_PRINT("info", ("MEDIUM_VAR: len=%u max_len=%u", len, max_len));
break;
default:
len = max_len;
- return true;
+ DBUG_PRINT("info", ("FIXED: len=%u max_len=%u", len, max_len));
+ DBUG_RETURN(true);
}
- return (len <= max_len);
+ DBUG_RETURN(len <= max_len);
}
inline
--- 1.42/storage/ndb/src/ndbapi/NdbRecAttr.cpp 2007-03-20 16:38:18 +01:00
+++ 1.43/storage/ndb/src/ndbapi/NdbRecAttr.cpp 2007-03-22 09:15:05 +01:00
@@ -426,15 +426,14 @@
case NdbDictionary::Column::Blob:
case NdbDictionary::Column::Text:
{
- // user defined aRef() may not be aligned to Uint64
NdbBlob::Head head;
- memcpy(&head, r.aRef(), sizeof(head));
+ NdbBlob::unpackBlobHead(head, r.aRef(), c->getBlobVersion());
out << head.length << ":";
- const unsigned char* p = (const unsigned char*)r.aRef() + sizeof(head);
- if (r.get_size_in_bytes() < sizeof(head))
+ const unsigned char* p = (const unsigned char*)r.aRef() + head.headsize;
+ if (r.get_size_in_bytes() < head.headsize)
out << "***error***"; // really cannot happen
else {
- unsigned n = r.get_size_in_bytes() - sizeof(head);
+ unsigned n = r.get_size_in_bytes() - head.headsize;
for (unsigned k = 0; k < n && k < head.length; k++) {
if (r.getType() == NdbDictionary::Column::Blob)
out.print("%02X", (int)p[k]);
--- 1.37/storage/ndb/test/ndbapi/testBlobs.cpp 2007-03-16 04:02:52 +01:00
+++ 1.38/storage/ndb/test/ndbapi/testBlobs.cpp 2007-03-22 09:15:05 +01:00
@@ -20,6 +20,7 @@
#include <ndb_global.h>
#include <NdbMain.h>
#include <NdbOut.hpp>
+#include <OutputStream.hpp>
#include <NdbTest.hpp>
#include <NdbTick.h>
@@ -41,16 +42,16 @@
unsigned m_batch;
bool m_core;
bool m_dbg;
- bool m_dbgall;
const char* m_dbug;
bool m_fac;
bool m_full;
unsigned m_loop;
unsigned m_parts;
unsigned m_rows;
- unsigned m_seed;
+ int m_seed;
const char* m_skip;
const char* m_test;
+ int m_blob_version;
// metadata
const char* m_tname;
const char* m_x1name; // hash index
@@ -70,27 +71,27 @@
m_batch(7),
m_core(false),
m_dbg(false),
- m_dbgall(false),
m_dbug(0),
m_fac(false),
m_full(false),
m_loop(1),
m_parts(10),
m_rows(100),
- m_seed(0),
+ m_seed(-1),
m_skip(0),
m_test(0),
+ m_blob_version(2),
// metadata
- m_tname("TBLOB1"),
- m_x1name("TBLOB1X1"),
- m_x2name("TBLOB1X2"),
+ m_tname("TB1"),
+ m_x1name("TB1X1"),
+ m_x2name("TB1X2"),
m_pk1off(0x12340000),
m_pk2len(55),
m_oneblob(false),
- m_blob1(false, 7, 1137, 10),
+ m_blob1(false, 240, 2000, 4), // head+inline=256 bytes
m_blob2(true, 99, 55, 1),
// perf
- m_tnameperf("TBLOB2"),
+ m_tnameperf("TB2"),
m_rowsperf(10000),
// bugs
m_bug(0),
@@ -108,18 +109,18 @@
<< "usage: testBlobs options [default/max]" << endl
<< " -batch N number of pk ops in batch [" << d.m_batch << "]" << endl
<< " -core dump core on error" << endl
- << " -dbg print debug" << endl
- << " -dbgall print also NDB API debug (if compiled in)" << endl
- << " -dbug opt dbug options" << endl
+ << " -dbg print program debug" << endl
+ << " -dbug opt print program debug and ndb api DBUG" << endl
<< " -fac fetch across commit in scan delete [" << d.m_fac << "]" << endl
<< " -full read/write only full blob values" << endl
<< " -loop N loop N times 0=forever [" << d.m_loop << "]" << endl
<< " -parts N max parts in blob value [" << d.m_parts << "]" << endl
<< " -rows N number of rows [" << d.m_rows << "]" << endl
<< " -rowsperf N rows for performace test [" << d.m_rowsperf << "]" << endl
- << " -seed N random seed 0=loop number [" << d.m_seed << "]" << endl
+ << " -seed N random seed 0=loop number -1=random [" << d.m_seed << "]" << endl
<< " -skip xxx skip given tests (see list) [no tests]" << endl
<< " -test xxx only given tests (see list) [all tests]" << endl
+ << " -version N blob version 1 or 2 [" << d.m_blob_version << "]" << endl
<< "metadata" << endl
<< " -pk2len N length of PK2 [" << d.m_pk2len << "/" << g_max_pk2len <<"]" << endl
<< " -oneblob only 1 blob attribute [default 2]" << endl
@@ -245,6 +246,7 @@
{ NdbDictionary::Column col("BL1");
const Bcol& b = g_opt.m_blob1;
col.setType(NdbDictionary::Column::Blob);
+ col.setBlobVersion(g_opt.m_blob_version);
col.setInlineSize(b.m_inline);
col.setPartSize(b.m_partsize);
col.setStripeSize(b.m_stripe);
@@ -263,6 +265,7 @@
{ NdbDictionary::Column col("BL2");
const Bcol& b = g_opt.m_blob2;
col.setType(NdbDictionary::Column::Text);
+ col.setBlobVersion(g_opt.m_blob_version);
col.setNullable(true);
col.setInlineSize(b.m_inline);
col.setPartSize(b.m_partsize);
@@ -710,10 +713,11 @@
CHK(ra->isNULL() == 1);
} else {
CHK(ra->isNULL() == 0);
- const NdbBlob::Head* head = (const NdbBlob::Head*)ra->aRef();
- CHK(head->length == v.m_len);
- const char* data = (const char*)(head + 1);
- for (unsigned i = 0; i < head->length && i < c.m_inline; i++)
+ NdbBlob::Head head;
+ NdbBlob::unpackBlobHead(head, ra->aRef(), g_opt.m_blob_version);
+ CHK(head.length == v.m_len);
+ const char* data = ra->aRef() + head.headsize;
+ for (unsigned i = 0; i < head.length && i < c.m_inline; i++)
CHK(data[i] == v.m_val[i]);
}
return 0;
@@ -752,19 +756,36 @@
return 0;
}
+static unsigned
+getvarsize(const char* buf)
+{
+ const unsigned char* p = (const unsigned char*)buf;
+ return p[0] + (p[1] << 8);
+}
+
static int
verifyBlobTable(const Bcol& b, const Bval& v, Uint32 pk1, bool exists)
{
DBG("verify " << b.m_btname << " pk1=" << hex << pk1);
- NdbRecAttr* ra_pk;
- NdbRecAttr* ra_part;
- NdbRecAttr* ra_data;
+ NdbRecAttr* ra_pk = 0; // V1
+ NdbRecAttr* ra_pk1 = 0; // V2
+ NdbRecAttr* ra_pk2 = 0; // V2
+ NdbRecAttr* ra_part = 0;
+ NdbRecAttr* ra_data = 0;
CHK((g_con = g_ndb->startTransaction()) != 0);
CHK((g_ops = g_con->getNdbScanOperation(b.m_btname)) != 0);
CHK(g_ops->readTuples() == 0);
- CHK((ra_pk = g_ops->getValue("PK")) != 0);
- CHK((ra_part = g_ops->getValue("PART")) != 0);
- CHK((ra_data = g_ops->getValue("DATA")) != 0);
+ if (g_opt.m_blob_version == 1) {
+ CHK((ra_pk = g_ops->getValue("PK")) != 0);
+ CHK((ra_part = g_ops->getValue("PART")) != 0);
+ CHK((ra_data = g_ops->getValue("DATA")) != 0);
+ } else {
+ CHK((ra_pk1 = g_ops->getValue("PK1")) != 0);
+ if (g_opt.m_pk2len != 0)
+ CHK((ra_pk2 = g_ops->getValue("PK2")) != 0);
+ CHK((ra_part = g_ops->getValue("NDB$PART")) != 0);
+ CHK((ra_data = g_ops->getValue("NDB$DATA")) != 0);
+ }
CHK(g_con->execute(NoCommit) == 0);
unsigned partcount;
if (! exists || v.m_len <= b.m_inline)
@@ -778,11 +799,15 @@
CHK((ret = g_ops->nextResult()) == 0 || ret == 1);
if (ret == 1)
break;
- if (pk1 != ra_pk->u_32_value())
- continue;
+ if (g_opt.m_blob_version == 1) {
+ if (pk1 != ra_pk->u_32_value())
+ continue;
+ } else {
+ if (pk1 != ra_pk1->u_32_value())
+ continue;
+ }
Uint32 part = ra_part->u_32_value();
DBG("part " << part << " of " << partcount);
- const char* data = ra_data->aRef();
CHK(part < partcount && ! seen[part]);
seen[part] = 1;
unsigned n = b.m_inline + part * b.m_partsize;
@@ -790,10 +815,23 @@
unsigned m = v.m_len - n;
if (m > b.m_partsize)
m = b.m_partsize;
+ const char* data = ra_data->aRef();
+ if (g_opt.m_blob_version == 1)
+ ;
+ else {
+ unsigned sz = getvarsize(data);
+ CHK(sz <= b.m_partsize);
+ data += 2;
+ if (part + 1 < partcount)
+ CHK(sz == b.m_partsize);
+ else
+ CHK(sz == m);
+ }
CHK(memcmp(data, v.m_val + n, m) == 0);
}
for (unsigned i = 0; i < partcount; i++)
CHK(seen[i] == 1);
+ delete [] seen;
g_ndb->closeTransaction(g_con);
g_ops = 0;
g_con = 0;
@@ -1347,11 +1385,6 @@
g_tups = new Tup [g_opt.m_rows];
CHK(dropTable() == 0);
CHK(createTable() == 0);
- if (g_opt.m_bugtest != 0) {
- // test a general bug instead of blobs
- CHK((*g_opt.m_bugtest)() == 0);
- return 0;
- }
Bcol& b1 = g_opt.m_blob1;
CHK(NdbBlob::getBlobTableName(b1.m_btname, g_ndb, g_opt.m_tname, "BL1") == 0);
DBG("BL1: inline=" << b1.m_inline << " part=" << b1.m_partsize << " table=" << b1.m_btname);
@@ -1360,13 +1393,22 @@
CHK(NdbBlob::getBlobTableName(b2.m_btname, g_ndb, g_opt.m_tname, "BL2") == 0);
DBG("BL2: inline=" << b2.m_inline << " part=" << b2.m_partsize << " table=" << b2.m_btname);
}
- if (g_opt.m_seed != 0)
+ if (g_opt.m_seed == -1)
+ g_opt.m_seed = getpid();
+ if (g_opt.m_seed != 0) {
+ DBG("random seed = " << g_opt.m_seed);
srandom(g_opt.m_seed);
+ }
for (g_loop = 0; g_opt.m_loop == 0 || g_loop < g_opt.m_loop; g_loop++) {
int style;
DBG("=== loop " << g_loop << " ===");
if (g_opt.m_seed == 0)
srandom(g_loop);
+ if (g_opt.m_bugtest != 0) {
+ // test some bug# instead
+ CHK((*g_opt.m_bugtest)() == 0);
+ continue;
+ }
// pk
for (style = 0; style <= 2; style++) {
if (! testcase('k') || ! testcase(style))
@@ -1553,6 +1595,7 @@
// col C - text
{ NdbDictionary::Column col("C");
col.setType(NdbDictionary::Column::Text);
+ col.setBlobVersion(g_opt.m_blob_version);
col.setInlineSize(20);
col.setPartSize(512);
col.setStripeSize(1);
@@ -1821,6 +1864,14 @@
{
Tup& tup= g_tups[k];
+ /* Update one byte in random position. */
+ Uint32 offset= urandom(tup.m_blob1.m_len + 1);
+ if (offset == tup.m_blob1.m_len) {
+ // testing write at end is another problem..
+ continue;
+ }
+ //DBG("len=" << tup.m_blob1.m_len << " offset=" << offset);
+
CHK((g_con= g_ndb->startTransaction()) != 0);
CHK((g_opr= g_con->getNdbOperation(g_opt.m_tname)) != 0);
CHK(g_opr->updateTuple() == 0);
@@ -1830,8 +1881,6 @@
CHK(getBlobHandles(g_opr) == 0);
CHK(g_con->execute(NoCommit) == 0);
- /* Update one byte in random position. */
- Uint32 offset= urandom(tup.m_blob1.m_len);
tup.m_blob1.m_buf[0]= 0xff ^ tup.m_blob1.m_val[offset];
CHK(g_bh1->setPos(offset) == 0);
CHK(g_bh1->writeData(&(tup.m_blob1.m_buf[0]), 1) == 0);
@@ -1848,12 +1897,15 @@
CHK(g_bh1->getValue(tup.m_blob1.m_buf, tup.m_blob1.m_len) == 0);
CHK(g_con->execute(Commit) == 0);
+
Uint64 len= ~0;
CHK(g_bh1->getLength(len) == 0 && len == tup.m_blob1.m_len);
tup.m_blob1.m_buf[offset]^= 0xff;
CHK(memcmp(tup.m_blob1.m_buf, tup.m_blob1.m_val, tup.m_blob1.m_len) == 0);
+
g_ndb->closeTransaction(g_con);
}
+ CHK(deletePk() == 0);
return 0;
}
@@ -1881,6 +1933,17 @@
NDB_COMMAND(testOdbcDriver, "testBlobs", "testBlobs", "testBlobs", 65535)
{
ndb_init();
+ // log the invocation
+ char cmdline[512];
+ {
+ const char* progname =
+ strchr(argv[0], '/') ? strrchr(argv[0], '/') + 1 : argv[0];
+ strcpy(cmdline, progname);
+ for (uint i = 0; i < argc; i++) {
+ strcat(cmdline, " ");
+ strcat(cmdline, argv[i]);
+ }
+ }
while (++argv, --argc > 0) {
const char* arg = argv[0];
if (strcmp(arg, "-batch") == 0) {
@@ -1897,14 +1960,9 @@
g_opt.m_dbg = true;
continue;
}
- if (strcmp(arg, "-dbgall") == 0) {
- g_opt.m_dbg = true;
- g_opt.m_dbgall = true;
- putenv(strdup("NDB_BLOB_DEBUG=1"));
- continue;
- }
if (strcmp(arg, "-dbug") == 0) {
if (++argv, --argc > 0) {
+ g_opt.m_dbg = true;
g_opt.m_dbug = strdup(argv[0]);
continue;
}
@@ -1959,6 +2017,13 @@
continue;
}
}
+ if (strcmp(arg, "-version") == 0) {
+ if (++argv, --argc > 0) {
+ g_opt.m_blob_version = atoi(argv[0]);
+ if (g_opt.m_blob_version == 1 || g_opt.m_blob_version == 2)
+ continue;
+ }
+ }
// metadata
if (strcmp(arg, "-pk2len") == 0) {
if (++argv, --argc > 0) {
@@ -1991,6 +2056,7 @@
}
if (g_opt.m_dbug != 0) {
DBUG_PUSH(g_opt.m_dbug);
+ ndbout.m_out = new FileOutputStream(DBUG_FILE);
}
if (g_opt.m_pk2len == 0) {
char b[100];
@@ -2001,6 +2067,7 @@
strcat(b, "r");
g_opt.m_skip = strdup(b);
}
+ ndbout << cmdline << endl;
g_ncc = new Ndb_cluster_connection();
if (g_ncc->connect(30) != 0 || testmain() == -1 || testperf() == -1) {
ndbout << "line " << __LINE__ << " FAIL loop=" << g_loop << endl;
--- 1.24/storage/ndb/include/ndbapi/NdbBlob.hpp 2006-12-23 20:20:07 +01:00
+++ 1.25/storage/ndb/include/ndbapi/NdbBlob.hpp 2007-03-22 09:15:04 +01:00
@@ -142,12 +142,33 @@
* operation post/pre data blob. Always succeeds.
*/
void getVersion(int& version);
+#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL
/**
- * Inline blob header.
+ * Blob head V1 is 8 bytes:
+ * 8 bytes blob length - native endian (of ndb apis)
+ *
+ * Blob head V2 is 16 bytes:
+ * 2 bytes head+inline length bytes (MEDIUM_VAR) - little-endian
+ * 2 bytes reserved (zero)
+ * 4 bytes NDB$PKID for blob events - little-endian
+ * 8 bytes blob length - litte-endian
+ *
+ * Following struct is for packing/unpacking the fields. It must
+ * not be C-cast to/from the head+inline attribute value.
*/
struct Head {
- Uint64 length;
+ Uint16 varsize; // length of head+inline minus the 2 length bytes
+ Uint16 reserved; // must be 0 wl3717_todo checksum?
+ Uint32 pkid; // connects part and row with same PK within tx
+ Uint64 length; // blob length
+ //
+ uint headsize; // for convenience, number of bytes in head
+ Head() :
+ varsize(0), reserved(0), pkid(0), length(0), headsize(0) {}
};
+ static void packBlobHead(const Head& head, char* buf, int blobVersion);
+ static void unpackBlobHead(Head& head, const char* buf, int blobVersion);
+#endif
/**
* Prepare to read blob value. The value is available after execute.
* Use getNull() to check for NULL and getLength() to get the real length
@@ -264,6 +285,9 @@
friend class NdbEventBuffer;
friend class NdbEventOperationImpl;
#endif
+ int theBlobVersion;
+ uint theHeadSize;
+ uint theVarsizeBytes;
// state
State theState;
void setState(State newState);
@@ -274,6 +298,15 @@
static void getBlobTable(NdbTableImpl& bt, const NdbTableImpl* t, const NdbColumnImpl* c);
static void getBlobEventName(char* bename, const NdbEventImpl* e, const NdbColumnImpl* c);
static void getBlobEvent(NdbEventImpl& be, const NdbEventImpl* e, const NdbColumnImpl* c);
+ // compute blob table column number for faster access
+ enum {
+ BtColumnPk = 0, /* V1 only */
+ BtColumnDist = 1,
+ BtColumnPart = 2,
+ BtColumnPkid = 3, /* V2 only */
+ BtColumnData = 4
+ };
+ int theBtColumnNo[5];
// ndb api stuff
Ndb* theNdb;
NdbTransaction* theNdbCon;
@@ -288,7 +321,7 @@
const NdbTableImpl* theAccessTable;
const NdbTableImpl* theBlobTable;
const NdbColumnImpl* theColumn;
- char theFillChar;
+ unsigned char theFillChar;
// sizes
Uint32 theInlineSize;
Uint32 thePartSize;
@@ -323,8 +356,9 @@
Buf thePartBuf;
Buf theBlobEventDataBuf;
Uint32 thePartNumber; // for event
- Head* theHead;
+ Head theHead;
char* theInlineData;
+ char* thePartData;
NdbRecAttr* theHeadInlineRecAttr;
NdbOperation* theHeadInlineReadOp;
bool theHeadInlineUpdateFlag;
@@ -354,20 +388,26 @@
bool isTakeOverOp();
// computations
Uint32 getPartNumber(Uint64 pos);
+ Uint32 getPartOffset(Uint64 pos);
Uint32 getPartCount();
Uint32 getDistKey(Uint32 part);
// pack / unpack
int packKeyValue(const NdbTableImpl* aTable, const Buf& srcBuf);
int unpackKeyValue(const NdbTableImpl* aTable, Buf& dstBuf);
// getters and setters
+ void packBlobHead();
+ void unpackBlobHead();
int getTableKeyValue(NdbOperation* anOp);
int setTableKeyValue(NdbOperation* anOp);
int setAccessKeyValue(NdbOperation* anOp);
int setPartKeyValue(NdbOperation* anOp, Uint32 part);
+ int setPartPkidValue(NdbOperation* anOp, Uint32 pkid);
int getHeadInlineValue(NdbOperation* anOp);
void getHeadFromRecAttr();
int setHeadInlineValue(NdbOperation* anOp);
// data operations
+ Uint32 getPartVarsize(const char* buf);
+ void setPartVarsize(char* buf, Uint32 sz);
int readDataPrivate(char* buf, Uint32& bytes);
int writeDataPrivate(const char* buf, Uint32 bytes);
int readParts(char* buf, Uint32 part, Uint32 count);
--- 1.54/storage/ndb/src/ndbapi/NdbBlob.cpp 2007-03-16 04:02:52 +01:00
+++ 1.55/storage/ndb/src/ndbapi/NdbBlob.cpp 2007-03-22 09:15:04 +01:00
@@ -87,6 +87,8 @@
NdbBlob::getBlobTable(NdbTableImpl& bt, const NdbTableImpl* t, const NdbColumnImpl* c)
{
DBUG_ENTER("NdbBlob::getBlobTable");
+ const int blobVersion = c->m_blobVersion;
+ assert(blobVersion == NDB_BLOB_V1 || blobVersion == NDB_BLOB_V2);
char btname[NdbBlobImpl::BlobTableNameSize];
getBlobTableName(btname, t, c);
bt.setName(btname);
@@ -124,44 +126,101 @@
DBUG_ASSERT(0);
break;
}
- DBUG_PRINT("info",
- ("Create BLOB table with primary table = %u and Fragment Type = %u",
- bt.m_primaryTableId, (uint)bt.getFragmentType()));
- { NdbDictionary::Column bc("PK");
- bc.setType(NdbDictionary::Column::Unsigned);
- assert(t->m_keyLenInWords != 0);
- bc.setLength(t->m_keyLenInWords);
- bc.setPrimaryKey(true);
- bc.setDistributionKey(true);
- bt.addColumn(bc);
- }
- { NdbDictionary::Column bc("DIST");
- bc.setType(NdbDictionary::Column::Unsigned);
- bc.setPrimaryKey(true);
- bc.setDistributionKey(true);
- bt.addColumn(bc);
- }
- { NdbDictionary::Column bc("PART");
- bc.setType(NdbDictionary::Column::Unsigned);
- bc.setPrimaryKey(true);
- bc.setDistributionKey(false);
- bt.addColumn(bc);
- }
- { NdbDictionary::Column bc("DATA");
- switch (c->m_type) {
- case NdbDictionary::Column::Blob:
- bc.setType(NdbDictionary::Column::Binary);
- break;
- case NdbDictionary::Column::Text:
- bc.setType(NdbDictionary::Column::Char);
- break;
- default:
- assert(false);
- break;
+ DBUG_PRINT("info", ("Define BLOB table V%d with"
+ " primary table = %u and Fragment Type = %u",
+ blobVersion,
+ bt.m_primaryTableId, (uint)bt.getFragmentType()));
+ if (unlikely(blobVersion == NDB_BLOB_V1)) {
+ { NdbDictionary::Column bc("PK");
+ bc.setType(NdbDictionary::Column::Unsigned);
+ assert(t->m_keyLenInWords != 0);
+ bc.setLength(t->m_keyLenInWords);
+ bc.setPrimaryKey(true);
+ bc.setDistributionKey(true);
+ bt.addColumn(bc);
+ }
+ { NdbDictionary::Column bc("DIST");
+ bc.setType(NdbDictionary::Column::Unsigned);
+ bc.setPrimaryKey(true);
+ bc.setDistributionKey(true);
+ bt.addColumn(bc);
+ }
+ { NdbDictionary::Column bc("PART");
+ bc.setType(NdbDictionary::Column::Unsigned);
+ bc.setPrimaryKey(true);
+ bc.setDistributionKey(false);
+ bt.addColumn(bc);
+ }
+ { NdbDictionary::Column bc("DATA");
+ switch (c->m_type) {
+ case NdbDictionary::Column::Blob:
+ bc.setType(NdbDictionary::Column::Binary);
+ break;
+ case NdbDictionary::Column::Text:
+ bc.setType(NdbDictionary::Column::Char);
+ break;
+ default:
+ assert(false);
+ break;
+ }
+ bc.setLength(c->getPartSize());
+ bc.setStorageType(c->getStorageType());
+ bt.addColumn(bc);
+ }
+ } else {
+ {
+ // table PK attributes
+ uint i;
+ const uint columns = t->m_columns.size();
+ unsigned n = t->m_noOfKeys;
+ assert(n != 0);
+ for (i = 0; i < columns && n != 0; i++) {
+ NdbColumnImpl* c = t->m_columns[i];
+ assert(c != NULL);
+ if (c->m_pk) {
+ bt.addColumn(*c);
+ n--;
+ }
+ }
+ }
+ // in V2 add NDB$ to avoid conflict with table PK
+ { NdbDictionary::Column bc("NDB$DIST");
+ bc.setType(NdbDictionary::Column::Unsigned);
+ bc.setPrimaryKey(true);
+ bc.setDistributionKey(true);
+ bt.addColumn(bc);
+ }
+ { NdbDictionary::Column bc("NDB$PART");
+ bc.setType(NdbDictionary::Column::Unsigned);
+ bc.setPrimaryKey(true);
+ bc.setDistributionKey(false);
+ bt.addColumn(bc);
+ }
+ // in V2 add id sequence for use in blob event code
+ { NdbDictionary::Column bc("NDB$PKID");
+ bc.setType(NdbDictionary::Column::Unsigned);
+ bc.setPrimaryKey(false);
+ bc.setDistributionKey(false);
+ bt.addColumn(bc);
+ }
+ // in V2 changes to Longvar* regardless of size
+ { NdbDictionary::Column bc("NDB$DATA");
+ switch (c->m_type) {
+ case NdbDictionary::Column::Blob:
+ bc.setType(NdbDictionary::Column::Longvarbinary);
+ break;
+ case NdbDictionary::Column::Text:
+ bc.setType(NdbDictionary::Column::Longvarchar);
+ break;
+ default:
+ assert(false);
+ break;
+ }
+ // the 2 length bytes are not part of part size
+ bc.setLength(c->getPartSize());
+ bc.setStorageType(c->getStorageType());
+ bt.addColumn(bc);
}
- bc.setLength(c->getPartSize());
- bc.setStorageType(c->getStorageType());
- bt.addColumn(bc);
}
DBUG_VOID_RETURN;
}
@@ -233,8 +292,16 @@
void
NdbBlob::init()
{
+ theBlobVersion = 0;
+ theHeadSize = 0;
+ theVarsizeBytes = 0;
theState = Idle;
theEventBlobVersion = -1;
+ theBtColumnNo[0] = -1;
+ theBtColumnNo[1] = -1;
+ theBtColumnNo[2] = -1;
+ theBtColumnNo[3] = -1;
+ theBtColumnNo[4] = -1;
theNdb = NULL;
theNdbCon = NULL;
theNdbOp = NULL;
@@ -248,7 +315,7 @@
theAccessTable = NULL;
theBlobTable = NULL;
theColumn = NULL;
- theFillChar = 0;
+ theFillChar = 0xFF;
theInlineSize = 0;
thePartSize = 0;
theStripeSize = 0;
@@ -260,8 +327,8 @@
thePendingBlobOps = 0;
theActiveHook = NULL;
theActiveHookArg = NULL;
- theHead = NULL;
theInlineData = NULL;
+ thePartData = NULL;
theHeadInlineRecAttr = NULL;
theHeadInlineReadOp = NULL;
theHeadInlineUpdateFlag = false;
@@ -419,6 +486,13 @@
}
inline Uint32
+NdbBlob::getPartOffset(Uint64 pos)
+{
+ assert(thePartSize != 0 && pos >= theInlineSize);
+ return (pos - theInlineSize) % thePartSize;
+}
+
+inline Uint32
NdbBlob::getPartCount()
{
if (theLength <= theInlineSize)
@@ -430,7 +504,14 @@
NdbBlob::getDistKey(Uint32 part)
{
assert(theStripeSize != 0);
- return (part / theStripeSize) % theStripeSize;
+ Uint32 dist = 0;
+ if (unlikely(theBlobVersion == NDB_BLOB_V1))
+ dist = (part / theStripeSize) % theStripeSize;
+ else {
+ // correct the mistake
+ dist = (part / theStripeSize);
+ }
+ return dist;
}
// pack/unpack table/index key XXX support routines, shortcuts
@@ -505,6 +586,82 @@
// getters and setters
+void
+NdbBlob::packBlobHead(const Head& head, char* buf, int blobVersion)
+{
+ DBUG_ENTER("NdbBlob::packBlobHead");
+ DBUG_PRINT("info", ("version=%d", blobVersion));
+ if (unlikely(blobVersion == NDB_BLOB_V1)) {
+ // native
+ memcpy(buf, &head.length, sizeof(head.length));
+ } else {
+ unsigned char* p = (unsigned char*)buf;
+ // all little-endian
+ uint i, n;
+ for (i = 0, n = 0; i < 2; i++, n += 8)
+ *p++ = (head.varsize >> n) & 0xff;
+ for (i = 0, n = 0; i < 2; i++, n += 8)
+ *p++ = (head.reserved >> n) & 0xff;
+ for (i = 0, n = 0; i < 4; i++, n += 8)
+ *p++ = (head.pkid >> n) & 0xff;
+ for (i = 0, n = 0; i < 8; i++, n += 8)
+ *p++ = (head.length >> n) & 0xff;
+ assert(p - (uchar*)buf == 16);
+ assert(head.reserved == 0);
+ DBUG_DUMP("info", buf, 16);
+ }
+ DBUG_PRINT("info", ("pack: varsize=%u length=%u pkid=%u",
+ (uint)head.varsize, (uint)head.length, (uint)head.pkid));
+ DBUG_VOID_RETURN;
+}
+
+void
+NdbBlob::unpackBlobHead(Head& head, const char* buf, int blobVersion)
+{
+ DBUG_ENTER("NdbBlob::unpackBlobHead");
+ DBUG_PRINT("info", ("version=%d", blobVersion));
+ head.varsize = 0;
+ head.reserved = 0;
+ head.pkid = 0;
+ head.length = 0;
+ if (unlikely(blobVersion == NDB_BLOB_V1)) {
+ // native
+ memcpy(&head.length, buf, sizeof(head.length));
+ head.headsize = (NDB_BLOB_V1_HEAD_SIZE << 2);
+ } else {
+ const unsigned char* p = (const unsigned char*)buf;
+ // all little-endian
+ uint i, n;
+ for (i = 0, n = 0; i < 2; i++, n += 8)
+ head.varsize |= ((Uint16)*p++ << n);
+ for (i = 0, n = 0; i < 2; i++, n += 8)
+ head.reserved |= ((Uint32)*p++ << n);
+ for (i = 0, n = 0; i < 4; i++, n += 8)
+ head.pkid |= ((Uint32)*p++ << n);
+ for (i = 0, n = 0; i < 8; i++, n += 8)
+ head.length |= ((Uint64)*p++ << n);
+ assert(p - (uchar*)buf == 16);
+ assert(head.reserved == 0); //wl3717_todo catch bad data
+ head.headsize = (NDB_BLOB_V2_HEAD_SIZE << 2);
+ DBUG_DUMP("info", buf, 16);
+ }
+ DBUG_PRINT("info", ("unpack: varsize=%u length=%u pkid=%u",
+ (uint)head.varsize, (uint)head.length, (uint)head.pkid));
+ DBUG_VOID_RETURN;
+}
+
+inline void
+NdbBlob::packBlobHead()
+{
+ packBlobHead(theHead, theHeadInlineBuf.data, theBlobVersion);
+}
+
+inline void
+NdbBlob::unpackBlobHead()
+{
+ unpackBlobHead(theHead, theHeadInlineBuf.data, theBlobVersion);
+}
+
int
NdbBlob::getTableKeyValue(NdbOperation* anOp)
{
@@ -532,6 +689,7 @@
DBUG_RETURN(0);
}
+// in V2 operation can also be on blob part
int
NdbBlob::setTableKeyValue(NdbOperation* anOp)
{
@@ -539,17 +697,22 @@
DBUG_DUMP("info", theKeyBuf.data, 4 * theTable->m_keyLenInWords);
const Uint32* data = (const Uint32*)theKeyBuf.data;
const unsigned columns = theTable->m_columns.size();
+ uint n = 0;
+ const uint noOfKeys = theTable->m_noOfKeys;
unsigned pos = 0;
- for (unsigned i = 0; i < columns; i++) {
+ for (unsigned i = 0; i < columns && n < noOfKeys; i++) {
NdbColumnImpl* c = theTable->m_columns[i];
assert(c != NULL);
if (c->m_pk) {
unsigned len = c->m_attrSize * c->m_arraySize;
+ if (anOp->m_currentTable == theBlobTable)
+ c = theBlobTable->m_columns[n];
if (anOp->equal_impl(c, (const char*)&data[pos]) == -1) {
setErrorCode(anOp);
DBUG_RETURN(-1);
}
pos += (len + 3) / 4;
+ n++;
}
}
if (theNdbOp->theDistrKeyIndicator_)
@@ -589,11 +752,37 @@
DBUG_PRINT("info", ("dist=%u part=%u packkey=", getDistKey(part), part));
DBUG_DUMP("info", thePackKeyBuf.data, 4 * thePackKeyBuf.size);
// TODO use attr ids after compatibility with 4.1.7 not needed
- if (anOp->equal("PK", thePackKeyBuf.data) == -1 ||
- anOp->equal("DIST", getDistKey(part)) == -1 ||
- anOp->equal("PART", part) == -1) {
- setErrorCode(anOp);
- DBUG_RETURN(-1);
+ if (unlikely(theBlobVersion == NDB_BLOB_V1)) {
+ // keep using names
+ if (anOp->equal("PK", thePackKeyBuf.data) == -1 ||
+ anOp->equal("DIST", getDistKey(part)) == -1 ||
+ anOp->equal("PART", part) == -1) {
+ setErrorCode(anOp);
+ DBUG_RETURN(-1);
+ }
+ } else {
+ if (setTableKeyValue(anOp) == -1 ||
+ anOp->equal(theBtColumnNo[BtColumnDist], getDistKey(part)) == -1 ||
+ anOp->equal(theBtColumnNo[BtColumnPart], part) == -1) {
+ setErrorCode(anOp);
+ DBUG_RETURN(-1);
+ }
+ }
+ DBUG_RETURN(0);
+}
+
+int
+NdbBlob::setPartPkidValue(NdbOperation* anOp, Uint32 pkid)
+{
+ DBUG_ENTER("NdbBlob::setPartPkidValue");
+ DBUG_PRINT("info", ("pkid=%u", pkid));
+ if (unlikely(theBlobVersion == NDB_BLOB_V1))
+ ;
+ else {
+ if (anOp->setValue(theBtColumnNo[BtColumnPkid], pkid) == -1) {
+ setErrorCode(anOp);
+ DBUG_RETURN(-1);
+ }
}
DBUG_RETURN(0);
}
@@ -617,7 +806,12 @@
assert(theHeadInlineRecAttr != NULL);
theNullFlag = theHeadInlineRecAttr->isNULL();
assert(theEventBlobVersion >= 0 || theNullFlag != -1);
- theLength = ! theNullFlag ? theHead->length : 0;
+ if (theNullFlag == 0) {
+ unpackBlobHead();
+ theLength = theHead.length;
+ } else {
+ theLength = 0;
+ }
DBUG_PRINT("info", ("theNullFlag=%d theLength=%llu",
theNullFlag, theLength));
DBUG_VOID_RETURN;
@@ -627,9 +821,19 @@
NdbBlob::setHeadInlineValue(NdbOperation* anOp)
{
DBUG_ENTER("NdbBlob::setHeadInlineValue");
- theHead->length = theLength;
- if (theLength < theInlineSize)
- memset(theInlineData + theLength, 0, theInlineSize - theLength);
+ theHead.length = theLength;
+ if (unlikely(theBlobVersion == NDB_BLOB_V1)) {
+ if (theLength < theInlineSize)
+ memset(theInlineData + theLength, 0, theInlineSize - theLength);
+ } else {
+ // the 2 length bytes are not counted in length
+ if (theLength < theInlineSize)
+ theHead.varsize = (theHeadSize - 2) + theLength;
+ else
+ theHead.varsize = (theHeadSize - 2) + theInlineSize;
+ theHead.pkid = 0; // wl3717_todo not yet
+ }
+ packBlobHead();
assert(theNullFlag != -1);
const char* aValue = theNullFlag ? 0 : theHeadInlineBuf.data;
if (anOp->setValue(theColumn, aValue) == -1) {
@@ -812,7 +1016,7 @@
NdbBlob::truncate(Uint64 length)
{
DBUG_ENTER("NdbBlob::truncate");
- DBUG_PRINT("info", ("length=%llu", length));
+ DBUG_PRINT("info", ("length old=%llu new=%llu", theLength, length));
if (isReadOnlyOp()) {
setErrorCode(NdbBlobImpl::ErrCompat);
DBUG_RETURN(-1);
@@ -828,6 +1032,23 @@
assert(part2 >= part1);
if (part2 > part1 && deleteParts(part1 + 1, part2 - part1) == -1)
DBUG_RETURN(-1);
+ if (unlikely(theBlobVersion == NDB_BLOB_V1))
+ ;
+ else {
+ Uint32 off = getPartOffset(length);
+ if (off != 0) {
+ assert(off < thePartSize);
+ if (readParts(thePartBuf.data, part1, 1) == -1)
+ DBUG_RETURN(-1);
+ if (executePendingBlobReads() == -1)
+ DBUG_RETURN(-1);
+ DBUG_PRINT("info", ("part %u varsize old=%u new=%u",
+ part1, getPartVarsize(thePartBuf.data), off));
+ setPartVarsize(thePartBuf.data, off);
+ if (updateParts(thePartBuf.data, part1, 1) == -1)
+ DBUG_RETURN(-1);
+ }
+ }
} else {
if (deleteParts(0, getPartCount()) == -1)
DBUG_RETURN(-1);
@@ -869,13 +1090,36 @@
DBUG_RETURN(0);
}
+// blob part length bytes
+
+inline Uint32
+NdbBlob::getPartVarsize(const char* buf)
+{
+ assert(theBlobVersion != NDB_BLOB_V1);
+ const unsigned char* p = (const unsigned char*)buf;
+ Uint32 sz = p[0] + (p[1] << 8);
+ assert(sz <= thePartSize);
+ return sz;
+}
+
+inline void
+NdbBlob::setPartVarsize(char* buf, Uint32 sz)
+{
+ assert(theBlobVersion != NDB_BLOB_V1);
+ unsigned char* p = (unsigned char*)buf;
+ p[0] = sz & 0xff;
+ p[1] = (sz >> 8) & 0xff;
+ assert(sz <= thePartSize);
+ assert(sz == getPartVarsize(buf));
+}
+
// read/write
int
NdbBlob::readData(void* data, Uint32& bytes)
{
DBUG_ENTER("NdbBlob::readData");
- if (theState != Active) {
+ if (unlikely(theState != Active)) {
setErrorCode(NdbBlobImpl::ErrState);
DBUG_RETURN(-1);
}
@@ -888,7 +1132,7 @@
NdbBlob::readDataPrivate(char* buf, Uint32& bytes)
{
DBUG_ENTER("NdbBlob::readDataPrivate");
- DBUG_PRINT("info", ("bytes=%u", bytes));
+ DBUG_PRINT("info", ("pos=%llu bytes=%u", thePos, bytes));
assert(thePos <= theLength);
Uint64 pos = thePos;
if (bytes > theLength - pos)
@@ -906,7 +1150,7 @@
len -= n;
}
}
- if (len > 0 && thePartSize == 0) {
+ if (unlikely(len > 0 && thePartSize == 0)) {
setErrorCode(NdbBlobImpl::ErrSeek);
DBUG_RETURN(-1);
}
@@ -925,7 +1169,13 @@
Uint32 n = thePartSize - off;
if (n > len)
n = len;
- memcpy(buf, thePartBuf.data + off, n);
+ if (unlikely(theBlobVersion == NDB_BLOB_V1))
+ ;
+ else {
+ Uint32 sz = getPartVarsize(thePartBuf.data);
+ assert(off + n <= sz);
+ }
+ memcpy(buf, thePartData + off, n);
pos += n;
buf += n;
len -= n;
@@ -937,12 +1187,37 @@
if (len >= thePartSize) {
Uint32 part = (pos - theInlineSize) / thePartSize;
Uint32 count = len / thePartSize;
- if (readParts(buf, part, count) == -1)
- DBUG_RETURN(-1);
- Uint32 n = thePartSize * count;
- pos += n;
- buf += n;
- len -= n;
+ if (unlikely(theBlobVersion == NDB_BLOB_V1)) {
+ if (readParts(buf, part, count) == -1)
+ DBUG_RETURN(-1);
+ Uint32 n = thePartSize * count;
+ pos += n;
+ buf += n;
+ len -= n;
+ } else {
+ /*
+ * wl3717_todo
+ * Currently in V2 the user buffer cannot be used directly
+ * and the reads cannot be parallelized or postponed.
+ * This is major lossage.
+ *
+ * Suggested fix is a new getValue() method which
+ * returns length bytes and data into separate buffers.
+ */
+ for (unsigned i = 0; i < count; i++) {
+ if (readParts(thePartBuf.data, part + i, 1) == -1)
+ DBUG_RETURN(-1);
+ if (executePendingBlobReads() == -1)
+ DBUG_RETURN(-1);
+ Uint32 sz = getPartVarsize(thePartBuf.data);
+ assert(sz == thePartSize);
+ memcpy(buf, thePartData, thePartSize);
+ Uint32 n = thePartSize;
+ pos += n;
+ buf += n;
+ len -= n;
+ }
+ }
}
}
if (len > 0) {
@@ -955,7 +1230,13 @@
// need result now
if (executePendingBlobReads() == -1)
DBUG_RETURN(-1);
- memcpy(buf, thePartBuf.data, len);
+ if (unlikely(theBlobVersion == NDB_BLOB_V1))
+ ;
+ else {
+ Uint32 sz = getPartVarsize(thePartBuf.data);
+ assert(len <= sz);
+ }
+ memcpy(buf, thePartData, len);
Uint32 n = len;
pos += n;
buf += n;
@@ -971,11 +1252,11 @@
NdbBlob::writeData(const void* data, Uint32 bytes)
{
DBUG_ENTER("NdbBlob::writeData");
- if (isReadOnlyOp()) {
+ if (unlikely(isReadOnlyOp())) {
setErrorCode(NdbBlobImpl::ErrCompat);
DBUG_RETURN(-1);
}
- if (theState != Active) {
+ if (unlikely(theState != Active)) {
setErrorCode(NdbBlobImpl::ErrState);
DBUG_RETURN(-1);
}
@@ -988,7 +1269,7 @@
NdbBlob::writeDataPrivate(const char* buf, Uint32 bytes)
{
DBUG_ENTER("NdbBlob::writeDataPrivate");
- DBUG_PRINT("info", ("bytes=%u", bytes));
+ DBUG_PRINT("info", ("pos=%llu bytes=%u", thePos, bytes));
assert(thePos <= theLength);
Uint64 pos = thePos;
Uint32 len = bytes;
@@ -1010,7 +1291,7 @@
len -= n;
}
}
- if (len > 0 && thePartSize == 0) {
+ if (unlikely(len > 0 && thePartSize == 0)) {
setErrorCode(NdbBlobImpl::ErrSeek);
DBUG_RETURN(-1);
}
@@ -1030,13 +1311,19 @@
if (executePendingBlobReads() == -1)
DBUG_RETURN(-1);
Uint32 n = thePartSize - off;
- if (n > len) {
- /* If we are adding data at the end, fill rest of part. */
- if (pos + len >= theLength)
- memset(thePartBuf.data + off + len, theFillChar, n - len);
+ if (n > len)
n = len;
+ if (unlikely(theBlobVersion == NDB_BLOB_V1))
+ // no need to set fill chars on existing part (bug#27018)
+ ;
+ else {
+ if (pos + n > theLength) {
+ // this is last part and we are extending it
+ Uint32 sz = off + n;
+ setPartVarsize(thePartBuf.data, sz);
+ }
}
- memcpy(thePartBuf.data + off, buf, n);
+ memcpy(thePartData + off, buf, n);
if (updateParts(thePartBuf.data, part, 1) == -1)
DBUG_RETURN(-1);
pos += n;
@@ -1051,11 +1338,32 @@
Uint32 part = (pos - theInlineSize) / thePartSize;
Uint32 count = len / thePartSize;
for (unsigned i = 0; i < count; i++) {
+ const char* tmpbuf;
+ if (unlikely(theBlobVersion == NDB_BLOB_V1)) {
+ tmpbuf = buf;
+ } else {
+ /*
+ * wl3717_todo
+ * Currently in V2 the user buffer cannot be used directly.
+ * The writes are still parallelized and can be postponed.
+ * This is minor lossage.
+ *
+ * However this relies on data being converted to signals
+ * immediately which is not true after NdbRecord.
+ *
+ * Suggested fix is a new setValue() method which takes
+ * variable length and data buffer separately.
+ */
+ Uint32 sz = thePartSize;
+ setPartVarsize(thePartBuf.data, sz);
+ memcpy(thePartData, buf, thePartSize);
+ tmpbuf = thePartBuf.data;
+ }
if (part + i < getPartCount()) {
- if (updateParts(buf, part + i, 1) == -1)
+ if (updateParts(tmpbuf, part + i, 1) == -1)
DBUG_RETURN(-1);
} else {
- if (insertParts(buf, part + i, 1) == -1)
+ if (insertParts(tmpbuf, part + i, 1) == -1)
DBUG_RETURN(-1);
}
Uint32 n = thePartSize;
@@ -1079,12 +1387,18 @@
// need result now
if (executePendingBlobReads() == -1)
DBUG_RETURN(-1);
- memcpy(thePartBuf.data, buf, len);
+ // keep old part varsize (in V2)
+ memcpy(thePartData, buf, len);
if (updateParts(thePartBuf.data, part, 1) == -1)
DBUG_RETURN(-1);
} else {
- memcpy(thePartBuf.data, buf, len);
- memset(thePartBuf.data + len, theFillChar, thePartSize - len);
+ memcpy(thePartData, buf, len);
+ if (unlikely(theBlobVersion == NDB_BLOB_V1)) {
+ memset(thePartData + len, theFillChar, thePartSize - len);
+ } else {
+ Uint32 sz = len;
+ setPartVarsize(thePartBuf.data, sz);
+ }
if (part < getPartCount()) {
if (updateParts(thePartBuf.data, part, 1) == -1)
DBUG_RETURN(-1);
@@ -1131,7 +1445,7 @@
if (tOp == NULL ||
tOp->committedRead() == -1 ||
setPartKeyValue(tOp, part + n) == -1 ||
- tOp->getValue((Uint32)3, buf) == NULL) {
+ tOp->getValue(theBtColumnNo[BtColumnData], buf) == NULL) {
setErrorCode(tOp);
DBUG_RETURN(-1);
}
@@ -1167,7 +1481,8 @@
if (tOp == NULL ||
tOp->insertTuple() == -1 ||
setPartKeyValue(tOp, part + n) == -1 ||
- tOp->setValue((Uint32)3, buf) == -1) {
+ setPartPkidValue(tOp, theHead.pkid) == -1 ||
+ tOp->setValue(theBtColumnNo[BtColumnData], buf) == -1) {
setErrorCode(tOp);
DBUG_RETURN(-1);
}
@@ -1191,7 +1506,8 @@
if (tOp == NULL ||
tOp->updateTuple() == -1 ||
setPartKeyValue(tOp, part + n) == -1 ||
- tOp->setValue((Uint32)3, buf) == -1) {
+ setPartPkidValue(tOp, theHead.pkid) == -1 ||
+ tOp->setValue(theBtColumnNo[BtColumnData], buf) == -1) {
setErrorCode(tOp);
DBUG_RETURN(-1);
}
@@ -1337,7 +1653,6 @@
NdbBlob::atPrepare(NdbTransaction* aCon, NdbOperation* anOp, const NdbColumnImpl* aColumn)
{
DBUG_ENTER("NdbBlob::atPrepare");
- DBUG_PRINT("info", ("this=%p op=%p con=%p", this, anOp, aCon));
assert(theState == Idle);
// ndb api stuff
theNdb = anOp->theNdb;
@@ -1349,9 +1664,11 @@
// prepare blob column and table
if (prepareColumn() == -1)
DBUG_RETURN(-1);
+ DBUG_PRINT("info", ("this=%p op=%p con=%p version=%d",
+ this, theNdbOp, theNdbCon, theBlobVersion));
// extra buffers
theAccessKeyBuf.alloc(theAccessTable->m_keyLenInWords << 2);
- theHeadInlineCopyBuf.alloc(sizeof(Head) + theInlineSize);
+ theHeadInlineCopyBuf.alloc(theHeadSize + theInlineSize);
// handle different operation types
bool supportedOp = false;
if (isKeyOp()) {
@@ -1423,7 +1740,7 @@
NdbBlob::atPrepare(NdbEventOperationImpl* anOp, NdbEventOperationImpl* aBlobOp, const NdbColumnImpl* aColumn, int version)
{
DBUG_ENTER("NdbBlob::atPrepare [event]");
- DBUG_PRINT("info", ("this=%p op=%p", this, anOp));
+ DBUG_PRINT("info", ("this=%p op=%p version=%d", this, anOp, theBlobVersion));
assert(theState == Idle);
assert(version == 0 || version == 1);
theEventBlobVersion = version;
@@ -1474,32 +1791,62 @@
{
DBUG_ENTER("prepareColumn");
NdbDictionary::Column::Type partType = NdbDictionary::Column::Undefined;
- switch (theColumn->getType()) {
- case NdbDictionary::Column::Blob:
- partType = NdbDictionary::Column::Binary;
- theFillChar = 0x0;
- break;
- case NdbDictionary::Column::Text:
- partType = NdbDictionary::Column::Char;
- theFillChar = 0x20;
- break;
- default:
- setErrorCode(NdbBlobImpl::ErrUsage);
- DBUG_RETURN(-1);
+ theBlobVersion = theColumn->m_blobVersion;
+ if (unlikely(theBlobVersion == NDB_BLOB_V1)) {
+ theHeadSize = (NDB_BLOB_V1_HEAD_SIZE << 2);
+ theVarsizeBytes = 0;
+ switch (theColumn->getType()) {
+ case NdbDictionary::Column::Blob:
+ partType = NdbDictionary::Column::Binary;
+ theFillChar = 0x0;
+ break;
+ case NdbDictionary::Column::Text:
+ partType = NdbDictionary::Column::Char;
+ theFillChar = 0x20;
+ break;
+ default:
+ setErrorCode(NdbBlobImpl::ErrUsage);
+ DBUG_RETURN(-1);
+ }
+ theBtColumnNo[BtColumnPk] = 0;
+ theBtColumnNo[BtColumnDist] = 1;
+ theBtColumnNo[BtColumnPart] = 2;
+ theBtColumnNo[BtColumnData] = 3;
+ } else if (theBlobVersion == NDB_BLOB_V2) {
+ theHeadSize = (NDB_BLOB_V2_HEAD_SIZE << 2);
+ theVarsizeBytes = 2;
+ switch (theColumn->getType()) {
+ case NdbDictionary::Column::Blob:
+ partType = NdbDictionary::Column::Longvarbinary;
+ break;
+ case NdbDictionary::Column::Text:
+ partType = NdbDictionary::Column::Longvarchar;
+ break;
+ default:
+ setErrorCode(NdbBlobImpl::ErrUsage);
+ DBUG_RETURN(-1);
+ }
+ uint noOfKeys = theTable->m_noOfKeys;
+ theBtColumnNo[BtColumnDist] = noOfKeys + 0;
+ theBtColumnNo[BtColumnPart] = noOfKeys + 1;
+ theBtColumnNo[BtColumnPkid] = noOfKeys + 2;
+ theBtColumnNo[BtColumnData] = noOfKeys + 3;
+ } else {
+ setErrorCode(NdbBlobImpl::ErrUsage);
+ DBUG_RETURN(-1);
}
// sizes
theInlineSize = theColumn->getInlineSize();
thePartSize = theColumn->getPartSize();
theStripeSize = theColumn->getStripeSize();
// sanity check
- assert((NDB_BLOB_HEAD_SIZE << 2) == sizeof(Head));
- assert(theColumn->m_attrSize * theColumn->m_arraySize == sizeof(Head) + theInlineSize);
+ assert(theColumn->m_attrSize * theColumn->m_arraySize == theHeadSize + theInlineSize);
if (thePartSize > 0) {
const NdbTableImpl* bt = NULL;
const NdbColumnImpl* bc = NULL;
if (theStripeSize == 0 ||
(bt = theColumn->m_blobTable) == NULL ||
- (bc = bt->getColumn("DATA")) == NULL ||
+ (bc = bt->getColumn(theBtColumnNo[BtColumnData])) == NULL ||
bc->getType() != partType ||
bc->getLength() != (int)thePartSize) {
setErrorCode(NdbBlobImpl::ErrTable);
@@ -1511,10 +1858,10 @@
// these buffers are always used
theKeyBuf.alloc(theTable->m_keyLenInWords << 2);
thePackKeyBuf.alloc(max(theTable->m_keyLenInWords, theAccessTable->m_keyLenInWords) << 2);
- theHeadInlineBuf.alloc(sizeof(Head) + theInlineSize);
- theHead = (Head*)theHeadInlineBuf.data;
- theInlineData = theHeadInlineBuf.data + sizeof(Head);
- thePartBuf.alloc(thePartSize);
+ theHeadInlineBuf.alloc(theHeadSize + theInlineSize);
+ theInlineData = theHeadInlineBuf.data + theHeadSize;
+ thePartBuf.alloc(theVarsizeBytes + thePartSize);
+ thePartData = thePartBuf.data + theVarsizeBytes;
DBUG_RETURN(0);
}
| Thread |
|---|
| • bk commit into 5.1 tree (pekka:1.2501) | pekka | 22 Mar |