From: John David Duncan Date: May 16 2011 6:15am Subject: bzr commit into mysql-5.1-telco-7.2 branch (john.duncan:4176) List-Archive: http://lists.mysql.com/commits/137379 Message-Id: <201105160615.p4G6FNxC017089@acsmt357.oracle.com> MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="===============1687591778==" --===============1687591778== MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Content-Disposition: inline #At file:///Users/jdd/bzr-repo/working/cluster-7.2-labs-memcached/ based on revid:john.duncan@stripped 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 === 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 \ === 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 === 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-05-16 05:37:57 +0000 +++ b/storage/ndb/memcache/unit/all_tests.h 2011-05-16 06:14:51 +0000 @@ -24,8 +24,8 @@ #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 @@ -50,6 +50,7 @@ TESTCASE test_cas_bitshifts; TESTCASE run_incr_test; TESTCASE run_allocator_test; TESTCASE run_pool_test; +TESTCASE run_tsv_test; #ifdef HARNESS @@ -59,6 +60,7 @@ struct test_item all_tests[] = { { 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 } }; === modified file 'storage/ndb/memcache/unit/harness.cc' --- a/storage/ndb/memcache/unit/harness.cc 2011-05-16 05:37:57 +0000 +++ b/storage/ndb/memcache/unit/harness.cc 2011-05-16 06:14:51 +0000 @@ -114,18 +114,20 @@ int main(int argc, char *argv[]) { 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++; + if(r) { + printf(" [FAIL] at line %d\n", r); nfail++; + } else { + printf(" [PASS]\n"); npass++; + } } else { /* Run all tests */ for(int i = 0; all_tests[i].name; i++) { if(all_tests[i].enabled) { 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++; + printf(" %s\n", r ? "[FAIL]" : "[PASS]"); + if(r) nfail++; + else npass++; } } printf("\nTotals: %d pass ... %d fail\n", npass, nfail); === 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; +} + --===============1687591778== MIME-Version: 1.0 Content-Type: text/bzr-bundle; charset="us-ascii"; name="bzr/john.duncan@stripped" Content-Transfer-Encoding: 7bit Content-Disposition: inline # Bazaar merge directive format 2 (Bazaar 0.90) # revision_id: john.duncan@stripped # target_branch: file:///Users/jdd/bzr-repo/working/cluster-7.2-labs-\ # memcached/ # testament_sha1: 1886cf2a6465552b31c701a406466d60e83aaf56 # timestamp: 2011-05-15 23:15:15 -0700 # base_revision_id: john.duncan@stripped\ # 1awsj0s7rqq54fp0 # # Begin bundle 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 --===============1687591778==--