From: John David Duncan Date: May 16 2011 5:02pm Subject: bzr push into mysql-5.1-telco-7.2 branch (john.duncan:4171 to 4176) List-Archive: http://lists.mysql.com/commits/137465 Message-Id: <201105161703.p4GH34N7028895@acsmt356.oracle.com> MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit 4176 John David Duncan 2011-05-15 New TabSeparatedValues class added: storage/ndb/memcache/include/TabSeparatedValues.h storage/ndb/memcache/src/TabSeparatedValues.cc storage/ndb/memcache/unit/tsv.cc modified: storage/ndb/memcache/Makefile.am storage/ndb/memcache/unit/Makefile.am storage/ndb/memcache/unit/all_tests.h storage/ndb/memcache/unit/harness.cc 4175 John David Duncan 2011-05-15 Support CHAR modified: storage/ndb/memcache/src/DataTypeHandler.cc 4174 John David Duncan 2011-05-15 Refactor DataTypeHandler so that readFromNdb() and writeToNdb() return an int -- the length read/written, or < 0 for error. modified: storage/ndb/memcache/include/DataTypeHandler.h storage/ndb/memcache/include/Operation.h storage/ndb/memcache/include/Record.h storage/ndb/memcache/src/DataTypeHandler.cc storage/ndb/memcache/src/Record.cc 4173 John David Duncan 2011-05-15 Improvements to unit-test framework modified: storage/ndb/memcache/unit/all_tests.h storage/ndb/memcache/unit/connpool.cc storage/ndb/memcache/unit/harness.cc 4172 John David Duncan 2011-05-15 ndb_types.h is available; just include it. modified: storage/ndb/memcache/include/ndbmemcache_config.h 4171 John David Duncan 2011-04-30 Fix for stack-corrupting, crashing bug when reading uint64 columns. modified: storage/ndb/memcache/src/Record.cc === modified file 'storage/ndb/memcache/Makefile.am' --- a/storage/ndb/memcache/Makefile.am 2011-04-26 07:24:58 +0000 +++ b/storage/ndb/memcache/Makefile.am 2011-05-16 06:14:51 +0000 @@ -37,6 +37,7 @@ ndb_engine_la_SOURCES= \ src/QueryPlan.cc \ src/Record.cc \ src/TableSpec.cc \ + src/TabSeparatedValues.cc \ src/workqueue.c \ src/schedulers/Stockholm.h \ src/schedulers/Stockholm.cc \ === modified file 'storage/ndb/memcache/include/DataTypeHandler.h' --- a/storage/ndb/memcache/include/DataTypeHandler.h 2011-03-30 06:54:53 +0000 +++ b/storage/ndb/memcache/include/DataTypeHandler.h 2011-05-16 05:49:22 +0000 @@ -36,25 +36,24 @@ /* Return status codes from some of the functions: */ -// TODO: Return an int: the encoded/read length, or < 0 on error. -enum TypeHandlerStatus { - DTH_OK = 0, - DTH_NOT_SUPPORTED, - DTH_VALUE_TOO_LONG + +enum { /* These can be returned by readFromNdb() or writeToNdb() */ + DTH_NOT_SUPPORTED = -1, + DTH_VALUE_TOO_LONG = -2 }; /* DataTypeHandler interface: */ typedef struct { - // String Readers - TypeHandlerStatus (*readFromNdb)(const NdbDictionary::Column *col, size_t &len, - char * &str, const void * const buf); + // String Readers. Returns length read. + int (*readFromNdb)(const NdbDictionary::Column *col, + char * &str, const void * const buf); size_t (*getStringifiedLength)(const NdbDictionary::Column *col, const void * const buf); - // String Writer - TypeHandlerStatus (*writeToNdb)(const NdbDictionary::Column *col, size_t len, - size_t offset, const char *str, void * const buf); + // String Writer. Returns length written or < 0 for error. + int (*writeToNdb)(const NdbDictionary::Column *col, size_t len, + size_t offset, const char *str, void * const buf); // For an integer column, this holds the int's size in bytes. Otherwise zero. int direct_int_size; === modified file 'storage/ndb/memcache/include/Operation.h' --- a/storage/ndb/memcache/include/Operation.h 2011-04-07 11:20:56 +0000 +++ b/storage/ndb/memcache/include/Operation.h 2011-05-16 05:49:22 +0000 @@ -134,8 +134,8 @@ inline void Operation::clearKeyNullBits( } inline bool Operation::setKeyPart(int idx, const char *strval, size_t strlen) { - TypeHandlerStatus s = plan->key_record->encode(idx, strval, strlen, key_buffer); - return (s == DTH_OK); + int s = plan->key_record->encode(idx, strval, strlen, key_buffer); + return (s > 0); } inline bool Operation::setKeyPartInt(int idx, int value) { @@ -157,8 +157,8 @@ inline void Operation::clearNullBits() { } inline bool Operation::setColumn(int idx, const char *strval, size_t strlen) { - TypeHandlerStatus s = record->encode(idx, strval, strlen, buffer); - return (s == DTH_OK); + int s = record->encode(idx, strval, strlen, buffer); + return (s > 0); } inline bool Operation::setColumnInt(int idx, int value) { === modified file 'storage/ndb/memcache/include/Record.h' --- a/storage/ndb/memcache/include/Record.h 2011-04-07 11:20:56 +0000 +++ b/storage/ndb/memcache/include/Record.h 2011-05-16 05:49:22 +0000 @@ -76,7 +76,7 @@ class Record { int getIntValue(int idx, char *data) const; bool setUint64Value(int idx, Uint64 value, char *buffer) const; Uint64 getUint64Value(int idx, char *data) const; - TypeHandlerStatus encode(int idx, const char *key, int nkey, char *buffer) const; + int encode(int idx, const char *key, int nkey, char *buffer) const; size_t getStringifiedLength(char *data) const; bool decodeNoCopy(int idx, char **dest_ptr, size_t *len_ptr, const char * const src) const; === added file 'storage/ndb/memcache/include/TabSeparatedValues.h' --- a/storage/ndb/memcache/include/TabSeparatedValues.h 1970-01-01 00:00:00 +0000 +++ b/storage/ndb/memcache/include/TabSeparatedValues.h 2011-05-16 06:14:51 +0000 @@ -0,0 +1,55 @@ +/* + Copyright (c) 2011, Oracle and/or its affiliates. All rights + reserved. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; version 2 of + the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + 02110-1301 USA + */ +#ifndef NDBMEMCACHE_TABSEP_H +#define NDBMEMCACHE_TABSEP_H + +#include "ndbmemcache_config.h" +#include "Record.h" + +class TabSeparatedValues { + public: + TabSeparatedValues(const char * string, Uint32 max_parts, size_t length); + int advance(); // inlined + const char * getPointer(); // inlined + size_t getLength(); // inlined + + private: + int index; + int parts; + const char * pointers[MAX_VAL_COLUMNS]; + size_t lengths[MAX_VAL_COLUMNS]; + int find_tab(const char *, int) const; +}; + + +inline int TabSeparatedValues::advance() { + return ++index < parts ? 1 : 0; +} + +inline const char * TabSeparatedValues::getPointer() { + return pointers[index]; +} + +inline size_t TabSeparatedValues::getLength() { + return lengths[index]; +} + + +#endif === modified file 'storage/ndb/memcache/include/ndbmemcache_config.h' --- a/storage/ndb/memcache/include/ndbmemcache_config.h 2011-04-21 10:45:07 +0000 +++ b/storage/ndb/memcache/include/ndbmemcache_config.h 2011-05-16 05:21:20 +0000 @@ -15,26 +15,10 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -/** - * @file ndb_types.h - */ - #ifndef MEMCACHED_CONFIG_H #define MEMCACHED_CONFIG_H #include #include -//typedef Uint64 uint64_t; -//typedef Uint32 uint32_t; - -//typedef Int64 int64_t; -/* -typedef signed char Int8; -typedef unsigned char Uint8; -typedef signed short Int16; -typedef unsigned short Uint16; -typedef signed int Int32; -typedef unsigned int Uint32; -*/ #endif // MEMCACHED_CONFIG_H === modified file 'storage/ndb/memcache/src/DataTypeHandler.cc' --- a/storage/ndb/memcache/src/DataTypeHandler.cc 2011-03-30 06:54:53 +0000 +++ b/storage/ndb/memcache/src/DataTypeHandler.cc 2011-05-16 06:07:15 +0000 @@ -31,58 +31,77 @@ #include "DataTypeHandler.h" #include "debug.h" -#define DECODE_ARGS const NdbDictionary::Column *, size_t &, char * &, const void * +#define DECODE_ARGS const NdbDictionary::Column *, char * &, const void * #define SFDLEN_ARGS const NdbDictionary::Column *, const void * -#define WRITE_ARGS const NdbDictionary::Column *, size_t, size_t, const char *, void * +#define WRITE_ARGS const NdbDictionary::Column *, size_t, size_t, const char *, void * -typedef TypeHandlerStatus impl_readFromNdb(DECODE_ARGS); -typedef size_t impl_getStringifiedLength(SFDLEN_ARGS); -typedef TypeHandlerStatus impl_writeToNdb(WRITE_ARGS); +typedef int impl_readFromNdb(DECODE_ARGS); +typedef size_t impl_getStringifiedLength(SFDLEN_ARGS); +typedef int impl_writeToNdb(WRITE_ARGS); /* Implementations for readFromNdb() */ impl_readFromNdb dth_decode_varchar; impl_readFromNdb dth_decode_longvarchar; +impl_readFromNdb dth_decode_char; +impl_readFromNdb dth_decode_char1; impl_readFromNdb dth_decode_int; impl_readFromNdb dth_decode_ubigint; -impl_readFromNdb dth_decode_char1; /* Implementations for impl_getStringifiedLength() */ -impl_getStringifiedLength dth_sfdlen_varchar; -impl_getStringifiedLength dth_sfdlen_longvarchar; -impl_getStringifiedLength dth_sfdlen_int; -impl_getStringifiedLength dth_sfdlen_ubigint; -impl_getStringifiedLength dth_sfdlen_char1; +impl_getStringifiedLength dth_length_varchar; +impl_getStringifiedLength dth_length_longvarchar; +impl_getStringifiedLength dth_length_char; +impl_getStringifiedLength dth_length_char1; +impl_getStringifiedLength dth_length_int; +impl_getStringifiedLength dth_length_ubigint; /* Implementations for writeToNdb() */ impl_writeToNdb dth_encode_varchar; impl_writeToNdb dth_encode_longvarchar; +impl_writeToNdb dth_encode_char; +impl_writeToNdb dth_encode_char1; impl_writeToNdb dth_encode_int; impl_writeToNdb dth_encode_ubigint; -impl_writeToNdb dth_encode_char1; /***** Singleton Handlers *****/ DataTypeHandler Handler_Varchar = { - dth_decode_varchar, - dth_sfdlen_varchar, - dth_encode_varchar, - 0, - true + dth_decode_varchar, // readFromNdb() + dth_length_varchar, // getStringifiedLength() + dth_encode_varchar, // writeToNdb() + 0, // direct_int_size + true // contains_string }; DataTypeHandler Handler_LongVarchar = { dth_decode_longvarchar, - dth_sfdlen_longvarchar, + dth_length_longvarchar, dth_encode_longvarchar, 0, true }; +DataTypeHandler Handler_Char = { + dth_decode_char, // readFromNdb() + dth_length_char, // getStringifiedLength() + dth_encode_char, // writeToNdb() + 0, // direct_int_size + true // contains_string +}; + +DataTypeHandler Handler_enum = { /* NDB sees ENUM columns as CHAR(1) */ + dth_decode_char1, + dth_length_char1, + dth_encode_char1, + 1, + false +}; + DataTypeHandler Handler_Int = { dth_decode_int, - dth_sfdlen_int, + dth_length_int, dth_encode_int, 4, false @@ -90,19 +109,12 @@ DataTypeHandler Handler_Int = { DataTypeHandler Handler_BigIntUnsigned = { dth_decode_ubigint, - dth_sfdlen_ubigint, + dth_length_ubigint, dth_encode_ubigint, 8, false }; -DataTypeHandler Handler_enum = { /* NDB sees ENUM columns as CHAR(1) */ - dth_decode_char1, - dth_sfdlen_char1, - dth_encode_char1, - 1, - false -}; /* @@ -128,7 +140,7 @@ DataTypeHandler * getDataTypeHandlerForC case NdbDictionary::Column::Char: if(col->getLength() == 1) return & Handler_enum; - /* fallthrough. TODO: support CHAR */ + else return & Handler_Char; default: return NULL; @@ -171,25 +183,23 @@ size_t getColumnRecordSize(const NdbDict /******************* IMPLEMENTATIONS *******************/ /***** VARCHAR *****/ -TypeHandlerStatus dth_decode_varchar(const NdbDictionary::Column *col, - size_t &len, char * &str, - const void *buf) { - len = dth_sfdlen_varchar(col, buf); +int dth_decode_varchar(const NdbDictionary::Column *col, + char * &str, const void *buf) { + size_t len = dth_length_varchar(col, buf); str = ((char *) buf) + 1; - return DTH_OK; + return len; } -size_t dth_sfdlen_varchar(const NdbDictionary::Column *col, const void *buf) { +size_t dth_length_varchar(const NdbDictionary::Column *col, const void *buf) { /* Return the actual length of the value string */ uint8_t * length_byte = (uint8_t *) buf; return (size_t) (*length_byte); } -TypeHandlerStatus dth_encode_varchar(const NdbDictionary::Column *col, - size_t len, size_t offset, - const char *str, void *buf) { +int dth_encode_varchar(const NdbDictionary::Column *col, + size_t len, size_t offset, const char *str, void *buf) { size_t total_len = len + offset; uint8_t * length_byte = (uint8_t *) buf; char *char_buffer = ((char *) buf) + 1 + offset; @@ -203,22 +213,21 @@ TypeHandlerStatus dth_encode_varchar(con /* Copy string value into buffer */ strncpy(char_buffer, str, len); - return DTH_OK; + return len; } /***** LONGVARCHAR *****/ -TypeHandlerStatus dth_decode_longvarchar(const NdbDictionary::Column *col, - size_t &len, char * &str, - const void *buf) { - len = dth_sfdlen_longvarchar(col, buf); +int dth_decode_longvarchar(const NdbDictionary::Column *col, + char * &str, const void *buf) { + size_t len = dth_length_longvarchar(col, buf); str = ((char *) buf) + 2; - return DTH_OK; + return len; } -size_t dth_sfdlen_longvarchar(const NdbDictionary::Column *col, const void *buf) { +size_t dth_length_longvarchar(const NdbDictionary::Column *col, const void *buf) { /* Return the actual length of the value string */ uint8_t * length_byte_1 = (uint8_t *) buf; uint8_t * length_byte_2 = ((uint8_t *) buf) + 1; @@ -227,7 +236,7 @@ size_t dth_sfdlen_longvarchar(const NdbD } -TypeHandlerStatus dth_encode_longvarchar(const NdbDictionary::Column *col, +int dth_encode_longvarchar(const NdbDictionary::Column *col, size_t len, size_t offset, const char *str, void *buf) { char *cbuf = ((char *) buf); @@ -246,20 +255,41 @@ TypeHandlerStatus dth_encode_longvarchar /* Copy string value into buffer */ strncpy(dest, str, len); - return DTH_OK; + return len; } +/***** CHAR *****/ +int dth_decode_char(const NdbDictionary::Column *col, + char * &str, const void *buf) { + *str = * (char *) buf; + // TODO: is it null-padded? space-padded? + return col->getLength(); +} + +size_t dth_length_char(const NdbDictionary::Column *col, const void *buf) { + return col->getLength(); +} + +int dth_encode_char(const NdbDictionary::Column *col, + size_t len, size_t offset, const char *str, void *buf) { + char *cbuf = ((char *) buf); + char *dest = cbuf + offset; + + if(len > col->getLength()) return DTH_VALUE_TOO_LONG; + + memcpy(dest, str, len); + return len; +} + /***** INT *****/ -TypeHandlerStatus dth_decode_int(const NdbDictionary::Column *col, size_t &len, - char * &str, const void *buf) { - len = sprintf(str, "%d",* (int *) buf) + 1; // +1 for null terminator - - return DTH_OK; +int dth_decode_int(const NdbDictionary::Column *col, + char * &str, const void *buf) { + return sprintf(str, "%d",* (int *) buf) + 1; // +1 for null terminator } -size_t dth_sfdlen_int(const NdbDictionary::Column *col, const void *buf) { +size_t dth_length_int(const NdbDictionary::Column *col, const void *buf) { int i = *((int *) buf); int len = ( i < 0) ? 2 : 1; for( ; i > 0 ; len++) i = i / 10; @@ -267,27 +297,24 @@ size_t dth_sfdlen_int(const NdbDictionar } -TypeHandlerStatus dth_encode_int(const NdbDictionary::Column *col, - size_t len, size_t offset, - const char *str, void *buf) { +int dth_encode_int(const NdbDictionary::Column *col, + size_t len, size_t offset, const char *str, void *buf) { assert(offset == 0); int *ibuf = (int *) buf; - *ibuf = strtol(str, NULL, 10); - - return DTH_OK; + *ibuf = strtol(str, NULL, 10); + + return len; } /***** BIGINT UNSIGNED *****/ -TypeHandlerStatus dth_decode_ubigint(const NdbDictionary::Column *col, size_t &len, - char * &str, const void *buf) { - len = sprintf(str, "%"PRIu64,* (uint64_t *) buf) + 1; // +1 for null - - return DTH_OK; +int dth_decode_ubigint(const NdbDictionary::Column *col, + char * &str, const void *buf) { + return sprintf(str, "%"PRIu64,* (Uint64 *) buf) + 1; // +1 for null } -size_t dth_sfdlen_ubigint(const NdbDictionary::Column *col, const void *buf) { +size_t dth_length_ubigint(const NdbDictionary::Column *col, const void *buf) { int i = *((uint64_t *) buf); int len = ( i < 0) ? 2 : 1; for( ; i > 0 ; len++) i = i / 10; @@ -295,37 +322,33 @@ size_t dth_sfdlen_ubigint(const NdbDicti } -TypeHandlerStatus dth_encode_ubigint(const NdbDictionary::Column *col, - size_t len, size_t offset, - const char *str, void *buf) { +int dth_encode_ubigint(const NdbDictionary::Column *col, + size_t len, size_t offset, const char *str, void *buf) { assert(offset == 0); uint64_t *ibuf = (uint64_t *) buf; *ibuf = strtoull(str, NULL, 10); - return DTH_OK; + return len; } /***** ENUM *****/ -TypeHandlerStatus dth_decode_char1(const NdbDictionary::Column *col, size_t &len, - char * &str, const void *buf) { - *str = * (char *) buf; - len = 1; - - return DTH_OK; +int dth_decode_char1(const NdbDictionary::Column *col, + char * &str, const void *buf) { + *str = * (char *) buf; + return 1; } -size_t dth_sfdlen_char1(const NdbDictionary::Column *col, const void *buf) { - return 1; +size_t dth_length_char1(const NdbDictionary::Column *col, const void *buf) { + return 1; } -TypeHandlerStatus dth_encode_char1(const NdbDictionary::Column *col, - size_t len, size_t offset, - const char *str, void *buf) { +int dth_encode_char1(const NdbDictionary::Column *col, + size_t len, size_t offset, const char *str, void *buf) { assert(offset == 0); char *cbuf = (char *) buf; *cbuf = *str; - return DTH_OK; + return 1; } === modified file 'storage/ndb/memcache/src/Record.cc' --- a/storage/ndb/memcache/src/Record.cc 2011-04-30 14:20:42 +0000 +++ b/storage/ndb/memcache/src/Record.cc 2011-05-16 05:49:22 +0000 @@ -149,7 +149,7 @@ bool Record::complete(NdbDictionary::Dic bool Record::appendCRLF(int idx, size_t len, char *buffer) const { if( handlers[col[idx]]->contains_string && handlers[col[idx]]->writeToNdb(specs[col[idx]].column, 2, len, "\r\n", buffer) - == DTH_OK) + >= 0) { return true; } @@ -164,7 +164,7 @@ bool Record::decodeNoCopy(int idx, if(! handlers[col[idx]]->contains_string) return false; const char * src_buffer = src + specs[col[idx]].offset; - handlers[col[idx]]->readFromNdb(specs[col[idx]].column, *len, *dest, src_buffer); + *len = handlers[col[idx]]->readFromNdb(specs[col[idx]].column, *dest, src_buffer); return true; } @@ -181,7 +181,7 @@ size_t Record::decodeCopy(int idx, char else { /* Types other than VARCHAR */ /* this works but it's strange; something has to be sorted out here. handlers[col[idx]] but specs[idx] ?? */ - handlers[col[idx]]->readFromNdb(specs[idx].column, out_len, dest, src_buffer); + out_len = handlers[col[idx]]->readFromNdb(specs[idx].column, dest, src_buffer); } *(dest + out_len) = 0; // terminating null; may be overwritten by a tab return out_len; @@ -234,7 +234,7 @@ Uint64 Record::getUint64Value(int idx, c } -TypeHandlerStatus Record::encode(int idx, const char *key, int nkey, +int Record::encode(int idx, const char *key, int nkey, char *buffer) const { return handlers[col[idx]]->writeToNdb(specs[col[idx]].column, nkey, 0, key, buffer + specs[col[idx]].offset); === added file 'storage/ndb/memcache/src/TabSeparatedValues.cc' --- a/storage/ndb/memcache/src/TabSeparatedValues.cc 1970-01-01 00:00:00 +0000 +++ b/storage/ndb/memcache/src/TabSeparatedValues.cc 2011-05-16 06:14:51 +0000 @@ -0,0 +1,46 @@ +/* + Copyright (c) 2011, Oracle and/or its affiliates. All rights + reserved. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; version 2 of + the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + 02110-1301 USA +*/ + +#include + +#include "TabSeparatedValues.h" + +TabSeparatedValues::TabSeparatedValues(const char *string, Uint32 max_parts, size_t length) : + parts(0), index(0) +{ + size_t parsed_len = 0; + + assert(max_parts < MAX_VAL_COLUMNS); + + while(parsed_len <= length && parts < max_parts) { + const char *s = string + parsed_len; + pointers[parts] = s; + lengths[parts] = find_tab(s, length - parsed_len); + parsed_len += lengths[parts] + 1; + parts++; + } +} + + +int TabSeparatedValues::find_tab(const char *s, int remaining) const { + int r; + for(r = 0; r < remaining && *(s+r) != '\t' && *(s+r) != '\0'; r++); + return r; +} === modified file 'storage/ndb/memcache/unit/Makefile.am' --- a/storage/ndb/memcache/unit/Makefile.am 2011-04-27 04:28:04 +0000 +++ b/storage/ndb/memcache/unit/Makefile.am 2011-05-16 06:14:51 +0000 @@ -36,7 +36,8 @@ run_unit_tests_SOURCES = harness.cc \ casbits.cc \ incr.cc \ alloc.cc \ - connpool.cc + connpool.cc \ + tsv.cc run_unit_tests_CFLAGS = -g -O0 \ -I${top_srcdir}/storage/ndb/memcache \ @@ -56,6 +57,7 @@ run_unit_tests_LDADD = ../ndb_engine_la- ../ndb_engine_la-Record.lo \ ../ndb_engine_la-Stockholm.lo \ ../ndb_engine_la-TableSpec.lo \ + ../ndb_engine_la-TabSeparatedValues.lo \ ../ndb_engine_la-assoc.lo \ ../ndb_engine_la-atomics.lo \ ../ndb_engine_la-debug.lo \ === modified file 'storage/ndb/memcache/unit/all_tests.h' --- a/storage/ndb/memcache/unit/all_tests.h 2011-03-30 06:54:53 +0000 +++ b/storage/ndb/memcache/unit/all_tests.h 2011-05-16 06:14:51 +0000 @@ -24,19 +24,25 @@ #include "QueryPlan.h" #include "Operation.h" -#define require(x) if(!(x)) return 0; -#define pass return 1; +#define require(x) if(!(x)) return __LINE__; +#define pass return 0; #define detail(v, fmt, ...) if(v) printf (fmt, ## __VA_ARGS__) #define RESULT getNdbError().code +#define REQ_NONE 0 +#define REQ_NDB_CONNECTION 1 +#define REQ_DEMO_TABLE 2 + void delete_row(QueryPlan *plan, const char * key, int verbose); typedef int TESTCASE(QueryPlan *plan, int verbose); struct test_item { + int enabled; const char *name; TESTCASE *function; + int requires; }; TESTCASE run_cas_test; @@ -44,16 +50,24 @@ TESTCASE test_cas_bitshifts; TESTCASE run_incr_test; TESTCASE run_allocator_test; TESTCASE run_pool_test; +TESTCASE run_tsv_test; #ifdef HARNESS struct test_item all_tests[] = { - { "cas operation", run_cas_test }, - { "cas bitshifting", test_cas_bitshifts }, - { "incr operation", run_incr_test }, - { "allocator", run_allocator_test }, - { "pool", run_pool_test }, - { NULL, NULL } + { 1, "cas operation", run_cas_test, REQ_DEMO_TABLE }, + { 1, "cas bitshifting", test_cas_bitshifts, REQ_NONE }, + { 1, "incr operation", run_incr_test, REQ_DEMO_TABLE }, + { 1, "allocator", run_allocator_test, REQ_NONE }, + { 0, "pool", run_pool_test, REQ_NDB_CONNECTION }, + { 1, "tsv", run_tsv_test, REQ_NONE }, + { 0, NULL, NULL, NULL } +}; + + +const char * requirements[3] = +{ + "none", "ndb connection", "demo_table" }; #else === modified file 'storage/ndb/memcache/unit/connpool.cc' --- a/storage/ndb/memcache/unit/connpool.cc 2011-03-30 06:54:53 +0000 +++ b/storage/ndb/memcache/unit/connpool.cc 2011-05-16 05:37:57 +0000 @@ -28,7 +28,6 @@ int run_pool_test(QueryPlan *plan, int v int r; Ndb_cluster_connection &main_conn = plan->db->get_ndb_cluster_connection(); - /* The pooled connection */ Ndb_cluster_connection * nc = new Ndb_cluster_connection(connect_string, & main_conn); === modified file 'storage/ndb/memcache/unit/harness.cc' --- a/storage/ndb/memcache/unit/harness.cc 2011-04-19 01:16:36 +0000 +++ b/storage/ndb/memcache/unit/harness.cc 2011-05-16 06:14:51 +0000 @@ -26,10 +26,9 @@ #define HARNESS 1 #include "all_tests.h" -/*** usage: ./run_unit_tests [connectstring] [test-id] - These tests require a running cluster. +/*** These tests require a running cluster. Some of them require the ndbmemcache.demo_table to exist. - If test-id is supplied, run one test verbosely; + If a particular test-id is supplied, run one test verbosely; otherwise run all tests and indicate pass or fail. ***/ @@ -39,32 +38,43 @@ extern EXTENSION_LOGGER_DESCRIPTOR *logg Ndb_cluster_connection * connect(const char *); +int list_tests(void); +int usage(char *); + int main(int argc, char *argv[]) { + connect_string = NULL; int test_number = -1; char * test_name = 0; - if(argc > 1) connect_string = argv[1]; - if(argc > 2) { - test_number = atoi(argv[2]); - if(test_number) test_number -= 1; - else test_name = argv[2]; - } - - ndb_init(); - DEBUG_INIT(NULL, 0); - - printf("Connecting to cluster (%s)\n", connect_string); - - Ndb_cluster_connection * conn = connect(connect_string); - Ndb *db = new Ndb(conn); - db->init(4); - - TableSpec spec("ndbmemcache.demo_table", "mkey", "string_value"); - spec.cas_column = "cas_value"; - spec.math_column = "math_value"; - QueryPlan plan(db, &spec); - + int optc; + int req_level; int npass = 0, nfail = 0; + Ndb_cluster_connection * conn = NULL; + QueryPlan *plan = NULL; + Ndb *db = NULL; + + /* Options */ + while((optc = getopt(argc, argv, "hlc:t:")) != -1) { + switch(optc) { + case 'c': + connect_string = optarg; + break; + case 't': + test_number = atoi(optarg); + if(test_number > 0) test_number -= 1; + else test_name = optarg; + break; + case 'l': + return list_tests(); + break; + case 'h': + default: + return usage(argv[0]); + break; + } + } + + /* If a test name was given, find it by number */ if(test_name) { for(int i = 0; all_tests[i].name; i++) { if(! strcmp(test_name, all_tests[i].name)) { @@ -77,24 +87,80 @@ int main(int argc, char *argv[]) { exit(1); } } + + /* Determine requirements level for this test */ + if(test_number >= 0) + req_level = all_tests[test_number].requires; + else + req_level = REQ_DEMO_TABLE; // highest level + + ndb_init(); + DEBUG_INIT(NULL, 0); + + if(req_level >= REQ_NDB_CONNECTION) { + printf("Connecting to cluster (%s)\n", connect_string); + conn = connect(connect_string); + db = new Ndb(conn); + db->init(4); + } + + if(req_level >= REQ_DEMO_TABLE) { + TableSpec spec("ndbmemcache.demo_table", "mkey", "string_value"); + spec.cas_column = "cas_value"; + spec.math_column = "math_value"; + plan = new QueryPlan(db, &spec); + } - if(test_number > -1) { + if(test_number >= 0) { /* Run a particular test */ printf("%s\n", all_tests[test_number].name); - int r = all_tests[test_number].function(& plan, 1); //verbose - printf(" %s\n", r ? "[PASS]" : "[FAIL]"); - if(r) npass++; - else nfail++; + int r = all_tests[test_number].function(plan, 1); //verbose + if(r) { + printf(" [FAIL] at line %d\n", r); nfail++; + } else { + printf(" [PASS]\n"); npass++; + } } - else { + else { /* Run all tests */ for(int i = 0; all_tests[i].name; i++) { - printf("%-30s", all_tests[i].name); - int r = all_tests[i].function(& plan, 0); // quiet - printf(" %s\n", r ? "[PASS]" : "[FAIL]"); - if(r) npass++; - else nfail++; + if(all_tests[i].enabled) { + printf("%-30s", all_tests[i].name); + int r = all_tests[i].function(plan, 0); // quiet + printf(" %s\n", r ? "[FAIL]" : "[PASS]"); + if(r) nfail++; + else npass++; + } } - printf("\nTotals: %d pass ... %d fail\n", npass, nfail); + printf("\nTotals: %d pass ... %d fail\n", npass, nfail); } + + exit((nfail > 0)); +} + + +int list_tests() { + printf("\n"); + printf("No. %-30s %-20s %-10s\n", "Name", "Requires","Enabled"); + printf("----------------------------------------------------------------\n"); + for(int i = 0; all_tests[i].name; i++) + printf("%d %-30s %-20s %-10s\n", i+1, all_tests[i].name, + requirements[all_tests[i].requires], + all_tests[i].enabled ? "Yes" : "No"); + printf("\n"); + return 0; +} + + +int usage(char *prog) { + printf("\n"); + printf("usage %s [options]\n", prog); + printf("options: \n"); + printf(" -c connectstring : specify NDB connect-string\n"); + printf(" -t test-id : run a particular test by number or name\n"); + printf(" -l : list tests\n"); + printf(" -h : help\n"); + printf("\n"); + + return 0; } === added file 'storage/ndb/memcache/unit/tsv.cc' --- a/storage/ndb/memcache/unit/tsv.cc 1970-01-01 00:00:00 +0000 +++ b/storage/ndb/memcache/unit/tsv.cc 2011-05-16 06:14:51 +0000 @@ -0,0 +1,157 @@ +/* + Copyright (c) 2011, Oracle and/or its affiliates. All rights + reserved. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; version 2 of + the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + 02110-1301 USA + */ +#include +#include + +#include "TabSeparatedValues.h" + +#include "all_tests.h" + + +int run_tsv_test(QueryPlan *, int v) { + { + TabSeparatedValues t1("frodo.xxx", 4, 5); + require(t1.getLength() == 5); + require(t1.advance() == 0); + detail(v, "tsv test 1 OK\n"); + } + + { + char sam[16]; + + const char *v2 = "sam\tjessie"; // null-terminated + TabSeparatedValues t2(v2, 4, strlen(v2)); + strncpy(sam, t2.getPointer(), t2.getLength()); + require(! strcmp(sam, "sam")); + require(t2.getLength() == 3); + + require( t2.advance() == 1); + + require(* t2.getPointer() == 'j'); + require(t2.getLength() == 6); + detail(v, "tsv test 2 OK\n"); + } + + { + char jes[16]; + const char *v3 = "sam\tjessie......"; // no null terminator + TabSeparatedValues t3(v3, 4, 10); + + require(t3.advance() == 1); + require(t3.getLength() == 6); + strncpy(jes, t3.getPointer(), t3.getLength()); + require(strncmp(jes,"jessie", t3.getLength()) == 0); + detail(v, "tsv test 3 OK\n"); + } + + { + const char *v4 = "\tabc"; // 2 values + TabSeparatedValues t4(v4, 4, strlen(v4)); + + /* First value is null */ + require(t4.getLength() == 0); + + /* Second value */ + require(t4.advance() == 1); + require(* t4.getPointer() == 'a'); + require( t4.getLength() == 3); + + /* No more */ + require(t4.advance() == 0); + detail(v, "tsv test 4 OK\n"); + } + + { + const char *v5 = "\t\tabc"; // 3 values + TabSeparatedValues t5(v5, 4, strlen(v5)); + + /* First value is null */ + require(t5.getLength() == 0); + + /* Second value */ + require(t5.advance() == 1); + require(t5.getLength() == 0); + + /* Third value */ + require(t5.advance() == 1); + require(* t5.getPointer() == 'a'); + require( t5.getLength() == 3); + + /* No more */ + require(t5.advance() == 0); + detail(v, "tsv test 5 OK\n"); + } + + { + const char *v6 = "\t\tabc\t\t"; // 5 values with null terminator + TabSeparatedValues t6(v6, 6, strlen(v6)); + + /* First value is null */ + require(t6.getLength() == 0); + + /* Second value is null */ + require(t6.advance() == 1); + require(t6.getLength() == 0); + + /* Third value is abc */ + require(t6.advance() == 1); + require( t6.getLength() == 3); + + /* 4th value is null */ + require(t6.advance() == 1); + require(t6.getLength() == 0); + + /* 5th value is null */ + require(t6.advance() == 1); + require(t6.getLength() == 0); + + /* No more */ + require(t6.advance() == 0); + detail(v, "tsv test 6 OK\n"); + } + + { + const char *v7 = "\t\tabc\t__"; // 4 values, no null + TabSeparatedValues t7(v7, 4, strlen(v7) - 2); + + /* First value is null */ + require(t7.getLength() == 0); + + /* Second value is null */ + require(t7.advance() == 1); + require(t7.getLength() == 0); + + /* Third value is abc */ + require(t7.advance() == 1); + require(t7.getLength() == 3); + + /* 4th value is null */ + require(t7.advance() == 1); + require(t7.getLength() == 0); + + /* No more */ + require(t7.advance() == 0); + detail(v, "tsv test 7 OK\n"); + } + + + pass; +} + No bundle (reason: useless for push emails).