├── .gitignore ├── AUTHORS ├── COPYING ├── ChangeLog ├── Makefile.am ├── README ├── autogen.sh ├── client ├── Makefile.am ├── hsclient.cpp ├── hslongrun.cpp ├── hspool_test.pl ├── hstest.cpp ├── hstest.pl ├── hstest_hs.sh ├── hstest_hs_more50.sh ├── hstest_md.sh ├── hstest_my.sh └── hstest_my_more50.sh ├── configure.ac ├── docs-en ├── about-handlersocket.en.txt ├── configuration-options.en.txt ├── installation.en.txt ├── perl-client.en.txt └── protocol.en.txt ├── docs-ja ├── about-handlersocket.ja.txt ├── installation.ja.txt ├── perl-client.ja.txt └── protocol.ja.txt ├── handlersocket ├── COPYRIGHT.txt ├── Makefile.am ├── Makefile.plain.template ├── database.cpp ├── database.hpp ├── handlersocket.cpp ├── handlersocket.spec.template ├── hstcpsvr.cpp ├── hstcpsvr.hpp ├── hstcpsvr_worker.cpp ├── hstcpsvr_worker.hpp └── mysql_incl.hpp ├── libhsclient ├── COPYRIGHT.txt ├── Makefile.am ├── Makefile.plain ├── allocator.hpp ├── auto_addrinfo.hpp ├── auto_file.hpp ├── auto_ptrcontainer.hpp ├── config.cpp ├── config.hpp ├── escape.cpp ├── escape.hpp ├── fatal.cpp ├── fatal.hpp ├── hstcpcli.cpp ├── hstcpcli.hpp ├── libhsclient.spec.template ├── mutex.hpp ├── socket.cpp ├── socket.hpp ├── string_buffer.hpp ├── string_ref.hpp ├── string_util.cpp ├── string_util.hpp ├── thread.hpp └── util.hpp ├── misc ├── microbench-hs.log ├── microbench-my.log └── mysql-5.6.10-server_started.diff ├── perl-Net-HandlerSocket ├── COPYRIGHT.txt ├── Changes ├── HandlerSocket.xs ├── MANIFEST ├── Makefile.PL ├── Makefile.PL.installed ├── README ├── lib │ └── Net │ │ ├── HandlerSocket.pm │ │ └── HandlerSocket │ │ └── Pool.pm ├── perl-Net-HandlerSocket.spec.template ├── ppport.h └── t │ └── Net-HandlerSocket.t └── regtest ├── Makefile ├── common ├── binary_my.cnf ├── compat.sh └── hstest.pm └── test_01_lib ├── Makefile ├── run.sh ├── test01.expected ├── test01.pl ├── test02.expected ├── test02.pl ├── test03.expected ├── test03.pl ├── test04.expected ├── test04.pl ├── test05.expected ├── test05.pl ├── test06.expected ├── test06.pl ├── test07.expected ├── test07.pl ├── test08.expected ├── test08.pl ├── test09.expected ├── test09.pl ├── test10.expected ├── test10.pl ├── test11.expected ├── test11.pl ├── test12.expected ├── test12.pl ├── test13.expected ├── test13.pl ├── test14.expected ├── test14.pl ├── test15.expected ├── test15.pl ├── test16.expected ├── test16.pl ├── test17.expected ├── test17.pl ├── test18.expected ├── test18.pl ├── test19.expected ├── test19.pl ├── test20.expected ├── test20.pl ├── test21.expected ├── test21.pl ├── test22.expected ├── test22.pl ├── test23.expected ├── test23.pl ├── test24.expected └── test24.pl /.gitignore: -------------------------------------------------------------------------------- 1 | configure 2 | Makefile.in 3 | Makefile 4 | .deps 5 | *.lo 6 | *.o 7 | INSTALL 8 | m4 9 | stamp-h1 10 | libtool 11 | ltmain.sh 12 | missing 13 | install-sh 14 | autom4te.cache 15 | config.h* 16 | config.status 17 | config.guess 18 | config.sub 19 | config.log 20 | depcomp 21 | TAGS 22 | aclocal.m4 23 | .libs 24 | ltmain.sh 25 | *.la 26 | handlersocket/Makefile.plain 27 | handlersocket/*.spec 28 | libhsclient/*.spec 29 | client/hstest 30 | client/hsclient 31 | perl-Net-HandlerSocket/*.spec 32 | regtest/*/*.log 33 | regtest/*/*.log2 34 | regtest/*/DONE 35 | dist/* 36 | ar-lib 37 | -------------------------------------------------------------------------------- /AUTHORS: -------------------------------------------------------------------------------- 1 | Akira Higuchi (https://github.com/ahiguti) 2 | - developed HanderSocket plugin, libhsclient, and perl-Net-HandlerSocket 3 | 4 | Yoshinori Matsunobu (https://github.com/yoshinorim) 5 | - introduced autotools, added support for MySQL 5.5.6, added statistics 6 | variables 7 | 8 | Jeff Hodges (https://github.com/jmhodges) 9 | - fixed some autotools scripts 10 | 11 | Toru Yamaguchi (https://github.com/zigorou) 12 | - ported to MacOS X 13 | 14 | Moriyoshi Koizumi (https://github.com/moriyoshi) 15 | - fixed some autotools scripts 16 | 17 | takeda-at (https://github.com/takada-at) 18 | - added simple authorization function 19 | 20 | WheresWardy (https://github.com/WheresWardy) 21 | - added authentication functions to libhsclient 22 | 23 | -------------------------------------------------------------------------------- /COPYING: -------------------------------------------------------------------------------- 1 | ----------------------------------------------------------------------------- 2 | HandlerSocket plugin for MySQL 3 | 4 | Copyright (c) 2010 DeNA Co.,Ltd. 5 | All rights reserved. 6 | 7 | Redistribution and use in source and binary forms, with or without 8 | modification, are permitted provided that the following conditions are met: 9 | 10 | * Redistributions of source code must retain the above copyright 11 | notice, this list of conditions and the following disclaimer. 12 | * Redistributions in binary form must reproduce the above copyright 13 | notice, this list of conditions and the following disclaimer in the 14 | documentation and/or other materials provided with the distribution. 15 | * Neither the name of DeNA Co.,Ltd. nor the names of its contributors 16 | may be used to endorse or promote products derived from this software 17 | without specific prior written permission. 18 | 19 | THIS SOFTWARE IS PROVIDED BY DeNA Co.,Ltd. "AS IS" AND ANY EXPRESS OR 20 | IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 21 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO 22 | EVENT SHALL DeNA Co.,Ltd. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 24 | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 25 | OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 26 | WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 27 | OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 28 | ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | 30 | 31 | -------------------------------------------------------------------------------- /ChangeLog: -------------------------------------------------------------------------------- 1 | 1.1.1 - 2013-05-06 2 | * 1.1.1 3 | * Fixed compilation problems with mysql 5.6.11 4 | 5 | 1.1.0 - 2011-12-29 6 | * 1.1.0 7 | 8 | 1.0.6 - 2010-10-29 9 | * Changed build instruction (autoreconf/configure/make), removed auto-generated files (Contributed by jmhodges) 10 | * 11 | 12 | 1.0.5 - 2010-10-18 13 | * Changed build procedures (using typical configure/make) 14 | * Supported 5.5.6 15 | * Added status variables 16 | 17 | 1.0.4 - 2010-08-15 18 | * Initial public release 19 | 20 | -------------------------------------------------------------------------------- /Makefile.am: -------------------------------------------------------------------------------- 1 | 2 | ACLOCAL_AMFLAGS = -I m4 3 | 4 | SUBDIRS = @HANDLERSOCKET_SUBDIRS@ 5 | 6 | perl: 7 | cd perl-Net-HandlerSocket && perl Makefile.PL && make 8 | 9 | install_perl: 10 | cd perl-Net-HandlerSocket && make install 11 | 12 | rpms: rpm_cli rpm_perl rpm_c 13 | 14 | rpm_dir: 15 | - mkdir dist 16 | - mkdir dist/BUILD dist/RPMS dist/SOURCES dist/SPECS dist/SRPMS 17 | 18 | rpm_cli: clean_cli rpm_dir 19 | sed -e "s/HANDLERSOCKET_VERSION/$(VERSION)/" \ 20 | libhsclient/libhsclient.spec.template \ 21 | > libhsclient/libhsclient.spec 22 | tar cvfz dist/libhsclient.tar.gz libhsclient 23 | rpmbuild --define "_topdir `pwd`/dist" -ta \ 24 | dist/libhsclient.tar.gz 25 | 26 | rpm_perl: clean_perl rpm_dir 27 | sed -e "s/HANDLERSOCKET_VERSION/$(VERSION)/" \ 28 | perl-Net-HandlerSocket/perl-Net-HandlerSocket.spec.template \ 29 | > perl-Net-HandlerSocket/perl-Net-HandlerSocket.spec 30 | cd perl-Net-HandlerSocket && perl Makefile.PL && make clean && \ 31 | rm -f Makefile.old 32 | tar cvfz dist/perl-Net-HandlerSocket.tar.gz perl-Net-HandlerSocket 33 | rpmbuild --define "_topdir `pwd`/dist" -ta \ 34 | dist/perl-Net-HandlerSocket.tar.gz 35 | 36 | rpm_c: clean_c rpm_dir 37 | sed -e "s/HANDLERSOCKET_VERSION/$(VERSION)/" \ 38 | handlersocket/handlersocket.spec.template \ 39 | > handlersocket/handlersocket.spec 40 | sed -e "s|HANDLERSOCKET_MYSQL_INC|$(MYSQL_CFLAGS) $(MYSQL_INC)|" \ 41 | -e "s|HANDLERSOCKET_MYSQL_LIB|$(MYSQL_LIB)|" \ 42 | handlersocket/Makefile.plain.template \ 43 | > handlersocket/Makefile.plain 44 | tar cvfz dist/handlersocket.tar.gz handlersocket 45 | rpmbuild --define "_topdir `pwd`/dist" -ta \ 46 | dist/handlersocket.tar.gz 47 | 48 | install_rpm_pl: 49 | - sudo rpm -e perl-Net-HandlerSocket 50 | - sudo rpm -e perl-Net-HandlerSocket-debuginfo 51 | make clean 52 | make rpm_perl 53 | - sudo rpm -U dist/RPMS/*/perl*.rpm 54 | 55 | installrpms: 56 | - sudo rpm -e handlersocket 57 | - sudo rpm -e handlersocket-debuginfo 58 | - sudo rpm -e perl-Net-HandlerSocket 59 | - sudo rpm -e perl-Net-HandlerSocket-debuginfo 60 | - sudo rpm -e libhsclient 61 | - sudo rpm -e libhsclient-debuginfo 62 | make clean 63 | make rpm_cli 64 | - sudo rpm -U dist/RPMS/*/libhsclient*.rpm 65 | make clean 66 | make rpm_perl 67 | - sudo rpm -U dist/RPMS/*/perl*.rpm 68 | make clean 69 | make rpm_c 70 | - sudo rpm -U dist/RPMS/*/handlersocket*.rpm 71 | 72 | clean_cli: 73 | cd libhsclient && make clean 74 | cd client && make clean 75 | 76 | clean_perl: 77 | cd perl-Net-HandlerSocket && perl Makefile.PL && make clean && \ 78 | rm -f Makefile.old 79 | 80 | clean_c: 81 | cd handlersocket && make clean 82 | 83 | clean_all: clean_cli clean_perl clean_c 84 | cd regtest && make clean 85 | rm -rf dist/*/* 86 | rm -f dist/*.tar.gz 87 | 88 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | 2 | ----------------------------------------------------------------------------- 3 | HandlerSocket plugin for MySQL 4 | 5 | Copyright (c) 2010 DeNA Co.,Ltd. 6 | All rights reserved. 7 | 8 | Redistribution and use in source and binary forms, with or without 9 | modification, are permitted provided that the following conditions are met: 10 | 11 | * Redistributions of source code must retain the above copyright 12 | notice, this list of conditions and the following disclaimer. 13 | * Redistributions in binary form must reproduce the above copyright 14 | notice, this list of conditions and the following disclaimer in the 15 | documentation and/or other materials provided with the distribution. 16 | * Neither the name of DeNA Co.,Ltd. nor the names of its contributors 17 | may be used to endorse or promote products derived from this software 18 | without specific prior written permission. 19 | 20 | THIS SOFTWARE IS PROVIDED BY DeNA Co.,Ltd. "AS IS" AND ANY EXPRESS OR 21 | IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 22 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO 23 | EVENT SHALL DeNA Co.,Ltd. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 25 | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 26 | OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 27 | WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 28 | OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 29 | ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | 31 | 32 | ----------------------------------------------------------------------------- 33 | About HandlerSocket 34 | 35 | HandlerSocket is a NoSQL plugin for MySQL. It works as a daemon inside the 36 | mysqld process, accept tcp connections, and execute requests from clients. 37 | HandlerSocket does not support SQL queries. Instead, it supports simple CRUD 38 | operations on tables. 39 | 40 | Because of the following reasons, HandlerSocket is much faster than the 41 | mysqld/libmysql pair in some circumstances: 42 | 43 | - HandlerSocket manipulates data without parsing SQL, which causes less 44 | CPU usage. 45 | - HandlerSocket reads many requests from clients and executes their 46 | requests in bulk, which causes less CPU and disk usage. 47 | - HandlerSocket client/server protocol is more compact than the 48 | mysql/libmysql pair, which causes less network usage. 49 | 50 | The current version of HandlerSocket only works with GNU/Linux. The source 51 | archive of HandlerSocket includes a C++ and a Perl client libraries. 52 | Here is a list of client libraries for other languages: 53 | 54 | - PHP 55 | http://openpear.org/package/Net_HandlerSocket 56 | http://github.com/tz-lom/HSPHP 57 | http://code.google.com/p/php-handlersocket/ 58 | - Java 59 | http://code.google.com/p/hs4j/ 60 | http://code.google.com/p/handlersocketforjava/ 61 | - Python 62 | http://pypi.python.org/pypi/python-handler-socket 63 | https://code.launchpad.net/~songofacandy/+junk/pyhandlersocket 64 | - Ruby 65 | https://github.com/winebarrel/ruby-handlersocket 66 | https://github.com/miyucy/handlersocket 67 | - JavaScript 68 | https://github.com/koichik/node-handlersocket 69 | - Scala 70 | https://github.com/fujohnwang/hs2client 71 | - Haskell 72 | https://github.com/wuxb45/HandlerSocket-Haskell-Client 73 | 74 | The home of HandlerSocket is here: 75 | https://github.com/DeNA/HandlerSocket-Plugin-for-MySQL 76 | 77 | More documents are available in docs-en/ and docs-ja/ directories. 78 | 79 | -------------------------------------------------------------------------------- /autogen.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | warn() { 4 | echo -e "\tWARNING: $@" 1>&2 5 | } 6 | 7 | # init 8 | 9 | LIBTOOLIZE=libtoolize 10 | ACLOCAL=aclocal 11 | AUTOCONF=autoconf 12 | AUTOHEADER=autoheader 13 | AUTOMAKE=automake 14 | 15 | case `uname -s` in 16 | Darwin) 17 | LIBTOOLIZE=glibtoolize 18 | ;; 19 | FreeBSD) 20 | ACLOCAL_ARGS="$ACLOCAL_ARGS -I /usr/local/share/aclocal/" 21 | ;; 22 | esac 23 | 24 | 25 | # libtoolize 26 | echo "Searching libtoolize..." 27 | if [ `which $LIBTOOLIZE` ] ; then 28 | echo -e "\tFOUND: libtoolize -> $LIBTOOLIZE" 29 | else 30 | warn "Cannot Found libtoolize... input libtool command" 31 | read LIBTOOLIZE 32 | LIBTOOLIZE=`which $LIBTOOLIZE` 33 | if [ `which $LIBTOOLIZE` ] ; then 34 | echo -e "\tSET: libtoolize -> $LIBTOOLIZE" 35 | else 36 | warn "$LIBTOOLIZE: Command not found." 37 | exit 1; 38 | fi 39 | fi 40 | 41 | # aclocal 42 | echo "Searching aclocal..." 43 | if [ `which $ACLOCAL` ] ; then 44 | echo -e "\tFOUND: aclocal -> $ACLOCAL" 45 | else 46 | warn "Cannot Found aclocal... input aclocal command" 47 | read ACLOCAL 48 | ACLOCAL=`which $ACLOCAL` 49 | if [ `which $ACLOCAL` ] ; then 50 | echo -e "\tSET: aclocal -> $ACLOCAL" 51 | else 52 | warn "$ACLOCAL: Command not found." 53 | exit 1; 54 | fi 55 | fi 56 | 57 | # automake 58 | echo "Searching automake..." 59 | if [ `which $AUTOMAKE` ] ; then 60 | echo -e "\tFOUND: automake -> $AUTOMAKE" 61 | else 62 | warn "Cannot Found automake... input automake command" 63 | read AUTOMAKE 64 | ACLOCAL=`which $AUTOMAKE` 65 | if [ `which $AUTOMAKE` ] ; then 66 | echo -e "\tSET: automake -> $AUTOMAKE" 67 | else 68 | warn "$AUTOMAKE: Command not found." 69 | exit 1; 70 | fi 71 | fi 72 | 73 | # autoheader 74 | echo "Searching autoheader..." 75 | if [ `which $AUTOHEADER` ] ; then 76 | echo -e "\tFOUND: autoheader -> $AUTOHEADER" 77 | else 78 | warn "Cannot Found autoheader... input autoheader command" 79 | read AUTOHEADER 80 | ACLOCAL=`which $AUTOHEADER` 81 | if [ `which $AUTOHEADER` ] ; then 82 | echo -e "\tSET: autoheader -> $AUTOHEADER" 83 | else 84 | warn "$AUTOHEADER: Command not found." 85 | exit 1; 86 | fi 87 | fi 88 | 89 | # autoconf 90 | echo "Searching autoconf..." 91 | if [ `which $AUTOCONF` ] ; then 92 | echo -e "\tFOUND: autoconf -> $AUTOCONF" 93 | else 94 | warn "Cannot Found autoconf... input autoconf command" 95 | read AUTOCONF 96 | ACLOCAL=`which $AUTOCONF` 97 | if [ `which $AUTOCONF` ] ; then 98 | echo -e "\tSET: autoconf -> $AUTOCONF" 99 | else 100 | warn "$AUTOCONF: Command not found." 101 | exit 1; 102 | fi 103 | fi 104 | 105 | echo "Running libtoolize ..." 106 | $LIBTOOLIZE --force --copy 107 | echo "Running aclocal ..." 108 | $ACLOCAL ${ACLOCAL_ARGS} -I . 109 | echo "Running autoheader..." 110 | $AUTOHEADER 111 | echo "Running automake ..." 112 | $AUTOMAKE --add-missing --copy 113 | echo "Running autoconf ..." 114 | $AUTOCONF 115 | 116 | mkdir -p m4 117 | 118 | -------------------------------------------------------------------------------- /client/Makefile.am: -------------------------------------------------------------------------------- 1 | AM_INCLUDES= -I../libhsclient 2 | bin_PROGRAMS=hsclient 3 | hsclient_SOURCES= hsclient.cpp 4 | hsclient_LDFLAGS= -static -L../libhsclient -lhsclient 5 | hsclient_CXXFLAGS= $(AM_INCLUDES) 6 | 7 | hstest: hstest.o 8 | $(CXX) $(CXXFLAGS) $(LFLAGS) hstest.o \ 9 | -L../libhsclient/.libs -lhsclient $$(mysql_config --libs_r) \ 10 | -o hstest 11 | 12 | hstest.o: hstest.cpp 13 | $(CXX) $(CXXFLAGS) $(AM_INCLUDES) $$(mysql_config --include) \ 14 | -c hstest.cpp 15 | 16 | hslongrun: hslongrun.o 17 | $(CXX) $(CXXFLAGS) $(LFLAGS) hslongrun.o \ 18 | -L../libhsclient/.libs -lhsclient $$(mysql_config --libs_r) \ 19 | -o hslongrun 20 | 21 | hslongrun.o: hslongrun.cpp 22 | $(CXX) $(CXXFLAGS) $(AM_INCLUDES) $$(mysql_config --include) \ 23 | -c hslongrun.cpp 24 | 25 | -------------------------------------------------------------------------------- /client/hsclient.cpp: -------------------------------------------------------------------------------- 1 | 2 | // vim:sw=2:ai 3 | 4 | #include "hstcpcli.hpp" 5 | #include "string_util.hpp" 6 | 7 | namespace dena { 8 | 9 | int 10 | hstcpcli_main(int argc, char **argv) 11 | { 12 | config conf; 13 | parse_args(argc, argv, conf); 14 | socket_args sockargs; 15 | sockargs.set(conf); 16 | hstcpcli_ptr cli = hstcpcli_i::create(sockargs); 17 | const std::string dbname = conf.get_str("dbname", "hstest"); 18 | const std::string table = conf.get_str("table", "hstest_table1"); 19 | const std::string index = conf.get_str("index", "PRIMARY"); 20 | const std::string fields = conf.get_str("fields", "k,v"); 21 | const int limit = conf.get_int("limit", 0); 22 | const int skip = conf.get_int("skip", 0); 23 | std::vector keys; 24 | std::vector keyrefs; 25 | size_t num_keys = 0; 26 | while (true) { 27 | const std::string conf_key = std::string("k") + to_stdstring(num_keys); 28 | const std::string k = conf.get_str(conf_key, ""); 29 | const std::string kx = conf.get_str(conf_key, "x"); 30 | if (k.empty() && kx == "x") { 31 | break; 32 | } 33 | ++num_keys; 34 | keys.push_back(k); 35 | } 36 | for (size_t i = 0; i < keys.size(); ++i) { 37 | const string_ref ref(keys[i].data(), keys[i].size()); 38 | keyrefs.push_back(ref); 39 | } 40 | const std::string op = conf.get_str("op", "="); 41 | const string_ref op_ref(op.data(), op.size()); 42 | cli->request_buf_open_index(0, dbname.c_str(), table.c_str(), 43 | index.c_str(), fields.c_str()); 44 | cli->request_buf_exec_generic(0, op_ref, num_keys == 0 ? 0 : &keyrefs[0], 45 | num_keys, limit, skip, string_ref(), 0, 0); 46 | int code = 0; 47 | size_t numflds = 0; 48 | do { 49 | if (cli->request_send() != 0) { 50 | fprintf(stderr, "request_send: %s\n", cli->get_error().c_str()); 51 | break; 52 | } 53 | if ((code = cli->response_recv(numflds)) != 0) { 54 | fprintf(stderr, "response_recv: %s\n", cli->get_error().c_str()); 55 | break; 56 | } 57 | } while (false); 58 | cli->response_buf_remove(); 59 | do { 60 | if ((code = cli->response_recv(numflds)) != 0) { 61 | fprintf(stderr, "response_recv: %s\n", cli->get_error().c_str()); 62 | break; 63 | } 64 | while (true) { 65 | const string_ref *const row = cli->get_next_row(); 66 | if (row == 0) { 67 | break; 68 | } 69 | printf("REC:"); 70 | for (size_t i = 0; i < numflds; ++i) { 71 | const std::string val(row[i].begin(), row[i].size()); 72 | printf(" %s", val.c_str()); 73 | } 74 | printf("\n"); 75 | } 76 | } while (false); 77 | cli->response_buf_remove(); 78 | return 0; 79 | } 80 | 81 | }; 82 | 83 | int 84 | main(int argc, char **argv) 85 | { 86 | return dena::hstcpcli_main(argc, argv); 87 | } 88 | 89 | -------------------------------------------------------------------------------- /client/hstest_hs.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | exec ./hstest test=10 tablesize=10000 host=localhost hsport=9998 num=10000000 \ 4 | num_threads=100 timelimit=10 $@ 5 | -------------------------------------------------------------------------------- /client/hstest_hs_more50.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | exec ./hstest test=10 key_mask=9999 host=localhost port=9998 num=10000000 \ 4 | num_threads=100 timelimit=10 moreflds=50 $@ 5 | -------------------------------------------------------------------------------- /client/hstest_md.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | ./hstest test=7 key_mask=9999 host=localhost port=11211 num=10000 \ 4 | num_threads=10 timelimit=10 op=R $@ 5 | ./hstest test=7 key_mask=9999 host=localhost port=11211 num=1000000 \ 6 | num_threads=100 timelimit=10 op=G $@ 7 | 8 | -------------------------------------------------------------------------------- /client/hstest_my.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | exec ./hstest test=9 tablesize=9999 host=localhost mysqlport=3306 num=1000000 \ 3 | num_threads=100 verbose=1 timelimit=10 $@ 4 | -------------------------------------------------------------------------------- /client/hstest_my_more50.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | exec ./hstest test=9 key_mask=9999 host=localhost port=3306 num=1000000 \ 3 | num_threads=100 verbose=1 timelimit=10 moreflds=50 $@ 4 | -------------------------------------------------------------------------------- /configure.ac: -------------------------------------------------------------------------------- 1 | # -*- Autoconf -*- 2 | # Process this file with autoconf to produce a configure script. 3 | 4 | #AC_PREREQ([2.63b]) 5 | AC_INIT([handlersocket-plugin], [1.1.1], [https://github.com/ahiguti/HandlerSocket-Plugin-for-MySQL/issues]) 6 | AC_CONFIG_HEADERS([config.h]) 7 | AM_INIT_AUTOMAKE([-Wall -Werror foreign]) 8 | AC_CONFIG_SRCDIR([libhsclient/fatal.cpp]) 9 | AC_CONFIG_MACRO_DIR([m4]) 10 | 11 | # For automake >= 1.12 12 | m4_ifdef([AM_PROG_AR], [AM_PROG_AR]) 13 | 14 | AC_PROG_CC 15 | AC_PROG_CXX 16 | AC_PROG_CPP 17 | AC_PROG_LIBTOOL 18 | 19 | ac_mysql_debug= 20 | AC_ARG_ENABLE(mysql-debug, 21 | [AS_HELP_STRING([--enable-mysql-debug], [specify whether MySQL is build with DBUG_ON])],[ac_mysql_debug="$enableval"],[ac_mysql_debug=no]) 22 | AC_MSG_CHECKING([if --enable-mysql-debug is specified]) 23 | AC_MSG_RESULT($ac_mysql_debug) 24 | 25 | AC_DEFUN([CONFIG_OPTION_MYSQL],[ 26 | AC_MSG_CHECKING([mysql source]) 27 | 28 | MYSQL_SOURCE_VERSION= 29 | MYSQL_INC= 30 | ac_mysql_source_dir= 31 | AC_ARG_WITH([mysql-source], 32 | [AS_HELP_STRING([--with-mysql-source=PATH], [MySQL source directory PATH])], 33 | [ 34 | ac_mysql_source_dir=`cd $withval && pwd` 35 | if test -f "$ac_mysql_source_dir/sql/handler.h" ; then 36 | MYSQL_INC="-I$ac_mysql_source_dir/sql" 37 | MYSQL_INC="$MYSQL_INC -I$ac_mysql_source_dir/include" 38 | MYSQL_INC="$MYSQL_INC -I$ac_mysql_source_dir/regex" 39 | MYSQL_INC="$MYSQL_INC -I$ac_mysql_source_dir" 40 | AC_SUBST(MYSQL_INC) 41 | if test -f "$ac_mysql_source_dir/VERSION"; then 42 | source "$ac_mysql_source_dir/VERSION" 43 | MYSQL_SOURCE_VERSION="$MYSQL_VERSION_MAJOR.$MYSQL_VERSION_MINOR.$MYSQL_VERSION_PATCH" 44 | else 45 | if test -f "$ac_mysql_source_dir/configure.in"; then 46 | MYSQL_SOURCE_VERSION=`cat $ac_mysql_source_dir/configure.in | grep "\[[\(MariaDB\|MySQL\) Server\]]" | sed -e "s|.*\([[0-9]]\+\.[[0-9]]\+\.[[0-9]]\+[[0-9a-zA-Z\_\-]]*\).*|\1|"` 47 | else 48 | AC_MSG_ERROR([invalid MySQL source directory: $ac_mysql_source_dir]) 49 | fi 50 | fi 51 | AC_MSG_RESULT([yes: Using $ac_mysql_source_dir, version $MYSQL_SOURCE_VERSION]) 52 | else 53 | AC_MSG_ERROR([invalid MySQL source directory: $ac_mysql_source_dir]) 54 | fi 55 | ], 56 | [AC_MSG_ERROR([--with-mysql-source=PATH is required for standalone build])] 57 | ) 58 | 59 | MYSQL_BIN_VERSION= 60 | ac_mysql_config= 61 | AC_ARG_WITH([mysql-bindir], 62 | [AS_HELP_STRING([--with-mysql-bindir=PATH], [MySQL binary directory PATH. This should be the directory where mysql_config is located.])], 63 | [ 64 | mysql_bin_dir=`cd $withval 2> /dev/null && pwd || echo ""` 65 | ac_mysql_config="$mysql_bin_dir/mysql_config" 66 | ], 67 | [ 68 | AC_PATH_PROG([ac_mysql_config], [mysql_config]) 69 | ] 70 | ) 71 | 72 | AC_MSG_CHECKING([mysql binary]) 73 | if test ! -x "$ac_mysql_config" ; then 74 | AC_MSG_ERROR([mysql_config not found! You have to specify the directory where mysql_config resides to --with-mysql-bindir=PATH.]) 75 | fi 76 | 77 | MYSQL_CFLAGS_ADD=`"$ac_mysql_config" --cflags` 78 | MYSQL_CFLAGS="$MYSQL_CFLAGS $MYSQL_CFLAGS_ADD" 79 | if test "$ac_mysql_debug" = "yes"; then 80 | MYSQL_CFLAGS="$MYSQL_CFLAGS -DDBUG_ON -DENABLED_DEBUG_SYNC" 81 | else 82 | MYSQL_CFLAGS="$MYSQL_CFLAGS -DDBUG_OFF" 83 | fi 84 | AC_SUBST(MYSQL_CFLAGS) 85 | 86 | MYSQL_BIN_VERSION=`"$ac_mysql_config" --version` 87 | AC_MSG_RESULT([yes: Using $ac_mysql_config, version $MYSQL_BIN_VERSION]) 88 | 89 | MYSQL_LIB=`"$ac_mysql_config" --libs_r` 90 | LIB_DIR=`echo $MYSQL_LIB | sed -e "s|.*-L/|/|" | sed -e "s| .*||"` 91 | # FIXME 92 | if test a`basename "$LIB_DIR"` = amysql ; then 93 | MYSQL_LIB="-L`dirname $LIB_DIR` $MYSQL_LIB" 94 | # FIXME 95 | fi 96 | AC_SUBST(MYSQL_LIB) 97 | 98 | if test a$MYSQL_SOURCE_VERSION != a$MYSQL_BIN_VERSION ; then 99 | AC_MSG_ERROR([MySQL source version does not match MySQL binary version]) 100 | fi 101 | 102 | AC_MSG_CHECKING([mysql plugin dir]) 103 | ac_mysql_plugin_dir= 104 | AC_ARG_WITH([mysql-plugindir], 105 | [AS_HELP_STRING([--with-mysql-plugindir=PATH], [MySQL plugin directory where handlersocket.so to be copied])], 106 | [ 107 | ac_mysql_plugin_dir=`cd $withval && pwd` 108 | if test -d "$ac_mysql_plugin_dir/" ; then 109 | PLUGIN_DIR="$ac_mysql_plugin_dir" 110 | AC_SUBST(PLUGIN_DIR) 111 | AC_MSG_RESULT([yes: Using $ac_mysql_plugin_dir]) 112 | else 113 | AC_MSG_ERROR([invalid MySQL plugin directory : $ac_mysql_plugin_dir]) 114 | fi 115 | ], 116 | [ 117 | LIB_DIR_TMP=`"$ac_mysql_config" --plugindir` 118 | if test ! -d "$LIB_DIR_TMP"; then 119 | LIB_DIR_TMP=`"$ac_mysql_config" --libs_r | sed -e "s|.*-L/|/|" | sed -e "s| .*||"`/plugin 120 | # FIXME 121 | fi 122 | ac_mysql_plugin_dir=$LIB_DIR_TMP 123 | PLUGIN_DIR="$ac_mysql_plugin_dir" 124 | AC_SUBST(PLUGIN_DIR) 125 | AC_MSG_RESULT([--with-mysql-plugindir was not set. Using $ac_mysql_plugin_dir]) 126 | ] 127 | ) 128 | ]) 129 | 130 | HANDLERSOCKET_SUBDIRS="libhsclient" 131 | AC_ARG_ENABLE(handlersocket_server, 132 | [ --enable-handlersocket-server build HandlerSocket plugin (defalut=yes)]) 133 | if test "$enable_handlersocket_server" != "no"; then 134 | CONFIG_OPTION_MYSQL 135 | HANDLERSOCKET_SUBDIRS="libhsclient handlersocket client" 136 | fi 137 | AC_SUBST(HANDLERSOCKET_SUBDIRS) 138 | 139 | CFLAGS="$CFLAGS -Werror" 140 | CXXFLAGS="$CXXFLAGS -Wall -g -fno-rtti -fno-exceptions -fPIC -DPIC" 141 | 142 | AC_CONFIG_FILES([Makefile 143 | handlersocket/Makefile 144 | libhsclient/Makefile 145 | client/Makefile]) 146 | 147 | AC_OUTPUT 148 | -------------------------------------------------------------------------------- /docs-en/about-handlersocket.en.txt: -------------------------------------------------------------------------------- 1 | 2 | ----------------------------------------------------------------------------- 3 | HandlerSocket plugin for MySQL 4 | 5 | Copyright (c) 2010 DeNA Co.,Ltd. 6 | All rights reserved. 7 | 8 | Redistribution and use in source and binary forms, with or without 9 | modification, are permitted provided that the following conditions are met: 10 | 11 | * Redistributions of source code must retain the above copyright 12 | notice, this list of conditions and the following disclaimer. 13 | * Redistributions in binary form must reproduce the above copyright 14 | notice, this list of conditions and the following disclaimer in the 15 | documentation and/or other materials provided with the distribution. 16 | * Neither the name of DeNA Co.,Ltd. nor the names of its contributors 17 | may be used to endorse or promote products derived from this software 18 | without specific prior written permission. 19 | 20 | THIS SOFTWARE IS PROVIDED BY DeNA Co.,Ltd. "AS IS" AND ANY EXPRESS OR 21 | IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 22 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO 23 | EVENT SHALL DeNA Co.,Ltd. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 25 | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 26 | OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 27 | WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 28 | OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 29 | ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | 31 | 32 | ----------------------------------------------------------------------------- 33 | About HandlerSocket 34 | 35 | HandlerSocket is a NoSQL plugin for MySQL. It works as a daemon inside the 36 | mysqld process, accept tcp connections, and execute requests from clients. 37 | HandlerSocket does not support SQL queries. Instead, it supports simple CRUD 38 | operations on tables. 39 | 40 | Because of the following reasons, HandlerSocket is much faster than the 41 | mysqld/libmysql pair in some circumstances: 42 | 43 | - HandlerSocket manipulates data without parsing SQL, which causes less 44 | CPU usage. 45 | - HandlerSocket reads many requests from clients and executes their 46 | requests in bulk, which causes less CPU and disk usage. 47 | - HandlerSocket client/server protocol is more compact than the 48 | mysql/libmysql pair, which causes less network usage. 49 | 50 | The current version of HandlerSocket only works with GNU/Linux. The source 51 | archive of HandlerSocket includes a C++ and a Perl client libraries. 52 | Here is a list of other language bindings: 53 | 54 | - PHP 55 | http://openpear.org/package/Net_HandlerSocket 56 | http://github.com/tz-lom/HSPHP 57 | http://code.google.com/p/php-handlersocket/ 58 | - Java 59 | http://code.google.com/p/handlersocketforjava/ 60 | - Python 61 | https://code.launchpad.net/~songofacandy/+junk/pyhandlersocket 62 | - Ruby 63 | https://github.com/winebarrel/ruby-handlersocket 64 | https://github.com/miyucy/handlersocket 65 | - JavaScript(Node.js) 66 | https://github.com/koichik/node-handlersocket 67 | 68 | The home of HandlerSocket is here: 69 | https://github.com/DeNADev/HandlerSocket-Plugin-for-MySQL 70 | 71 | More documents are available in docs-en/ and docs-ja/ directories. 72 | 73 | -------------------------------------------------------------------------------- /docs-en/configuration-options.en.txt: -------------------------------------------------------------------------------- 1 | 2 | ----------------------------------------------------------------- 3 | handlersocket_verbose (default = 10, min = 0, max = 10000) 4 | 5 | Specify the logging verboseness. 6 | 7 | ----------------------------------------------------------------- 8 | handlersocket_address (default = '') 9 | 10 | Specify the address to bind. If empty, it binds to 0.0.0.0. 11 | 12 | ----------------------------------------------------------------- 13 | handlersocket_port (default = '9998') 14 | 15 | Specify the port to bind. This option is for the listener for 16 | read requests. If empty, the listener is disabled. 17 | 18 | ----------------------------------------------------------------- 19 | handlersocket_port_wr (default = '9999') 20 | 21 | Specify the port to bind. This option is for the listener for 22 | write requests. If empty, the listener is disabled. 23 | 24 | ----------------------------------------------------------------- 25 | handlersocket_epoll (default = 1, min = 0, max = 1) 26 | 27 | Specify whether handlersocket uses epoll for I/O multiplexing. 28 | 29 | ----------------------------------------------------------------- 30 | handlersocket_threads (default = 16, min = 1, max = 3000) 31 | 32 | Specify the number of handlersocket worker threads. This option 33 | is for the listener for read requests. Recommended value is 34 | (the number of CPU cores * 2). 35 | 36 | ----------------------------------------------------------------- 37 | handlersocket_threads_wr (default = 1, min = 1, max = 3000) 38 | 39 | Specify the number of handlersocket worker threads. This option 40 | is for the listener for write requests. Recommended value is 1. 41 | 42 | ----------------------------------------------------------------- 43 | handlersocket_timeout (default = 300, min = 30, max = 3600) 44 | 45 | Specify the socket timeout in seconds. 46 | 47 | ----------------------------------------------------------------- 48 | handlersocket_backlog (default = 32768, min = 5, max = 1000000) 49 | 50 | Specify the length of the listen backlog. 51 | 52 | ----------------------------------------------------------------- 53 | handlersocket_sndbuf (default = 0, min = 0, max = 1677216) 54 | 55 | Specify the maximum socket send buffer in bytes. If 0, the 56 | system-wide default value is set. 57 | 58 | ----------------------------------------------------------------- 59 | handlersocket_rcvbuf (default = 0, min = 0, max = 1677216) 60 | 61 | Specify the maximum socket receive buffer in bytes. If 0, the 62 | system-wide default value is set. 63 | 64 | ----------------------------------------------------------------- 65 | handlersocket_readsize (default = 0, min = 0, max = 1677216) 66 | 67 | Specify the minimum length of the handlersocket request buffer. 68 | Larger value can make handlersocket faster for large requests, 69 | but can consume memory. The default value is possibly 4096. 70 | 71 | ----------------------------------------------------------------- 72 | handlersocket_accept_balance (default = 0, min = 0, max = 10000) 73 | 74 | When this option is set to non-zero, handlersocket tries to 75 | balance accepted connections among threads. Non-zero is 76 | recommended if you use persistent connections (i.e., connection 77 | pooling on the client side). 78 | 79 | ----------------------------------------------------------------- 80 | handlersocket_wrlock_timeout (default = 12, min = 0, max = 3600) 81 | 82 | Specify the lock timeout in seconds. When a write request is 83 | performed, handlersocket acquires an advisory lock named 84 | 'handlersocket_wr'. This option sets the timeout for the 85 | locking. 86 | 87 | ----------------------------------------------------------------- 88 | handlersocket_plain_secret (default = '') 89 | 90 | When this option is specified, a plain-text authentication is 91 | enabled for the listener for read requests. This option 92 | specifies the secret key for the authentication. 93 | 94 | ----------------------------------------------------------------- 95 | handlersocket_plain_secret_wr (default = '') 96 | 97 | This option specifies the secret key for the listener for write 98 | requests. 99 | 100 | -------------------------------------------------------------------------------- /docs-en/installation.en.txt: -------------------------------------------------------------------------------- 1 | 1. Building Handlersocket 2 | 3 | Handlersocket mainly consists of libhsclient, handlersocket, and C++/Perl clients. libhsclient is a common library shared from both client and server(plugin). handlersocket is a MySQL daemon plugin. 4 | To build Handlersocket, you need both MySQL source code and MySQL binary. It is not required to pre-build MySQL source code, but source itself is needed because Handlersocket depends on MySQL header files that only MySQL source distribution contains. MySQL binary is just a normal MySQL binary distribution. You can use official MySQL binaries provided by Oracle. 5 | Since Handlersocket uses daemon plugin interface supported from MySQL 5.1, 6 | MySQL 5.1 or higher version is required. 7 | Please make sure that you use identical MySQL version between MySQL source 8 | and MySQL binary. Otherwise you might encounter serious problems (i.e. server 9 | crash, etc). 10 | Here are steps to build Handlersocket. 11 | 12 | * Get MySQL source code 13 | 14 | * Get MySQL binary 15 | 16 | * Build Handlersocket 17 | $ ./autogen.sh 18 | $ ./configure --with-mysql-source=/work/mysql-5.1.50 --with-mysql-bindir=/work/mysql-5.1.50-linux-x86_64-glibc23/bin --with-mysql-plugindir=/work/mysql-5.1.50-linux-x86_64-glibc23/lib/plugin 19 | 20 | --with-mysql-source refers to the top of MySQL source directory (which 21 | contains the VERSION file or the configure.in file), --with-mysql-bindir 22 | refers to where MySQL binary executables (i.e. mysql_config) are located, 23 | and --with-mysql-plugindir refers to a plugin directory where plugin 24 | libraries (*.so) are installed. 25 | 26 | $ make 27 | $ sudo make install 28 | 29 | Both libhsclient and the handlersocket plugin will be installed. 30 | 31 | 32 | 2. Using Handlersocket 33 | 34 | Append configuration options for handlersocket to my.cnf. 35 | 36 | [mysqld] 37 | loose_handlersocket_port = 9998 38 | # the port number to bind to (for read requests) 39 | loose_handlersocket_port_wr = 9999 40 | # the port number to bind to (for write requests) 41 | loose_handlersocket_threads = 16 42 | # the number of worker threads (for read requests) 43 | loose_handlersocket_threads_wr = 1 44 | # the number of worker threads (for write requests) 45 | open_files_limit = 65535 46 | # to allow handlersocket accept many concurrent 47 | # connections, make open_files_limit as large as 48 | # possible. 49 | 50 | Log in to mysql as root, and execute the following query. 51 | 52 | mysql> install plugin handlersocket soname 'handlersocket.so'; 53 | 54 | If handlersocket.so is successfully installed, it starts 55 | accepting connections on port 9998 and 9999. Running 56 | 'show processlist' should show handlersocket worker threads. 57 | 58 | ----------------------------------------------------------------- 59 | On the client side, you need to install libhsclient for c++ apps 60 | and perl-Net-HandlerSocket for perl apps. They do not require 61 | MySQL to compile. 62 | 63 | $ ./autogen.sh 64 | $ ./configure --disable-handlersocket-server 65 | $ make 66 | $ sudo make install 67 | $ cd perl-Net-HandlerSocket 68 | $ perl Makefile.PL 69 | $ make 70 | $ sudo make install 71 | 72 | ----------------------------------------------------------------- 73 | Alternatively, you can use the rpm installation. If your OS 74 | supports rpms, you can use the following commands to build and 75 | install handlersocket rpm packages. 76 | 77 | (Server side, installs HandlerSocket plugin) 78 | $ ./autogen.sh 79 | $ ./configure --with-mysql-source=/work/mysql-5.1.50 --with-mysql-bindir=/work/mysql-5.1.50-linux-x86_64-glibc23/bin --with-mysql-plugindir=/work/mysql-5.1.50-linux-x86_64-glibc23/lib/plugin 80 | $ make rpm_cli 81 | $ sudo rpm -U dist/RPMS/*/libhsclient*.rpm 82 | $ make rpm_c 83 | $ sudo rpm -U dist/RPMS/*/handlersocket*.rpm 84 | 85 | (Client side, installs client libraries) 86 | $ ./autogen.sh 87 | $ ./configure --disable-handlersocket-server 88 | $ make rpm_cli 89 | $ sudo rpm -U dist/RPMS/*/libhsclient*.rpm 90 | $ make rpm_perl 91 | $ sudo rpm -U dist/RPMS/*/perl-Net-HandlerSocket*.rpm 92 | 93 | -------------------------------------------------------------------------------- /docs-en/perl-client.en.txt: -------------------------------------------------------------------------------- 1 | 2 | ----------------------------------------------------------------- 3 | To open a connection to the handlersocket plugin, you need to 4 | create a Net::HandlerSocket object. 5 | 6 | use Net::HandlerSocket; 7 | my $args = { host => 'localhost', port => 9998 }; 8 | my $hs = new Net::HandlerSocket($args); 9 | 10 | ----------------------------------------------------------------- 11 | Before executing table operations, you need to open an index to 12 | work with. 13 | 14 | my $err = $hs->open_index(3, 'database1', 'table1', 'PRIMARY', 15 | 'f1,f2'); 16 | die $hs->get_error() if $res->[0] != 0; 17 | 18 | The first argument for open_index is an integer value which is 19 | used to identify an open table, which is only valid within the 20 | same Net::HandlerSocket object. The 4th argument is the name of 21 | index to open. If 'PRIMARY' is specified, the primary index is 22 | open. The 5th argument is a comma-separated list of column names. 23 | 24 | ----------------------------------------------------------------- 25 | To read a record from a table using an index, call the 26 | execute_single method. 27 | 28 | my $res = $hs->execute_single(3, '=', [ 'foo' ], 1, 0); 29 | die $hs->get_error() if $res->[0] != 0; 30 | shift(@$res); 31 | 32 | The first argument must be an integer which has specified as the 33 | first argument for open_index on the same Net::HandlerSocket 34 | object. The second argument specifies the search operation. The 35 | current version of handlersocket supports '=', '>=', '<=', '>', 36 | and '<'. The 3rd argument specifies the key to find, which must 37 | an arrayref whose length is equal to or smaller than the number 38 | of key columns of the index. The 4th and the 5th arguments 39 | specify the maximum number of records to be retrieved, and the 40 | number of records skipped before retrieving records. The columns 41 | to be retrieved are specified by the 5th argument for the 42 | corresponding open_index call. 43 | 44 | The execute_single method always returns an arrayref. The first 45 | element is the error code, which is 0 when no error is occured. 46 | The remaining are the field values. If more than one record is 47 | returned, it is flatten to an 1-dimensional array. For example, 48 | when 5 records that have 3 columns are returned, you can retrieve 49 | values using the following code. 50 | 51 | die $hs->get_error() if $res->[0] != 0; 52 | shift(@$res); 53 | for (my $row = 0; $row < 5; ++$row) { 54 | for (my $col = 0; $col < 3; ++$col) { 55 | my $value = $res->[$row * 5 + $col]; 56 | # ... 57 | } 58 | } 59 | 60 | ----------------------------------------------------------------- 61 | To update or delete records, you need to specify more arguments 62 | for the execute_single method. Note that the Net::HandlerSocket 63 | object must be connected to a handlersocket worker for write 64 | operations, which is port 9999 by default. 65 | (For safety, the port 9998 only allows read operations, and the 66 | port 9999 allows write operations also. The port 9999 allows 67 | read operations too, but slower than 9998 because of record 68 | locking etc.. Port numbers can be changed using the 69 | 'handlersocket_port' and the 'handlersocket_port_wr' 70 | configuration options of mysqld.) 71 | 72 | my $args = { host => 'localhost', port => 9999 }; 73 | my $hs = new Net::HandlerSocket($args); 74 | 75 | my $res = $hs->execute_single(3, '=', [ 'bar' ], 1, 0, 'U', 76 | [ 'fubar', 'hoge' ]); 77 | die $hs->get_error() if $res->[0] != 0; 78 | my $num_updated_rows = $res->[1]; 79 | 80 | my $res = $hs->execute_single(3, '=', [ 'baz' ], 1, 0, 'D'); 81 | die $hs->get_error() if $res->[0] != 0; 82 | my $num_deleted_rows = $res->[1]; 83 | 84 | The 6th argument for execute_single specifies the modification 85 | operation. The current version supports 'U' and 'D'. For the 'U' 86 | operation, the 7th argument specifies the new value for the row. 87 | The columns to be modified are specified by the 5th argument for 88 | the corresponding open_index call. For the 'D' operation, the 89 | 7th argument can be omitted. 90 | 91 | ----------------------------------------------------------------- 92 | The execute_single method can be used for inserting records also. 93 | 94 | my $res = $hs->execute_single(3, '+', [ 'foo', 'bar', 'baz' ]); 95 | die $hs->get_error() if $res->[0] != 0; 96 | 97 | The 3rd argument must be an arrayref whose elements correspond to 98 | the 5th argument for the corresponding open_index call. If there 99 | is a column which is not appeared in the 5th argument for the 100 | open_index, the default value for the column is set. 101 | 102 | ----------------------------------------------------------------- 103 | Multiple operations can be executed in a single call. Executing 104 | multiple operations in a single call is much faster than 105 | executing them separatedly. 106 | 107 | my $rarr = $hs->execute_multi([ 108 | [ 0, '>=', [ 'foo' ], 5, 0 ], 109 | [ 2, '=', [ 'bar' ], 1, 0 ], 110 | [ 4, '<', [ 'baz' ], 10, 5 ], 111 | ]); 112 | for my $res (@$rarr) { 113 | die $hs->get_error() if $res->[0] != 0; 114 | shift(@$res); 115 | # ... 116 | } 117 | 118 | ----------------------------------------------------------------- 119 | If handlersocket is configured to authenticate client connections 120 | (ie., handlersocket_plain_secret or handlersocket_plain_secret_wr 121 | is set), a client must call 'auth' method before any other 122 | methods. 123 | 124 | my $res = $hs->auth('password'); 125 | die $hs->get_error() if $res->[0] != 0; 126 | 127 | ----------------------------------------------------------------- 128 | When an error is occured, the first element of the returned 129 | arrayref becomes a non-zero value. A negative value indicates 130 | that an I/O error is occured and the Net::HandlerSocket object 131 | should be disposed. A positive value means that the connection is 132 | still active and the Net::HandlerSocket object can be reused 133 | later. 134 | 135 | -------------------------------------------------------------------------------- /docs-ja/about-handlersocket.ja.txt: -------------------------------------------------------------------------------- 1 | 2 | 3 | ----------------------------------------------------------------- 4 | ソースコードの利用にあたっての免責事項 5 | 6 | 本ソフトウェアの開発者および株式会社ディー・エヌ・エーは、本フト 7 | ウェアの不稼動、稼動不良を含む法律上の瑕疵担保責任、その他保証責 8 | 任を負わないものとします。また、本ソフトウエアの開発者および株式 9 | 会社ディー・エヌ・エーは、本ソフトウェアの商品性、またはお客様の 10 | 特定の目的に対する適合性について、いかなる保証も負わないものとし 11 | ます。 12 | 13 | ----------------------------------------------------------------- 14 | handlersocket pluginについて 15 | 16 | mysqlサーバに常駐し、innodb等のストレージエンジンへの直接のアクセ 17 | スを提供するプラグインです。handlersocketプラグインは自前のリス 18 | ナーを持ち、専用のクライアントライブラリ(libhsclient)を使ってそれ 19 | にアクセスします。 20 | 21 | mysqlの標準クライアントライブラリ(libmysql)を使ったアクセスと比べ 22 | て、以下のような利点があります。 23 | ・接続あたりに消費するリソースが少ないため、同時接続数が事実上無 24 | 制限。したがって接続数を気にせず持続接続を使えます。 25 | ・高速(単純な参照クエリで3倍〜10倍程度)。 26 | ・通信プロトコルがコンパクト。libmysqlを使うとデータ転送時にレ 27 | コード名などが付随するために通信内容が冗長ですが、libhsclientで 28 | はデータのみが転送されるため、帯域消費が少なくなります。場合に 29 | よっては10倍以上libmysqlのほうが冗長になります。 30 | 31 | 現在のバージョンでは以下のような処理をサポートしています。 32 | ・指定された索引について、指定された値と完全一致するようなレコー 33 | ドを取得。(SELECT ??? FROM tbl WHERE k1 = v1 AND k2 = v2...)。 34 | 索引を使わない検索はサポートしていません。 35 | ・指定された索引について、指定された値の位置の前後のレコードを取 36 | 得。(SELECT ??? FROM tbl WHERE k1 >= v1 LIMIT 100) 37 | ・前述のような手段で取得したレコードに対するUPDATEとDELETE 38 | ・レコードのINSERT 39 | 40 | 以下のような言語をサポートします。 41 | ・C++。libhsclientをリンクします。 42 | ・Perl。Net::HandlerSocketをuseします。 43 | 44 | 現在のバージョンではGNU/Linuxでのみ動作します。 45 | 46 | ----------------------------------------------------------------- 47 | 既知の問題 48 | 49 | ・killでhandlersocketスレッドを殺すと、スレッド数が減ったまま回復 50 | しません。 51 | 52 | -------------------------------------------------------------------------------- /docs-ja/installation.ja.txt: -------------------------------------------------------------------------------- 1 | 2 | ----------------------------------------------------------------- 3 | HandlerSocketプラグインのビルド方法(RPMを使わない方法) 4 | 5 | 以下のようにしてconfigureを実行します。 6 | 7 | $ ./autogen.sh 8 | $ ./configure --with-mysql-source=/work/mysql-5.1.50 --with-mysql-bindir=/work/mysql-5.1.50-linux-x86_64-glibc23/bin --with-mysql-plugindir=/work/mysql-5.1.50-linux-x86_64-glibc23/lib/plugin 9 | 10 | ここで--with-mysql-sourceにはMySQLのソースコードのトップディレク 11 | トリを指定します(そこにVERSIONファイルかconfigure.inファイルがなく 12 | てはなりません)。--with-mysql-bindirにはインストール済みのMySQL 13 | のmysql_configコマンドが有るディレクトリを指定します。 14 | その後以下のようにビルド・インストールします。 15 | 16 | $ make 17 | $ sudo make install 18 | 19 | ----------------------------------------------------------------- 20 | クライアントライブラリのビルド方法(RPMを使わない方法) 21 | 22 | クライアントライブラリをビルドする際には、MySQLのソースコードは 23 | 必要ありません。またMySQLがインストールされている必要もありません。 24 | 25 | $ ./autogen.sh 26 | $ ./configure --disable-handlersocket-server 27 | $ make 28 | $ sudo make install 29 | $ cd perl-Net-HandlerSocket 30 | $ perl Makefile.PL 31 | $ make 32 | $ sudo make install 33 | 34 | ----------------------------------------------------------------- 35 | ビルド方法(RPM) 36 | 37 | 以下のように実行すれば、rpmパッケージがビルド&インストールされま 38 | す。 39 | 40 | (MySQLサーバ側、HandlerSocketプラグインをインストールする) 41 | $ ./autogen.sh 42 | $ ./configure --with-mysql-source=/work/mysql-5.1.50 --with-mysql-bindir=/work/mysql-5.1.50-linux-x86_64-glibc23/bin --with-mysql-plugindir=/work/mysql-5.1.50-linux-x86_64-glibc23/lib/plugin 43 | $ make rpm_cli 44 | $ sudo rpm -U dist/RPMS/*/libhsclient*.rpm 45 | $ make rpm_c 46 | $ sudo rpm -U dist/RPMS/*/handlersocket*.rpm 47 | 48 | (クライアント側、クライアントライブラリをインストールする) 49 | $ ./autogen.sh 50 | $ ./configure --disable-handlersocket-server 51 | $ make rpm_cli 52 | $ sudo rpm -U dist/RPMS/*/libhsclient*.rpm 53 | $ make rpm_perl 54 | $ sudo rpm -U dist/RPMS/*/perl-Net-HandlerSocket*.rpm 55 | 56 | ----------------------------------------------------------------- 57 | 起動 58 | 59 | mysqlを起動した状態で、mysqlの設定ファイル(my.cnf等)に以下の内容を 60 | 追加します。 61 | 62 | [mysqld] 63 | handlersocket_port = 9998 64 | # handlersocketが接続を受け付けるポート(参照系リクエスト用) 65 | handlersocket_port_wr = 9999 66 | # handlersocketが接続を受け付けるポート(更新系リクエスト用) 67 | handlersocket_address = 68 | # handlersocketがバインドするアドレス(空のままでOK) 69 | handlersocket_verbose = 0 70 | # デバッグ用 71 | handlersocket_timeout = 300 72 | # 通信タイムアウト(秒) 73 | handlersocket_threads = 16 74 | # handlersocketのワーカースレッド数 75 | thread_concurrency = 128 76 | # handlersocketが幾つかのスレッドを占有するため、大きめの 77 | # 値を指定してください 78 | open_files_limit = 65535 79 | # ソケットを大量に開けるようにするため、大きめの値を指定し 80 | # てください 81 | 82 | 以下のクエリを実行します。 83 | 84 | mysql> install plugin handlersocket soname 'handlersocket.so'; 85 | Query OK, 0 rows affected (0.06 sec) 86 | 87 | 以上でhandlersocketへクライアントからアクセスできるようになります。 88 | 89 | -------------------------------------------------------------------------------- /docs-ja/perl-client.ja.txt: -------------------------------------------------------------------------------- 1 | 2 | ----------------------------------------------------------------- 3 | handlersocketプラグインへの接続を開くには、Net::HandlerSocketオブ 4 | ジェクトを作成します。 5 | 6 | use Net::HandlerSocket; 7 | my $args = { host => 'localhost', port => 9998 }; 8 | my $hs = new Net::HandlerSocket($args); 9 | 10 | ----------------------------------------------------------------- 11 | 検索などの命令を実行する前に、処理対象となる索引を開く必要があり 12 | ます。 13 | 14 | my $err = $hs->open_index(3, 'database1', 'table1', 'PRIMARY', 15 | 'f1,f2'); 16 | die $hs->get_error() if $res->[0] != 0; 17 | 18 | 最初の引数は開く索引に付ける番号です。付けた番号は同一の 19 | Net::HandlerSocketオブジェクトについてのみ有効です。第4引数は開く 20 | 索引の名前で、「PRIMARY」が指定され場合はプライマリキーが開かれま 21 | す。第5引数は「,」で区切られた列名のリストです。 22 | 23 | ----------------------------------------------------------------- 24 | テーブルから索引を使って行を取得するには、execute_singleメソッド 25 | を呼びます。 26 | 27 | my $res = $hs->execute_single(3, '=', [ 'foo' ], 1, 0); 28 | die $hs->get_error() if $res->[0] != 0; 29 | shift(@$res); 30 | 31 | 最初の引数は索引の番号で、同じNet::HandlerSocketオブジェクトへ 32 | open_indexで付けたものでなければなりません。第2引数には操作を指定 33 | します。現在のバージョンでは、「=」、「>=」、「<=」、「>」、「<」 34 | の操作が利用可能です。第3引数は配列への参照で、これは探すべき行の 35 | キー値を指定します。配列の長さは索引のキーの個数と同じか少ない数 36 | でなければなりません。第4引数と第5引数はそれぞれ、取得する最大行 37 | 数、取得前に読み飛ばす行数を指定します。取得される列は対応する 38 | open_index呼び出しの第5引数で指定されたものになります。 39 | 40 | execute_singleメソッドは常に配列への参照を返します。最初の要素は 41 | エラーコードで、これが0ならば成功を表します。残りの要素は列の値で 42 | す。もし取得されたデータが複数行の場合は、それが一つの配列へ連結 43 | された形で格納されています。例えば、5行3列のデータの場合、次のよ 44 | うなコードによってその内容を取得できます。 45 | 46 | die $hs->get_error() if $res->[0] != 0; 47 | shift(@$res); 48 | for (my $row = 0; $row < 5; ++$row) { 49 | for (my $col = 0; $col < 3; ++$col) { 50 | my $value = $res->[$row * 5 + $col]; 51 | # ... 52 | } 53 | } 54 | 55 | ----------------------------------------------------------------- 56 | 行を更新または削除するには、更に多くの引数を指定して 57 | execute_singleメソッドを呼び出します。書き込み処理をするには、 58 | 対象のNet::HandlerSocketオブジェクトは更新用handlersocketワーカ(既 59 | 定ではポート9999)へ接続されたものでなくてはなりません。 60 | (安全のため、ポート9998は参照処理だけを受け付け、ポート9999は更新 61 | 処理も受け付けるようになっています。ポート9999は参照処理も受け付 62 | けますが、レコードロック等の影響で遅くなります。ポート番号は 63 | mysqldの「handlersocket_port」と「handlersocket_port_wr」の設定項 64 | 目で変更できます。) 65 | 66 | my $args = { host => 'localhost', port => 9999 }; 67 | my $hs = new Net::HandlerSocket($args); 68 | 69 | my $res = $hs->execute_single(3, '=', [ 'bar' ], 1, 0, 'U', 70 | [ 'fubar', 'hoge' ]); 71 | die $hs->get_error() if $res->[0] != 0; 72 | my $num_updated_rows = $res->[1]; 73 | 74 | my $res = $hs->execute_single(3, '=', [ 'baz' ], 1, 0, 'D'); 75 | die $hs->get_error() if $res->[0] != 0; 76 | my $num_deleted_rows = $res->[1]; 77 | 78 | execute_singleの第6引数は変更処理の種類を指定します。現在のバー 79 | ジョンでは「U」と「D」が利用可能です。「U」については、第7引数で 80 | 新しい値を指定します。更新される列は、対応するopen_index呼び出し 81 | の第5引数で指定されたものになります。「D」については第7引数は省 82 | 略できます。 83 | 84 | ----------------------------------------------------------------- 85 | execute_singleメソッドは列の挿入にも使用できます。 86 | 87 | my $res = $hs->execute_single(3, '+', [ 'foo', 'bar', 'baz' ]); 88 | die $hs->get_error() if $res->[0] != 0; 89 | 90 | 第3引数は、対応するopen_index呼び出しの第5引数の列リストと同じだ 91 | けの長さの配列への参照でなければなりません。open_index呼び出しの 92 | 第5引数に指定されていない列については、その列の既定値がセットされ 93 | ます。 94 | 95 | ----------------------------------------------------------------- 96 | execute_multiメソッドを使えば、複数のリクエストを一つの呼び出しで 97 | 実行することができます。これはリクエストを個別に実行するより高速 98 | です。 99 | 100 | my $rarr = $hs->execute_multi([ 101 | [ 0, '>=', [ 'foo' ], 5, 0 ], 102 | [ 2, '=', [ 'bar' ], 1, 0 ], 103 | [ 4, '<', [ 'baz' ], 10, 5 ], 104 | ]); 105 | for my $res (@$rarr) { 106 | die $hs->get_error() if $res->[0] != 0; 107 | shift(@$res); 108 | # ... 109 | } 110 | 111 | ----------------------------------------------------------------- 112 | もしhandlersocketが接続を認証するように設定されている 113 | (handlersocket_plain_secret又はhandlersocket_plain_secret_wrがセッ 114 | トされている)ならば、クライアントは他のメソッド呼び出しの前にauth 115 | メソッドを呼び出す必要があります。 116 | 117 | my $res = $hs->auth('password'); 118 | die $hs->get_error() if $res->[0] != 0; 119 | 120 | ----------------------------------------------------------------- 121 | エラーが起こると返値の配列参照の最初の要素が0以外になります。負の 122 | 数の場合はI/Oエラーが起こったことを示し、その場合はその 123 | Net::HandlerSocketオブジェクトは破棄するべきです。正の値の場合は 124 | 接続は維持されているため、そのオブジェクトはそれ以後も再利用でき 125 | ます。 126 | 127 | -------------------------------------------------------------------------------- /docs-ja/protocol.ja.txt: -------------------------------------------------------------------------------- 1 | 2 | ---------------------------------------------------------------------------- 3 | handlersocketの通信プロトコル 4 | 5 | ---------------------------------------------------------------------------- 6 | 基本的な構文 7 | 8 | ・HandlerSocketのプロトコルは行ベース。各行は改行文字(0x0a)で終わる。 9 | ・各行は複数のトークンからなり、トークン間はTAB文字(0x09)で区切られる。 10 | ・トークンはNULLトークンか、文字列トークンのいずれか。 11 | ・NULLトークンは単一のNUL文字(0x00)であらわされる。 12 | ・文字列トークンは、0バイト以上の文字列であらわされる。ただし0x10未満の文字 13 | については0x01を前置し、0x40を加えたコードであらわされる。それ以外の文字は 14 | その文字自身のコードであらわされる。 15 | 16 | ---------------------------------------------------------------------------- 17 | リクエストとレスポンス 18 | 19 | ・HandlerSocketのプロトコルは単純なリクエスト・レスポンスプロトコルになって 20 | いる。接続が確立した後は、まずクライアントがリクエストを送る。 21 | ・サーバは、クライアントが送ったリクエストと丁度同じ数の行(レスポンス)を返 22 | す。 23 | ・リクエストはパイプライン化してよい。つまりクライアントは前に送ったリクエス 24 | トに対する返事(レスポンス)を待たずに次のリクエストを送ってもよい。 25 | 26 | ---------------------------------------------------------------------------- 27 | インデックスを開く 28 | 29 | open_index命令は次のような構文を持つ。 30 | 31 | P [] 32 | 33 | - は数字で、同一接続上で後に実行する命令の、対象索引を指定するため 34 | に使われる。 35 | - , , は文字列で、それぞれDB名、テーブル名、 36 | 索引の名前を指定する。として「PRIMARY」を指定するとプライマリ 37 | キーが開かれる。 38 | - はカンマ区切りの列名のリスト。 39 | - はカンマ区切りの列名のリスト。これは省略することができる。 40 | 41 | このopen_index命令が実行されると、HandlerSocketプラグインは指定されたDB、 42 | テーブル、索引を開く。開かれた索引は接続が閉じられるまで開かれたままになる。 43 | 開かれた索引はの数字で識別される。もし既にに指定された番号 44 | の索引が既に開かれている場合は古いほうが閉じられる。このはなるべく 45 | 小さな数字を使ったほうが効率が良い。 46 | 47 | ---------------------------------------------------------------------------- 48 | データ取得 49 | 50 | find命令は次のような構文を持つ。 51 | 52 | ... [LIM] [IN] [FILTER ...] 53 | 54 | LIMは次のようなパラメータの並び 55 | 56 | 57 | 58 | INは次のようなパラメータの並び 59 | 60 | @ ... 61 | 62 | FILTERは次のようなパラメータの並び 63 | 64 | 65 | 66 | - は数字で、これは同じ接続上で過去に実行したopen_index命令に指定さ 67 | れた数字でなければならない。 68 | - は比較演算子で、現在のバージョンでは '=', '>', '>=', '<', '<=' をサ 69 | ポートしている。 70 | - は後に続くパラメータ ... の長さ。この値は対応するopen_index 71 | 命令のパラメータで指定された索引のキー列の数と同じか小さいもの 72 | でなければならない。 73 | - ... は取得するべきキーの値を指定するパラメータ。 74 | - LIMは省略できる。は数字で、これはSQLのLIMITと同じように 75 | はたらく。省略した場合は1と0を指定した場合と同じ動作をする。FILTERによっ 76 | て読み飛ばされたレコードはにカウントされない。 77 | - INは省略できる。指定されると、これはSQLの WHERE ... IN のように動作する。 78 | は対応するopen_index命令のパラメータで指定された索引の 79 | キー列の数より小さいものでなければならない。INが指定されたときは、find命 80 | 令の ... のうち番目の値は無視される。 81 | - FILTERは省略できる。これは行取得の際のフィルタを指定する。は 82 | 'F'(filter)か'W'(while)のいずれかでなければならない。は比較演算子。 83 | は数字で、これは対応するopen_index命令ので指定された列の 84 | 数より小さいものでなければならない。複数のフィルタを指定することもでき、 85 | その場合は各フィルタのANDと解釈される。'F'と'W'の違いは、条件にあてはま 86 | らない行があったときに'F'は単にそれをスキップするが、'W'はその時点でルー 87 | プを抜けるという点。 88 | 89 | ---------------------------------------------------------------------------- 90 | 更新と削除 91 | 92 | find_modify命令は次のような構文を持つ。 93 | 94 | ... [LIM] [IN] [FILTER ...] MOD 95 | 96 | MODは次のようなパラメータの並び 97 | 98 | ... 99 | 100 | - は'U', '+', '-', 'D', 'U?', '+?', '-?', 'D?'のいずれか。'?'が付いた 101 | ものは付いていないものとほぼ同じ動作をするが、付いていないものがレスポン 102 | スとして更新された行の数を返すのに対し、付いているものは更新される前の行 103 | の内容を返す点のみが異なる。'U'は更新、'D'は削除、'+'はインクリメント、 104 | '-'はデクリメントを実行する。 105 | - ... はセットされる各列の値。 ... の長さは対応する 106 | open_index命令のの長さと等しいか小さくなければならない。が 107 | 'D'のときはこれらのパラメータは無視される。が'+'か'-'のときは、これら 108 | の値は数値でなければならない。が'-'で、それが負数から正数、または正数 109 | から負数へ列の値を変更するようなものであった場合は、値は変更されない。 110 | 111 | ---------------------------------------------------------------------------- 112 | 行の挿入 113 | 114 | insert命令は次のような構文を持つ。 115 | 116 | + ... 117 | 118 | - は後に続くパラメータ ... の長さ。これは対応するopen_indexの 119 | の長さに等しいか小さくなければならない。 120 | - ... はセットされる各列の値。指定されないかった列についてはその列 121 | のデフォルト値がセットされる。 122 | 123 | ---------------------------------------------------------------------------- 124 | 認証 125 | 126 | auth命令は次のような構文を持つ。 127 | 128 | A 129 | 130 | - は現在のバージョンでは'1'のみが有効。 131 | - 指定されたが、サーバの設定の'handlersocket_plain_secret'や 132 | 'handlersocket_plain_secret_wr'に指定された文字列と一致した場合にのみ認証 133 | は成功する。 134 | - HandlerSocketの認証が有効になっているときは、この'auth'が成功しない限りそ 135 | れ以外の命令は全て失敗する。 136 | 137 | ---------------------------------------------------------------------------- 138 | open_indexに対するレスポンス 139 | 140 | open_index命令が成功したとき、レスポンスは次の構文を持つ。 141 | 142 | 0 1 143 | 144 | ---------------------------------------------------------------------------- 145 | findに対するレスポンス 146 | 147 | find命令が成功したとき、レスポンスは次の構文を持つ。 148 | 149 | 0 ... 150 | 151 | - はfind命令の対応するopen_index命令に指定したの長さに 152 | 一致する。 153 | - ... は結果セット。もしN行がfind命令で見つかったなら、 ... 154 | の長さは ( * N )になる。 155 | 156 | ---------------------------------------------------------------------------- 157 | find_modifyに対するレスポンス 158 | 159 | find_modify命令が成功したとき、レスポンスは次の構文を持つ。 160 | 161 | 0 1 162 | 163 | - は変更された行の数。 164 | - 例外として、が'?'の付いたものであった場合には、find命令に対するレスポ 165 | ンスと同じ構文のレスポンスを返す。 166 | 167 | ---------------------------------------------------------------------------- 168 | insertに対するレスポンス 169 | 170 | insert命令が成功したとき、レスポンスは次の構文を持つ。 171 | 172 | 0 1 173 | 174 | ---------------------------------------------------------------------------- 175 | authに対するレスポンス 176 | 177 | auth命令が成功したとき、レスポンスは次の構文を持つ。 178 | 179 | 0 1 180 | 181 | -------------------------------------------------------------------------------- /handlersocket/COPYRIGHT.txt: -------------------------------------------------------------------------------- 1 | 2 | Copyright (c) 2010 DeNA Co.,Ltd. 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions are met: 7 | 8 | * Redistributions of source code must retain the above copyright 9 | notice, this list of conditions and the following disclaimer. 10 | * Redistributions in binary form must reproduce the above copyright 11 | notice, this list of conditions and the following disclaimer in the 12 | documentation and/or other materials provided with the distribution. 13 | * Neither the name of DeNA Co.,Ltd. nor the names of its contributors 14 | may be used to endorse or promote products derived from this software 15 | without specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY DeNA Co.,Ltd. "AS IS" AND ANY EXPRESS OR 18 | IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 19 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO 20 | EVENT SHALL DeNA Co.,Ltd. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 22 | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 23 | OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 24 | WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 25 | OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 26 | ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | 28 | -------------------------------------------------------------------------------- /handlersocket/Makefile.am: -------------------------------------------------------------------------------- 1 | pkgplugindir = $(PLUGIN_DIR) 2 | noinst_HEADERS = database.hpp hstcpsvr.hpp hstcpsvr_worker.hpp mysql_incl.hpp 3 | pkgplugin_LTLIBRARIES = handlersocket.la 4 | handlersocket_la_LDFLAGS = -module ../libhsclient/libhsclient.la 5 | handlersocket_la_CFLAGS = $(MYSQL_INC) $(MYSQL_CFLAGS) $(AM_CFLAGS) \ 6 | -I../libhsclient 7 | handlersocket_la_CXXFLAGS = $(MYSQL_INC) $(MYSQL_CFLAGS) $(AM_CFLAGS) \ 8 | -I../libhsclient 9 | handlersocket_la_SOURCES = database.cpp handlersocket.cpp \ 10 | hstcpsvr_worker.cpp hstcpsvr.cpp 11 | -------------------------------------------------------------------------------- /handlersocket/Makefile.plain.template: -------------------------------------------------------------------------------- 1 | 2 | MYSQL_INC = HANDLERSOCKET_MYSQL_INC 3 | MYSQL_LIB = HANDLERSOCKET_MYSQL_LIB 4 | 5 | CXX = g++ -Wall -g -fno-rtti -fno-exceptions -fPIC -DPIC 6 | LIBS = $(MYSQL_LIB) -lhsclient -lpthread -lz 7 | CXXFLAGS = -I../libhsclient $(MYSQL_INC) 8 | LDFLAGS = 9 | 10 | CXXFLAGS += -O3 -DNDEBUG 11 | 12 | HANDLERSOCKET_OBJS = database.o hstcpsvr.o hstcpsvr_worker.o 13 | 14 | all: handlersocket.so 15 | 16 | handlersocket.so: $(HANDLERSOCKET_OBJS) handlersocket.cpp 17 | $(CXX) $(CXXFLAGS) -fno-strict-aliasing -shared $^ -o $@ $(LDFLAGS) \ 18 | -Wl,-soname -Wl,$@ $(LIBS) 19 | clean: 20 | rm -f *.a *.so *.o 21 | 22 | LIBDIR = $(shell \ 23 | if [ -e /usr/lib64/mysql ]; then echo /usr/lib64; else echo /usr/lib; fi) 24 | 25 | install: handlersocket.so 26 | sudo sh -c 'ulimit -c unlimited ; /etc/init.d/mysql stop ; \ 27 | cp handlersocket.so handlersocket.so.cpy && \ 28 | mv handlersocket.so.cpy \ 29 | $(LIBDIR)/mysql/plugin/handlersocket.so && \ 30 | /etc/init.d/mysql start' 31 | 32 | -------------------------------------------------------------------------------- /handlersocket/database.hpp: -------------------------------------------------------------------------------- 1 | 2 | // vim:sw=2:ai 3 | 4 | /* 5 | * Copyright (C) 2010 DeNA Co.,Ltd.. All rights reserved. 6 | * See COPYRIGHT.txt for details. 7 | */ 8 | 9 | #ifndef DENA_DATABASE_HPP 10 | #define DENA_DATABASE_HPP 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | #include "string_buffer.hpp" 18 | #include "string_ref.hpp" 19 | #include "config.hpp" 20 | 21 | namespace dena { 22 | 23 | struct database_i; 24 | typedef std::auto_ptr database_ptr; 25 | 26 | struct dbcontext_i; 27 | typedef std::auto_ptr dbcontext_ptr; 28 | 29 | struct database_i { 30 | virtual ~database_i() { } 31 | virtual dbcontext_ptr create_context(bool for_write) volatile = 0; 32 | virtual void stop() volatile = 0; 33 | virtual const config& get_conf() const volatile = 0; 34 | static database_ptr create(const config& conf); 35 | }; 36 | 37 | struct prep_stmt { 38 | typedef std::vector fields_type; 39 | private: 40 | dbcontext_i *dbctx; /* must be valid while *this is alive */ 41 | size_t table_id; /* a prep_stmt object holds a refcount of the table */ 42 | size_t idxnum; 43 | fields_type ret_fields; 44 | fields_type filter_fields; 45 | public: 46 | prep_stmt(); 47 | prep_stmt(dbcontext_i *c, size_t tbl, size_t idx, const fields_type& rf, 48 | const fields_type& ff); 49 | ~prep_stmt(); 50 | prep_stmt(const prep_stmt& x); 51 | prep_stmt& operator =(const prep_stmt& x); 52 | public: 53 | size_t get_table_id() const { return table_id; } 54 | size_t get_idxnum() const { return idxnum; } 55 | const fields_type& get_ret_fields() const { return ret_fields; } 56 | const fields_type& get_filter_fields() const { return filter_fields; } 57 | }; 58 | 59 | struct dbcallback_i { 60 | virtual ~dbcallback_i () { } 61 | virtual void dbcb_set_prep_stmt(size_t pst_id, const prep_stmt& v) = 0; 62 | virtual const prep_stmt *dbcb_get_prep_stmt(size_t pst_id) const = 0; 63 | virtual void dbcb_resp_short(uint32_t code, const char *msg) = 0; 64 | virtual void dbcb_resp_short_num(uint32_t code, uint32_t value) = 0; 65 | virtual void dbcb_resp_short_num64(uint32_t code, uint64_t value) = 0; 66 | virtual void dbcb_resp_begin(size_t num_flds) = 0; 67 | virtual void dbcb_resp_entry(const char *fld, size_t fldlen) = 0; 68 | virtual void dbcb_resp_end() = 0; 69 | virtual void dbcb_resp_cancel() = 0; 70 | }; 71 | 72 | enum record_filter_type { 73 | record_filter_type_skip = 0, 74 | record_filter_type_break = 1, 75 | }; 76 | 77 | struct record_filter { 78 | record_filter_type filter_type; 79 | string_ref op; 80 | uint32_t ff_offset; /* offset in filter_fields */ 81 | string_ref val; 82 | record_filter() : filter_type(record_filter_type_skip), ff_offset(0) { } 83 | }; 84 | 85 | struct cmd_open_args { 86 | size_t pst_id; 87 | const char *dbn; 88 | const char *tbl; 89 | const char *idx; 90 | const char *retflds; 91 | const char *filflds; 92 | cmd_open_args() : pst_id(0), dbn(0), tbl(0), idx(0), retflds(0), 93 | filflds(0) { } 94 | }; 95 | 96 | struct cmd_exec_args { 97 | const prep_stmt *pst; 98 | string_ref op; 99 | const string_ref *kvals; 100 | size_t kvalslen; 101 | uint32_t limit; 102 | uint32_t skip; 103 | string_ref mod_op; 104 | const string_ref *uvals; /* size must be pst->retfieelds.size() */ 105 | const record_filter *filters; 106 | int invalues_keypart; 107 | const string_ref *invalues; 108 | size_t invalueslen; 109 | cmd_exec_args() : pst(0), kvals(0), kvalslen(0), limit(0), skip(0), 110 | uvals(0), filters(0), invalues_keypart(-1), invalues(0), invalueslen(0) { } 111 | }; 112 | 113 | struct dbcontext_i { 114 | virtual ~dbcontext_i() { } 115 | virtual void init_thread(const void *stack_bottom, 116 | volatile int& shutdown_flag) = 0; 117 | virtual void term_thread() = 0; 118 | virtual bool check_alive() = 0; 119 | virtual void lock_tables_if() = 0; 120 | virtual void unlock_tables_if() = 0; 121 | virtual bool get_commit_error() = 0; 122 | virtual void clear_error() = 0; 123 | virtual void close_tables_if() = 0; 124 | virtual void table_addref(size_t tbl_id) = 0; /* TODO: hide */ 125 | virtual void table_release(size_t tbl_id) = 0; /* TODO: hide */ 126 | virtual void cmd_open(dbcallback_i& cb, const cmd_open_args& args) = 0; 127 | virtual void cmd_exec(dbcallback_i& cb, const cmd_exec_args& args) = 0; 128 | virtual void set_statistics(size_t num_conns, size_t num_active) = 0; 129 | }; 130 | 131 | }; 132 | 133 | extern unsigned long long int open_tables_count; 134 | extern unsigned long long int close_tables_count; 135 | extern unsigned long long int lock_tables_count; 136 | extern unsigned long long int unlock_tables_count; 137 | #if 0 138 | extern unsigned long long int index_exec_count; 139 | #endif 140 | 141 | #endif 142 | 143 | -------------------------------------------------------------------------------- /handlersocket/handlersocket.spec.template: -------------------------------------------------------------------------------- 1 | Summary: handlersocket plugin for mysql 2 | Name: handlersocket 3 | Version: HANDLERSOCKET_VERSION 4 | Release: 1%{?dist} 5 | Group: System Environment/Libraries 6 | License: BSD 7 | Source: handlersocket.tar.gz 8 | Packager: Akira Higuchi 9 | BuildRoot: /var/tmp/%{name}-%{version}-root 10 | 11 | %description 12 | 13 | %prep 14 | %setup -n %{name} 15 | 16 | %define _use_internal_dependency_generator 0 17 | 18 | %build 19 | make -f Makefile.plain 20 | 21 | %install 22 | rm -rf $RPM_BUILD_ROOT 23 | mkdir -p $RPM_BUILD_ROOT/%{_libdir}/mysql/plugin 24 | install -m 755 handlersocket.so $RPM_BUILD_ROOT/%{_libdir}/mysql/plugin/ 25 | 26 | %files 27 | %defattr(-, root, root) 28 | %{_libdir}/mysql/plugin/*.so 29 | 30 | -------------------------------------------------------------------------------- /handlersocket/hstcpsvr.cpp: -------------------------------------------------------------------------------- 1 | 2 | // vim:sw=2:ai 3 | 4 | /* 5 | * Copyright (C) 2010 DeNA Co.,Ltd.. All rights reserved. 6 | * See COPYRIGHT.txt for details. 7 | */ 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | #include "hstcpsvr.hpp" 19 | #include "hstcpsvr_worker.hpp" 20 | #include "thread.hpp" 21 | #include "fatal.hpp" 22 | #include "auto_ptrcontainer.hpp" 23 | 24 | #define DBG(x) 25 | 26 | namespace dena { 27 | 28 | struct worker_throbj { 29 | worker_throbj(const hstcpsvr_worker_arg& arg) 30 | : worker(hstcpsvr_worker_i::create(arg)) { } 31 | void operator ()() { 32 | worker->run(); 33 | } 34 | hstcpsvr_worker_ptr worker; 35 | }; 36 | 37 | struct hstcpsvr : public hstcpsvr_i, private noncopyable { 38 | hstcpsvr(const config& c); 39 | ~hstcpsvr(); 40 | virtual std::string start_listen(); 41 | private: 42 | hstcpsvr_shared_c cshared; 43 | volatile hstcpsvr_shared_v vshared; 44 | typedef thread worker_thread_type; 45 | typedef auto_ptrcontainer< std::vector > threads_type; 46 | threads_type threads; 47 | std::vector thread_num_conns_vec; 48 | private: 49 | void stop_workers(); 50 | }; 51 | 52 | namespace { 53 | 54 | void 55 | check_nfile(size_t nfile) 56 | { 57 | struct rlimit rl = { }; 58 | const int r = getrlimit(RLIMIT_NOFILE, &rl); 59 | if (r != 0) { 60 | fatal_abort("check_nfile: getrlimit failed"); 61 | } 62 | if (rl.rlim_cur < static_cast(nfile + 1000)) { 63 | fprintf(stderr, 64 | "[Warning] handlersocket: open_files_limit is too small.\n"); 65 | } 66 | } 67 | 68 | }; 69 | 70 | hstcpsvr::hstcpsvr(const config& c) 71 | : cshared(), vshared() 72 | { 73 | vshared.shutdown = 0; 74 | cshared.conf = c; /* copy */ 75 | if (cshared.conf["port"] == "") { 76 | cshared.conf["port"] = "9999"; 77 | } 78 | cshared.num_threads = cshared.conf.get_int("num_threads", 32); 79 | cshared.sockargs.nonblocking = cshared.conf.get_int("nonblocking", 1); 80 | cshared.sockargs.use_epoll = cshared.conf.get_int("use_epoll", 1); 81 | if (cshared.sockargs.use_epoll) { 82 | cshared.sockargs.nonblocking = 1; 83 | } 84 | cshared.readsize = cshared.conf.get_int("readsize", 1); 85 | cshared.nb_conn_per_thread = cshared.conf.get_int("conn_per_thread", 1024); 86 | cshared.for_write_flag = cshared.conf.get_int("for_write", 0); 87 | cshared.plain_secret = cshared.conf.get_str("plain_secret", ""); 88 | cshared.require_auth = !cshared.plain_secret.empty(); 89 | cshared.sockargs.set(cshared.conf); 90 | cshared.dbptr = database_i::create(c); 91 | check_nfile(cshared.num_threads * cshared.nb_conn_per_thread); 92 | thread_num_conns_vec.resize(cshared.num_threads); 93 | cshared.thread_num_conns = thread_num_conns_vec.empty() 94 | ? 0 : &thread_num_conns_vec[0]; 95 | } 96 | 97 | hstcpsvr::~hstcpsvr() 98 | { 99 | stop_workers(); 100 | } 101 | 102 | std::string 103 | hstcpsvr::start_listen() 104 | { 105 | std::string err; 106 | if (threads.size() != 0) { 107 | return "start_listen: already running"; 108 | } 109 | if (socket_bind(cshared.listen_fd, cshared.sockargs, err) != 0) { 110 | return "bind: " + err; 111 | } 112 | DENA_VERBOSE(20, fprintf(stderr, "bind done\n")); 113 | const size_t stack_size = std::max( 114 | cshared.conf.get_int("stack_size", 1 * 1024LL * 1024), 8 * 1024LL * 1024); 115 | for (long i = 0; i < cshared.num_threads; ++i) { 116 | hstcpsvr_worker_arg arg; 117 | arg.cshared = &cshared; 118 | arg.vshared = &vshared; 119 | arg.worker_id = i; 120 | std::auto_ptr< thread > thr( 121 | new thread(arg, stack_size)); 122 | threads.push_back_ptr(thr); 123 | } 124 | DENA_VERBOSE(20, fprintf(stderr, "threads created\n")); 125 | for (size_t i = 0; i < threads.size(); ++i) { 126 | threads[i]->start(); 127 | } 128 | DENA_VERBOSE(20, fprintf(stderr, "threads started\n")); 129 | return std::string(); 130 | } 131 | 132 | void 133 | hstcpsvr::stop_workers() 134 | { 135 | vshared.shutdown = 1; 136 | for (size_t i = 0; i < threads.size(); ++i) { 137 | threads[i]->join(); 138 | } 139 | threads.clear(); 140 | } 141 | 142 | hstcpsvr_ptr 143 | hstcpsvr_i::create(const config& conf) 144 | { 145 | return hstcpsvr_ptr(new hstcpsvr(conf)); 146 | } 147 | 148 | }; 149 | 150 | -------------------------------------------------------------------------------- /handlersocket/hstcpsvr.hpp: -------------------------------------------------------------------------------- 1 | 2 | // vim:sw=2:ai 3 | 4 | /* 5 | * Copyright (C) 2010 DeNA Co.,Ltd.. All rights reserved. 6 | * See COPYRIGHT.txt for details. 7 | */ 8 | 9 | #ifndef DENA_HSTCPSVR_HPP 10 | #define DENA_HSTCPSVR_HPP 11 | 12 | #include 13 | #include 14 | #include 15 | 16 | #include "mutex.hpp" 17 | #include "auto_file.hpp" 18 | #include "database.hpp" 19 | #include "config.hpp" 20 | #include "socket.hpp" 21 | 22 | namespace dena { 23 | 24 | struct hstcpsvr_shared_c { 25 | config conf; 26 | long num_threads; 27 | long nb_conn_per_thread; 28 | bool for_write_flag; 29 | bool require_auth; 30 | std::string plain_secret; 31 | int readsize; 32 | socket_args sockargs; 33 | auto_file listen_fd; 34 | database_ptr dbptr; 35 | volatile unsigned int *thread_num_conns; /* 0 .. num_threads-1 */ 36 | hstcpsvr_shared_c() : num_threads(0), nb_conn_per_thread(100), 37 | for_write_flag(false), require_auth(false), readsize(0), 38 | thread_num_conns(0) { } 39 | }; 40 | 41 | struct hstcpsvr_shared_v : public mutex { 42 | int shutdown; 43 | hstcpsvr_shared_v() : shutdown(0) { } 44 | }; 45 | 46 | struct hstcpsvr_i; 47 | typedef std::auto_ptr hstcpsvr_ptr; 48 | 49 | struct hstcpsvr_i { 50 | virtual ~hstcpsvr_i() { } 51 | virtual std::string start_listen() = 0; 52 | static hstcpsvr_ptr create(const config& conf); 53 | }; 54 | 55 | }; 56 | 57 | #endif 58 | 59 | -------------------------------------------------------------------------------- /handlersocket/hstcpsvr_worker.hpp: -------------------------------------------------------------------------------- 1 | 2 | // vim:sw=2:ai 3 | 4 | /* 5 | * Copyright (C) 2010 DeNA Co.,Ltd.. All rights reserved. 6 | * See COPYRIGHT.txt for details. 7 | */ 8 | 9 | #ifndef DENA_HSTCPSVR_WORKER_HPP 10 | #define DENA_HSTCPSVR_WORKER_HPP 11 | 12 | #include "hstcpsvr.hpp" 13 | 14 | namespace dena { 15 | 16 | struct hstcpsvr_worker_i; 17 | typedef std::auto_ptr hstcpsvr_worker_ptr; 18 | 19 | struct hstcpsvr_worker_arg { 20 | const hstcpsvr_shared_c *cshared; 21 | volatile hstcpsvr_shared_v *vshared; 22 | long worker_id; 23 | hstcpsvr_worker_arg() : cshared(0), vshared(0), worker_id(0) { } 24 | }; 25 | 26 | struct hstcpsvr_worker_i { 27 | virtual ~hstcpsvr_worker_i() { } 28 | virtual void run() = 0; 29 | static hstcpsvr_worker_ptr create(const hstcpsvr_worker_arg& arg); 30 | }; 31 | 32 | }; 33 | 34 | #endif 35 | 36 | -------------------------------------------------------------------------------- /handlersocket/mysql_incl.hpp: -------------------------------------------------------------------------------- 1 | 2 | // vim:sw=2:ai 3 | 4 | /* 5 | * Copyright (C) 2010 DeNA Co.,Ltd.. All rights reserved. 6 | * See COPYRIGHT.txt for details. 7 | */ 8 | 9 | #ifndef DENA_MYSQL_INCL_HPP 10 | #define DENA_MYSQL_INCL_HPP 11 | 12 | #ifndef HAVE_CONFIG_H 13 | #define HAVE_CONFIG_H 14 | #endif 15 | 16 | #define MYSQL_DYNAMIC_PLUGIN 17 | #define MYSQL_SERVER 1 18 | 19 | #include 20 | 21 | #include 22 | 23 | #if MYSQL_VERSION_ID >= 50505 24 | #include 25 | #include 26 | #include "sql_class.h" 27 | #include "unireg.h" 28 | #include "lock.h" 29 | #include "key.h" // key_copy() 30 | #include 31 | #include 32 | #include 33 | #include 34 | // FIXME FIXME FIXME 35 | #define safeFree(X) my_free(X) 36 | #define pthread_cond_timedwait mysql_cond_timedwait 37 | #define pthread_mutex_lock mysql_mutex_lock 38 | #define pthread_mutex_unlock mysql_mutex_unlock 39 | #define current_stmt_binlog_row_based is_current_stmt_binlog_format_row 40 | #define clear_current_stmt_binlog_row_based clear_current_stmt_binlog_format_row 41 | 42 | #else 43 | #include "mysql_priv.h" 44 | #endif 45 | 46 | #if MYSQL_VERSION_ID >= 50600 47 | #include 48 | #endif 49 | 50 | #undef min 51 | #undef max 52 | 53 | #endif 54 | 55 | -------------------------------------------------------------------------------- /libhsclient/COPYRIGHT.txt: -------------------------------------------------------------------------------- 1 | 2 | Copyright (c) 2010 DeNA Co.,Ltd. 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions are met: 7 | 8 | * Redistributions of source code must retain the above copyright 9 | notice, this list of conditions and the following disclaimer. 10 | * Redistributions in binary form must reproduce the above copyright 11 | notice, this list of conditions and the following disclaimer in the 12 | documentation and/or other materials provided with the distribution. 13 | * Neither the name of DeNA Co.,Ltd. nor the names of its contributors 14 | may be used to endorse or promote products derived from this software 15 | without specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY DeNA Co.,Ltd. "AS IS" AND ANY EXPRESS OR 18 | IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 19 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO 20 | EVENT SHALL DeNA Co.,Ltd. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 22 | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 23 | OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 24 | WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 25 | OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 26 | ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | 28 | -------------------------------------------------------------------------------- /libhsclient/Makefile.am: -------------------------------------------------------------------------------- 1 | instdir = $(includedir)/handlersocket 2 | # TODO: these headers should be in dena/ 3 | inst_HEADERS = allocator.hpp config.hpp mutex.hpp string_util.hpp \ 4 | auto_addrinfo.hpp escape.hpp socket.hpp thread.hpp auto_file.hpp \ 5 | fatal.hpp string_buffer.hpp util.hpp auto_ptrcontainer.hpp \ 6 | hstcpcli.hpp string_ref.hpp 7 | lib_LTLIBRARIES = libhsclient.la 8 | libhsclient_la_SOURCES = config.cpp escape.cpp fatal.cpp hstcpcli.cpp \ 9 | socket.cpp string_util.cpp 10 | libhsclient_la_LDFLAGS = -static 11 | libhsclient_la_CFLAGS = $(AM_CFLAGS) 12 | libhsclient_la_CXXFLAGS = $(AM_CFLAGS) 13 | -------------------------------------------------------------------------------- /libhsclient/Makefile.plain: -------------------------------------------------------------------------------- 1 | 2 | CXX = g++ -Wall -g -fno-rtti -fno-exceptions -fPIC -DPIC 3 | LDFLAGS = 4 | 5 | CXXFLAGS += -O3 -DNDEBUG 6 | 7 | COMMON_OBJS = config.o fatal.o socket.o string_util.o escape.o 8 | HSCLIENT_OBJS = $(COMMON_OBJS) hstcpcli.o 9 | 10 | all: libhsclient.a 11 | 12 | libhsclient.a: $(HSCLIENT_OBJS) 13 | $(AR) rc $@ $^ 14 | $(AR) s $@ 15 | 16 | clean: 17 | rm -f *.a *.so *.o 18 | 19 | LIBDIR = $(shell \ 20 | if [ -e /usr/lib64/mysql ]; then echo /usr/lib64; else echo /usr/lib; fi) 21 | 22 | install: libhsclient.a 23 | sudo sh -c 'cp libhsclient.a libhsclient.a.cpy && \ 24 | mv libhsclient.a.cpy $(LIBDIR)/libhsclient.a && \ 25 | mkdir -p /usr/include/handlersocket && \ 26 | cp -a *.hpp /usr/include/handlersocket/' 27 | 28 | -------------------------------------------------------------------------------- /libhsclient/allocator.hpp: -------------------------------------------------------------------------------- 1 | 2 | // vim:sw=2:ai 3 | 4 | /* 5 | * Copyright (C) 2010 DeNA Co.,Ltd.. All rights reserved. 6 | * See COPYRIGHT.txt for details. 7 | */ 8 | 9 | #ifndef DENA_ALLOCATOR_HPP 10 | #define DENA_ALLOCATOR_HPP 11 | 12 | #include 13 | #include 14 | 15 | #if 0 16 | extern "C" { 17 | #include 18 | }; 19 | #define DENA_MALLOC(x) tlsf_malloc(x) 20 | #define DENA_REALLOC(x, y) tlsf_realloc(x, y) 21 | #define DENA_FREE(x) tlsf_free(x) 22 | #define DENA_NEWCHAR(x) static_cast(tlsf_malloc(x)) 23 | #define DENA_DELETE(x) tlsf_free(x) 24 | typedef std::allocator allocator_type; 25 | #endif 26 | 27 | #if 1 28 | #define DENA_MALLOC(x) malloc(x) 29 | #define DENA_REALLOC(x, y) realloc(x, y) 30 | #define DENA_FREE(x) free(x) 31 | #define DENA_NEWCHAR(x) (new char[x]) 32 | #define DENA_DELETE(x) (delete [] x) 33 | typedef std::allocator allocator_type; 34 | #endif 35 | 36 | #if 1 37 | #define DENA_ALLOCA_ALLOCATE(typ, len) \ 38 | static_cast(alloca((len) * sizeof(typ))) 39 | #define DENA_ALLOCA_FREE(x) 40 | #else 41 | #define DENA_ALLOCA_ALLOCATE(typ, len) \ 42 | static_cast(malloc((len) * sizeof(typ))) 43 | #define DENA_ALLOCA_FREE(x) free(x) 44 | #endif 45 | 46 | namespace dena { 47 | 48 | template struct auto_alloca_free { 49 | auto_alloca_free(T *value) : value(value) { } 50 | ~auto_alloca_free() { 51 | /* no-op if alloca() is used */ 52 | DENA_ALLOCA_FREE(value); 53 | } 54 | private: 55 | auto_alloca_free(const auto_alloca_free&); 56 | auto_alloca_free& operator =(const auto_alloca_free&); 57 | private: 58 | T *value; 59 | }; 60 | 61 | }; 62 | 63 | #endif 64 | 65 | -------------------------------------------------------------------------------- /libhsclient/auto_addrinfo.hpp: -------------------------------------------------------------------------------- 1 | 2 | // vim:sw=2:ai 3 | 4 | /* 5 | * Copyright (C) 2010 DeNA Co.,Ltd.. All rights reserved. 6 | * See COPYRIGHT.txt for details. 7 | */ 8 | 9 | #ifndef DENA_AUTO_ADDRINFO_HPP 10 | #define DENA_AUTO_ADDRINFO_HPP 11 | 12 | #include 13 | #include 14 | #include 15 | 16 | #include "util.hpp" 17 | 18 | namespace dena { 19 | 20 | struct auto_addrinfo : private noncopyable { 21 | auto_addrinfo() : addr(0) { } 22 | ~auto_addrinfo() { 23 | reset(); 24 | } 25 | void reset(addrinfo *a = 0) { 26 | if (addr != 0) { 27 | freeaddrinfo(addr); 28 | } 29 | addr = a; 30 | } 31 | const addrinfo *get() const { return addr; } 32 | int resolve(const char *node, const char *service, int flags = 0, 33 | int family = AF_UNSPEC, int socktype = SOCK_STREAM, int protocol = 0) { 34 | reset(); 35 | addrinfo hints = { }; 36 | hints.ai_flags = flags; 37 | hints.ai_family = family; 38 | hints.ai_socktype = socktype; 39 | hints.ai_protocol = protocol; 40 | return getaddrinfo(node, service, &hints, &addr); 41 | } 42 | private: 43 | addrinfo *addr; 44 | }; 45 | 46 | }; 47 | 48 | #endif 49 | 50 | -------------------------------------------------------------------------------- /libhsclient/auto_file.hpp: -------------------------------------------------------------------------------- 1 | 2 | // vim:sw=2:ai 3 | 4 | /* 5 | * Copyright (C) 2010 DeNA Co.,Ltd.. All rights reserved. 6 | * See COPYRIGHT.txt for details. 7 | */ 8 | 9 | #ifndef DENA_AUTO_FILE_HPP 10 | #define DENA_AUTO_FILE_HPP 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | #include "util.hpp" 18 | 19 | namespace dena { 20 | 21 | struct auto_file : private noncopyable { 22 | auto_file() : fd(-1) { } 23 | ~auto_file() { 24 | reset(); 25 | } 26 | int get() const { return fd; } 27 | int close() { 28 | if (fd < 0) { 29 | return 0; 30 | } 31 | const int r = ::close(fd); 32 | fd = -1; 33 | return r; 34 | } 35 | void reset(int x = -1) { 36 | if (fd >= 0) { 37 | this->close(); 38 | } 39 | fd = x; 40 | } 41 | private: 42 | int fd; 43 | }; 44 | 45 | struct auto_dir : private noncopyable { 46 | auto_dir() : dp(0) { } 47 | ~auto_dir() { 48 | reset(); 49 | } 50 | DIR *get() const { return dp; } 51 | void reset(DIR *d = 0) { 52 | if (dp != 0) { 53 | closedir(dp); 54 | } 55 | dp = d; 56 | } 57 | private: 58 | DIR *dp; 59 | }; 60 | 61 | }; 62 | 63 | #endif 64 | 65 | -------------------------------------------------------------------------------- /libhsclient/auto_ptrcontainer.hpp: -------------------------------------------------------------------------------- 1 | 2 | // vim:sw=2:ai 3 | 4 | /* 5 | * Copyright (C) 2010 DeNA Co.,Ltd.. All rights reserved. 6 | * See COPYRIGHT.txt for details. 7 | */ 8 | 9 | #ifndef DENA_AUTO_PTRCONTAINER_HPP 10 | #define DENA_AUTO_PTRCONTAINER_HPP 11 | 12 | namespace dena { 13 | 14 | template 15 | struct auto_ptrcontainer { 16 | typedef Tcnt container_type; 17 | typedef typename container_type::value_type value_type; 18 | typedef typename container_type::pointer pointer; 19 | typedef typename container_type::reference reference; 20 | typedef typename container_type::const_reference const_reference; 21 | typedef typename container_type::size_type size_type; 22 | typedef typename container_type::difference_type difference_type; 23 | typedef typename container_type::iterator iterator; 24 | typedef typename container_type::const_iterator const_iterator; 25 | typedef typename container_type::reverse_iterator reverse_iterator; 26 | typedef typename container_type::const_reverse_iterator 27 | const_reverse_iterator; 28 | iterator begin() { return cnt.begin(); } 29 | const_iterator begin() const { return cnt.begin(); } 30 | iterator end() { return cnt.end(); } 31 | const_iterator end() const { return cnt.end(); } 32 | reverse_iterator rbegin() { return cnt.rbegin(); } 33 | reverse_iterator rend() { return cnt.rend(); } 34 | const_reverse_iterator rbegin() const { return cnt.rbegin(); } 35 | const_reverse_iterator rend() const { return cnt.rend(); } 36 | size_type size() const { return cnt.size(); } 37 | size_type max_size() const { return cnt.max_size(); } 38 | bool empty() const { return cnt.empty(); } 39 | reference front() { return cnt.front(); } 40 | const_reference front() const { cnt.front(); } 41 | reference back() { return cnt.back(); } 42 | const_reference back() const { cnt.back(); } 43 | void swap(auto_ptrcontainer& x) { cnt.swap(x.cnt); } 44 | ~auto_ptrcontainer() { 45 | for (iterator i = begin(); i != end(); ++i) { 46 | delete *i; 47 | } 48 | } 49 | template void push_back_ptr(Tap& ap) { 50 | cnt.push_back(ap.get()); 51 | ap.release(); 52 | } 53 | void erase_ptr(iterator i) { 54 | delete *i; 55 | cnt.erase(i); 56 | } 57 | reference operator [](size_type n) { return cnt[n]; } 58 | const_reference operator [](size_type n) const { return cnt[n]; } 59 | void clear() { cnt.clear(); } 60 | private: 61 | Tcnt cnt; 62 | }; 63 | 64 | }; 65 | 66 | #endif 67 | 68 | -------------------------------------------------------------------------------- /libhsclient/config.cpp: -------------------------------------------------------------------------------- 1 | 2 | // vim:sw=2:ai 3 | 4 | /* 5 | * Copyright (C) 2010 DeNA Co.,Ltd.. All rights reserved. 6 | * See COPYRIGHT.txt for details. 7 | */ 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | #include "config.hpp" 14 | 15 | namespace dena { 16 | 17 | unsigned int verbose_level = 0; 18 | 19 | std::string 20 | config::get_str(const std::string& key, const std::string& def) const 21 | { 22 | const_iterator iter = this->find(key); 23 | if (iter == this->end()) { 24 | DENA_VERBOSE(10, fprintf(stderr, "CONFIG: %s=%s(default)\n", key.c_str(), 25 | def.c_str())); 26 | return def; 27 | } 28 | DENA_VERBOSE(10, fprintf(stderr, "CONFIG: %s=%s\n", key.c_str(), 29 | iter->second.c_str())); 30 | return iter->second; 31 | } 32 | 33 | long long 34 | config::get_int(const std::string& key, long long def) const 35 | { 36 | const_iterator iter = this->find(key); 37 | if (iter == this->end()) { 38 | DENA_VERBOSE(10, fprintf(stderr, "CONFIG: %s=%lld(default)\n", key.c_str(), 39 | def)); 40 | return def; 41 | } 42 | const long long r = atoll(iter->second.c_str()); 43 | DENA_VERBOSE(10, fprintf(stderr, "CONFIG: %s=%lld\n", key.c_str(), r)); 44 | return r; 45 | } 46 | 47 | void 48 | parse_args(int argc, char **argv, config& conf) 49 | { 50 | for (int i = 1; i < argc; ++i) { 51 | const char *const arg = argv[i]; 52 | const char *const eq = strchr(arg, '='); 53 | if (eq == 0) { 54 | continue; 55 | } 56 | const std::string key(arg, eq - arg); 57 | const std::string val(eq + 1); 58 | conf[key] = val; 59 | } 60 | config::const_iterator iter = conf.find("verbose"); 61 | if (iter != conf.end()) { 62 | verbose_level = atoi(iter->second.c_str()); 63 | } 64 | } 65 | 66 | }; 67 | 68 | -------------------------------------------------------------------------------- /libhsclient/config.hpp: -------------------------------------------------------------------------------- 1 | 2 | // vim:sw=2:ai 3 | 4 | /* 5 | * Copyright (C) 2010 DeNA Co.,Ltd.. All rights reserved. 6 | * See COPYRIGHT.txt for details. 7 | */ 8 | 9 | #ifndef DENA_CONFIG_HPP 10 | #define DENA_CONFIG_HPP 11 | 12 | #include 13 | #include 14 | 15 | #define DENA_VERBOSE(lv, x) if (dena::verbose_level >= (lv)) { (x); } 16 | 17 | namespace dena { 18 | 19 | struct config : public std::map { 20 | std::string get_str(const std::string& key, const std::string& def = "") 21 | const; 22 | long long get_int(const std::string& key, long long def = 0) const; 23 | }; 24 | 25 | void parse_args(int argc, char **argv, config& conf); 26 | 27 | extern unsigned int verbose_level; 28 | 29 | }; 30 | 31 | #endif 32 | 33 | -------------------------------------------------------------------------------- /libhsclient/escape.cpp: -------------------------------------------------------------------------------- 1 | 2 | // vim:sw=2:ai 3 | 4 | /* 5 | * Copyright (C) 2010 DeNA Co.,Ltd.. All rights reserved. 6 | * See COPYRIGHT.txt for details. 7 | */ 8 | 9 | #include 10 | 11 | #include "escape.hpp" 12 | #include "string_buffer.hpp" 13 | #include "fatal.hpp" 14 | #include "string_util.hpp" 15 | 16 | #define DBG_OP(x) 17 | #define DBG_BUF(x) 18 | 19 | namespace dena { 20 | 21 | enum special_char_t { 22 | special_char_escape_prefix = 0x01, /* SOH */ 23 | special_char_noescape_min = 0x10, /* DLE */ 24 | special_char_escape_shift = 0x40, /* '@' */ 25 | }; 26 | 27 | void 28 | escape_string(char *& wp, const char *start, const char *finish) 29 | { 30 | while (start != finish) { 31 | const unsigned char c = *start; 32 | if (c >= special_char_noescape_min) { 33 | wp[0] = c; /* no need to escape */ 34 | } else { 35 | wp[0] = special_char_escape_prefix; 36 | ++wp; 37 | wp[0] = c + special_char_escape_shift; 38 | } 39 | ++start; 40 | ++wp; 41 | } 42 | } 43 | 44 | void 45 | escape_string(string_buffer& ar, const char *start, const char *finish) 46 | { 47 | const size_t buflen = (finish - start) * 2; 48 | char *const wp_begin = ar.make_space(buflen); 49 | char *wp = wp_begin; 50 | escape_string(wp, start, finish); 51 | ar.space_wrote(wp - wp_begin); 52 | } 53 | 54 | bool 55 | unescape_string(char *& wp, const char *start, const char *finish) 56 | { 57 | /* works even if wp == start */ 58 | while (start != finish) { 59 | const unsigned char c = *start; 60 | if (c != special_char_escape_prefix) { 61 | wp[0] = c; 62 | } else if (start + 1 != finish) { 63 | ++start; 64 | const unsigned char cn = *start; 65 | if (cn < special_char_escape_shift) { 66 | return false; 67 | } 68 | wp[0] = cn - special_char_escape_shift; 69 | } else { 70 | return false; 71 | } 72 | ++start; 73 | ++wp; 74 | } 75 | return true; 76 | } 77 | 78 | bool 79 | unescape_string(string_buffer& ar, const char *start, const char *finish) 80 | { 81 | const size_t buflen = finish - start; 82 | char *const wp_begin = ar.make_space(buflen); 83 | char *wp = wp_begin; 84 | const bool r = unescape_string(wp, start, finish); 85 | ar.space_wrote(wp - wp_begin); 86 | return r; 87 | } 88 | 89 | uint32_t 90 | read_ui32(char *& start, char *finish) 91 | { 92 | char *const n_begin = start; 93 | read_token(start, finish); 94 | char *const n_end = start; 95 | uint32_t v = 0; 96 | for (char *p = n_begin; p != n_end; ++p) { 97 | const char ch = p[0]; 98 | if (ch >= '0' && ch <= '9') { 99 | v *= 10; 100 | v += (ch - '0'); 101 | } 102 | } 103 | return v; 104 | } 105 | 106 | void 107 | write_ui32(string_buffer& buf, uint32_t v) 108 | { 109 | char *wp = buf.make_space(12); 110 | int len = snprintf(wp, 12, "%u", v); 111 | if (len > 0) { 112 | buf.space_wrote(len); 113 | } 114 | } 115 | 116 | void 117 | write_ui64(string_buffer& buf, uint64_t v) 118 | { 119 | char *wp = buf.make_space(22); 120 | int len = snprintf(wp, 22, "%llu", static_cast(v)); 121 | if (len > 0) { 122 | buf.space_wrote(len); 123 | } 124 | } 125 | 126 | }; 127 | 128 | -------------------------------------------------------------------------------- /libhsclient/escape.hpp: -------------------------------------------------------------------------------- 1 | 2 | // vim:sw=2:ai 3 | 4 | /* 5 | * Copyright (C) 2010 DeNA Co.,Ltd.. All rights reserved. 6 | * See COPYRIGHT.txt for details. 7 | */ 8 | 9 | #include 10 | 11 | #include "string_buffer.hpp" 12 | #include "string_ref.hpp" 13 | #include "string_util.hpp" 14 | 15 | #ifndef DENA_ESCAPE_HPP 16 | #define DENA_ESCAPE_HPP 17 | 18 | namespace dena { 19 | 20 | void escape_string(char *& wp, const char *start, const char *finish); 21 | void escape_string(string_buffer& ar, const char *start, const char *finish); 22 | bool unescape_string(char *& wp, const char *start, const char *finish); 23 | /* unescaped_string() works even if wp == start */ 24 | bool unescape_string(string_buffer& ar, const char *start, const char *finish); 25 | 26 | uint32_t read_ui32(char *& start, char *finish); 27 | void write_ui32(string_buffer& buf, uint32_t v); 28 | void write_ui64(string_buffer& buf, uint64_t v); 29 | 30 | inline bool 31 | is_null_expression(const char *start, const char *finish) 32 | { 33 | return (finish == start + 1 && start[0] == 0); 34 | } 35 | 36 | inline void 37 | read_token(char *& start, char *finish) 38 | { 39 | char *const p = memchr_char(start, '\t', finish - start); 40 | if (p == 0) { 41 | start = finish; 42 | } else { 43 | start = p; 44 | } 45 | } 46 | 47 | inline void 48 | skip_token_delim_fold(char *& start, char *finish) 49 | { 50 | while (start != finish && start[0] == '\t') { 51 | ++start; 52 | } 53 | } 54 | 55 | inline void 56 | skip_one(char *& start, char *finish) 57 | { 58 | if (start != finish) { 59 | ++start; 60 | } 61 | } 62 | 63 | }; 64 | 65 | #endif 66 | 67 | -------------------------------------------------------------------------------- /libhsclient/fatal.cpp: -------------------------------------------------------------------------------- 1 | 2 | // vim:sw=2:ai 3 | 4 | /* 5 | * Copyright (C) 2010 DeNA Co.,Ltd.. All rights reserved. 6 | * See COPYRIGHT.txt for details. 7 | */ 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | #include "fatal.hpp" 15 | 16 | namespace dena { 17 | 18 | const int opt_syslog = LOG_ERR | LOG_PID | LOG_CONS; 19 | 20 | void 21 | fatal_exit(const std::string& message) 22 | { 23 | fprintf(stderr, "FATAL_EXIT: %s\n", message.c_str()); 24 | syslog(opt_syslog, "FATAL_EXIT: %s", message.c_str()); 25 | _exit(1); 26 | } 27 | 28 | void 29 | fatal_abort(const std::string& message) 30 | { 31 | fprintf(stderr, "FATAL_COREDUMP: %s\n", message.c_str()); 32 | syslog(opt_syslog, "FATAL_COREDUMP: %s", message.c_str()); 33 | abort(); 34 | } 35 | 36 | }; 37 | 38 | -------------------------------------------------------------------------------- /libhsclient/fatal.hpp: -------------------------------------------------------------------------------- 1 | 2 | // vim:sw=2:ai 3 | 4 | /* 5 | * Copyright (C) 2010 DeNA Co.,Ltd.. All rights reserved. 6 | * See COPYRIGHT.txt for details. 7 | */ 8 | 9 | #ifndef DENA_FATAL_HPP 10 | #define DENA_FATAL_HPP 11 | 12 | #include 13 | 14 | namespace dena { 15 | 16 | void fatal_exit(const std::string& message); 17 | void fatal_abort(const std::string& message); 18 | 19 | }; 20 | 21 | #endif 22 | 23 | -------------------------------------------------------------------------------- /libhsclient/hstcpcli.hpp: -------------------------------------------------------------------------------- 1 | 2 | // vim:sw=2:ai 3 | 4 | /* 5 | * Copyright (C) 2010 DeNA Co.,Ltd.. All rights reserved. 6 | * See COPYRIGHT.txt for details. 7 | */ 8 | 9 | #ifndef DENA_HSTCPCLI_HPP 10 | #define DENA_HSTCPCLI_HPP 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | #include "config.hpp" 18 | #include "socket.hpp" 19 | #include "string_ref.hpp" 20 | #include "string_buffer.hpp" 21 | 22 | namespace dena { 23 | 24 | struct hstcpcli_filter { 25 | string_ref filter_type; 26 | string_ref op; 27 | size_t ff_offset; 28 | string_ref val; 29 | hstcpcli_filter() : ff_offset(0) { } 30 | }; 31 | 32 | struct hstcpcli_i; 33 | typedef std::auto_ptr hstcpcli_ptr; 34 | 35 | struct hstcpcli_i { 36 | virtual ~hstcpcli_i() { } 37 | virtual void close() = 0; 38 | virtual int reconnect() = 0; 39 | virtual bool stable_point() = 0; 40 | virtual void request_buf_auth(const char *secret, const char *typ) = 0; 41 | virtual void request_buf_open_index(size_t pst_id, const char *dbn, 42 | const char *tbl, const char *idx, const char *retflds, 43 | const char *filflds = 0) = 0; 44 | virtual void request_buf_exec_generic(size_t pst_id, const string_ref& op, 45 | const string_ref *kvs, size_t kvslen, uint32_t limit, uint32_t skip, 46 | const string_ref& mod_op, const string_ref *mvs, size_t mvslen, 47 | const hstcpcli_filter *fils = 0, size_t filslen = 0, 48 | int invalues_keypart = -1, const string_ref *invalues = 0, 49 | size_t invalueslen = 0) = 0; // FIXME: too long 50 | virtual int request_send() = 0; 51 | virtual int response_recv(size_t& num_flds_r) = 0; 52 | virtual const string_ref *get_next_row() = 0; 53 | virtual void response_buf_remove() = 0; 54 | virtual int get_error_code() = 0; 55 | virtual std::string get_error() = 0; 56 | static hstcpcli_ptr create(const socket_args& args); 57 | }; 58 | 59 | }; 60 | 61 | #endif 62 | 63 | -------------------------------------------------------------------------------- /libhsclient/libhsclient.spec.template: -------------------------------------------------------------------------------- 1 | Summary: handlersocket client library 2 | Name: libhsclient 3 | Version: HANDLERSOCKET_VERSION 4 | Release: 1%{?dist} 5 | Group: System Environment/Libraries 6 | License: BSD 7 | Source: libhsclient.tar.gz 8 | Packager: Akira Higuchi 9 | BuildRoot: /var/tmp/%{name}-%{version}-root 10 | 11 | %description 12 | 13 | %prep 14 | %setup -n %{name} 15 | 16 | %define _use_internal_dependency_generator 0 17 | 18 | %build 19 | make -f Makefile.plain 20 | 21 | %install 22 | rm -rf $RPM_BUILD_ROOT 23 | mkdir -p $RPM_BUILD_ROOT/usr/include/handlersocket 24 | mkdir -p $RPM_BUILD_ROOT/%{_bindir} 25 | mkdir -p $RPM_BUILD_ROOT/%{_libdir} 26 | install -m 755 libhsclient.a $RPM_BUILD_ROOT/%{_libdir} 27 | install -m 644 *.hpp $RPM_BUILD_ROOT/usr/include/handlersocket/ 28 | 29 | %post 30 | /sbin/ldconfig 31 | 32 | %postun 33 | /sbin/ldconfig 34 | 35 | %files 36 | %defattr(-, root, root) 37 | /usr/include/* 38 | %{_libdir}/*.a 39 | 40 | -------------------------------------------------------------------------------- /libhsclient/mutex.hpp: -------------------------------------------------------------------------------- 1 | 2 | // vim:sw=2:ai 3 | 4 | /* 5 | * Copyright (C) 2010 DeNA Co.,Ltd.. All rights reserved. 6 | * See COPYRIGHT.txt for details. 7 | */ 8 | 9 | #ifndef DENA_MUTEX_HPP 10 | #define DENA_MUTEX_HPP 11 | 12 | #include 13 | #include 14 | 15 | #include "fatal.hpp" 16 | #include "util.hpp" 17 | 18 | namespace dena { 19 | 20 | struct condition; 21 | 22 | struct mutex : private noncopyable { 23 | friend struct condition; 24 | mutex() { 25 | if (pthread_mutex_init(&mtx, 0) != 0) { 26 | fatal_abort("pthread_mutex_init"); 27 | } 28 | } 29 | ~mutex() { 30 | if (pthread_mutex_destroy(&mtx) != 0) { 31 | fatal_abort("pthread_mutex_destroy"); 32 | } 33 | } 34 | void lock() const { 35 | if (pthread_mutex_lock(&mtx) != 0) { 36 | fatal_abort("pthread_mutex_lock"); 37 | } 38 | } 39 | void unlock() const { 40 | if (pthread_mutex_unlock(&mtx) != 0) { 41 | fatal_abort("pthread_mutex_unlock"); 42 | } 43 | } 44 | private: 45 | mutable pthread_mutex_t mtx; 46 | }; 47 | 48 | }; 49 | 50 | #endif 51 | 52 | -------------------------------------------------------------------------------- /libhsclient/socket.cpp: -------------------------------------------------------------------------------- 1 | 2 | // vim:sw=2:ai 3 | 4 | /* 5 | * Copyright (C) 2010 DeNA Co.,Ltd.. All rights reserved. 6 | * See COPYRIGHT.txt for details. 7 | */ 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | #include "socket.hpp" 18 | #include "string_util.hpp" 19 | #include "fatal.hpp" 20 | 21 | namespace dena { 22 | 23 | void 24 | ignore_sigpipe() 25 | { 26 | if (signal(SIGPIPE, SIG_IGN) == SIG_ERR) { 27 | fatal_abort("SIGPIPE SIG_IGN"); 28 | } 29 | } 30 | 31 | void 32 | socket_args::set(const config& conf) 33 | { 34 | timeout = conf.get_int("timeout", 600); 35 | listen_backlog = conf.get_int("listen_backlog", 256); 36 | std::string node = conf.get_str("host", ""); 37 | std::string port = conf.get_str("port", ""); 38 | if (!node.empty() || !port.empty()) { 39 | if (family == AF_UNIX || node == "/") { 40 | set_unix_domain(port.c_str()); 41 | } else { 42 | const char *nd = node.empty() ? 0 : node.c_str(); 43 | if (resolve(nd, port.c_str()) != 0) { 44 | fatal_exit("getaddrinfo failed: " + node + ":" + port); 45 | } 46 | } 47 | } 48 | sndbuf = conf.get_int("sndbuf", 0); 49 | rcvbuf = conf.get_int("rcvbuf", 0); 50 | } 51 | 52 | void 53 | socket_args::set_unix_domain(const char *path) 54 | { 55 | family = AF_UNIX; 56 | addr = sockaddr_storage(); 57 | addrlen = sizeof(sockaddr_un); 58 | sockaddr_un *const ap = reinterpret_cast(&addr); 59 | ap->sun_family = AF_UNIX; 60 | strncpy(ap->sun_path, path, sizeof(ap->sun_path) - 1); 61 | } 62 | 63 | int 64 | socket_args::resolve(const char *node, const char *service) 65 | { 66 | const int flags = (node == 0) ? AI_PASSIVE : 0; 67 | auto_addrinfo ai; 68 | addr = sockaddr_storage(); 69 | addrlen = 0; 70 | const int r = ai.resolve(node, service, flags, family, socktype, protocol); 71 | if (r != 0) { 72 | return r; 73 | } 74 | memcpy(&addr, ai.get()->ai_addr, ai.get()->ai_addrlen); 75 | addrlen = ai.get()->ai_addrlen; 76 | return 0; 77 | } 78 | 79 | int 80 | socket_set_options(auto_file& fd, const socket_args& args, std::string& err_r) 81 | { 82 | if (args.timeout != 0 && !args.nonblocking) { 83 | struct timeval tv = { }; 84 | tv.tv_sec = args.timeout; 85 | tv.tv_usec = 0; 86 | if (setsockopt(fd.get(), SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) != 0) { 87 | return errno_string("setsockopt SO_RCVTIMEO", errno, err_r); 88 | } 89 | tv.tv_sec = args.timeout; 90 | tv.tv_usec = 0; 91 | if (setsockopt(fd.get(), SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv)) != 0) { 92 | return errno_string("setsockopt SO_RCVTIMEO", errno, err_r); 93 | } 94 | } 95 | if (args.nonblocking && fcntl(fd.get(), F_SETFL, O_NONBLOCK) != 0) { 96 | return errno_string("fcntl O_NONBLOCK", errno, err_r); 97 | } 98 | if (args.sndbuf != 0) { 99 | const int v = args.sndbuf; 100 | if (setsockopt(fd.get(), SOL_SOCKET, SO_SNDBUF, &v, sizeof(v)) != 0) { 101 | return errno_string("setsockopt SO_SNDBUF", errno, err_r); 102 | } 103 | } 104 | if (args.rcvbuf != 0) { 105 | const int v = args.rcvbuf; 106 | if (setsockopt(fd.get(), SOL_SOCKET, SO_RCVBUF, &v, sizeof(v)) != 0) { 107 | return errno_string("setsockopt SO_RCVBUF", errno, err_r); 108 | } 109 | } 110 | return 0; 111 | } 112 | 113 | int 114 | socket_open(auto_file& fd, const socket_args& args, std::string& err_r) 115 | { 116 | fd.reset(socket(args.family, args.socktype, args.protocol)); 117 | if (fd.get() < 0) { 118 | return errno_string("socket", errno, err_r); 119 | } 120 | return socket_set_options(fd, args, err_r); 121 | } 122 | 123 | int 124 | socket_connect(auto_file& fd, const socket_args& args, std::string& err_r) 125 | { 126 | int r = 0; 127 | if ((r = socket_open(fd, args, err_r)) != 0) { 128 | return r; 129 | } 130 | 131 | again: 132 | if (connect(fd.get(), reinterpret_cast(&args.addr), 133 | args.addrlen) != 0) { 134 | if (errno == EINTR) { 135 | if (args.nonblocking) { 136 | return errno_string("connect", errno, err_r); 137 | } else { 138 | goto again; 139 | } 140 | } else if (!args.nonblocking || errno != EINPROGRESS) { 141 | return errno_string("connect", errno, err_r); 142 | } 143 | } 144 | return 0; 145 | } 146 | 147 | int 148 | socket_bind(auto_file& fd, const socket_args& args, std::string& err_r) 149 | { 150 | fd.reset(socket(args.family, args.socktype, args.protocol)); 151 | if (fd.get() < 0) { 152 | return errno_string("socket", errno, err_r); 153 | } 154 | if (args.reuseaddr) { 155 | if (args.family == AF_UNIX) { 156 | const sockaddr_un *const ap = 157 | reinterpret_cast(&args.addr); 158 | if (unlink(ap->sun_path) != 0 && errno != ENOENT) { 159 | return errno_string("unlink uds", errno, err_r); 160 | } 161 | } else { 162 | int v = 1; 163 | if (setsockopt(fd.get(), SOL_SOCKET, SO_REUSEADDR, &v, sizeof(v)) != 0) { 164 | return errno_string("setsockopt SO_REUSEADDR", errno, err_r); 165 | } 166 | } 167 | } 168 | if (bind(fd.get(), reinterpret_cast(&args.addr), 169 | args.addrlen) != 0) { 170 | return errno_string("bind", errno, err_r); 171 | } 172 | if (listen(fd.get(), args.listen_backlog) != 0) { 173 | return errno_string("listen", errno, err_r); 174 | } 175 | if (args.nonblocking && fcntl(fd.get(), F_SETFL, O_NONBLOCK) != 0) { 176 | return errno_string("fcntl O_NONBLOCK", errno, err_r); 177 | } 178 | return 0; 179 | } 180 | 181 | int 182 | socket_accept(int listen_fd, auto_file& fd, const socket_args& args, 183 | sockaddr_storage& addr_r, socklen_t& addrlen_r, std::string& err_r) 184 | { 185 | fd.reset(accept(listen_fd, reinterpret_cast(&addr_r), 186 | &addrlen_r)); 187 | if (fd.get() < 0) { 188 | return errno_string("accept", errno, err_r); 189 | } 190 | return socket_set_options(fd, args, err_r); 191 | } 192 | 193 | }; 194 | 195 | -------------------------------------------------------------------------------- /libhsclient/socket.hpp: -------------------------------------------------------------------------------- 1 | 2 | // vim:sw=2:ai 3 | 4 | /* 5 | * Copyright (C) 2010 DeNA Co.,Ltd.. All rights reserved. 6 | * See COPYRIGHT.txt for details. 7 | */ 8 | 9 | #ifndef DENA_SOCKET_HPP 10 | #define DENA_SOCKET_HPP 11 | 12 | #include 13 | 14 | #include "auto_addrinfo.hpp" 15 | #include "auto_file.hpp" 16 | #include "config.hpp" 17 | 18 | namespace dena { 19 | 20 | struct socket_args { 21 | sockaddr_storage addr; 22 | socklen_t addrlen; 23 | int family; 24 | int socktype; 25 | int protocol; 26 | int timeout; 27 | int listen_backlog; 28 | bool reuseaddr; 29 | bool nonblocking; 30 | bool use_epoll; 31 | int sndbuf; 32 | int rcvbuf; 33 | socket_args() : addr(), addrlen(0), family(AF_INET), socktype(SOCK_STREAM), 34 | protocol(0), timeout(600), listen_backlog(256), 35 | reuseaddr(true), nonblocking(false), use_epoll(false), 36 | sndbuf(0), rcvbuf(0) { } 37 | void set(const config& conf); 38 | void set_unix_domain(const char *path); 39 | int resolve(const char *node, const char *service); 40 | }; 41 | 42 | void ignore_sigpipe(); 43 | int socket_bind(auto_file& fd, const socket_args& args, std::string& err_r); 44 | int socket_connect(auto_file& fd, const socket_args& args, std::string& err_r); 45 | int socket_accept(int listen_fd, auto_file& fd, const socket_args& args, 46 | sockaddr_storage& addr_r, socklen_t& addrlen_r, std::string& err_r); 47 | 48 | }; 49 | 50 | #endif 51 | 52 | -------------------------------------------------------------------------------- /libhsclient/string_buffer.hpp: -------------------------------------------------------------------------------- 1 | 2 | // vim:sw=2:ai 3 | 4 | /* 5 | * Copyright (C) 2010 DeNA Co.,Ltd.. All rights reserved. 6 | * See COPYRIGHT.txt for details. 7 | */ 8 | 9 | #ifndef DENA_STRING_BUFFER_HPP 10 | #define DENA_STRING_BUFFER_HPP 11 | 12 | #include 13 | #include 14 | #include 15 | 16 | #include "util.hpp" 17 | #include "allocator.hpp" 18 | #include "fatal.hpp" 19 | 20 | namespace dena { 21 | 22 | struct string_buffer : private noncopyable { 23 | string_buffer() : buffer(0), begin_offset(0), end_offset(0), alloc_size(0) { } 24 | ~string_buffer() { 25 | DENA_FREE(buffer); 26 | } 27 | const char *begin() const { 28 | return buffer + begin_offset; 29 | } 30 | const char *end() const { 31 | return buffer + end_offset; 32 | } 33 | char *begin() { 34 | return buffer + begin_offset; 35 | } 36 | char *end() { 37 | return buffer + end_offset; 38 | } 39 | size_t size() const { 40 | return end_offset - begin_offset; 41 | } 42 | void clear() { 43 | begin_offset = end_offset = 0; 44 | } 45 | void resize(size_t len) { 46 | if (size() < len) { 47 | reserve(len); 48 | memset(buffer + end_offset, 0, len - size()); 49 | } 50 | end_offset = begin_offset + len; 51 | } 52 | void reserve(size_t len) { 53 | if (alloc_size >= begin_offset + len) { 54 | return; 55 | } 56 | size_t asz = alloc_size; 57 | while (asz < begin_offset + len) { 58 | if (asz == 0) { 59 | asz = 16; 60 | } 61 | const size_t asz_n = asz << 1; 62 | if (asz_n < asz) { 63 | fatal_abort("string_buffer::resize() overflow"); 64 | } 65 | asz = asz_n; 66 | } 67 | void *const p = DENA_REALLOC(buffer, asz); 68 | if (p == 0) { 69 | fatal_abort("string_buffer::resize() realloc"); 70 | } 71 | buffer = static_cast(p); 72 | alloc_size = asz; 73 | } 74 | void erase_front(size_t len) { 75 | if (len >= size()) { 76 | clear(); 77 | } else { 78 | begin_offset += len; 79 | } 80 | } 81 | char *make_space(size_t len) { 82 | reserve(size() + len); 83 | return buffer + end_offset; 84 | } 85 | void space_wrote(size_t len) { 86 | len = std::min(len, alloc_size - end_offset); 87 | end_offset += len; 88 | } 89 | template 90 | void append_literal(const char (& str)[N]) { 91 | append(str, str + N - 1); 92 | } 93 | void append(const char *start, const char *finish) { 94 | const size_t len = finish - start; 95 | reserve(size() + len); 96 | memcpy(buffer + end_offset, start, len); 97 | end_offset += len; 98 | } 99 | void append_2(const char *s1, const char *f1, const char *s2, 100 | const char *f2) { 101 | const size_t l1 = f1 - s1; 102 | const size_t l2 = f2 - s2; 103 | reserve(end_offset + l1 + l2); 104 | memcpy(buffer + end_offset, s1, l1); 105 | memcpy(buffer + end_offset + l1, s2, l2); 106 | end_offset += l1 + l2; 107 | } 108 | private: 109 | char *buffer; 110 | size_t begin_offset; 111 | size_t end_offset; 112 | size_t alloc_size; 113 | }; 114 | 115 | }; 116 | 117 | #endif 118 | 119 | -------------------------------------------------------------------------------- /libhsclient/string_ref.hpp: -------------------------------------------------------------------------------- 1 | 2 | // vim:sw=2:ai 3 | 4 | /* 5 | * Copyright (C) 2010 DeNA Co.,Ltd.. All rights reserved. 6 | * See COPYRIGHT.txt for details. 7 | */ 8 | 9 | #ifndef DENA_STRING_REF_HPP 10 | #define DENA_STRING_REF_HPP 11 | 12 | #include 13 | #include 14 | 15 | namespace dena { 16 | 17 | struct string_wref { 18 | typedef char value_type; 19 | char *begin() const { return start; } 20 | char *end() const { return start + length; } 21 | size_t size() const { return length; } 22 | private: 23 | char *start; 24 | size_t length; 25 | public: 26 | string_wref(char *s = 0, size_t len = 0) : start(s), length(len) { } 27 | }; 28 | 29 | struct string_ref { 30 | typedef const char value_type; 31 | const char *begin() const { return start; } 32 | const char *end() const { return start + length; } 33 | size_t size() const { return length; } 34 | private: 35 | const char *start; 36 | size_t length; 37 | public: 38 | string_ref(const char *s = 0, size_t len = 0) : start(s), length(len) { } 39 | string_ref(const char *s, const char *f) : start(s), length(f - s) { } 40 | string_ref(const string_wref& w) : start(w.begin()), length(w.size()) { } 41 | }; 42 | 43 | template inline bool 44 | operator ==(const string_ref& x, const char (& y)[N]) { 45 | return (x.size() == N - 1) && (::memcmp(x.begin(), y, N - 1) == 0); 46 | } 47 | 48 | inline bool 49 | operator ==(const string_ref& x, const string_ref& y) { 50 | return (x.size() == y.size()) && 51 | (::memcmp(x.begin(), y.begin(), x.size()) == 0); 52 | } 53 | 54 | inline bool 55 | operator !=(const string_ref& x, const string_ref& y) { 56 | return (x.size() != y.size()) || 57 | (::memcmp(x.begin(), y.begin(), x.size()) != 0); 58 | } 59 | 60 | }; 61 | 62 | #endif 63 | 64 | -------------------------------------------------------------------------------- /libhsclient/string_util.cpp: -------------------------------------------------------------------------------- 1 | 2 | // vim:sw=2:ai 3 | 4 | /* 5 | * Copyright (C) 2010 DeNA Co.,Ltd.. All rights reserved. 6 | * See COPYRIGHT.txt for details. 7 | */ 8 | 9 | #include 10 | #include 11 | 12 | #include "string_util.hpp" 13 | 14 | namespace dena { 15 | 16 | string_wref 17 | get_token(char *& wp, char *wp_end, char delim) 18 | { 19 | char *const wp_begin = wp; 20 | char *const p = memchr_char(wp_begin, delim, wp_end - wp_begin); 21 | if (p == 0) { 22 | wp = wp_end; 23 | return string_wref(wp_begin, wp_end - wp_begin); 24 | } 25 | wp = p + 1; 26 | return string_wref(wp_begin, p - wp_begin); 27 | } 28 | 29 | template T 30 | atoi_tmpl_nocheck(const char *start, const char *finish) 31 | { 32 | T v = 0; 33 | for (; start != finish; ++start) { 34 | const char c = *start; 35 | if (c < '0' || c > '9') { 36 | break; 37 | } 38 | v *= 10; 39 | v += static_cast(c - '0'); 40 | } 41 | return v; 42 | } 43 | 44 | template T 45 | atoi_signed_tmpl_nocheck(const char *start, const char *finish) 46 | { 47 | T v = 0; 48 | bool negative = false; 49 | if (start != finish) { 50 | if (start[0] == '-') { 51 | ++start; 52 | negative = true; 53 | } else if (start[0] == '+') { 54 | ++start; 55 | } 56 | } 57 | for (; start != finish; ++start) { 58 | const char c = *start; 59 | if (c < '0' || c > '9') { 60 | break; 61 | } 62 | v *= 10; 63 | if (negative) { 64 | v -= static_cast(c - '0'); 65 | } else { 66 | v += static_cast(c - '0'); 67 | } 68 | } 69 | return v; 70 | } 71 | 72 | uint32_t 73 | atoi_uint32_nocheck(const char *start, const char *finish) 74 | { 75 | return atoi_tmpl_nocheck(start, finish); 76 | } 77 | 78 | long long 79 | atoll_nocheck(const char *start, const char *finish) 80 | { 81 | return atoi_signed_tmpl_nocheck(start, finish); 82 | } 83 | 84 | void 85 | append_uint32(string_buffer& buf, uint32_t v) 86 | { 87 | char *const wp = buf.make_space(64); 88 | const int len = snprintf(wp, 64, "%lu", static_cast(v)); 89 | if (len > 0) { 90 | buf.space_wrote(len); 91 | } 92 | } 93 | 94 | std::string 95 | to_stdstring(uint32_t v) 96 | { 97 | char buf[64]; 98 | snprintf(buf, sizeof(buf), "%lu", static_cast(v)); 99 | return std::string(buf); 100 | } 101 | 102 | int 103 | errno_string(const char *s, int en, std::string& err_r) 104 | { 105 | char buf[64]; 106 | snprintf(buf, sizeof(buf), "%s: %d", s, en); 107 | err_r = std::string(buf); 108 | return en; 109 | } 110 | 111 | template size_t 112 | split_tmpl_arr(char delim, const T& buf, T *parts, size_t parts_len) 113 | { 114 | typedef typename T::value_type value_type; 115 | size_t i = 0; 116 | value_type *start = buf.begin(); 117 | value_type *const finish = buf.end(); 118 | for (i = 0; i < parts_len; ++i) { 119 | value_type *const p = memchr_char(start, delim, finish - start); 120 | if (p == 0) { 121 | parts[i] = T(start, finish - start); 122 | ++i; 123 | break; 124 | } 125 | parts[i] = T(start, p - start); 126 | start = p + 1; 127 | } 128 | const size_t r = i; 129 | for (; i < parts_len; ++i) { 130 | parts[i] = T(); 131 | } 132 | return r; 133 | } 134 | 135 | size_t 136 | split(char delim, const string_ref& buf, string_ref *parts, 137 | size_t parts_len) 138 | { 139 | return split_tmpl_arr(delim, buf, parts, parts_len); 140 | } 141 | 142 | size_t 143 | split(char delim, const string_wref& buf, string_wref *parts, 144 | size_t parts_len) 145 | { 146 | return split_tmpl_arr(delim, buf, parts, parts_len); 147 | } 148 | 149 | template size_t 150 | split_tmpl_vec(char delim, const T& buf, V& parts) 151 | { 152 | typedef typename T::value_type value_type; 153 | size_t i = 0; 154 | value_type *start = buf.begin(); 155 | value_type *const finish = buf.end(); 156 | while (true) { 157 | value_type *const p = memchr_char(start, delim, finish - start); 158 | if (p == 0) { 159 | parts.push_back(T(start, finish - start)); 160 | break; 161 | } 162 | parts.push_back(T(start, p - start)); 163 | start = p + 1; 164 | } 165 | const size_t r = i; 166 | return r; 167 | } 168 | 169 | size_t 170 | split(char delim, const string_ref& buf, std::vector& parts_r) 171 | { 172 | return split_tmpl_vec(delim, buf, parts_r); 173 | } 174 | 175 | size_t 176 | split(char delim, const string_wref& buf, std::vector& parts_r) 177 | { 178 | return split_tmpl_vec(delim, buf, parts_r); 179 | } 180 | 181 | }; 182 | 183 | -------------------------------------------------------------------------------- /libhsclient/string_util.hpp: -------------------------------------------------------------------------------- 1 | 2 | // vim:sw=2:ai 3 | 4 | /* 5 | * Copyright (C) 2010 DeNA Co.,Ltd.. All rights reserved. 6 | * See COPYRIGHT.txt for details. 7 | */ 8 | 9 | #ifndef DENA_STRING_UTIL_HPP 10 | #define DENA_STRING_UTIL_HPP 11 | 12 | #include 13 | #include 14 | #include 15 | 16 | #include "string_buffer.hpp" 17 | #include "string_ref.hpp" 18 | 19 | namespace dena { 20 | 21 | inline const char * 22 | memchr_char(const char *s, int c, size_t n) 23 | { 24 | return static_cast(memchr(s, c, n)); 25 | } 26 | 27 | inline char * 28 | memchr_char(char *s, int c, size_t n) 29 | { 30 | return static_cast(memchr(s, c, n)); 31 | } 32 | 33 | string_wref get_token(char *& wp, char *wp_end, char delim); 34 | uint32_t atoi_uint32_nocheck(const char *start, const char *finish); 35 | std::string to_stdstring(uint32_t v); 36 | void append_uint32(string_buffer& buf, uint32_t v); 37 | long long atoll_nocheck(const char *start, const char *finish); 38 | 39 | int errno_string(const char *s, int en, std::string& err_r); 40 | 41 | size_t split(char delim, const string_ref& buf, string_ref *parts, 42 | size_t parts_len); 43 | size_t split(char delim, const string_wref& buf, string_wref *parts, 44 | size_t parts_len); 45 | size_t split(char delim, const string_ref& buf, 46 | std::vector& parts_r); 47 | size_t split(char delim, const string_wref& buf, 48 | std::vector& parts_r); 49 | 50 | }; 51 | 52 | #endif 53 | 54 | -------------------------------------------------------------------------------- /libhsclient/thread.hpp: -------------------------------------------------------------------------------- 1 | 2 | // vim:sw=2:ai 3 | 4 | /* 5 | * Copyright (C) 2010 DeNA Co.,Ltd.. All rights reserved. 6 | * See COPYRIGHT.txt for details. 7 | */ 8 | 9 | #ifndef DENA_THREAD_HPP 10 | #define DENA_THREAD_HPP 11 | 12 | #include 13 | #include 14 | 15 | #include "fatal.hpp" 16 | 17 | namespace dena { 18 | 19 | template 20 | struct thread : private noncopyable { 21 | template thread(const Ta& arg, size_t stack_sz = 256 * 1024) 22 | : obj(arg), thr(0), need_join(false), stack_size(stack_sz) { } 23 | template thread(const Ta0& a0, 24 | volatile Ta1& a1, size_t stack_sz = 256 * 1024) 25 | : obj(a0, a1), thr(0), need_join(false), stack_size(stack_sz) { } 26 | ~thread() { 27 | join(); 28 | } 29 | void start() { 30 | if (!start_nothrow()) { 31 | fatal_abort("thread::start"); 32 | } 33 | } 34 | bool start_nothrow() { 35 | if (need_join) { 36 | return need_join; /* true */ 37 | } 38 | void *const arg = this; 39 | pthread_attr_t attr; 40 | if (pthread_attr_init(&attr) != 0) { 41 | fatal_abort("pthread_attr_init"); 42 | } 43 | if (pthread_attr_setstacksize(&attr, stack_size) != 0) { 44 | fatal_abort("pthread_attr_setstacksize"); 45 | } 46 | const int r = pthread_create(&thr, &attr, thread_main, arg); 47 | if (pthread_attr_destroy(&attr) != 0) { 48 | fatal_abort("pthread_attr_destroy"); 49 | } 50 | if (r != 0) { 51 | return need_join; /* false */ 52 | } 53 | need_join = true; 54 | return need_join; /* true */ 55 | } 56 | void join() { 57 | if (!need_join) { 58 | return; 59 | } 60 | int e = 0; 61 | if ((e = pthread_join(thr, 0)) != 0) { 62 | fatal_abort("pthread_join"); 63 | } 64 | need_join = false; 65 | } 66 | T& operator *() { return obj; } 67 | T *operator ->() { return &obj; } 68 | private: 69 | static void *thread_main(void *arg) { 70 | thread *p = static_cast(arg); 71 | p->obj(); 72 | return 0; 73 | } 74 | private: 75 | T obj; 76 | pthread_t thr; 77 | bool need_join; 78 | size_t stack_size; 79 | }; 80 | 81 | }; 82 | 83 | #endif 84 | 85 | -------------------------------------------------------------------------------- /libhsclient/util.hpp: -------------------------------------------------------------------------------- 1 | 2 | // vim:sw=2:ai 3 | 4 | /* 5 | * Copyright (C) 2010 DeNA Co.,Ltd.. All rights reserved. 6 | * See COPYRIGHT.txt for details. 7 | */ 8 | 9 | #ifndef DENA_UTIL_HPP 10 | #define DENA_UTIL_HPP 11 | 12 | namespace dena { 13 | 14 | /* boost::noncopyable */ 15 | struct noncopyable { 16 | noncopyable() { } 17 | private: 18 | noncopyable(const noncopyable&); 19 | noncopyable& operator =(const noncopyable&); 20 | }; 21 | 22 | }; 23 | 24 | #endif 25 | 26 | -------------------------------------------------------------------------------- /misc/microbench-hs.log: -------------------------------------------------------------------------------- 1 | [a@c54hdd libhsclient]$ ./hstest_hs.sh host=192.168.100.104 key_mask=1000000 num_threads=100 num=10000000 timelimit=10 dbname=hstest 2 | now: 1274127653 cntdiff: 265538 tdiff: 1.000996 rps: 265273.757409 3 | now: 1274127654 cntdiff: 265762 tdiff: 1.000995 rps: 265497.850684 4 | now: 1274127655 cntdiff: 265435 tdiff: 1.001010 rps: 265167.196749 5 | now: 1274127656 cntdiff: 265144 tdiff: 1.000994 rps: 264880.654203 6 | now: 1274127657 cntdiff: 265593 tdiff: 1.000995 rps: 265329.018659 7 | now: 1274127658 cntdiff: 264863 tdiff: 1.000996 rps: 264599.492138 8 | now: 1274127659 cntdiff: 265688 tdiff: 1.001008 rps: 265420.447231 9 | now: 1274127660 cntdiff: 265727 tdiff: 1.000999 rps: 265461.810594 10 | now: 1274127661 cntdiff: 265848 tdiff: 1.001010 rps: 265579.716809 11 | now: 1274127662 cntdiff: 265430 tdiff: 1.000992 rps: 265167.001723 12 | now: 1274127663 cntdiff: 266379 tdiff: 1.001008 rps: 266110.751381 13 | now: 1274127664 cntdiff: 266244 tdiff: 1.001003 rps: 265977.217679 14 | now: 1274127665 cntdiff: 265737 tdiff: 1.000996 rps: 265472.559379 15 | now: 1274127666 cntdiff: 265878 tdiff: 1.001003 rps: 265611.647683 16 | (1274127656.104648: 1328292, 1274127666.114649: 3985679), 265473.20173 qps 17 | 18 | 19 | *************************** 1. row *************************** 20 | Type: InnoDB 21 | Name: 22 | Status: 23 | ===================================== 24 | 100518 5:18:13 INNODB MONITOR OUTPUT 25 | ===================================== 26 | Per second averages calculated from the last 5 seconds 27 | ---------- 28 | BACKGROUND THREAD 29 | ---------- 30 | srv_master_thread loops: 191 1_second, 190 sleeps, 18 10_second, 5 background, 5 flush 31 | srv_master_thread log flush and writes: 190 32 | ---------- 33 | SEMAPHORES 34 | ---------- 35 | OS WAIT ARRAY INFO: reservation count 53519, signal count 29547 36 | Mutex spin waits 3083488, rounds 5159906, OS waits 50700 37 | RW-shared spins 21, OS waits 16; RW-excl spins 1, OS waits 4 38 | Spin rounds per wait: 1.67 mutex, 30.00 RW-shared, 151.00 RW-excl 39 | ------------ 40 | TRANSACTIONS 41 | ------------ 42 | Trx id counter EDA36085 43 | Purge done for trx's n:o < EC1F94A7 undo n:o < 0 44 | History list length 20 45 | LIST OF TRANSACTIONS FOR EACH SESSION: 46 | ---TRANSACTION 0, not started, process no 4533, OS thread id 1079281984 47 | MySQL thread id 11, query id 16 localhost root 48 | show engine innodb status 49 | ---TRANSACTION ED9D5959, not started, process no 4533, OS thread id 1089849664 50 | MySQL thread id 7, query id 0 handlersocket: mode=rd, 0 conns, 0 active 51 | ---TRANSACTION ED9D5956, not started, process no 4533, OS thread id 1238796608 52 | MySQL thread id 1, query id 0 handlersocket: mode=rd, 0 conns, 0 active 53 | ---TRANSACTION EDA36084, not started, process no 4533, OS thread id 1255582016 54 | mysql tables in use 1, locked 1 55 | MySQL thread id 3, query id 0 handlersocket: mode=rd, 12 conns, 7 active 56 | ---TRANSACTION EDA36080, not started, process no 4533, OS thread id 1247189312 57 | mysql tables in use 1, locked 1 58 | MySQL thread id 2, query id 0 handlersocket: mode=rd, 36 conns, 18 active 59 | ---TRANSACTION EDA36082, ACTIVE 0 sec, process no 4533, OS thread id 1263974720 committing 60 | MySQL thread id 4, query id 0 handlersocket: mode=rd, 37 conns, 20 active 61 | Trx read view will not see trx with id >= EDA36083, sees < EDA3607D 62 | ---TRANSACTION EDA3607D, ACTIVE 0 sec, process no 4533, OS thread id 1272367424, thread declared inside InnoDB 500 63 | mysql tables in use 1, locked 1 64 | MySQL thread id 5, query id 0 handlersocket: mode=rd, 15 conns, 9 active 65 | Trx read view will not see trx with id >= EDA3607E, sees < EDA36079 66 | -------- 67 | FILE I/O 68 | -------- 69 | I/O thread 0 state: waiting for i/o request (insert buffer thread) 70 | I/O thread 1 state: waiting for i/o request (log thread) 71 | I/O thread 2 state: waiting for i/o request (read thread) 72 | I/O thread 3 state: waiting for i/o request (read thread) 73 | I/O thread 4 state: waiting for i/o request (read thread) 74 | I/O thread 5 state: waiting for i/o request (read thread) 75 | I/O thread 6 state: waiting for i/o request (write thread) 76 | I/O thread 7 state: waiting for i/o request (write thread) 77 | I/O thread 8 state: waiting for i/o request (write thread) 78 | I/O thread 9 state: waiting for i/o request (write thread) 79 | Pending normal aio reads: 0, aio writes: 0, 80 | ibuf aio reads: 0, log i/o's: 0, sync i/o's: 0 81 | Pending flushes (fsync) log: 0; buffer pool: 0 82 | 71 OS file reads, 235 OS file writes, 235 OS fsyncs 83 | 0.00 reads/s, 0 avg bytes/read, 1.00 writes/s, 1.00 fsyncs/s 84 | ------------------------------------- 85 | INSERT BUFFER AND ADAPTIVE HASH INDEX 86 | ------------------------------------- 87 | Ibuf: size 1, free list len 0, seg size 2, 88 | 0 inserts, 0 merged recs, 0 merges 89 | Hash table size 12750011, node heap has 2 buffer(s) 90 | 267203.76 hash searches/s, 0.00 non-hash searches/s 91 | --- 92 | LOG 93 | --- 94 | Log sequence number 147179727377 95 | Log flushed up to 147179726685 96 | Last checkpoint at 147179716475 97 | 0 pending log writes, 0 pending chkp writes 98 | 194 log i/o's done, 1.00 log i/o's/second 99 | ---------------------- 100 | BUFFER POOL AND MEMORY 101 | ---------------------- 102 | Total memory allocated 6587154432; in additional pool allocated 0 103 | Dictionary memory allocated 33640 104 | Buffer pool size 393216 105 | Free buffers 393154 106 | Database pages 60 107 | Old database pages 0 108 | Modified db pages 1 109 | Pending reads 0 110 | Pending writes: LRU 0, flush list 0, single page 0 111 | Pages made young 0, not young 0 112 | 0.00 youngs/s, 0.00 non-youngs/s 113 | Pages read 60, created 0, written 23 114 | 0.00 reads/s, 0.00 creates/s, 0.00 writes/s 115 | Buffer pool hit rate 1000 / 1000, young-making rate 0 / 1000 not 0 / 1000 116 | Pages read ahead 0.00/s, evicted without access 0.00/s 117 | LRU len: 60, unzip_LRU len: 0 118 | I/O sum[0]:cur[0], unzip sum[0]:cur[0] 119 | -------------- 120 | ROW OPERATIONS 121 | -------------- 122 | 2 queries inside InnoDB, 0 queries in queue 123 | 3 read views open inside InnoDB 124 | Main thread process no. 4533, id 1230403904, state: sleeping 125 | Number of rows inserted 0, updated 0, deleted 0, read 37653556 126 | 0.00 inserts/s, 0.00 updates/s, 0.00 deletes/s, 266608.28 reads/s 127 | ---------------------------- 128 | END OF INNODB MONITOR OUTPUT 129 | ============================ 130 | 131 | -------------------------------------------------------------------------------- /misc/microbench-my.log: -------------------------------------------------------------------------------- 1 | 2 | [a@c54hdd libhsclient]$ ./hstest_my.sh host=192.168.100.104 key_mask=1000000 num_threads=100 num=10000000 timelimit=10 dbname=hstest 3 | now: 1274128046 cntdiff: 63061 tdiff: 1.000999 rps: 62998.066579 4 | now: 1274128047 cntdiff: 61227 tdiff: 1.001013 rps: 61165.037337 5 | now: 1274128048 cntdiff: 61367 tdiff: 1.001029 rps: 61303.917375 6 | now: 1274128049 cntdiff: 61959 tdiff: 1.000962 rps: 61899.451554 7 | now: 1274128050 cntdiff: 62176 tdiff: 1.001006 rps: 62113.520756 8 | now: 1274128051 cntdiff: 61367 tdiff: 1.000998 rps: 61305.815559 9 | now: 1274128052 cntdiff: 61644 tdiff: 1.001015 rps: 61581.497988 10 | now: 1274128053 cntdiff: 60659 tdiff: 1.000984 rps: 60599.373036 11 | now: 1274128054 cntdiff: 59459 tdiff: 1.000996 rps: 59399.831067 12 | now: 1274128055 cntdiff: 62310 tdiff: 1.001011 rps: 62247.074757 13 | now: 1274128056 cntdiff: 61947 tdiff: 1.000991 rps: 61885.664744 14 | now: 1274128057 cntdiff: 60675 tdiff: 1.001006 rps: 60614.029076 15 | now: 1274128058 cntdiff: 60312 tdiff: 1.001001 rps: 60251.680861 16 | now: 1274128059 cntdiff: 60290 tdiff: 1.001004 rps: 60229.530717 17 | (1274128049.309634: 309654, 1274128059.319648: 920493), 61022.79143 qps 18 | 19 | *************************** 1. row *************************** 20 | Type: InnoDB 21 | Name: 22 | Status: 23 | ===================================== 24 | 100518 5:24:51 INNODB MONITOR OUTPUT 25 | ===================================== 26 | Per second averages calculated from the last 5 seconds 27 | ---------- 28 | BACKGROUND THREAD 29 | ---------- 30 | srv_master_thread loops: 220 1_second, 219 sleeps, 21 10_second, 6 background, 6 flush 31 | srv_master_thread log flush and writes: 219 32 | ---------- 33 | SEMAPHORES 34 | ---------- 35 | OS WAIT ARRAY INFO: reservation count 56193, signal count 30826 36 | Mutex spin waits 3415153, rounds 5618661, OS waits 53251 37 | RW-shared spins 24, OS waits 17; RW-excl spins 1, OS waits 5 38 | Spin rounds per wait: 1.65 mutex, 30.00 RW-shared, 181.00 RW-excl 39 | ------------ 40 | TRANSACTIONS 41 | ------------ 42 | Trx id counter EDB514D6 43 | Purge done for trx's n:o < EC1F94A7 undo n:o < 0 44 | History list length 20 45 | LIST OF TRANSACTIONS FOR EACH SESSION: 46 | ---TRANSACTION 0, not started, process no 4533, OS thread id 1306585408 47 | MySQL thread id 113, query id 920620 localhost root 48 | show engine innodb status 49 | ---TRANSACTION EDA708BB, not started, process no 4533, OS thread id 1272367424 50 | MySQL thread id 5, query id 0 handlersocket: mode=rd, 0 conns, 0 active 51 | ---TRANSACTION ED9D5959, not started, process no 4533, OS thread id 1089849664 52 | MySQL thread id 7, query id 0 handlersocket: mode=rd, 0 conns, 0 active 53 | ---TRANSACTION ED9D5956, not started, process no 4533, OS thread id 1238796608 54 | MySQL thread id 1, query id 0 handlersocket: mode=rd, 0 conns, 0 active 55 | ---TRANSACTION EDA708BD, not started, process no 4533, OS thread id 1255582016 56 | MySQL thread id 3, query id 0 handlersocket: mode=rd, 0 conns, 0 active 57 | ---TRANSACTION EDA708BF, not started, process no 4533, OS thread id 1247189312 58 | MySQL thread id 2, query id 0 handlersocket: mode=rd, 0 conns, 0 active 59 | ---TRANSACTION EDA708BE, not started, process no 4533, OS thread id 1263974720 60 | MySQL thread id 4, query id 0 handlersocket: mode=rd, 0 conns, 0 active 61 | -------- 62 | FILE I/O 63 | -------- 64 | I/O thread 0 state: waiting for i/o request (insert buffer thread) 65 | I/O thread 1 state: waiting for i/o request (log thread) 66 | I/O thread 2 state: waiting for i/o request (read thread) 67 | I/O thread 3 state: waiting for i/o request (read thread) 68 | I/O thread 4 state: waiting for i/o request (read thread) 69 | I/O thread 5 state: waiting for i/o request (read thread) 70 | I/O thread 6 state: waiting for i/o request (write thread) 71 | I/O thread 7 state: waiting for i/o request (write thread) 72 | I/O thread 8 state: waiting for i/o request (write thread) 73 | I/O thread 9 state: waiting for i/o request (write thread) 74 | Pending normal aio reads: 0, aio writes: 0, 75 | ibuf aio reads: 0, log i/o's: 0, sync i/o's: 0 76 | Pending flushes (fsync) log: 0; buffer pool: 0 77 | 71 OS file reads, 269 OS file writes, 269 OS fsyncs 78 | 0.00 reads/s, 0 avg bytes/read, 2.40 writes/s, 2.40 fsyncs/s 79 | ------------------------------------- 80 | INSERT BUFFER AND ADAPTIVE HASH INDEX 81 | ------------------------------------- 82 | Ibuf: size 1, free list len 0, seg size 2, 83 | 0 inserts, 0 merged recs, 0 merges 84 | Hash table size 12750011, node heap has 2 buffer(s) 85 | 65739.45 hash searches/s, 0.00 non-hash searches/s 86 | --- 87 | LOG 88 | --- 89 | Log sequence number 147179774153 90 | Log flushed up to 147179771813 91 | Last checkpoint at 147179761899 92 | 0 pending log writes, 0 pending chkp writes 93 | 220 log i/o's done, 1.60 log i/o's/second 94 | ---------------------- 95 | BUFFER POOL AND MEMORY 96 | ---------------------- 97 | Total memory allocated 6587154432; in additional pool allocated 0 98 | Dictionary memory allocated 33640 99 | Buffer pool size 393216 100 | Free buffers 393154 101 | Database pages 60 102 | Old database pages 0 103 | Modified db pages 1 104 | Pending reads 0 105 | Pending writes: LRU 0, flush list 0, single page 0 106 | Pages made young 0, not young 0 107 | 0.00 youngs/s, 0.00 non-youngs/s 108 | Pages read 60, created 0, written 27 109 | 0.00 reads/s, 0.00 creates/s, 0.40 writes/s 110 | Buffer pool hit rate 1000 / 1000, young-making rate 0 / 1000 not 0 / 1000 111 | Pages read ahead 0.00/s, evicted without access 0.00/s 112 | LRU len: 60, unzip_LRU len: 0 113 | I/O sum[0]:cur[0], unzip sum[0]:cur[0] 114 | -------------- 115 | ROW OPERATIONS 116 | -------------- 117 | 0 queries inside InnoDB, 0 queries in queue 118 | 1 read views open inside InnoDB 119 | Main thread process no. 4533, id 1230403904, state: sleeping 120 | Number of rows inserted 0, updated 0, deleted 0, read 40071920 121 | 0.00 inserts/s, 0.00 updates/s, 0.00 deletes/s, 66321.54 reads/s 122 | ---------------------------- 123 | END OF INNODB MONITOR OUTPUT 124 | ============================ 125 | 126 | -------------------------------------------------------------------------------- /misc/mysql-5.6.10-server_started.diff: -------------------------------------------------------------------------------- 1 | --- mysql-5.6.10/sql/mysqld.cc.org 2013-03-19 18:12:44.923208944 +0900 2 | +++ mysql-5.6.10/sql/mysqld.cc 2013-03-19 18:14:16.638988599 +0900 3 | @@ -5532,7 +5532,7 @@ 4 | /* Signal threads waiting for server to be started */ 5 | mysql_mutex_lock(&LOCK_server_started); 6 | mysqld_server_started= 1; 7 | - mysql_cond_signal(&COND_server_started); 8 | + mysql_cond_broadcast(&COND_server_started); 9 | mysql_mutex_unlock(&LOCK_server_started); 10 | 11 | bootstrap(mysql_stdin); 12 | @@ -5560,7 +5560,7 @@ 13 | /* Signal threads waiting for server to be started */ 14 | mysql_mutex_lock(&LOCK_server_started); 15 | mysqld_server_started= 1; 16 | - mysql_cond_signal(&COND_server_started); 17 | + mysql_cond_broadcast(&COND_server_started); 18 | mysql_mutex_unlock(&LOCK_server_started); 19 | 20 | #ifdef WITH_NDBCLUSTER_STORAGE_ENGINE 21 | -------------------------------------------------------------------------------- /perl-Net-HandlerSocket/COPYRIGHT.txt: -------------------------------------------------------------------------------- 1 | 2 | Copyright (c) 2010 DeNA Co.,Ltd. 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions are met: 7 | 8 | * Redistributions of source code must retain the above copyright 9 | notice, this list of conditions and the following disclaimer. 10 | * Redistributions in binary form must reproduce the above copyright 11 | notice, this list of conditions and the following disclaimer in the 12 | documentation and/or other materials provided with the distribution. 13 | * Neither the name of DeNA Co.,Ltd. nor the names of its contributors 14 | may be used to endorse or promote products derived from this software 15 | without specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY DeNA Co.,Ltd. "AS IS" AND ANY EXPRESS OR 18 | IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 19 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO 20 | EVENT SHALL DeNA Co.,Ltd. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 22 | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 23 | OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 24 | WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 25 | OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 26 | ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | 28 | -------------------------------------------------------------------------------- /perl-Net-HandlerSocket/Changes: -------------------------------------------------------------------------------- 1 | Revision history for Perl extension HandlerSocket. 2 | 3 | 0.01 Wed Mar 31 11:50:23 2010 4 | - original version; created by h2xs 1.23 with options 5 | -A -n HandlerSocket 6 | 7 | -------------------------------------------------------------------------------- /perl-Net-HandlerSocket/MANIFEST: -------------------------------------------------------------------------------- 1 | Changes 2 | HandlerSocket.xs 3 | Makefile.PL 4 | MANIFEST 5 | ppport.h 6 | README 7 | t/Net-HandlerSocket.t 8 | lib/Net/HandlerSocket.pm 9 | -------------------------------------------------------------------------------- /perl-Net-HandlerSocket/Makefile.PL: -------------------------------------------------------------------------------- 1 | # use 5.010000; 2 | use ExtUtils::MakeMaker; 3 | # See lib/ExtUtils/MakeMaker.pm for details of how to influence 4 | # the contents of the Makefile that is written. 5 | WriteMakefile( 6 | NAME => 'Net::HandlerSocket', 7 | VERSION_FROM => 'lib/Net/HandlerSocket.pm', # finds $VERSION 8 | PREREQ_PM => {}, # e.g., Module::Name => 1.1 9 | ($] >= 5.005 ? ## Add these new keywords supported since 5.005 10 | (ABSTRACT_FROM => 'lib/Net/HandlerSocket.pm', # retrieve abstract from module 11 | AUTHOR => 'higuchi dot akira at dena dot jp>') : ()), 12 | CC => 'g++', 13 | CCFLAGS => '-fPIC -Werror=vla', 14 | LD => '$(CC)', 15 | LDFLAGS => '-fPIC', 16 | XSOPT => '-C++', 17 | LIBS => ['-lhsclient'], 18 | DEFINE => '', 19 | OPTIMIZE => '-g -O3 -Wall -Wno-unused', 20 | ); 21 | -------------------------------------------------------------------------------- /perl-Net-HandlerSocket/Makefile.PL.installed: -------------------------------------------------------------------------------- 1 | # use 5.010000; 2 | use ExtUtils::MakeMaker; 3 | # See lib/ExtUtils/MakeMaker.pm for details of how to influence 4 | # the contents of the Makefile that is written. 5 | WriteMakefile( 6 | NAME => 'Net::HandlerSocket', 7 | VERSION_FROM => 'lib/Net/HandlerSocket.pm', # finds $VERSION 8 | PREREQ_PM => {}, # e.g., Module::Name => 1.1 9 | ($] >= 5.005 ? ## Add these new keywords supported since 5.005 10 | (ABSTRACT_FROM => 'lib/Net/HandlerSocket.pm', # retrieve abstract from module 11 | AUTHOR => 'higuchi dot akira at dena dot jp>') : ()), 12 | CC => 'g++ -fPIC', 13 | LD => 'g++ -fPIC', 14 | LIBS => ['-lhsclient'], # e.g., '-lm' 15 | DEFINE => '', # e.g., '-DHAVE_SOMETHING' 16 | INC => '-I. -I/usr/include/handlersocket', 17 | OPTIMIZE => '-g -O3 -Wall -Wno-unused', 18 | # Un-comment this if you add C files to link with later: 19 | # OBJECT => '$(O_FILES)', # link all the C files too 20 | ); 21 | -------------------------------------------------------------------------------- /perl-Net-HandlerSocket/README: -------------------------------------------------------------------------------- 1 | HandlerSocket version 0.01 2 | ========================== 3 | 4 | The README is used to introduce the module and provide instructions on 5 | how to install the module, any machine dependencies it may have (for 6 | example C compilers and installed libraries) and any other information 7 | that should be provided before the module is installed. 8 | 9 | A README file is required for CPAN modules since CPAN extracts the 10 | README file from a module distribution so that people browsing the 11 | archive can use it get an idea of the modules uses. It is usually a 12 | good idea to provide version information here so that people can 13 | decide whether fixes for the module are worth downloading. 14 | 15 | INSTALLATION 16 | 17 | To install this module type the following: 18 | 19 | perl Makefile.PL 20 | make 21 | make test 22 | make install 23 | 24 | DEPENDENCIES 25 | 26 | COPYRIGHT AND LICENCE 27 | 28 | Copyright (C) 2010 DeNA Co.,Ltd.. All rights reserved. 29 | See COPYRIGHT.txt for details. 30 | 31 | -------------------------------------------------------------------------------- /perl-Net-HandlerSocket/lib/Net/HandlerSocket.pm: -------------------------------------------------------------------------------- 1 | 2 | package Net::HandlerSocket; 3 | 4 | use strict; 5 | use warnings; 6 | 7 | require Exporter; 8 | 9 | our @ISA = qw(Exporter); 10 | 11 | # Items to export into callers namespace by default. Note: do not export 12 | # names by default without a very good reason. Use EXPORT_OK instead. 13 | # Do not simply export all your public functions/methods/constants. 14 | 15 | # This allows declaration use Net::HandlerSocket ':all'; 16 | # If you do not need this, moving things directly into @EXPORT or @EXPORT_OK 17 | # will save memory. 18 | our %EXPORT_TAGS = ( 'all' => [ qw( 19 | 20 | ) ] ); 21 | 22 | our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } ); 23 | 24 | our @EXPORT = qw( 25 | 26 | ); 27 | 28 | our $VERSION = '0.01'; 29 | 30 | require XSLoader; 31 | XSLoader::load('Net::HandlerSocket', $VERSION); 32 | 33 | # Preloaded methods go here. 34 | 35 | 1; 36 | __END__ 37 | # Below is stub documentation for your module. You'd better edit it! 38 | 39 | =head1 NAME 40 | 41 | Net::HandlerSocket - Perl extension for blah blah blah 42 | 43 | =head1 SYNOPSIS 44 | 45 | use Net::HandlerSocket; 46 | my $hsargs = { host => 'localhost', port => 9999 }; 47 | my $cli = new Net::HandlerSocket($hsargs); 48 | $cli->open_index(1, 'testdb', 'testtable1', 'PRIMARY', 'foo,bar,baz'); 49 | $cli->open_index(2, 'testdb', 'testtable2', 'i2', 'hoge,fuga'); 50 | $cli->execute_find(1, '>=', [ 'aaa', 'bbb' ], 5, 100); 51 | # select foo,bar,baz from testdb.testtable1 52 | # where pk1 = 'aaa' and pk2 = 'bbb' order by pk1, pk2 53 | # limit 100, 5 54 | 55 | =head1 DESCRIPTION 56 | 57 | Stub documentation for Net::HandlerSocket, created by h2xs. 58 | 59 | =head1 AUTHOR 60 | 61 | Akira HiguchiEhiguchi dot akira at dena dot jpE 62 | 63 | =head1 COPYRIGHT AND LICENSE 64 | 65 | Copyright (C) 2010 DeNA Co.,Ltd.. All rights reserved. 66 | See COPYRIGHT.txt for details. 67 | 68 | =cut 69 | -------------------------------------------------------------------------------- /perl-Net-HandlerSocket/perl-Net-HandlerSocket.spec.template: -------------------------------------------------------------------------------- 1 | # 2 | # - HandlerSocket - 3 | # This spec file was automatically generated by cpan2rpm [ver: 2.027] 4 | # The following arguments were used: 5 | # --no-sign perl-Net-HandlerSocket.tar.gz 6 | # For more information on cpan2rpm please visit: http://perl.arix.com/ 7 | # 8 | 9 | %define pkgname perl-Net-HandlerSocket 10 | %define filelist %{pkgname}-%{version}-filelist 11 | %define NVR %{pkgname}-%{version}-%{release} 12 | %define maketest 1 13 | 14 | name: perl-Net-HandlerSocket 15 | summary: HandlerSocket - Perl extension for handlersocket 16 | version: HANDLERSOCKET_VERSION 17 | release: 1%{?dist} 18 | packager: Akira Higuchi 19 | license: BSD 20 | group: Applications/CPAN 21 | group: System Environment/Libraries 22 | buildroot: %{_tmppath}/%{name}-%{version}-%(id -u -n) 23 | prefix: %(echo %{_prefix}) 24 | source: perl-Net-HandlerSocket.tar.gz 25 | BuildRequires: libhsclient perl-Test-Simple 26 | Requires: libhsclient 27 | Obsoletes: perl-DB-HandlerSocket 28 | 29 | %description 30 | Stub documentation for HandlerSocket, created by h2xs. It looks like the 31 | author of the extension was negligent enough to leave the stub 32 | unedited. 33 | 34 | # 35 | # This package was generated automatically with the cpan2rpm 36 | # utility. To get this software or for more information 37 | # please visit: http://perl.arix.com/ 38 | # 39 | 40 | %prep 41 | %setup -q -n %{pkgname} 42 | chmod -R u+w %{_builddir}/%{pkgname} 43 | 44 | %build 45 | grep -rsl '^#!.*perl' . | 46 | grep -v '.bak$' |xargs --no-run-if-empty \ 47 | %__perl -MExtUtils::MakeMaker -e 'MY->fixin(@ARGV)' 48 | CFLAGS="$RPM_OPT_FLAGS" 49 | %{__perl} Makefile.PL.installed `%{__perl} -MExtUtils::MakeMaker -e ' print qq|PREFIX=%{buildroot}%{_prefix}| if \$ExtUtils::MakeMaker::VERSION =~ /5\.9[1-6]|6\.0[0-5]/ '` 50 | %{__make} 51 | %if %maketest 52 | %{__make} test 53 | %endif 54 | 55 | %install 56 | [ "%{buildroot}" != "/" ] && rm -rf %{buildroot} 57 | 58 | %{makeinstall} `%{__perl} -MExtUtils::MakeMaker -e ' print \$ExtUtils::MakeMaker::VERSION <= 6.05 ? qq|PREFIX=%{buildroot}%{_prefix}| : qq|DESTDIR=%{buildroot}| '` 59 | 60 | cmd=/usr/share/spec-helper/compress_files 61 | [ -x $cmd ] || cmd=/usr/lib/rpm/brp-compress 62 | [ -x $cmd ] && $cmd 63 | 64 | # SuSE Linux 65 | if [ -e /etc/SuSE-release -o -e /etc/UnitedLinux-release ] 66 | then 67 | %{__mkdir_p} %{buildroot}/var/adm/perl-modules 68 | %{__cat} `find %{buildroot} -name "perllocal.pod"` \ 69 | | %{__sed} -e s+%{buildroot}++g \ 70 | > %{buildroot}/var/adm/perl-modules/%{name} 71 | fi 72 | 73 | # remove special files 74 | find %{buildroot} -name "perllocal.pod" \ 75 | -o -name ".packlist" \ 76 | -o -name "*.bs" \ 77 | |xargs -i rm -f {} 78 | 79 | # no empty directories 80 | find %{buildroot}%{_prefix} \ 81 | -type d -depth \ 82 | -exec rmdir {} \; 2>/dev/null 83 | 84 | %{__perl} -MFile::Find -le ' 85 | find({ wanted => \&wanted, no_chdir => 1}, "%{buildroot}"); 86 | print "%doc Changes README"; 87 | for my $x (sort @dirs, @files) { 88 | push @ret, $x unless indirs($x); 89 | } 90 | print join "\n", sort @ret; 91 | 92 | sub wanted { 93 | return if /auto$/; 94 | 95 | local $_ = $File::Find::name; 96 | my $f = $_; s|^\Q%{buildroot}\E||; 97 | return unless length; 98 | return $files[@files] = $_ if -f $f; 99 | 100 | $d = $_; 101 | /\Q$d\E/ && return for reverse sort @INC; 102 | $d =~ /\Q$_\E/ && return 103 | for qw|/etc %_prefix/man %_prefix/bin %_prefix/share|; 104 | 105 | $dirs[@dirs] = $_; 106 | } 107 | 108 | sub indirs { 109 | my $x = shift; 110 | $x =~ /^\Q$_\E\// && $x ne $_ && return 1 for @dirs; 111 | } 112 | ' > %filelist 113 | 114 | [ -z %filelist ] && { 115 | echo "ERROR: empty %files listing" 116 | exit -1 117 | } 118 | 119 | %clean 120 | [ "%{buildroot}" != "/" ] && rm -rf %{buildroot} 121 | 122 | %files -f %filelist 123 | %defattr(-,root,root) 124 | 125 | %changelog 126 | * Thu Apr 1 2010 a@localhost.localdomain 127 | - Initial build. 128 | -------------------------------------------------------------------------------- /perl-Net-HandlerSocket/t/Net-HandlerSocket.t: -------------------------------------------------------------------------------- 1 | # Before `make install' is performed this script should be runnable with 2 | # `make test'. After `make install' it should work as `perl HandlerSocket.t' 3 | 4 | ######################### 5 | 6 | # change 'tests => 1' to 'tests => last_test_to_print'; 7 | 8 | use Test::More tests => 1; 9 | BEGIN { use_ok('Net::HandlerSocket') }; 10 | 11 | ######################### 12 | 13 | # Insert your test code below, the Test::More module is use()ed here so read 14 | # its man page ( perldoc Test::More ) for help writing this test script. 15 | 16 | -------------------------------------------------------------------------------- /regtest/Makefile: -------------------------------------------------------------------------------- 1 | 2 | SHELL=/bin/bash 3 | 4 | all: 5 | if [ "`uname -o`" = "Cygwin" ]; then \ 6 | ../../scripts/vsenv90.bat -c 'make test'; \ 7 | else \ 8 | $(MAKE) test; \ 9 | fi 10 | 11 | force: 12 | export CXX="$(CXX)"; \ 13 | export SUNJDK="$(SUNJDK)"; \ 14 | for i in test_*; do \ 15 | pushd $$i > /dev/null; \ 16 | echo -n "$$i ... "; \ 17 | if [ -f ./DONE ]; then \ 18 | echo "skip"; \ 19 | elif ! ./run.sh > test.log; then \ 20 | echo -n "FORCE ... "; \ 21 | $(MAKE) accept; \ 22 | if ! ./run.sh > test.log; then \ 23 | echo "FAILED"; \ 24 | exit 1; \ 25 | fi; \ 26 | else \ 27 | echo "success"; \ 28 | fi; \ 29 | touch ./DONE; \ 30 | popd > /dev/null; \ 31 | done; \ 32 | exit 0; 33 | 34 | test: 35 | export CXX="$(CXX)"; \ 36 | export SUNJDK="$(SUNJDK)"; \ 37 | for i in test_*; do \ 38 | pushd $$i > /dev/null; \ 39 | echo -n "$$i ... "; \ 40 | if [ -f ./DONE ]; then \ 41 | echo "skip"; \ 42 | elif ! ./run.sh > test.log; then \ 43 | echo "FAILED"; \ 44 | exit 1; \ 45 | else \ 46 | echo "success"; \ 47 | fi; \ 48 | touch ./DONE; \ 49 | popd > /dev/null; \ 50 | done; \ 51 | exit 0; 52 | 53 | retest: clean test 54 | 55 | clean: 56 | for i in test_*; do \ 57 | pushd $$i > /dev/null; \ 58 | if [ -f Makefile ]; then \ 59 | $(MAKE) clean; \ 60 | fi; \ 61 | rm -rf ./GWS_db; \ 62 | rm -f ./DONE; \ 63 | popd > /dev/null; \ 64 | done; \ 65 | exit 0; 66 | rm -f test_*/*.log 67 | rm -f test_*/*.out 68 | rm -rf test_*/*_db 69 | rm -f test_*/*.dll 70 | rm -f test_*/*.idb 71 | rm -f test_*/*.obj 72 | rm -f test_*/*.manifest 73 | rm -f test_*/*.so 74 | 75 | cleanprepare: 76 | rm -f ../run/*.exe 77 | rm -f ../run/poi.jar 78 | rm -f ../run/*.dll 79 | 80 | -------------------------------------------------------------------------------- /regtest/common/binary_my.cnf: -------------------------------------------------------------------------------- 1 | 2 | [perl] 3 | default-character-set-name = binary 4 | 5 | -------------------------------------------------------------------------------- /regtest/common/compat.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | if [ "`uname -o`" = "Cygwin" ]; then 4 | export DIFF='diff --ignore-space --strip-trailing-cr' 5 | elif [ "`uname`" = "Darwin" ]; then 6 | export DIFF='diff' 7 | else 8 | export DIFF='diff --ignore-space --strip-trailing-cr' 9 | fi 10 | 11 | compile_c() { 12 | if [ "`uname -o`" = "Cygwin" ]; then 13 | cl /W3 /I../.. /EHsc /FD /MD "$1" /link /DLL "/OUT:$2.dll" \ 14 | ../../libase.lib 2> cl.log 15 | else 16 | $CXX -I../.. -O3 -g -Wall -fPIC -shared "$1" -o "$2.so" 17 | fi 18 | } 19 | 20 | compile_j() { 21 | if [ "`uname -o`" = "Cygwin" ]; then 22 | jdk="`echo /cygdrive/c/Program\ Files/Java/jdk* | head -1`" 23 | else 24 | jdk="$SUNJDK" 25 | fi 26 | "$jdk/bin/javac" -g "$1"/*.java 27 | "$jdk/bin/jar" -cf "$1.jar" "$1"/*.class 28 | } 29 | 30 | -------------------------------------------------------------------------------- /regtest/common/hstest.pm: -------------------------------------------------------------------------------- 1 | 2 | # vim:sw=2:ai 3 | 4 | package hstest; 5 | 6 | use DBI; 7 | use Net::HandlerSocket; 8 | 9 | our %conf = (); 10 | 11 | sub get_conf_env { 12 | my ($key, $defval) = @_; 13 | return $ENV{$key} || $defval; 14 | } 15 | 16 | sub init_conf { 17 | $conf{host} = get_conf_env("MYHOST", "localhost"); 18 | $conf{myport} = get_conf_env("MYPORT", 3306); 19 | $conf{dbname} = get_conf_env("MYDBNAME", "hstestdb"); 20 | $conf{ssps} = get_conf_env("MYSSPS"); 21 | $conf{user} = get_conf_env("MYSQLUSER", "root"); 22 | $conf{pass} = get_conf_env("MYSQLPASS", ""); 23 | $conf{hsport} = get_conf_env("HSPORT", 9998); 24 | $conf{hspass} = get_conf_env("HSPASS", undef); 25 | } 26 | 27 | sub get_dbi_connection { 28 | my ($dbname, $host, $myport, $ssps, $user, $pass) 29 | = ($conf{dbname}, $conf{host}, $conf{myport}, $conf{ssps}, 30 | $conf{user}, $conf{pass}); 31 | my $mycnf = "binary_my.cnf"; 32 | my $dsn = "DBI:mysql:database=;host=$host;port=$myport" 33 | . ";mysql_server_prepare=$ssps" 34 | . ";mysql_read_default_group=perl" 35 | . ";mysql_read_default_file=../common/$mycnf"; 36 | my $dbh = DBI->connect($dsn, $user, $pass, { RaiseError => 1 }); 37 | return $dbh; 38 | } 39 | 40 | sub init_testdb { 41 | my $charset = $_[0] || "binary"; 42 | my $dbh = get_dbi_connection(); 43 | my $dbname = $conf{dbname}; 44 | $dbh->do("drop database if exists $dbname"); 45 | $dbh->do("create database $dbname default character set $charset"); 46 | $dbh->do("use $dbname"); 47 | return $dbh; 48 | } 49 | 50 | sub get_hs_connection { 51 | my ($host, $port) = @_; 52 | $host ||= $conf{host}; 53 | $port ||= $conf{hsport}; 54 | my $hsargs = { 'host' => $host, 'port' => $port }; 55 | my $conn = new Net::HandlerSocket($hsargs); 56 | if (defined($conn) && defined($conf{hspass})) { 57 | $conn->auth($conf{hspass}); 58 | } 59 | return $conn; 60 | } 61 | 62 | 63 | init_conf(); 64 | 65 | 1; 66 | 67 | -------------------------------------------------------------------------------- /regtest/test_01_lib/Makefile: -------------------------------------------------------------------------------- 1 | 2 | clean: 3 | rm -f *.log *.log2 *.log2h 4 | 5 | -------------------------------------------------------------------------------- /regtest/test_01_lib/run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | TESTS="01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24"; 4 | 5 | source ../common/compat.sh 6 | 7 | for i in $TESTS; do 8 | perl "test$i.pl" > test$i.log 2> test$i.log2 9 | done 10 | for i in $TESTS; do 11 | if ! $DIFF -u test$i.log test$i.expected; then 12 | echo "test$i failed"; 13 | exit 1 14 | fi 15 | if [ -f "test$i.expect2" ]; then 16 | lines="`wc -l < test$i.expect2`" 17 | head -$lines test$i.log2 > test$i.log2h 18 | if ! $DIFF -u test$i.log2h test$i.expect2 && \ 19 | ! $DIFF -u test$i.log2h test$i.expect2ef; then 20 | echo "test$i failed"; 21 | exit 1 22 | fi 23 | fi 24 | done 25 | echo "OK." 26 | exit 0 27 | 28 | -------------------------------------------------------------------------------- /regtest/test_01_lib/test01.expected: -------------------------------------------------------------------------------- 1 | k0 v1020 2 | k1 v6351 3 | k10 v70410 4 | k11 v75111 5 | k12 v36712 6 | k13 v40013 7 | k14 v39714 8 | k15 v17015 9 | k16 v71916 10 | k17 v73417 11 | k18 v58718 12 | k19 v49419 13 | k2 v8032 14 | k20 v52320 15 | k21 v95421 16 | k22 v43322 17 | k23 v82023 18 | k24 v28324 19 | k25 v83725 20 | k26 v20526 21 | k27 v41527 22 | k28 v54528 23 | k29 v58329 24 | k3 v9253 25 | k30 v5230 26 | k31 v32331 27 | k32 v61432 28 | k33 v67933 29 | k34 v80534 30 | k35 v45135 31 | k36 v11536 32 | k37 v26937 33 | k38 v21838 34 | k39 v61739 35 | k4 v7754 36 | k40 v87840 37 | k41 v34541 38 | k42 v51242 39 | k43 v96943 40 | k44 v40844 41 | k45 v29145 42 | k46 v85846 43 | k47 v95347 44 | k48 v71048 45 | k49 v14249 46 | k5 v5375 47 | k50 v68250 48 | k51 v93451 49 | k52 v62152 50 | k53 v96553 51 | k54 v57454 52 | k55 v20455 53 | k56 v29856 54 | k57 v13457 55 | k58 v98358 56 | k59 v44459 57 | k6 v5926 58 | k60 v14460 59 | k61 v15261 60 | k62 v18762 61 | k63 v21563 62 | k64 v864 63 | k65 v69765 64 | k66 v65166 65 | k67 v28067 66 | k68 v70168 67 | k69 v53769 68 | k7 v4147 69 | k70 v41370 70 | k71 v6971 71 | k72 v8672 72 | k73 v82273 73 | k74 v67074 74 | k75 v37075 75 | k76 v80676 76 | k77 v68877 77 | k78 v2678 78 | k79 v6679 79 | k8 v5908 80 | k80 v80280 81 | k81 v17181 82 | k82 v55782 83 | k83 v84783 84 | k84 v77784 85 | k85 v73085 86 | k86 v98786 87 | k87 v11587 88 | k88 v64688 89 | k89 v49689 90 | k9 v3029 91 | k90 v12090 92 | k91 v68491 93 | k92 v37492 94 | k93 v6593 95 | k94 v37094 96 | k95 v17495 97 | k96 v82896 98 | k97 v86797 99 | k98 v75998 100 | k99 v70399 101 | -------------------------------------------------------------------------------- /regtest/test_01_lib/test01.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | 3 | # vim:sw=2:ai 4 | 5 | # test for libmysql 6 | 7 | BEGIN { 8 | push @INC, "../common/"; 9 | }; 10 | 11 | use strict; 12 | use warnings; 13 | use hstest; 14 | 15 | my $dbh = hstest::init_testdb(); 16 | my $table = 'hstesttbl'; 17 | my $tablesize = 100; 18 | $dbh->do( 19 | "create table $table (k varchar(30) primary key, v varchar(30) not null) " . 20 | "engine = innodb"); 21 | srand(999); 22 | 23 | my %valmap = (); 24 | 25 | my $sth = $dbh->prepare("insert into $table values (?,?)"); 26 | for (my $i = 0; $i < $tablesize; ++$i) { 27 | my $k = "k" . $i; 28 | my $v = "v" . int(rand(1000)) . $i; 29 | $sth->execute($k, $v); 30 | $valmap{$k} = $v; 31 | } 32 | 33 | my $aref = $dbh->selectall_arrayref("select k,v from $table order by k"); 34 | for my $row (@$aref) { 35 | my ($k, $v) = @$row; 36 | print "$k $v\n"; 37 | } 38 | 39 | -------------------------------------------------------------------------------- /regtest/test_01_lib/test02.expected: -------------------------------------------------------------------------------- 1 | k0 v1020 2 | k1 v6351 3 | k10 v70410 4 | k11 v75111 5 | k12 v36712 6 | k13 v40013 7 | k14 v39714 8 | k15 v17015 9 | k16 v71916 10 | k17 v73417 11 | k18 v58718 12 | k19 v49419 13 | k2 v8032 14 | k20 v52320 15 | k21 v95421 16 | k22 v43322 17 | k23 v82023 18 | k24 v28324 19 | k25 v83725 20 | k26 v20526 21 | k27 v41527 22 | k28 v54528 23 | k29 v58329 24 | k3 v9253 25 | k30 v5230 26 | k31 v32331 27 | k32 v61432 28 | k33 v67933 29 | k34 v80534 30 | k35 v45135 31 | k36 v11536 32 | k37 v26937 33 | k38 v21838 34 | k39 v61739 35 | k4 v7754 36 | k40 v87840 37 | k41 v34541 38 | k42 v51242 39 | k43 v96943 40 | k44 v40844 41 | k45 v29145 42 | k46 v85846 43 | k47 v95347 44 | k48 v71048 45 | k49 v14249 46 | k5 v5375 47 | k50 v68250 48 | k51 v93451 49 | k52 v62152 50 | k53 v96553 51 | k54 v57454 52 | k55 v20455 53 | k56 v29856 54 | k57 v13457 55 | k58 v98358 56 | k59 v44459 57 | k6 v5926 58 | k60 v14460 59 | k61 v15261 60 | k62 v18762 61 | k63 v21563 62 | k64 v864 63 | k65 v69765 64 | k66 v65166 65 | k67 v28067 66 | k68 v70168 67 | k69 v53769 68 | k7 v4147 69 | k70 v41370 70 | k71 v6971 71 | k72 v8672 72 | k73 v82273 73 | k74 v67074 74 | k75 v37075 75 | k76 v80676 76 | k77 v68877 77 | k78 v2678 78 | k79 v6679 79 | k8 v5908 80 | k80 v80280 81 | k81 v17181 82 | k82 v55782 83 | k83 v84783 84 | k84 v77784 85 | k85 v73085 86 | k86 v98786 87 | k87 v11587 88 | k88 v64688 89 | k89 v49689 90 | k9 v3029 91 | k90 v12090 92 | k91 v68491 93 | k92 v37492 94 | k93 v6593 95 | k94 v37094 96 | k95 v17495 97 | k96 v82896 98 | k97 v86797 99 | k98 v75998 100 | k99 v70399 101 | -------------------------------------------------------------------------------- /regtest/test_01_lib/test02.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | 3 | # vim:sw=2:ai 4 | 5 | # test for '>=' 6 | 7 | BEGIN { 8 | push @INC, "../common/"; 9 | }; 10 | 11 | use strict; 12 | use warnings; 13 | use hstest; 14 | 15 | my $dbh = hstest::init_testdb(); 16 | my $table = 'hstesttbl'; 17 | my $tablesize = 100; 18 | $dbh->do( 19 | "create table $table (k varchar(30) primary key, v varchar(30) not null) " . 20 | "engine = innodb"); 21 | srand(999); 22 | 23 | my %valmap = (); 24 | 25 | my $sth = $dbh->prepare("insert into $table values (?,?)"); 26 | for (my $i = 0; $i < $tablesize; ++$i) { 27 | my $k = "k" . $i; 28 | my $v = "v" . int(rand(1000)) . $i; 29 | $sth->execute($k, $v); 30 | $valmap{$k} = $v; 31 | } 32 | 33 | my $hs = hstest::get_hs_connection(); 34 | my $dbname = $hstest::conf{dbname}; 35 | $hs->open_index(1, $dbname, $table, '', 'k,v'); 36 | my $r = $hs->execute_single(1, '>=', [ '' ], 10000, 0); 37 | shift(@$r); 38 | for (my $i = 0; $i < $tablesize; ++$i) { 39 | my $k = $r->[$i * 2]; 40 | my $v = $r->[$i * 2 + 1]; 41 | print "$k $v\n"; 42 | } 43 | 44 | my $aref = $dbh->selectall_arrayref("select k,v from $table order by k"); 45 | for my $row (@$aref) { 46 | my ($k, $v) = @$row; 47 | #print "$k $v\n"; 48 | } 49 | 50 | -------------------------------------------------------------------------------- /regtest/test_01_lib/test03.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | 3 | # vim:sw=2:ai 4 | 5 | # test for binary cleanness (#1) 6 | 7 | BEGIN { 8 | push @INC, "../common/"; 9 | }; 10 | 11 | use strict; 12 | use warnings; 13 | use hstest; 14 | 15 | my $dbh = hstest::init_testdb(); 16 | my $table = 'hstesttbl'; 17 | my $tablesize = 256; 18 | $dbh->do( 19 | "create table $table (k varchar(30) primary key, v varchar(30) not null) " . 20 | "engine = innodb default charset = binary"); 21 | srand(999); 22 | 23 | my %valmap = (); 24 | 25 | print "WR\n"; 26 | my $sth = $dbh->prepare("insert into $table values (?,?)"); 27 | for (my $i = 0; $i < $tablesize; ++$i) { 28 | my $k = "" . $i; 29 | my $v = pack("C", $i); 30 | my $vnum = unpack("C", $v); 31 | print "$k $vnum\n"; 32 | $sth->execute($k, $v); 33 | $valmap{$k} = $v; 34 | } 35 | 36 | my $hs = hstest::get_hs_connection(); 37 | my $dbname = $hstest::conf{dbname}; 38 | $hs->open_index(1, $dbname, $table, '', 'k,v'); 39 | my $r = $hs->execute_single(1, '>=', [ '' ], 10000, 0); 40 | shift(@$r); 41 | print "HS\n"; 42 | for (my $i = 0; $i < $tablesize; ++$i) { 43 | my $k = $r->[$i * 2]; 44 | my $v = $r->[$i * 2 + 1]; 45 | my $vnum = unpack("C", $v); 46 | print "$k $vnum\n"; 47 | print "MISMATCH\n" if ($k ne $vnum); 48 | print "LEN\n" if (length($v) != 1); 49 | } 50 | undef $hs; 51 | 52 | print "MY\n"; 53 | my $aref = $dbh->selectall_arrayref("select k,v from $table order by k"); 54 | for my $row (@$aref) { 55 | my ($k, $v) = @$row; 56 | my $vnum = unpack("C", $v); 57 | print "$k $vnum\n"; 58 | print "MISMATCH\n" if ($k ne $vnum); 59 | print "LEN\n" if (length($v) != 1); 60 | } 61 | 62 | -------------------------------------------------------------------------------- /regtest/test_01_lib/test04.expected: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DeNA/HandlerSocket-Plugin-for-MySQL/1b648f0bbafd5c06ddd49d7f74331630f3b54e91/regtest/test_01_lib/test04.expected -------------------------------------------------------------------------------- /regtest/test_01_lib/test04.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | 3 | # vim:sw=2:ai 4 | 5 | # test for binary cleanness (#2) 6 | 7 | BEGIN { 8 | push @INC, "../common/"; 9 | }; 10 | 11 | use strict; 12 | use warnings; 13 | use hstest; 14 | 15 | my $dbh = hstest::init_testdb(); 16 | my $table = 'hstesttbl'; 17 | my $tablesize = 256; 18 | $dbh->do( 19 | "create table $table (k varchar(30) primary key, v varchar(30) not null) " . 20 | "engine = innodb default charset = binary"); 21 | srand(999); 22 | 23 | my %valmap = (); 24 | 25 | print "WR\n"; 26 | my $sth = $dbh->prepare("insert into $table values (?,?)"); 27 | for (my $i = 0; $i < $tablesize; ++$i) { 28 | my $k = "" . $i; 29 | my $v = pack("C", $i); 30 | my $vnum = unpack("C", $v); 31 | print "$k $vnum\n"; 32 | $sth->execute($k, "a" . $v . "a"); 33 | $valmap{$k} = $v; 34 | } 35 | 36 | my $hs = hstest::get_hs_connection(); 37 | my $dbname = $hstest::conf{dbname}; 38 | $hs->open_index(1, $dbname, $table, '', 'k,v'); 39 | my $r = $hs->execute_single(1, '>=', [ '' ], 10000, 0); 40 | shift(@$r); 41 | print "HS\n"; 42 | for (my $i = 0; $i < $tablesize; ++$i) { 43 | my $k = $r->[$i * 2]; 44 | my $v = $r->[$i * 2 + 1]; 45 | my $len = length($v); 46 | my $vnum = unpack("C", substr($v, 1, 1)); 47 | print "$k $vnum $len [$v]\n"; 48 | print "MISMATCH\n" if ($k ne $vnum); 49 | print "LEN\n" if $len != 3; 50 | } 51 | undef $hs; 52 | 53 | print "MY\n"; 54 | my $aref = $dbh->selectall_arrayref("select k,v from $table order by k"); 55 | for my $row (@$aref) { 56 | my ($k, $v) = @$row; 57 | my $len = length($v); 58 | my $vnum = unpack("C", substr($v, 1, 1)); 59 | print "$k $vnum $len [$v]\n"; 60 | print "MISMATCH\n" if ($k ne $vnum); 61 | print "LEN\n" if $len != 3; 62 | } 63 | 64 | -------------------------------------------------------------------------------- /regtest/test_01_lib/test05.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | 3 | # vim:sw=2:ai 4 | 5 | # test for binary cleanness (#3) 6 | 7 | BEGIN { 8 | push @INC, "../common/"; 9 | }; 10 | 11 | use strict; 12 | use warnings; 13 | use hstest; 14 | 15 | my $dbh = hstest::init_testdb(); 16 | my $table = 'hstesttbl'; 17 | my $tablesize = 256; 18 | $dbh->do( 19 | "create table $table (k varchar(30) primary key, v varchar(30)) " . 20 | "engine = innodb default charset = binary"); 21 | srand(999); 22 | 23 | my %valmap = (); 24 | 25 | print "WR\n"; 26 | my $sth = $dbh->prepare("insert into $table values (?,?)"); 27 | for (my $i = 0; $i < $tablesize; ++$i) { 28 | my $k = "" . $i; 29 | my $v = ($i % 2 == 1) ? $i : undef; 30 | $sth->execute($k, $v); 31 | $v = "[null]" if !defined($v); 32 | print "$k $v\n"; 33 | $valmap{$k} = $v; 34 | } 35 | 36 | my $hs = hstest::get_hs_connection(); 37 | my $dbname = $hstest::conf{dbname}; 38 | $hs->open_index(1, $dbname, $table, '', 'k,v'); 39 | my $r = $hs->execute_single(1, '>=', [ '' ], 10000, 0); 40 | shift(@$r); 41 | print "HS\n"; 42 | for (my $i = 0; $i < $tablesize; ++$i) { 43 | my $k = $r->[$i * 2]; 44 | my $v = $r->[$i * 2 + 1]; 45 | $v = "[null]" if !defined($v); 46 | print "$k $v\n"; 47 | print "MISMATCH\n" if ($valmap{$k} ne $v); 48 | } 49 | undef $hs; 50 | 51 | print "MY\n"; 52 | my $aref = $dbh->selectall_arrayref("select k,v from $table order by k"); 53 | for my $row (@$aref) { 54 | my ($k, $v) = @$row; 55 | $v = "[null]" if !defined($v); 56 | print "$k $v\n"; 57 | print "MISMATCH\n" if ($valmap{$k} ne $v); 58 | } 59 | 60 | -------------------------------------------------------------------------------- /regtest/test_01_lib/test06.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | 3 | # vim:sw=2:ai 4 | 5 | # test for insert/update/delete 6 | 7 | BEGIN { 8 | push @INC, "../common/"; 9 | }; 10 | 11 | use strict; 12 | use warnings; 13 | use hstest; 14 | 15 | my $dbh = hstest::init_testdb(); 16 | my $table = 'hstesttbl'; 17 | my $tablesize = 256; 18 | $dbh->do( 19 | "create table $table (" . 20 | "k varchar(30) primary key, " . 21 | "v1 varchar(30), " . 22 | "v2 varchar(30)) " . 23 | "engine = innodb default charset = binary"); 24 | srand(999); 25 | 26 | my %valmap = (); 27 | 28 | print "HSINSERT"; 29 | my $hs = hstest::get_hs_connection(undef, 9999); 30 | my $dbname = $hstest::conf{dbname}; 31 | $hs->open_index(1, $dbname, $table, '', 'k,v1,v2'); 32 | for (my $i = 0; $i < $tablesize; ++$i) { 33 | my $k = "" . $i; 34 | my $v1 = "v1_" . $i; 35 | my $v2 = "v2_" . $i; 36 | my $r = $hs->execute_insert(1, [ $k, $v1, $v2 ]); 37 | my $err = $r->[0]; 38 | if ($err != 0) { 39 | my $err_str = $r->[1]; 40 | print "$err $err_str\n"; 41 | } 42 | } 43 | undef $hs; 44 | 45 | dump_table(); 46 | 47 | print "HSUPDATE"; 48 | $hs = hstest::get_hs_connection(undef, 9999); 49 | $dbname = $hstest::conf{dbname}; 50 | $hs->open_index(2, $dbname, $table, '', 'v1'); 51 | for (my $i = 0; $i < $tablesize; ++$i) { 52 | my $r = $hs->execute_single(2, '=', [ $i ], 1000, 0, 'U', [ "mod_$i" ]); 53 | my $err = $r->[0]; 54 | if ($err != 0) { 55 | my $err_str = $r->[1]; 56 | print "$err $err_str\n"; 57 | } 58 | } 59 | undef $hs; 60 | 61 | dump_table(); 62 | 63 | print "HSDELETE\n"; 64 | $hs = hstest::get_hs_connection(undef, 9999); 65 | $dbname = $hstest::conf{dbname}; 66 | $hs->open_index(3, $dbname, $table, '', ''); 67 | for (my $i = 0; $i < $tablesize; $i = $i + 2) { 68 | my $r = $hs->execute_single(3, '=', [ $i ], 1000, 0, 'D'); 69 | my $err = $r->[0]; 70 | if ($err != 0) { 71 | my $err_str = $r->[1]; 72 | print "$err $err_str\n"; 73 | } 74 | } 75 | undef $hs; 76 | 77 | dump_table(); 78 | 79 | sub dump_table { 80 | print "DUMP_TABLE\n"; 81 | my $aref = $dbh->selectall_arrayref("select k,v1,v2 from $table order by k"); 82 | for my $row (@$aref) { 83 | my ($k, $v1, $v2) = @$row; 84 | $v1 = "[null]" if !defined($v1); 85 | $v2 = "[null]" if !defined($v2); 86 | print "$k $v1 $v2\n"; 87 | # print "MISMATCH\n" if ($valmap{$k} ne $v); 88 | } 89 | } 90 | 91 | -------------------------------------------------------------------------------- /regtest/test_01_lib/test07.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | 3 | # vim:sw=2:ai 4 | 5 | # test for nulls 6 | 7 | BEGIN { 8 | push @INC, "../common/"; 9 | }; 10 | 11 | # use strict; 12 | use warnings; 13 | use hstest; 14 | 15 | my $dbh = hstest::init_testdb(); 16 | my $table = 'hstesttbl'; 17 | my $tablesize = 100; 18 | $dbh->do( 19 | "create table $table (" . 20 | "k int primary key, v1 varchar(30), v2 varchar(30), " . 21 | "key idxv1 (v1) " . 22 | ") engine = innodb"); 23 | srand(999); 24 | 25 | my %valmap = (); 26 | 27 | my $sth = $dbh->prepare("insert into $table values (?,?,?)"); 28 | for (my $i = 0; $i < $tablesize; ++$i) { 29 | my $k = "" . $i; 30 | my $v1 = "1v" . int(rand(1000)) . $i; 31 | my $v2 = "2v" . int(rand(1000)) . $i; 32 | if ($i % 10 == 3) { 33 | $v1 = undef; 34 | } 35 | $sth->execute($k, $v1, $v2); 36 | $valmap{$k} = $v1; 37 | } 38 | 39 | print "MY\n"; 40 | my $aref = $dbh->selectall_arrayref("select k,v1,v2 from $table order by k"); 41 | for my $row (@$aref) { 42 | my ($k, $v1, $v2) = @$row; 43 | $v1 = "[NULL]" if (!defined($v1)); 44 | print "$k $v1 $v2\n"; 45 | } 46 | 47 | print "HS\n"; 48 | my $hs = hstest::get_hs_connection(); 49 | my $dbname = $hstest::conf{dbname}; 50 | $hs->open_index(1, $dbname, $table, '', 'k,v1,v2'); 51 | my $r = $hs->execute_single(1, '>=', [ '' ], 10000, 0); 52 | shift(@$r); 53 | for (my $i = 0; $i < $tablesize; ++$i) { 54 | my $k = $r->[$i * 3]; 55 | my $v1 = $r->[$i * 3 + 1]; 56 | my $v2 = $r->[$i * 3 + 2]; 57 | $v1 = "[NULL]" if (!defined($v1)); 58 | print "$k $v1 $v2\n"; 59 | } 60 | 61 | print "2ndIDX\n"; 62 | $hs->open_index(2, $dbname, $table, 'idxv1', 'k,v1,v2'); 63 | for (my $i = 0; $i < $tablesize; ++$i) { 64 | my $k = "" . $i; 65 | my $v1 = $valmap{$k}; 66 | next if !defined($v1); 67 | my $r = $hs->execute_single(2, '=', [ $v1 ], 1, 0); 68 | shift(@$r); 69 | my $r_k = $r->[0]; 70 | my $r_v1 = $r->[1]; 71 | my $r_v2 = $r->[2]; 72 | print "2ndidx $k $v1 => $r_k $r_v1 $r_v2\n"; 73 | } 74 | 75 | print "2ndIDX NULL\n"; 76 | { 77 | my %rvals = (); 78 | my $v1 = undef; 79 | my @arr; 80 | push(@arr, undef); 81 | my $kv = \@arr; 82 | my $r = $hs->execute_single(2, "=", $kv, 10000, 0); 83 | shift(@$r); 84 | for (my $i = 0; $i < scalar(@$r); $i += 3) { 85 | my $k = $r->[$i]; 86 | my $v1 = $r->[$i + 1]; 87 | my $v2 = $r->[$i + 2]; 88 | $rvals{$k} = [ $k, $v1, $v2 ]; 89 | } 90 | for my $i (sort { $a <=> $b } keys %rvals) { 91 | my $rec = $rvals{$i}; 92 | my $k = $rec->[0]; 93 | my $v1 = $rec->[1]; 94 | my $v2 = $rec->[2]; 95 | print "2ndidxnull $k $v2\n"; 96 | } 97 | } 98 | 99 | -------------------------------------------------------------------------------- /regtest/test_01_lib/test08.expected: -------------------------------------------------------------------------------- 1 | [0][k5][v5375] 2 | [0] 3 | -------------------------------------------------------------------------------- /regtest/test_01_lib/test08.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | 3 | # vim:sw=2:ai 4 | 5 | # test for not-found 6 | 7 | BEGIN { 8 | push @INC, "../common/"; 9 | }; 10 | 11 | use strict; 12 | use warnings; 13 | use hstest; 14 | 15 | my $dbh = hstest::init_testdb(); 16 | my $table = 'hstesttbl'; 17 | my $tablesize = 100; 18 | $dbh->do( 19 | "create table $table (k varchar(30) primary key, v varchar(30) not null) " . 20 | "engine = innodb"); 21 | srand(999); 22 | 23 | my %valmap = (); 24 | 25 | my $sth = $dbh->prepare("insert into $table values (?,?)"); 26 | for (my $i = 0; $i < $tablesize; ++$i) { 27 | my $k = "k" . $i; 28 | my $v = "v" . int(rand(1000)) . $i; 29 | $sth->execute($k, $v); 30 | $valmap{$k} = $v; 31 | } 32 | 33 | my $hs = hstest::get_hs_connection(); 34 | my $dbname = $hstest::conf{dbname}; 35 | $hs->open_index(1, $dbname, $table, '', 'k,v'); 36 | 37 | dump_rec($hs, 1, 'k5'); # found 38 | dump_rec($hs, 1, 'k000000'); # notfound 39 | 40 | sub dump_rec { 41 | my ($hs, $idxid, $key) = @_; 42 | my $r = $hs->execute_single($idxid, '=', [ $key ], 1, 0); 43 | for my $fld (@$r) { 44 | print "[$fld]"; 45 | } 46 | print "\n"; 47 | } 48 | 49 | -------------------------------------------------------------------------------- /regtest/test_01_lib/test09.expected: -------------------------------------------------------------------------------- 1 | DEL 2 | [0][1] 3 | [0][k50][v68250][k51][v93451] 4 | DELINS 5 | [0][k6][v5926][k60][v14460][k61][v15261] 6 | [0][1] 7 | [0] 8 | [0][k6][v5926][k60][INS][k61][v15261] 9 | DELUPUP 10 | [0][k7][v4147][k70][v41370][k71][v6971] 11 | [0][1] 12 | [0][k7][v4147][k70][UP][k71][v6971] 13 | -------------------------------------------------------------------------------- /regtest/test_01_lib/test09.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | 3 | # vim:sw=2:ai 4 | 5 | # test for multiple modify requests 6 | 7 | BEGIN { 8 | push @INC, "../common/"; 9 | }; 10 | 11 | use strict; 12 | use warnings; 13 | use hstest; 14 | 15 | my $dbh = hstest::init_testdb(); 16 | my $table = 'hstesttbl'; 17 | my $tablesize = 100; 18 | $dbh->do( 19 | "create table $table (k varchar(30) primary key, v varchar(30) not null) " . 20 | "engine = innodb"); 21 | srand(999); 22 | 23 | my %valmap = (); 24 | 25 | my $sth = $dbh->prepare("insert into $table values (?,?)"); 26 | for (my $i = 0; $i < $tablesize; ++$i) { 27 | my $k = "k" . $i; 28 | my $v = "v" . int(rand(1000)) . $i; 29 | $sth->execute($k, $v); 30 | $valmap{$k} = $v; 31 | } 32 | 33 | my $hs = hstest::get_hs_connection(undef, 9999); 34 | my $dbname = $hstest::conf{dbname}; 35 | $hs->open_index(1, $dbname, $table, '', 'k,v'); 36 | 37 | exec_multi( 38 | "DEL", 39 | [ 1, '=', [ 'k5' ], 1, 0, 'D' ], 40 | [ 1, '>=', [ 'k5' ], 2, 0 ], 41 | ); 42 | exec_multi( 43 | "DELINS", 44 | [ 1, '>=', [ 'k6' ], 3, 0 ], 45 | [ 1, '=', [ 'k60' ], 1, 0, 'D' ], 46 | [ 1, '+', [ 'k60', 'INS' ] ], 47 | [ 1, '>=', [ 'k6' ], 3, 0 ], 48 | ); 49 | exec_multi( 50 | "DELUPUP", 51 | [ 1, '>=', [ 'k7' ], 3, 0 ], 52 | [ 1, '=', [ 'k70' ], 1, 0, 'U', [ 'k70', 'UP' ] ], 53 | [ 1, '>=', [ 'k7' ], 3, 0 ], 54 | ); 55 | 56 | sub exec_multi { 57 | my $mess = shift(@_); 58 | print "$mess\n"; 59 | my $mres = $hs->execute_multi(\@_); 60 | for my $res (@$mres) { 61 | for my $fld (@$res) { 62 | print "[$fld]"; 63 | } 64 | print "\n"; 65 | } 66 | } 67 | 68 | -------------------------------------------------------------------------------- /regtest/test_01_lib/test10.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | 3 | # vim:sw=2:ai 4 | 5 | # test for nulls 6 | 7 | BEGIN { 8 | push @INC, "../common/"; 9 | }; 10 | 11 | use strict; 12 | use warnings; 13 | use hstest; 14 | 15 | my $dbh = hstest::init_testdb(); 16 | my $table = 'hstesttbl'; 17 | my $tablesize = 256; 18 | $dbh->do( 19 | "create table $table (" . 20 | "k varchar(30) primary key, " . 21 | "v1 varchar(30), " . 22 | "v2 varchar(30)) " . 23 | "engine = innodb default charset = binary"); 24 | srand(999); 25 | 26 | my %valmap = (); 27 | 28 | # setting null 29 | print "HSINSERT"; 30 | my $hs = hstest::get_hs_connection(undef, 9999); 31 | my $dbname = $hstest::conf{dbname}; 32 | $hs->open_index(1, $dbname, $table, '', 'k,v1,v2'); 33 | for (my $i = 0; $i < $tablesize; ++$i) { 34 | my $k = "" . $i; 35 | my $v1 = "v1_" . $i; 36 | my $v2 = undef; # null value 37 | my $r = $hs->execute_insert(1, [ $k, $v1, $v2 ]); 38 | my $err = $r->[0]; 39 | if ($err != 0) { 40 | my $err_str = $r->[1]; 41 | print "$err $err_str\n"; 42 | } 43 | } 44 | undef $hs; 45 | 46 | dump_table(); 47 | 48 | # setting null 49 | print "HSUPDATE"; 50 | $hs = hstest::get_hs_connection(undef, 9999); 51 | $dbname = $hstest::conf{dbname}; 52 | $hs->open_index(2, $dbname, $table, '', 'v1'); 53 | for (my $i = 0; $i < $tablesize; ++$i) { 54 | my $r = $hs->execute_single(2, '=', [ $i ], 1000, 0, 'U', [ undef ]); 55 | my $err = $r->[0]; 56 | if ($err != 0) { 57 | my $err_str = $r->[1]; 58 | print "$err $err_str\n"; 59 | } 60 | } 61 | undef $hs; 62 | 63 | dump_table(); 64 | 65 | # setting non-null 66 | print "HSUPDATE"; 67 | $hs = hstest::get_hs_connection(undef, 9999); 68 | $dbname = $hstest::conf{dbname}; 69 | $hs->open_index(2, $dbname, $table, '', 'v1'); 70 | for (my $i = 0; $i < $tablesize; ++$i) { 71 | my $r = $hs->execute_single(2, '=', [ $i ], 1000, 0, 'U', [ "hoge" ]); 72 | my $err = $r->[0]; 73 | if ($err != 0) { 74 | my $err_str = $r->[1]; 75 | print "$err $err_str\n"; 76 | } 77 | } 78 | undef $hs; 79 | 80 | dump_table(); 81 | 82 | sub dump_table { 83 | print "DUMP_TABLE\n"; 84 | my $aref = $dbh->selectall_arrayref("select k,v1,v2 from $table order by k"); 85 | for my $row (@$aref) { 86 | my ($k, $v1, $v2) = @$row; 87 | $v1 = "[null]" if !defined($v1); 88 | $v2 = "[null]" if !defined($v2); 89 | print "$k $v1 $v2\n"; 90 | # print "MISMATCH\n" if ($valmap{$k} ne $v); 91 | } 92 | } 93 | 94 | -------------------------------------------------------------------------------- /regtest/test_01_lib/test11.expected: -------------------------------------------------------------------------------- 1 | VAL 2 | [0][k5][5] 3 | [0][k6][6] 4 | [0][k7][7] 5 | [0][k8][8] 6 | INCREMENT 7 | [0][1] 8 | [0][1] 9 | [0][1] 10 | [0][1] 11 | VAL 12 | [0][k5][8] 13 | [0][k6][18] 14 | [0][k7][-4] 15 | [0][k8][-7] 16 | DECREMENT 17 | [0][1] 18 | [0][0] 19 | [0][1] 20 | [0][0] 21 | VAL 22 | [0][k5][6] 23 | [0][k6][18] 24 | [0][k7][-84] 25 | [0][k8][-7] 26 | INCREMENT 27 | [0][6] 28 | [0][7] 29 | [0][8] 30 | [0][9] 31 | [0][10] 32 | [0][11] 33 | [0][12] 34 | [0][13] 35 | [0][14] 36 | VAL 37 | [0][k5][15] 38 | -------------------------------------------------------------------------------- /regtest/test_01_lib/test11.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | 3 | # vim:sw=2:ai 4 | 5 | # test for increment/decrement 6 | 7 | BEGIN { 8 | push @INC, "../common/"; 9 | }; 10 | 11 | use strict; 12 | use warnings; 13 | use hstest; 14 | 15 | my $dbh = hstest::init_testdb(); 16 | my $table = 'hstesttbl'; 17 | my $tablesize = 100; 18 | $dbh->do( 19 | "create table $table (k varchar(30) primary key, v varchar(30) not null) " . 20 | "engine = innodb"); 21 | srand(999); 22 | 23 | my %valmap = (); 24 | 25 | my $sth = $dbh->prepare("insert into $table values (?,?)"); 26 | for (my $i = 0; $i < $tablesize; ++$i) { 27 | my $k = "k" . $i; 28 | my $v = $i; 29 | $sth->execute($k, $v); 30 | $valmap{$k} = $v; 31 | } 32 | 33 | my $hs = hstest::get_hs_connection(undef, 9999); 34 | my $dbname = $hstest::conf{dbname}; 35 | $hs->open_index(1, $dbname, $table, '', 'k,v'); 36 | $hs->open_index(2, $dbname, $table, '', 'v'); 37 | 38 | exec_multi( 39 | "VAL", 40 | [ 1, '=', [ 'k5' ], 1, 0 ], 41 | [ 1, '=', [ 'k6' ], 1, 0 ], 42 | [ 1, '=', [ 'k7' ], 1, 0 ], 43 | [ 1, '=', [ 'k8' ], 1, 0 ], 44 | ); 45 | # 5, 6, 7, 8 46 | 47 | exec_multi( 48 | "INCREMENT", 49 | [ 2, '=', [ 'k5' ], 1, 0, '+', [ 3 ] ], 50 | [ 2, '=', [ 'k6' ], 1, 0, '+', [ 12 ] ], 51 | [ 2, '=', [ 'k7' ], 1, 0, '+', [ -11 ] ], 52 | [ 2, '=', [ 'k8' ], 1, 0, '+', [ -15 ] ], 53 | ); 54 | 55 | exec_multi( 56 | "VAL", 57 | [ 1, '=', [ 'k5' ], 1, 0 ], 58 | [ 1, '=', [ 'k6' ], 1, 0 ], 59 | [ 1, '=', [ 'k7' ], 1, 0 ], 60 | [ 1, '=', [ 'k8' ], 1, 0 ], 61 | ); 62 | # 8, 18, -4, -7 63 | 64 | exec_multi( 65 | "DECREMENT", 66 | [ 2, '=', [ 'k5' ], 1, 0, '-', [ 2 ] ], 67 | [ 2, '=', [ 'k6' ], 1, 0, '-', [ 24 ] ], 68 | [ 2, '=', [ 'k7' ], 1, 0, '-', [ 80 ] ], 69 | [ 2, '=', [ 'k8' ], 1, 0, '-', [ -80 ] ], 70 | ); 71 | # mod, no, mod, no 72 | 73 | exec_multi( 74 | "VAL", 75 | [ 1, '=', [ 'k5' ], 1, 0 ], 76 | [ 1, '=', [ 'k6' ], 1, 0 ], 77 | [ 1, '=', [ 'k7' ], 1, 0 ], 78 | [ 1, '=', [ 'k8' ], 1, 0 ], 79 | ); 80 | # 6, 18, -84, -7 81 | 82 | exec_multi( 83 | "INCREMENT", 84 | [ 2, '=', [ 'k5' ], 1, 0, '+?', [ 1 ] ], 85 | [ 2, '=', [ 'k5' ], 1, 0, '+?', [ 1 ] ], 86 | [ 2, '=', [ 'k5' ], 1, 0, '+?', [ 1 ] ], 87 | [ 2, '=', [ 'k5' ], 1, 0, '+?', [ 1 ] ], 88 | [ 2, '=', [ 'k5' ], 1, 0, '+?', [ 1 ] ], 89 | [ 2, '=', [ 'k5' ], 1, 0, '+?', [ 1 ] ], 90 | [ 2, '=', [ 'k5' ], 1, 0, '+?', [ 1 ] ], 91 | [ 2, '=', [ 'k5' ], 1, 0, '+?', [ 1 ] ], 92 | [ 2, '=', [ 'k5' ], 1, 0, '+?', [ 1 ] ], 93 | ); 94 | 95 | exec_multi( 96 | "VAL", 97 | [ 1, '=', [ 'k5' ], 1, 0 ], 98 | ); 99 | # 15 100 | 101 | sub exec_multi { 102 | my $mess = shift(@_); 103 | print "$mess\n"; 104 | my $mres = $hs->execute_multi(\@_); 105 | for my $res (@$mres) { 106 | for my $fld (@$res) { 107 | print "[$fld]"; 108 | } 109 | print "\n"; 110 | } 111 | } 112 | 113 | -------------------------------------------------------------------------------- /regtest/test_01_lib/test12.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | 3 | # vim:sw=2:ai 4 | 5 | # test for filters 6 | 7 | BEGIN { 8 | push @INC, "../common/"; 9 | }; 10 | 11 | use strict; 12 | use warnings; 13 | use hstest; 14 | 15 | my $dbh = hstest::init_testdb(); 16 | my $table = 'hstesttbl'; 17 | my $tablesize = 10; 18 | $dbh->do( 19 | "create table $table " . 20 | "(k1 varchar(30) not null, k2 varchar(30) not null, " . 21 | "v1 int not null, v2 int not null, " . 22 | "primary key (k1, k2) ) engine = innodb"); 23 | srand(999); 24 | 25 | my $sth = $dbh->prepare("insert into $table values (?,?,?,?)"); 26 | for (my $i = 0; $i < $tablesize; ++$i) { 27 | for (my $j = 0; $j < $tablesize; ++$j) { 28 | my $k1 = "k1_" . $i; 29 | my $k2 = "k2_" . $j; 30 | my $v1 = $i + $j; 31 | my $v2 = $i * $j; 32 | $sth->execute($k1, $k2, $v1, $v2); 33 | } 34 | } 35 | 36 | my $hs = hstest::get_hs_connection(undef, 9999); 37 | my $dbname = $hstest::conf{dbname}; 38 | $hs->open_index(1, $dbname, $table, '', 'k1,k2,v1,v2', 'k2'); 39 | $hs->open_index(2, $dbname, $table, '', 'k1,k2,v1,v2', 'k1,k2,v1,v2'); 40 | $hs->open_index(3, $dbname, $table, '', 'v1', 'k1,v2'); 41 | 42 | exec_multi( 43 | 4, "VAL", 44 | [ 1, '>=', [ '', '' ], 1000, 0 ], 45 | ); 46 | # all 47 | 48 | # select k1, k2, v1, v2 ... where (k1, k2) >= ('', '') and k2 = 'k2_5' 49 | exec_single( 50 | 4, "FILTER", 51 | [ 1, '>=', [ '', '' ], 1000, 0, undef, undef, [ [ 'F', '=', 0, 'k2_5' ] ] ] 52 | ); 53 | 54 | # same as above 55 | exec_multi( 56 | 4, "FILTER", 57 | [ 1, '>=', [ '', '' ], 1000, 0, undef, undef, [ [ 'F', '=', 0, 'k2_5' ] ] ], 58 | ); 59 | 60 | # select k1, k2, v1, v2 ... where (k1, k2) >= ('', '') and v1 = 3 61 | exec_multi( 62 | 4, "FILTER", 63 | [ 2, '>=', [ '', '' ], 1000, 0, undef, undef, [ [ 'F', '=', 2, 3 ] ] ], 64 | ); 65 | 66 | # select k1, k2, v1, v2 ... where (k1, k2) >= ('k1_1', '') and k1 <= 'k1_2' 67 | exec_multi( 68 | 4, "FILTER", 69 | [ 2, '>=', [ 'k1_1', '' ], 1000, 0, undef, undef, 70 | [ [ 'W', '<=', 0, 'k1_2' ] ] ], 71 | ); 72 | 73 | # select k1, k2, v1, v2 ... where (k1, k2) >= ('k1_1', '') and k1 <= 'k1_2' 74 | # and v2 >= 10 75 | exec_multi( 76 | 4, "FILTER", 77 | [ 2, '>=', [ 'k1_1', '' ], 1000, 0, undef, undef, 78 | [ [ 'W', '<=', 0, 'k1_2' ], [ 'F', '>=', 3, 10 ] ] ], 79 | ); 80 | 81 | # update ... set v2 = -1 where (k1, k2) >= ('k1_3', '') and v2 = 10 82 | exec_multi( 83 | 4, "FILTER", 84 | [ 3, '>=', [ 'k1_1', '' ], 1000, 0, 'U', [ -1 ], 85 | [ [ 'F', '=', 1, 10 ] ] ], 86 | ); 87 | 88 | exec_multi( 89 | 4, "VAL", 90 | [ 1, '>=', [ '', '' ], 1000, 0 ], 91 | ); 92 | # all 93 | 94 | exit 0; 95 | 96 | sub exec_single { 97 | my ($width, $mess, $req) = @_; 98 | print "$mess\n"; 99 | my $res = $hs->execute_single(@$req); 100 | { 101 | my $code = shift(@$res); 102 | print "code=$code\n"; 103 | my $i = 0; 104 | for my $fld (@$res) { 105 | print "[$fld]"; 106 | if (++$i >= $width) { 107 | print "\n"; 108 | $i = 0; 109 | } 110 | } 111 | print "\n"; 112 | } 113 | } 114 | 115 | sub exec_multi { 116 | my $width = shift(@_); 117 | my $mess = shift(@_); 118 | print "$mess\n"; 119 | my $mres = $hs->execute_multi(\@_); 120 | for my $res (@$mres) { 121 | my $code = shift(@$res); 122 | print "code=$code\n"; 123 | my $i = 0; 124 | for my $fld (@$res) { 125 | print "[$fld]"; 126 | if (++$i >= $width) { 127 | print "\n"; 128 | $i = 0; 129 | } 130 | } 131 | print "\n"; 132 | } 133 | } 134 | 135 | -------------------------------------------------------------------------------- /regtest/test_01_lib/test13.expected: -------------------------------------------------------------------------------- 1 | HSINSERT 2 | 11 v1hs_0 3 | 12 v1hs_1 4 | 13 v1hs_2 5 | 14 v1hs_3 6 | 15 v1hs_4 7 | 16 v1hs_5 8 | 17 v1hs_6 9 | 18 v1hs_7 10 | 19 v1hs_8 11 | 20 v1hs_9 12 | 21 v1hs3_0 13 | 22 v1hs3_0 14 | 23 v1hs3_0 15 | 24 v1hs3_1 16 | 25 v1hs3_1 17 | 26 v1hs3_1 18 | 27 v1hs3_2 19 | 28 v1hs3_2 20 | 29 v1hs3_2 21 | 30 v1hs3_3 22 | 31 v1hs3_3 23 | 32 v1hs3_3 24 | 33 v1hs3_4 25 | 34 v1hs3_4 26 | 35 v1hs3_4 27 | 36 v1hs3_5 28 | 37 v1hs3_5 29 | 38 v1hs3_5 30 | 39 v1hs3_6 31 | 40 v1hs3_6 32 | 41 v1hs3_6 33 | 42 v1hs3_7 34 | 43 v1hs3_7 35 | 44 v1hs3_7 36 | 45 v1hs3_8 37 | 46 v1hs3_8 38 | 47 v1hs3_8 39 | 48 v1hs3_9 40 | 49 v1hs3_9 41 | 50 v1hs3_9 42 | DUMP_TABLE 43 | 1 v1sql_0 v2sql_0 44 | 2 v1sql_1 v2sql_1 45 | 3 v1sql_2 v2sql_2 46 | 4 v1sql_3 v2sql_3 47 | 5 v1sql_4 v2sql_4 48 | 6 v1sql_5 v2sql_5 49 | 7 v1sql_6 v2sql_6 50 | 8 v1sql_7 v2sql_7 51 | 9 v1sql_8 v2sql_8 52 | 10 v1sql_9 v2sql_9 53 | 11 v1hs_0 v2hs_0 54 | 12 v1hs_1 v2hs_1 55 | 13 v1hs_2 v2hs_2 56 | 14 v1hs_3 v2hs_3 57 | 15 v1hs_4 v2hs_4 58 | 16 v1hs_5 v2hs_5 59 | 17 v1hs_6 v2hs_6 60 | 18 v1hs_7 v2hs_7 61 | 19 v1hs_8 v2hs_8 62 | 20 v1hs_9 v2hs_9 63 | 21 v1hs3_0 v2hs3_0 64 | 22 v1hs3_0 v2hs3_0 65 | 23 v1hs3_0 v2hs3_0 66 | 24 v1hs3_1 v2hs3_1 67 | 25 v1hs3_1 v2hs3_1 68 | 26 v1hs3_1 v2hs3_1 69 | 27 v1hs3_2 v2hs3_2 70 | 28 v1hs3_2 v2hs3_2 71 | 29 v1hs3_2 v2hs3_2 72 | 30 v1hs3_3 v2hs3_3 73 | 31 v1hs3_3 v2hs3_3 74 | 32 v1hs3_3 v2hs3_3 75 | 33 v1hs3_4 v2hs3_4 76 | 34 v1hs3_4 v2hs3_4 77 | 35 v1hs3_4 v2hs3_4 78 | 36 v1hs3_5 v2hs3_5 79 | 37 v1hs3_5 v2hs3_5 80 | 38 v1hs3_5 v2hs3_5 81 | 39 v1hs3_6 v2hs3_6 82 | 40 v1hs3_6 v2hs3_6 83 | 41 v1hs3_6 v2hs3_6 84 | 42 v1hs3_7 v2hs3_7 85 | 43 v1hs3_7 v2hs3_7 86 | 44 v1hs3_7 v2hs3_7 87 | 45 v1hs3_8 v2hs3_8 88 | 46 v1hs3_8 v2hs3_8 89 | 47 v1hs3_8 v2hs3_8 90 | 48 v1hs3_9 v2hs3_9 91 | 49 v1hs3_9 v2hs3_9 92 | 50 v1hs3_9 v2hs3_9 93 | -------------------------------------------------------------------------------- /regtest/test_01_lib/test13.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | 3 | # vim:sw=2:ai 4 | 5 | # test for auto_increment 6 | 7 | BEGIN { 8 | push @INC, "../common/"; 9 | }; 10 | 11 | use strict; 12 | use warnings; 13 | use hstest; 14 | 15 | my $dbh = hstest::init_testdb(); 16 | my $table = 'hstesttbl'; 17 | my $tablesize = 10; 18 | $dbh->do( 19 | "create table $table (" . 20 | "k int primary key auto_increment, " . 21 | "v1 varchar(30), " . 22 | "v2 varchar(30)) " . 23 | "engine = myisam default charset = binary"); 24 | srand(999); 25 | 26 | my $sth = $dbh->prepare("insert into $table values (?,?,?)"); 27 | for (my $i = 0; $i < $tablesize; ++$i) { 28 | my $k = 0; 29 | my $v1 = "v1sql_" . $i; 30 | my $v2 = "v2sql_" . $i; 31 | $sth->execute($k, $v1, $v2); 32 | } 33 | 34 | my %valmap = (); 35 | 36 | print "HSINSERT\n"; 37 | my $hs = hstest::get_hs_connection(undef, 9999); 38 | my $dbname = $hstest::conf{dbname}; 39 | $hs->open_index(1, $dbname, $table, '', 'k,v1,v2'); 40 | # inserts with auto_increment 41 | for (my $i = 0; $i < $tablesize; ++$i) { 42 | my $k = 0; 43 | my $v1 = "v1hs_" . $i; 44 | my $v2 = "v2hs_" . $i; 45 | my $r = $hs->execute_insert(1, [ $k, $v1, $v2 ]); 46 | my $err = $r->[0]; 47 | if ($err != 0) { 48 | my $err_str = $r->[1]; 49 | print "$err $err_str\n"; 50 | } else { 51 | my $id = $r->[1]; 52 | print "$id $v1\n"; 53 | } 54 | } 55 | # make sure that it works even when inserts are pipelined. these requests 56 | # are possibly executed in a single transaction. 57 | for (my $i = 0; $i < $tablesize; ++$i) { 58 | my $k = 0; 59 | my $v1 = "v1hs3_" . $i; 60 | my $v2 = "v2hs3_" . $i; 61 | my $r = $hs->execute_multi([ 62 | [ 1, '+', [$k, $v1, $v2] ], 63 | [ 1, '+', [$k, $v1, $v2] ], 64 | [ 1, '+', [$k, $v1, $v2] ], 65 | ]); 66 | for (my $i = 0; $i < 3; ++$i) { 67 | my $err = $r->[$i]->[0]; 68 | if ($err != 0) { 69 | my $err_str = $r->[$i]->[1]; 70 | print "$err $err_str\n"; 71 | } else { 72 | my $id = $r->[$i]->[1]; 73 | print "$id $v1\n"; 74 | } 75 | } 76 | } 77 | undef $hs; 78 | 79 | dump_table(); 80 | 81 | sub dump_table { 82 | print "DUMP_TABLE\n"; 83 | my $aref = $dbh->selectall_arrayref("select k,v1,v2 from $table order by k"); 84 | for my $row (@$aref) { 85 | my ($k, $v1, $v2) = @$row; 86 | $v1 = "[null]" if !defined($v1); 87 | $v2 = "[null]" if !defined($v2); 88 | print "$k $v1 $v2\n"; 89 | # print "MISMATCH\n" if ($valmap{$k} ne $v); 90 | } 91 | } 92 | 93 | -------------------------------------------------------------------------------- /regtest/test_01_lib/test14.expected: -------------------------------------------------------------------------------- 1 | DUMP_TABLE 2 | 0 3 | 1 0 A 4 | 2 01 AB 5 | 3 012 ABC 6 | 4 0123 ABCD 7 | 5 01234 ABCDE 8 | 6 012345 ABCDEF 9 | 7 0123456 ABCDEFG 10 | 8 01234567 ABCDEFGH 11 | 9 012345678 ABCDEFGHI 12 | 10 0123456789 ABCDEFGHIJ 13 | 11 01234567890 ABCDEFGHIJA 14 | 12 012345678901 ABCDEFGHIJAB 15 | 13 0123456789012 ABCDEFGHIJABC 16 | 14 01234567890123 ABCDEFGHIJABCD 17 | 15 012345678901234 ABCDEFGHIJABCDE 18 | 16 0123456789012345 ABCDEFGHIJABCDEF 19 | 17 01234567890123456 ABCDEFGHIJABCDEFG 20 | 18 012345678901234567 ABCDEFGHIJABCDEFGH 21 | 19 0123456789012345678 ABCDEFGHIJABCDEFGHI 22 | 20 01234567890123456789 ABCDEFGHIJABCDEFGHIJ 23 | 21 012345678901234567890 ABCDEFGHIJABCDEFGHIJA 24 | 22 0123456789012345678901 ABCDEFGHIJABCDEFGHIJAB 25 | 23 01234567890123456789012 ABCDEFGHIJABCDEFGHIJABC 26 | 24 012345678901234567890123 ABCDEFGHIJABCDEFGHIJABCD 27 | 25 0123456789012345678901234 ABCDEFGHIJABCDEFGHIJABCDE 28 | 26 01234567890123456789012345 ABCDEFGHIJABCDEFGHIJABCDEF 29 | 27 012345678901234567890123456 ABCDEFGHIJABCDEFGHIJABCDEFG 30 | 28 0123456789012345678901234567 ABCDEFGHIJABCDEFGHIJABCDEFGH 31 | 29 01234567890123456789012345678 ABCDEFGHIJABCDEFGHIJABCDEFGHI 32 | 30 012345678901234567890123456789 ABCDEFGHIJABCDEFGHIJABCDEFGHIJ 33 | 31 012345678901234567890123456789 ABCDEFGHIJABCDEFGHIJABCDEFGHIJ 34 | 32 012345678901234567890123456789 ABCDEFGHIJABCDEFGHIJABCDEFGHIJ 35 | 33 012345678901234567890123456789 ABCDEFGHIJABCDEFGHIJABCDEFGHIJ 36 | 34 012345678901234567890123456789 ABCDEFGHIJABCDEFGHIJABCDEFGHIJ 37 | 35 012345678901234567890123456789 ABCDEFGHIJABCDEFGHIJABCDEFGHIJ 38 | 36 012345678901234567890123456789 ABCDEFGHIJABCDEFGHIJABCDEFGHIJ 39 | 37 012345678901234567890123456789 ABCDEFGHIJABCDEFGHIJABCDEFGHIJ 40 | 38 012345678901234567890123456789 ABCDEFGHIJABCDEFGHIJABCDEFGHIJ 41 | 39 012345678901234567890123456789 ABCDEFGHIJABCDEFGHIJABCDEFGHIJ 42 | 40 012345678901234567890123456789 ABCDEFGHIJABCDEFGHIJABCDEFGHIJ 43 | 41 012345678901234567890123456789 ABCDEFGHIJABCDEFGHIJABCDEFGHIJ 44 | 42 012345678901234567890123456789 ABCDEFGHIJABCDEFGHIJABCDEFGHIJ 45 | 43 012345678901234567890123456789 ABCDEFGHIJABCDEFGHIJABCDEFGHIJ 46 | 44 012345678901234567890123456789 ABCDEFGHIJABCDEFGHIJABCDEFGHIJ 47 | 45 012345678901234567890123456789 ABCDEFGHIJABCDEFGHIJABCDEFGHIJ 48 | 46 012345678901234567890123456789 ABCDEFGHIJABCDEFGHIJABCDEFGHIJ 49 | 47 012345678901234567890123456789 ABCDEFGHIJABCDEFGHIJABCDEFGHIJ 50 | 48 012345678901234567890123456789 ABCDEFGHIJABCDEFGHIJABCDEFGHIJ 51 | 49 012345678901234567890123456789 ABCDEFGHIJABCDEFGHIJABCDEFGHIJ 52 | PK 0 53 | I1 0 54 | I2 0 55 | PK 1 0 A 56 | I1 1 0 A 57 | I2 1 0 A 58 | PK 2 01 AB 59 | I1 2 01 AB 60 | I2 2 01 AB 61 | PK 3 012 ABC 62 | I1 3 012 ABC 63 | I2 3 012 ABC 64 | PK 4 0123 ABCD 65 | I1 4 0123 ABCD 66 | I2 4 0123 ABCD 67 | PK 5 01234 ABCDE 68 | I1 5 01234 ABCDE 69 | I2 5 01234 ABCDE 70 | PK 6 012345 ABCDEF 71 | I1 6 012345 ABCDEF 72 | I2 6 012345 ABCDEF 73 | PK 7 0123456 ABCDEFG 74 | I1 7 0123456 ABCDEFG 75 | I2 7 0123456 ABCDEFG 76 | PK 8 01234567 ABCDEFGH 77 | I1 8 01234567 ABCDEFGH 78 | I2 8 01234567 ABCDEFGH 79 | PK 9 012345678 ABCDEFGHI 80 | I1 9 012345678 ABCDEFGHI 81 | I2 9 012345678 ABCDEFGHI 82 | PK 10 0123456789 ABCDEFGHIJ 83 | I1 10 0123456789 ABCDEFGHIJ 84 | I2 10 0123456789 ABCDEFGHIJ 85 | PK 11 01234567890 ABCDEFGHIJA 86 | I1 11 01234567890 ABCDEFGHIJA 87 | I2 11 01234567890 ABCDEFGHIJA 88 | PK 12 012345678901 ABCDEFGHIJAB 89 | I1 12 012345678901 ABCDEFGHIJAB 90 | I2 12 012345678901 ABCDEFGHIJAB 91 | PK 13 0123456789012 ABCDEFGHIJABC 92 | I1 13 0123456789012 ABCDEFGHIJABC 93 | I2 13 0123456789012 ABCDEFGHIJABC 94 | PK 14 01234567890123 ABCDEFGHIJABCD 95 | I1 14 01234567890123 ABCDEFGHIJABCD 96 | I2 14 01234567890123 ABCDEFGHIJABCD 97 | PK 15 012345678901234 ABCDEFGHIJABCDE 98 | I1 15 012345678901234 ABCDEFGHIJABCDE 99 | I2 15 012345678901234 ABCDEFGHIJABCDE 100 | PK 16 0123456789012345 ABCDEFGHIJABCDEF 101 | I1 16 0123456789012345 ABCDEFGHIJABCDEF 102 | I2 16 0123456789012345 ABCDEFGHIJABCDEF 103 | PK 17 01234567890123456 ABCDEFGHIJABCDEFG 104 | I1 17 01234567890123456 ABCDEFGHIJABCDEFG 105 | I2 17 01234567890123456 ABCDEFGHIJABCDEFG 106 | PK 18 012345678901234567 ABCDEFGHIJABCDEFGH 107 | I1 18 012345678901234567 ABCDEFGHIJABCDEFGH 108 | I2 18 012345678901234567 ABCDEFGHIJABCDEFGH 109 | PK 19 0123456789012345678 ABCDEFGHIJABCDEFGHI 110 | I1 19 0123456789012345678 ABCDEFGHIJABCDEFGHI 111 | I2 19 0123456789012345678 ABCDEFGHIJABCDEFGHI 112 | PK 20 01234567890123456789 ABCDEFGHIJABCDEFGHIJ 113 | I1 20 01234567890123456789 ABCDEFGHIJABCDEFGHIJ 114 | I2 20 01234567890123456789 ABCDEFGHIJABCDEFGHIJ 115 | PK 21 012345678901234567890 ABCDEFGHIJABCDEFGHIJA 116 | I1 21 012345678901234567890 ABCDEFGHIJABCDEFGHIJA 117 | I2 21 012345678901234567890 ABCDEFGHIJABCDEFGHIJA 118 | PK 22 0123456789012345678901 ABCDEFGHIJABCDEFGHIJAB 119 | I1 22 0123456789012345678901 ABCDEFGHIJABCDEFGHIJAB 120 | I2 22 0123456789012345678901 ABCDEFGHIJABCDEFGHIJAB 121 | PK 23 01234567890123456789012 ABCDEFGHIJABCDEFGHIJABC 122 | I1 23 01234567890123456789012 ABCDEFGHIJABCDEFGHIJABC 123 | I2 23 01234567890123456789012 ABCDEFGHIJABCDEFGHIJABC 124 | PK 24 012345678901234567890123 ABCDEFGHIJABCDEFGHIJABCD 125 | I1 24 012345678901234567890123 ABCDEFGHIJABCDEFGHIJABCD 126 | I2 24 012345678901234567890123 ABCDEFGHIJABCDEFGHIJABCD 127 | PK 25 0123456789012345678901234 ABCDEFGHIJABCDEFGHIJABCDE 128 | I1 25 0123456789012345678901234 ABCDEFGHIJABCDEFGHIJABCDE 129 | I2 25 0123456789012345678901234 ABCDEFGHIJABCDEFGHIJABCDE 130 | PK 26 01234567890123456789012345 ABCDEFGHIJABCDEFGHIJABCDEF 131 | I1 26 01234567890123456789012345 ABCDEFGHIJABCDEFGHIJABCDEF 132 | I2 26 01234567890123456789012345 ABCDEFGHIJABCDEFGHIJABCDEF 133 | PK 27 012345678901234567890123456 ABCDEFGHIJABCDEFGHIJABCDEFG 134 | I1 27 012345678901234567890123456 ABCDEFGHIJABCDEFGHIJABCDEFG 135 | I2 27 012345678901234567890123456 ABCDEFGHIJABCDEFGHIJABCDEFG 136 | PK 28 0123456789012345678901234567 ABCDEFGHIJABCDEFGHIJABCDEFGH 137 | I1 28 0123456789012345678901234567 ABCDEFGHIJABCDEFGHIJABCDEFGH 138 | I2 28 0123456789012345678901234567 ABCDEFGHIJABCDEFGHIJABCDEFGH 139 | PK 29 01234567890123456789012345678 ABCDEFGHIJABCDEFGHIJABCDEFGHI 140 | I1 29 01234567890123456789012345678 ABCDEFGHIJABCDEFGHIJABCDEFGHI 141 | I2 29 01234567890123456789012345678 ABCDEFGHIJABCDEFGHIJABCDEFGHI 142 | PK 30 012345678901234567890123456789 ABCDEFGHIJABCDEFGHIJABCDEFGHIJ 143 | I1 30 012345678901234567890123456789 ABCDEFGHIJABCDEFGHIJABCDEFGHIJ 144 | I2 30 012345678901234567890123456789 ABCDEFGHIJABCDEFGHIJABCDEFGHIJ 145 | -------------------------------------------------------------------------------- /regtest/test_01_lib/test14.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | 3 | # vim:sw=2:ai 4 | 5 | # test for bugfix: commit/c88efe637f6a184b55d2bd8d060bda3e556572d8 6 | # (some trailing bytes were dropped for varlen or nullable key fields) 7 | 8 | BEGIN { 9 | push @INC, "../common/"; 10 | }; 11 | 12 | use strict; 13 | use warnings; 14 | use hstest; 15 | 16 | my $dbh = hstest::init_testdb(); 17 | my $table = 'hstesttbl'; 18 | my $tablesize = 50; 19 | $dbh->do( 20 | "create table $table (" . 21 | "k int primary key, " . 22 | "v1 varchar(30), " . 23 | "v2 varchar(30), " . 24 | "index i1(v1), index i2(v2, v1)) " . 25 | "engine = myisam default charset = binary"); 26 | srand(999); 27 | 28 | my %valmap = (); 29 | 30 | my $sth = $dbh->prepare("insert ignore into $table values (?,?,?)"); 31 | for (my $i = 0; $i < $tablesize; ++$i) { 32 | my $k = $i; 33 | my ($s1, $s2) = ("", ""); 34 | for (my $j = 0; $j < $i; ++$j) { 35 | $s1 .= chr(48 + $j % 10); 36 | $s2 .= chr(65 + $j % 10); 37 | } 38 | my $v1 = $s1; 39 | my $v2 = $s2; 40 | $sth->execute($k, $v1, $v2); 41 | $valmap{$k} = [ $v1, $v2 ]; 42 | } 43 | 44 | dump_table(); 45 | 46 | my $hs = hstest::get_hs_connection(undef, 9999); 47 | my $dbname = $hstest::conf{dbname}; 48 | $hs->open_index(1, $dbname, $table, '', 'k,v1,v2'); 49 | $hs->open_index(2, $dbname, $table, 'i1', 'k,v1,v2'); 50 | $hs->open_index(3, $dbname, $table, 'i2', 'k,v1,v2'); 51 | 52 | for (my $i = 0; $i <= 30; ++$i) { 53 | my ($v1, $v2) = @{$valmap{$i}}; 54 | my ($rk, $rv1, $rv2); 55 | my $r = $hs->execute_single(1, '=', [ $i ], 1, 0); 56 | shift(@$r); 57 | ($rk, $rv1, $rv2) = @$r; 58 | print "PK $rk $rv1 $rv2\n"; 59 | $r = $hs->execute_single(2, '=', [ $v1 ], 1, 0); 60 | shift(@$r); 61 | ($rk, $rv1, $rv2) = @$r; 62 | print "I1 $rk $rv1 $rv2\n"; 63 | $r = $hs->execute_single(3, '=', [ $v2, $v1 ], 1, 0); 64 | shift(@$r); 65 | ($rk, $rv1, $rv2) = @$r; 66 | print "I2 $rk $rv1 $rv2\n"; 67 | } 68 | 69 | sub dump_table { 70 | print "DUMP_TABLE\n"; 71 | my $aref = $dbh->selectall_arrayref("select k,v1,v2 from $table order by k"); 72 | for my $row (@$aref) { 73 | my ($k, $v1, $v2) = @$row; 74 | $v1 = "[null]" if !defined($v1); 75 | $v2 = "[null]" if !defined($v2); 76 | print "$k $v1 $v2\n"; 77 | # print "MISMATCH\n" if ($valmap{$k} ne $v); 78 | } 79 | } 80 | 81 | -------------------------------------------------------------------------------- /regtest/test_01_lib/test15.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | 3 | # vim:sw=2:ai 4 | 5 | # test for various numeric types 6 | 7 | BEGIN { 8 | push @INC, "../common/"; 9 | }; 10 | 11 | use strict; 12 | use warnings; 13 | use bigint; 14 | use hstest; 15 | 16 | my $numeric_types = [ 17 | [ 'TINYINT', -128, 127 ], 18 | [ 'TINYINT UNSIGNED', 0, 255 ], 19 | [ 'SMALLINT', -32768, 32768 ], 20 | [ 'SMALLINT UNSIGNED', 0, 65535 ], 21 | [ 'MEDIUMINT', -8388608, 8388607 ], 22 | [ 'MEDIUMINT UNSIGNED', 0, 16777215 ], 23 | [ 'INT', -2147483648, 2147483647 ], 24 | [ 'INT UNSIGNED', 0, 4294967295 ], 25 | [ 'BIGINT', -9223372036854775808, 9223372036854775807 ], 26 | [ 'BIGINT UNSIGNED', 0, 18446744073709551615 ], 27 | [ 'FLOAT', -32768, 32768 ], 28 | [ 'DOUBLE', -2147483648, 2147483647 ], 29 | ]; 30 | 31 | my $table = 'hstesttbl'; 32 | my $dbh; 33 | for my $rec (@$numeric_types) { 34 | my ($typ, $minval, $maxval) = @$rec; 35 | my @vals = (); 36 | push(@vals, 0); 37 | push(@vals, 1); 38 | push(@vals, $maxval); 39 | if ($minval != 0) { 40 | push(@vals, -1); 41 | push(@vals, $minval); 42 | } 43 | my $v1 = $minval; 44 | my $v2 = $maxval; 45 | for (my $i = 0; $i < 5; ++$i) { 46 | $v1 /= 3; 47 | $v2 /= 3; 48 | if ($v1 != 0) { 49 | push(@vals, int($v1)); 50 | } 51 | push(@vals, int($v2)); 52 | } 53 | @vals = sort { $a <=> $b } @vals; 54 | print("TYPE $typ\n"); 55 | test_one($typ, \@vals); 56 | print("\n"); 57 | } 58 | 59 | sub test_one { 60 | my ($typ, $values) = @_; 61 | $dbh = hstest::init_testdb(); 62 | $dbh->do( 63 | "create table $table (" . 64 | "k $typ primary key, " . 65 | "v1 varchar(512), " . 66 | "v2 $typ, " . 67 | "index i1(v1), index i2(v2, v1)) " . 68 | "engine = myisam default charset = binary"); 69 | my $hs = hstest::get_hs_connection(undef, 9999); 70 | my $dbname = $hstest::conf{dbname}; 71 | $hs->open_index(1, $dbname, $table, '', 'k,v1,v2'); 72 | $hs->open_index(2, $dbname, $table, 'i1', 'k,v1,v2'); 73 | $hs->open_index(3, $dbname, $table, 'i2', 'k,v1,v2'); 74 | for my $k (@$values) { 75 | my $kstr = 's' . $k; 76 | $hs->execute_single(1, '+', [ $k, $kstr, $k ], 0, 0); 77 | } 78 | dump_table(); 79 | for my $k (@$values) { 80 | my $kstr = 's' . $k; 81 | my ($rk, $rv1, $rv2); 82 | my $r; 83 | $r = $hs->execute_single(1, '=', [ $k ], 1, 0); 84 | shift(@$r); 85 | ($rk, $rv1, $rv2) = @$r; 86 | print "PK[$k] $rk $rv1 $rv2\n"; 87 | $r = $hs->execute_single(2, '=', [ $kstr ], 1, 0); 88 | shift(@$r); 89 | ($rk, $rv1, $rv2) = @$r; 90 | print "I1[$kstr] $rk $rv1 $rv2\n"; 91 | $r = $hs->execute_single(3, '=', [ $k, $kstr ], 1, 0); 92 | shift(@$r); 93 | ($rk, $rv1, $rv2) = @$r; 94 | print "I2[$k, $kstr] $rk $rv1 $rv2\n"; 95 | $r = $hs->execute_single(3, '=', [ $k ], 1, 0); 96 | shift(@$r); 97 | ($rk, $rv1, $rv2) = @$r; 98 | print "I2p[$k] $rk $rv1 $rv2\n"; 99 | } 100 | } 101 | 102 | sub dump_table { 103 | print "DUMP_TABLE_BEGIN\n"; 104 | my $aref = $dbh->selectall_arrayref("select k,v1,v2 from $table order by k"); 105 | for my $row (@$aref) { 106 | my ($k, $v1, $v2) = @$row; 107 | $v1 = "[null]" if !defined($v1); 108 | $v2 = "[null]" if !defined($v2); 109 | print "$k $v1 $v2\n"; 110 | # print "MISMATCH\n" if ($valmap{$k} ne $v); 111 | } 112 | print "DUMP_TABLE_END\n"; 113 | } 114 | 115 | -------------------------------------------------------------------------------- /regtest/test_01_lib/test16.expected: -------------------------------------------------------------------------------- 1 | TYPE DATE 2 | DUMP_TABLE_BEGIN 3 | 0000-00-00 s0000-00-00 0000-00-00 4 | 2011-01-01 s2011-01-01 2011-01-01 5 | 9999-12-31 s9999-12-31 9999-12-31 6 | DUMP_TABLE_END 7 | PK[0000-00-00] 0000-00-00 s0000-00-00 0000-00-00 8 | I1[s0000-00-00] 0000-00-00 s0000-00-00 0000-00-00 9 | I2[0000-00-00, s0000-00-00] 0000-00-00 s0000-00-00 0000-00-00 10 | I2p[0000-00-00] 0000-00-00 s0000-00-00 0000-00-00 11 | PK[2011-01-01] 2011-01-01 s2011-01-01 2011-01-01 12 | I1[s2011-01-01] 2011-01-01 s2011-01-01 2011-01-01 13 | I2[2011-01-01, s2011-01-01] 2011-01-01 s2011-01-01 2011-01-01 14 | I2p[2011-01-01] 2011-01-01 s2011-01-01 2011-01-01 15 | PK[9999-12-31] 9999-12-31 s9999-12-31 9999-12-31 16 | I1[s9999-12-31] 9999-12-31 s9999-12-31 9999-12-31 17 | I2[9999-12-31, s9999-12-31] 9999-12-31 s9999-12-31 9999-12-31 18 | I2p[9999-12-31] 9999-12-31 s9999-12-31 9999-12-31 19 | 20 | TYPE DATETIME 21 | DUMP_TABLE_BEGIN 22 | 0000-00-00 00:00:00 s0 0000-00-00 00:00:00 23 | 2011-01-01 18:30:25 s2011-01-01 18:30:25 2011-01-01 18:30:25 24 | DUMP_TABLE_END 25 | PK[0] 0000-00-00 00:00:00 s0 0000-00-00 00:00:00 26 | I1[s0] 0000-00-00 00:00:00 s0 0000-00-00 00:00:00 27 | I2[0, s0] 0000-00-00 00:00:00 s0 0000-00-00 00:00:00 28 | I2p[0] 0000-00-00 00:00:00 s0 0000-00-00 00:00:00 29 | PK[2011-01-01 18:30:25] 2011-01-01 18:30:25 s2011-01-01 18:30:25 2011-01-01 18:30:25 30 | I1[s2011-01-01 18:30:25] 2011-01-01 18:30:25 s2011-01-01 18:30:25 2011-01-01 18:30:25 31 | I2[2011-01-01 18:30:25, s2011-01-01 18:30:25] 2011-01-01 18:30:25 s2011-01-01 18:30:25 2011-01-01 18:30:25 32 | I2p[2011-01-01 18:30:25] 2011-01-01 18:30:25 s2011-01-01 18:30:25 2011-01-01 18:30:25 33 | 34 | TYPE TIME 35 | DUMP_TABLE_BEGIN 36 | 00:00:00 s0 00:00:00 37 | 18:30:25 s18:30:25 18:30:25 38 | DUMP_TABLE_END 39 | PK[0] 00:00:00 s0 00:00:00 40 | I1[s0] 00:00:00 s0 00:00:00 41 | I2[0, s0] 00:00:00 s0 00:00:00 42 | I2p[0] 00:00:00 s0 00:00:00 43 | PK[18:30:25] 18:30:25 s18:30:25 18:30:25 44 | I1[s18:30:25] 18:30:25 s18:30:25 18:30:25 45 | I2[18:30:25, s18:30:25] 18:30:25 s18:30:25 18:30:25 46 | I2p[18:30:25] 18:30:25 s18:30:25 18:30:25 47 | 48 | TYPE YEAR(4) 49 | DUMP_TABLE_BEGIN 50 | 1901 s1901 1901 51 | 2011 s2011 2011 52 | 2155 s2155 2155 53 | DUMP_TABLE_END 54 | PK[1901] 1901 s1901 1901 55 | I1[s1901] 1901 s1901 1901 56 | I2[1901, s1901] 1901 s1901 1901 57 | I2p[1901] 1901 s1901 1901 58 | PK[2011] 2011 s2011 2011 59 | I1[s2011] 2011 s2011 2011 60 | I2[2011, s2011] 2011 s2011 2011 61 | I2p[2011] 2011 s2011 2011 62 | PK[2155] 2155 s2155 2155 63 | I1[s2155] 2155 s2155 2155 64 | I2[2155, s2155] 2155 s2155 2155 65 | I2p[2155] 2155 s2155 2155 66 | 67 | -------------------------------------------------------------------------------- /regtest/test_01_lib/test16.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | 3 | # vim:sw=2:ai 4 | 5 | # test for date/datetime types 6 | 7 | BEGIN { 8 | push @INC, "../common/"; 9 | }; 10 | 11 | use strict; 12 | use warnings; 13 | use bigint; 14 | use hstest; 15 | 16 | my $datetime_types = [ 17 | [ 'DATE', '0000-00-00', '2011-01-01', '9999-12-31' ], 18 | [ 'DATETIME', 0, '2011-01-01 18:30:25' ], 19 | [ 'TIME', 0, '18:30:25' ], 20 | [ 'YEAR(4)', 1901, 2011, 2155 ], 21 | # [ 'TIMESTAMP', 0, 999999999 ], # DOES NOT WORK YET 22 | ]; 23 | 24 | my $table = 'hstesttbl'; 25 | my $dbh; 26 | for my $rec (@$datetime_types) { 27 | my ($typ, @vals) = @$rec; 28 | print("TYPE $typ\n"); 29 | test_one($typ, \@vals); 30 | print("\n"); 31 | } 32 | 33 | sub test_one { 34 | my ($typ, $values) = @_; 35 | $dbh = hstest::init_testdb(); 36 | $dbh->do( 37 | "create table $table (" . 38 | "k $typ primary key, " . 39 | "v1 varchar(512), " . 40 | "v2 $typ, " . 41 | "index i1(v1), index i2(v2, v1)) " . 42 | "engine = myisam default charset = binary"); 43 | my $hs = hstest::get_hs_connection(undef, 9999); 44 | my $dbname = $hstest::conf{dbname}; 45 | $hs->open_index(1, $dbname, $table, '', 'k,v1,v2'); 46 | $hs->open_index(2, $dbname, $table, 'i1', 'k,v1,v2'); 47 | $hs->open_index(3, $dbname, $table, 'i2', 'k,v1,v2'); 48 | for my $k (@$values) { 49 | my $kstr = 's' . $k; 50 | $hs->execute_single(1, '+', [ $k, $kstr, $k ], 0, 0); 51 | } 52 | dump_table(); 53 | for my $k (@$values) { 54 | my $kstr = 's' . $k; 55 | my ($rk, $rv1, $rv2); 56 | my $r; 57 | $r = $hs->execute_single(1, '=', [ $k ], 1, 0); 58 | shift(@$r); 59 | ($rk, $rv1, $rv2) = @$r; 60 | print "PK[$k] $rk $rv1 $rv2\n"; 61 | $r = $hs->execute_single(2, '=', [ $kstr ], 1, 0); 62 | shift(@$r); 63 | ($rk, $rv1, $rv2) = @$r; 64 | print "I1[$kstr] $rk $rv1 $rv2\n"; 65 | $r = $hs->execute_single(3, '=', [ $k, $kstr ], 1, 0); 66 | shift(@$r); 67 | ($rk, $rv1, $rv2) = @$r; 68 | print "I2[$k, $kstr] $rk $rv1 $rv2\n"; 69 | $r = $hs->execute_single(3, '=', [ $k ], 1, 0); 70 | shift(@$r); 71 | ($rk, $rv1, $rv2) = @$r; 72 | print "I2p[$k] $rk $rv1 $rv2\n"; 73 | } 74 | } 75 | 76 | sub dump_table { 77 | print "DUMP_TABLE_BEGIN\n"; 78 | my $aref = $dbh->selectall_arrayref("select k,v1,v2 from $table order by k"); 79 | for my $row (@$aref) { 80 | my ($k, $v1, $v2) = @$row; 81 | $v1 = "[null]" if !defined($v1); 82 | $v2 = "[null]" if !defined($v2); 83 | print "$k $v1 $v2\n"; 84 | # print "MISMATCH\n" if ($valmap{$k} ne $v); 85 | } 86 | print "DUMP_TABLE_END\n"; 87 | } 88 | 89 | -------------------------------------------------------------------------------- /regtest/test_01_lib/test17.expected: -------------------------------------------------------------------------------- 1 | TYPE CHAR(10) 2 | CHAR(10):PK: EQ 3 | CHAR(10):I1: EQ 4 | CHAR(10):I2: EQ 5 | CHAR(10):I2p: EQ 6 | CHAR(10):PK: EQ 7 | CHAR(10):I1: EQ 8 | CHAR(10):I2: EQ 9 | CHAR(10):I2p: EQ 10 | CHAR(10):PK: EQ 11 | CHAR(10):I1: EQ 12 | CHAR(10):I2: EQ 13 | CHAR(10):I2p: EQ 14 | CHAR(10):PK: EQ 15 | CHAR(10):I1: EQ 16 | CHAR(10):I2: EQ 17 | CHAR(10):I2p: EQ 18 | 19 | TYPE VARCHAR(10) 20 | VARCHAR(10):PK: EQ 21 | VARCHAR(10):I1: EQ 22 | VARCHAR(10):I2: EQ 23 | VARCHAR(10):I2p: EQ 24 | VARCHAR(10):PK: EQ 25 | VARCHAR(10):I1: EQ 26 | VARCHAR(10):I2: EQ 27 | VARCHAR(10):I2p: EQ 28 | VARCHAR(10):PK: EQ 29 | VARCHAR(10):I1: EQ 30 | VARCHAR(10):I2: EQ 31 | VARCHAR(10):I2p: EQ 32 | VARCHAR(10):PK: EQ 33 | VARCHAR(10):I1: EQ 34 | VARCHAR(10):I2: EQ 35 | VARCHAR(10):I2p: EQ 36 | 37 | TYPE BINARY(10) 38 | BINARY(10):PK: V1 NE 39 | B 40 | sB 41 | BINARY(10):I1: V1 NE 42 | B 43 | sB 44 | BINARY(10):I2: V1 NE 45 | B 46 | sB 47 | BINARY(10):I2p: V1 NE 48 | B 49 | sB 50 | BINARY(10):PK: V1 NE 51 | BG 52 | sBG 53 | BINARY(10):I1: V1 NE 54 | BG 55 | sBG 56 | BINARY(10):I2: V1 NE 57 | BG 58 | sBG 59 | BINARY(10):I2p: V1 NE 60 | BG 61 | sBG 62 | BINARY(10):PK: V1 NE 63 | BGIJH 64 | sBGIJH 65 | BINARY(10):I1: V1 NE 66 | BGIJH 67 | sBGIJH 68 | BINARY(10):I2: V1 NE 69 | BGIJH 70 | sBGIJH 71 | BINARY(10):I2p: V1 NE 72 | BGIJH 73 | sBGIJH 74 | BINARY(10):PK: EQ 75 | BINARY(10):I1: EQ 76 | BINARY(10):I2: EQ 77 | BINARY(10):I2p: EQ 78 | 79 | TYPE VARBINARY(10) 80 | VARBINARY(10):PK: EQ 81 | VARBINARY(10):I1: EQ 82 | VARBINARY(10):I2: EQ 83 | VARBINARY(10):I2p: EQ 84 | VARBINARY(10):PK: EQ 85 | VARBINARY(10):I1: EQ 86 | VARBINARY(10):I2: EQ 87 | VARBINARY(10):I2p: EQ 88 | VARBINARY(10):PK: EQ 89 | VARBINARY(10):I1: EQ 90 | VARBINARY(10):I2: EQ 91 | VARBINARY(10):I2p: EQ 92 | VARBINARY(10):PK: EQ 93 | VARBINARY(10):I1: EQ 94 | VARBINARY(10):I2: EQ 95 | VARBINARY(10):I2p: EQ 96 | 97 | TYPE CHAR(255) 98 | CHAR(255):PK: EQ 99 | CHAR(255):I1: EQ 100 | CHAR(255):I2: EQ 101 | CHAR(255):I2p: EQ 102 | CHAR(255):PK: EQ 103 | CHAR(255):I1: EQ 104 | CHAR(255):I2: EQ 105 | CHAR(255):I2p: EQ 106 | CHAR(255):PK: EQ 107 | CHAR(255):I1: EQ 108 | CHAR(255):I2: EQ 109 | CHAR(255):I2p: EQ 110 | CHAR(255):PK: EQ 111 | CHAR(255):I1: EQ 112 | CHAR(255):I2: EQ 113 | CHAR(255):I2p: EQ 114 | CHAR(255):PK: EQ 115 | CHAR(255):I1: EQ 116 | CHAR(255):I2: EQ 117 | CHAR(255):I2p: EQ 118 | CHAR(255):PK: EQ 119 | CHAR(255):I1: EQ 120 | CHAR(255):I2: EQ 121 | CHAR(255):I2p: EQ 122 | CHAR(255):PK: EQ 123 | CHAR(255):I1: EQ 124 | CHAR(255):I2: EQ 125 | CHAR(255):I2p: EQ 126 | 127 | TYPE VARCHAR(255) 128 | VARCHAR(255):PK: EQ 129 | VARCHAR(255):I1: EQ 130 | VARCHAR(255):I2: EQ 131 | VARCHAR(255):I2p: EQ 132 | VARCHAR(255):PK: EQ 133 | VARCHAR(255):I1: EQ 134 | VARCHAR(255):I2: EQ 135 | VARCHAR(255):I2p: EQ 136 | VARCHAR(255):PK: EQ 137 | VARCHAR(255):I1: EQ 138 | VARCHAR(255):I2: EQ 139 | VARCHAR(255):I2p: EQ 140 | VARCHAR(255):PK: EQ 141 | VARCHAR(255):I1: EQ 142 | VARCHAR(255):I2: EQ 143 | VARCHAR(255):I2p: EQ 144 | VARCHAR(255):PK: EQ 145 | VARCHAR(255):I1: EQ 146 | VARCHAR(255):I2: EQ 147 | VARCHAR(255):I2p: EQ 148 | VARCHAR(255):PK: EQ 149 | VARCHAR(255):I1: EQ 150 | VARCHAR(255):I2: EQ 151 | VARCHAR(255):I2p: EQ 152 | VARCHAR(255):PK: EQ 153 | VARCHAR(255):I1: EQ 154 | VARCHAR(255):I2: EQ 155 | VARCHAR(255):I2p: EQ 156 | 157 | TYPE VARCHAR(511) 158 | VARCHAR(511):PK: EQ 159 | VARCHAR(511):I1: EQ 160 | VARCHAR(511):I2: EQ 161 | VARCHAR(511):I2p: EQ 162 | VARCHAR(511):PK: EQ 163 | VARCHAR(511):I1: EQ 164 | VARCHAR(511):I2: EQ 165 | VARCHAR(511):I2p: EQ 166 | VARCHAR(511):PK: EQ 167 | VARCHAR(511):I1: EQ 168 | VARCHAR(511):I2: EQ 169 | VARCHAR(511):I2p: EQ 170 | VARCHAR(511):PK: EQ 171 | VARCHAR(511):I1: EQ 172 | VARCHAR(511):I2: EQ 173 | VARCHAR(511):I2p: EQ 174 | VARCHAR(511):PK: EQ 175 | VARCHAR(511):I1: EQ 176 | VARCHAR(511):I2: EQ 177 | VARCHAR(511):I2p: EQ 178 | VARCHAR(511):PK: EQ 179 | VARCHAR(511):I1: EQ 180 | VARCHAR(511):I2: EQ 181 | VARCHAR(511):I2p: EQ 182 | VARCHAR(511):PK: EQ 183 | VARCHAR(511):I1: EQ 184 | VARCHAR(511):I2: EQ 185 | VARCHAR(511):I2p: EQ 186 | 187 | TYPE LONGTEXT 188 | LONGTEXT:PK: EQ 189 | LONGTEXT:I1: EQ 190 | LONGTEXT:I2: EQ 191 | LONGTEXT:I2p: EQ 192 | LONGTEXT:PK: EQ 193 | LONGTEXT:I1: EQ 194 | LONGTEXT:I2: EQ 195 | LONGTEXT:I2p: EQ 196 | LONGTEXT:PK: EQ 197 | LONGTEXT:I1: EQ 198 | LONGTEXT:I2: EQ 199 | LONGTEXT:I2p: EQ 200 | LONGTEXT:PK: EQ 201 | LONGTEXT:I1: EQ 202 | LONGTEXT:I2: EQ 203 | LONGTEXT:I2p: EQ 204 | LONGTEXT:PK: EQ 205 | LONGTEXT:I1: EQ 206 | LONGTEXT:I2: EQ 207 | LONGTEXT:I2p: EQ 208 | LONGTEXT:PK: EQ 209 | LONGTEXT:I1: EQ 210 | LONGTEXT:I2: EQ 211 | LONGTEXT:I2p: EQ 212 | LONGTEXT:PK: EQ 213 | LONGTEXT:I1: EQ 214 | LONGTEXT:I2: EQ 215 | LONGTEXT:I2p: EQ 216 | 217 | TYPE LONGBLOB 218 | LONGBLOB:PK: EQ 219 | LONGBLOB:I1: EQ 220 | LONGBLOB:I2: EQ 221 | LONGBLOB:I2p: EQ 222 | LONGBLOB:PK: EQ 223 | LONGBLOB:I1: EQ 224 | LONGBLOB:I2: EQ 225 | LONGBLOB:I2p: EQ 226 | LONGBLOB:PK: EQ 227 | LONGBLOB:I1: EQ 228 | LONGBLOB:I2: EQ 229 | LONGBLOB:I2p: EQ 230 | LONGBLOB:PK: EQ 231 | LONGBLOB:I1: EQ 232 | LONGBLOB:I2: EQ 233 | LONGBLOB:I2p: EQ 234 | LONGBLOB:PK: EQ 235 | LONGBLOB:I1: EQ 236 | LONGBLOB:I2: EQ 237 | LONGBLOB:I2p: EQ 238 | LONGBLOB:PK: EQ 239 | LONGBLOB:I1: EQ 240 | LONGBLOB:I2: EQ 241 | LONGBLOB:I2p: EQ 242 | LONGBLOB:PK: EQ 243 | LONGBLOB:I1: EQ 244 | LONGBLOB:I2: EQ 245 | LONGBLOB:I2p: EQ 246 | 247 | -------------------------------------------------------------------------------- /regtest/test_01_lib/test17.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | 3 | # vim:sw=2:ai 4 | 5 | # test for string types 6 | 7 | BEGIN { 8 | push @INC, "../common/"; 9 | }; 10 | 11 | use strict; 12 | use warnings; 13 | use bigint; 14 | use hstest; 15 | 16 | my $string_types = [ 17 | [ 'CHAR(10)', undef, 1, 2, 5, 10 ], 18 | [ 'VARCHAR(10)', undef, 1, 2, 5, 10 ], 19 | [ 'BINARY(10)', undef, 1, 2, 5, 10 ], 20 | [ 'VARBINARY(10)', undef, 1, 2, 5, 10 ], 21 | [ 'CHAR(255)', undef, 1, 2, 5, 10, 100, 200, 255 ], 22 | [ 'VARCHAR(255)', undef, 1, 2, 5, 10, 100, 200, 255 ], 23 | [ 'VARCHAR(511)', undef, 1, 2, 5, 10, 100, 200, 511 ], 24 | [ 'LONGTEXT', 500, 1, 2, 5, 10, 100, 200, 511 ], 25 | [ 'LONGBLOB', 500, 1, 2, 5, 10, 100, 200, 511 ], 26 | # [ 'VARCHAR(4096)', 500, 1, 2, 5, 10, 100, 200, 255, 256, 4095 ], 27 | # [ 'VARCHAR(16383)', 500, 1, 2, 5, 10, 100, 200, 255, 256, 4095, 4096, 16383 ], 28 | # [ 'VARBINARY(16383)', 500, 1, 2, 5, 10, 100, 200, 255, 256, 4095, 4096, 16383 ], 29 | ]; 30 | 31 | my $table = 'hstesttbl'; 32 | my $dbh; 33 | for my $rec (@$string_types) { 34 | my ($typ, $keylen, @vs) = @$rec; 35 | my @vals = (); 36 | for my $len (@vs) { 37 | my $s = ''; 38 | my @arr = (); 39 | srand(999); 40 | # print "$len 1\n"; 41 | for (my $i = 0; $i < $len; ++$i) { 42 | my $v = int(rand(10)); 43 | $arr[$i] = chr(65 + $v); 44 | } 45 | # print "2\n"; 46 | push(@vals, join('', @arr)); 47 | } 48 | print("TYPE $typ\n"); 49 | test_one($typ, $keylen, \@vals); 50 | print("\n"); 51 | } 52 | 53 | sub test_one { 54 | my ($typ, $keylen, $values) = @_; 55 | my $keylen_str = ''; 56 | if (defined($keylen)) { 57 | $keylen_str = "($keylen)"; 58 | } 59 | $dbh = hstest::init_testdb(); 60 | $dbh->do( 61 | "create table $table (" . 62 | "k $typ, " . 63 | "v1 varchar(1000), " . 64 | "v2 $typ, " . 65 | "primary key(k$keylen_str), " . 66 | "index i1(v1), index i2(v2$keylen_str, v1(300))) " . 67 | "engine = myisam default charset = latin1"); 68 | my $hs = hstest::get_hs_connection(undef, 9999); 69 | my $dbname = $hstest::conf{dbname}; 70 | $hs->open_index(1, $dbname, $table, '', 'k,v1,v2'); 71 | $hs->open_index(2, $dbname, $table, 'i1', 'k,v1,v2'); 72 | $hs->open_index(3, $dbname, $table, 'i2', 'k,v1,v2'); 73 | for my $k (@$values) { 74 | my $kstr = 's' . $k; 75 | $hs->execute_single(1, '+', [ $k, $kstr, $k ], 0, 0); 76 | } 77 | # dump_table(); 78 | for my $k (@$values) { 79 | my $kstr = 's' . $k; 80 | my ($rk, $rv1, $rv2); 81 | my $r; 82 | $r = $hs->execute_single(1, '=', [ $k ], 1, 0); 83 | shift(@$r); 84 | check_value("$typ:PK", @$r); 85 | $r = $hs->execute_single(2, '=', [ $kstr ], 1, 0); 86 | shift(@$r); 87 | check_value("$typ:I1", @$r); 88 | $r = $hs->execute_single(3, '=', [ $k, $kstr ], 1, 0); 89 | shift(@$r); 90 | check_value("$typ:I2", @$r); 91 | $r = $hs->execute_single(3, '=', [ $k ], 1, 0); 92 | shift(@$r); 93 | check_value("$typ:I2p", @$r); 94 | } 95 | } 96 | 97 | sub check_value { 98 | my ($mess, $rk, $rv1, $rv2) = @_; 99 | $rk ||= ''; 100 | $rv1 ||= ''; 101 | $rv2 ||= ''; 102 | if ($rv2 ne $rk) { 103 | print "$mess: V2 NE\n$rk\n$rv2\n"; 104 | return; 105 | } 106 | if ($rv1 ne 's' . $rk) { 107 | print "$mess: V1 NE\n$rk\n$rv1\n"; 108 | return; 109 | } 110 | print "$mess: EQ\n"; 111 | } 112 | 113 | sub dump_table { 114 | print "DUMP_TABLE_BEGIN\n"; 115 | my $aref = $dbh->selectall_arrayref("select k,v1,v2 from $table order by k"); 116 | for my $row (@$aref) { 117 | my ($k, $v1, $v2) = @$row; 118 | $v1 = "[null]" if !defined($v1); 119 | $v2 = "[null]" if !defined($v2); 120 | print "$k $v1 $v2\n"; 121 | # print "MISMATCH\n" if ($valmap{$k} ne $v); 122 | } 123 | print "DUMP_TABLE_END\n"; 124 | } 125 | 126 | -------------------------------------------------------------------------------- /regtest/test_01_lib/test18.expected: -------------------------------------------------------------------------------- 1 | HSINSERT 2 | 1 v1hs_0 3 | 2 v1hs_1 4 | 3 v1hs_2 5 | 4 v1hs_3 6 | 5 v1hs_4 7 | 6 v1hs_5 8 | 7 v1hs_6 9 | 8 v1hs_7 10 | 9 v1hs_8 11 | 10 v1hs_9 12 | DUMP_TABLE 13 | 1 v1hs_0 14 | 2 v1hs_1 15 | 3 v1hs_2 16 | 4 v1hs_3 17 | 5 v1hs_4 18 | 6 v1hs_5 19 | 7 v1hs_6 20 | 8 v1hs_7 21 | 9 v1hs_8 22 | 10 v1hs_9 23 | -------------------------------------------------------------------------------- /regtest/test_01_lib/test18.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | 3 | # vim:sw=2:ai 4 | 5 | # tests that columns to be inserted are specified by open_index 6 | 7 | BEGIN { 8 | push @INC, "../common/"; 9 | }; 10 | 11 | use strict; 12 | use warnings; 13 | use hstest; 14 | 15 | my $dbh = hstest::init_testdb(); 16 | my $table = 'hstesttbl'; 17 | my $tablesize = 10; 18 | $dbh->do( 19 | "create table $table (" . 20 | "k int primary key auto_increment, " . 21 | "v1 varchar(30), " . 22 | "v2 varchar(30)) " . 23 | "engine = myisam default charset = binary"); 24 | srand(999); 25 | 26 | my %valmap = (); 27 | 28 | print "HSINSERT\n"; 29 | my $hs = hstest::get_hs_connection(undef, 9999); 30 | my $dbname = $hstest::conf{dbname}; 31 | $hs->open_index(1, $dbname, $table, '', 'v1'); 32 | # inserts with auto_increment 33 | for (my $i = 0; $i < $tablesize; ++$i) { 34 | my $k = 0; 35 | my $v1 = "v1hs_" . $i; 36 | my $v2 = "v2hs_" . $i; 37 | my $r = $hs->execute_insert(1, [ $v1 ]); 38 | my $err = $r->[0]; 39 | if ($err != 0) { 40 | my $err_str = $r->[1]; 41 | print "$err $err_str\n"; 42 | } else { 43 | my $id = $r->[1]; 44 | print "$id $v1\n"; 45 | } 46 | } 47 | 48 | undef $hs; 49 | 50 | dump_table(); 51 | 52 | sub dump_table { 53 | print "DUMP_TABLE\n"; 54 | my $aref = $dbh->selectall_arrayref("select k,v1,v2 from $table order by k"); 55 | for my $row (@$aref) { 56 | my ($k, $v1, $v2) = @$row; 57 | $v1 = "[null]" if !defined($v1); 58 | $v2 = "[null]" if !defined($v2); 59 | print "$k $v1 $v2\n"; 60 | # print "MISMATCH\n" if ($valmap{$k} ne $v); 61 | } 62 | } 63 | 64 | -------------------------------------------------------------------------------- /regtest/test_01_lib/test20.expected: -------------------------------------------------------------------------------- 1 | open_index 1st r=1 2 | open_index 2nd r=0 3 | -------------------------------------------------------------------------------- /regtest/test_01_lib/test20.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | 3 | # vim:sw=2:ai 4 | 5 | # test for a bug that table mdl is not released when open_index is failed 6 | 7 | BEGIN { 8 | push @INC, "../common/"; 9 | }; 10 | 11 | use strict; 12 | use warnings; 13 | use hstest; 14 | 15 | my $dbh = hstest::init_testdb(); 16 | my $dbname = $hstest::conf{dbname}; 17 | my $table = 'hstesttbl'; 18 | 19 | $dbh->do("drop table if exists $table"); 20 | 21 | my $hs = hstest::get_hs_connection(); 22 | my $r = $hs->open_index(1, $dbname, $table, '', 'k,v'); # fails 23 | print "open_index 1st r=$r\n"; 24 | undef $hs; 25 | 26 | $dbh->do( 27 | "create table $table (k varchar(30) primary key, v varchar(30) not null) " . 28 | "engine = innodb"); 29 | 30 | $hs = hstest::get_hs_connection(); 31 | $r = $hs->open_index(1, $dbname, $table, '', 'k,v'); # success 32 | print "open_index 2nd r=$r\n"; 33 | 34 | -------------------------------------------------------------------------------- /regtest/test_01_lib/test21.expected: -------------------------------------------------------------------------------- 1 | HS 2 | k10 v704-10 3 | k30 v52-30 4 | k40 v878-40 5 | k50 v682-50 6 | SQL 7 | k10 v704-10 8 | k30 v52-30 9 | k40 v878-40 10 | k50 v682-50 11 | END 12 | -------------------------------------------------------------------------------- /regtest/test_01_lib/test21.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | 3 | # vim:sw=2:ai 4 | 5 | # test for 'IN' 6 | 7 | BEGIN { 8 | push @INC, "../common/"; 9 | }; 10 | 11 | use strict; 12 | use warnings; 13 | use hstest; 14 | 15 | my $dbh = hstest::init_testdb(); 16 | my $table = 'hstesttbl'; 17 | my $tablesize = 100; 18 | $dbh->do( 19 | "create table $table (k varchar(30) primary key, v varchar(30) not null) " . 20 | "engine = innodb"); 21 | srand(999); 22 | 23 | my %valmap = (); 24 | 25 | my $sth = $dbh->prepare("insert into $table values (?,?)"); 26 | for (my $i = 0; $i < $tablesize; ++$i) { 27 | my $k = "k" . $i; 28 | my $v = "v" . int(rand(1000)) . "-" . $i; 29 | $sth->execute($k, $v); 30 | $valmap{$k} = $v; 31 | } 32 | 33 | my $hs = hstest::get_hs_connection(); 34 | my $dbname = $hstest::conf{dbname}; 35 | $hs->open_index(1, $dbname, $table, '', 'k,v'); 36 | my $vs = [ 'k10', 'k20x', 'k30', 'k40', 'k50' ]; 37 | # select k,v from $table where k in $vs 38 | my $r = $hs->execute_single(1, '=', [ '' ], 10000, 0, undef, undef, undef, 39 | 0, $vs); 40 | shift(@$r); 41 | print "HS\n"; 42 | my $len = scalar(@$r) / 2; 43 | for (my $i = 0; $i < $len; ++$i) { 44 | my $k = $r->[$i * 2]; 45 | my $v = $r->[$i * 2 + 1]; 46 | print "$k $v\n"; 47 | } 48 | 49 | print "SQL\n"; 50 | my $aref = $dbh->selectall_arrayref( 51 | "select k,v from $table where k in ('k10', 'k20x', 'k30', 'k40', 'k50') " 52 | . "order by k"); 53 | for my $row (@$aref) { 54 | my ($k, $v) = @$row; 55 | print "$k $v\n"; 56 | } 57 | print "END\n"; 58 | 59 | -------------------------------------------------------------------------------- /regtest/test_01_lib/test22.expected: -------------------------------------------------------------------------------- 1 | HS 2 | k10 v704-10 1 3 | k30 v52-30 1 4 | k50 v682-50 1 5 | SQL 6 | k10 v704-10 1 7 | k30 v52-30 1 8 | k50 v682-50 1 9 | END 10 | -------------------------------------------------------------------------------- /regtest/test_01_lib/test22.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | 3 | # vim:sw=2:ai 4 | 5 | # test for 'IN' and filters 6 | 7 | BEGIN { 8 | push @INC, "../common/"; 9 | }; 10 | 11 | use strict; 12 | use warnings; 13 | use hstest; 14 | 15 | my $dbh = hstest::init_testdb(); 16 | my $table = 'hstesttbl'; 17 | my $tablesize = 100; 18 | $dbh->do( 19 | "create table $table (k varchar(30) primary key, " . 20 | "v varchar(30) not null, v2 int not null) " . 21 | "engine = innodb"); 22 | srand(999); 23 | 24 | my %valmap = (); 25 | 26 | my $sth = $dbh->prepare("insert into $table values (?,?,?)"); 27 | for (my $i = 0; $i < $tablesize; ++$i) { 28 | my $k = "k" . $i; 29 | my $v = "v" . int(rand(1000)) . "-" . $i; 30 | my $v2 = ($i / 10) % 2; 31 | $sth->execute($k, $v, $v2); 32 | $valmap{$k} = $v; 33 | } 34 | 35 | my $hs = hstest::get_hs_connection(); 36 | my $dbname = $hstest::conf{dbname}; 37 | $hs->open_index(1, $dbname, $table, '', 'k,v,v2', 'v2'); 38 | my $vs = [ 'k10', 'k20x', 'k30', 'k40', 'k50' ]; 39 | # select k,v,v2 from $table where k in $vs 40 | my $r = $hs->execute_single(1, '=', [ '' ], 10000, 0, undef, undef, 41 | [['F', '=', 0, '1']], 0, $vs); 42 | shift(@$r); 43 | print "HS\n"; 44 | my $len = scalar(@$r) / 3; 45 | for (my $i = 0; $i < $len; ++$i) { 46 | my $k = $r->[$i * 3]; 47 | my $v = $r->[$i * 3 + 1]; 48 | my $v2 = $r->[$i * 3 + 2]; 49 | print "$k $v $v2\n"; 50 | } 51 | 52 | print "SQL\n"; 53 | my $aref = $dbh->selectall_arrayref( 54 | "select k,v,v2 from $table where k in ('k10', 'k20x', 'k30', 'k40', 'k50') " 55 | . "and v2 = '1' order by k"); 56 | for my $row (@$aref) { 57 | my ($k, $v, $v2) = @$row; 58 | print "$k $v $v2\n"; 59 | } 60 | print "END\n"; 61 | 62 | -------------------------------------------------------------------------------- /regtest/test_01_lib/test23.expected: -------------------------------------------------------------------------------- 1 | HS 2 | k0 v102-0 0 3 | k1 v635-1 0 4 | k10 MOD 1 5 | k11 v751-11 1 6 | k12 v367-12 1 7 | k13 v400-13 1 8 | k14 v397-14 1 9 | k15 v170-15 1 10 | k16 v719-16 1 11 | k17 v734-17 1 12 | k18 v587-18 1 13 | k19 v494-19 1 14 | k2 v803-2 0 15 | k20 v523-20 0 16 | k21 v954-21 0 17 | k22 v433-22 0 18 | k23 v820-23 0 19 | k24 v283-24 0 20 | k25 v837-25 0 21 | k26 v205-26 0 22 | k27 v415-27 0 23 | k28 v545-28 0 24 | k29 v583-29 0 25 | k3 v925-3 0 26 | k30 MOD 1 27 | k31 v323-31 1 28 | k32 v614-32 1 29 | k33 v679-33 1 30 | k34 v805-34 1 31 | k35 v451-35 1 32 | k36 v115-36 1 33 | k37 v269-37 1 34 | k38 v218-38 1 35 | k39 v617-39 1 36 | k4 v775-4 0 37 | k40 v878-40 0 38 | k41 v345-41 0 39 | k42 v512-42 0 40 | k43 v969-43 0 41 | k44 v408-44 0 42 | k45 v291-45 0 43 | k46 v858-46 0 44 | k47 v953-47 0 45 | k48 v710-48 0 46 | k49 v142-49 0 47 | k5 v537-5 0 48 | k50 MOD 1 49 | k51 v934-51 1 50 | k52 v621-52 1 51 | k53 v965-53 1 52 | k54 v574-54 1 53 | k55 v204-55 1 54 | k56 v298-56 1 55 | k57 v134-57 1 56 | k58 v983-58 1 57 | k59 v444-59 1 58 | k6 v592-6 0 59 | k60 v144-60 0 60 | k61 v152-61 0 61 | k62 v187-62 0 62 | k63 v215-63 0 63 | k64 v8-64 0 64 | k65 v697-65 0 65 | k66 v651-66 0 66 | k67 v280-67 0 67 | k68 v701-68 0 68 | k69 v537-69 0 69 | k7 v414-7 0 70 | k70 v413-70 1 71 | k71 v69-71 1 72 | k72 v86-72 1 73 | k73 v822-73 1 74 | k74 v670-74 1 75 | k75 v370-75 1 76 | k76 v806-76 1 77 | k77 v688-77 1 78 | k78 v26-78 1 79 | k79 v66-79 1 80 | k8 v590-8 0 81 | k80 v802-80 0 82 | k81 v171-81 0 83 | k82 v557-82 0 84 | k83 v847-83 0 85 | k84 v777-84 0 86 | k85 v730-85 0 87 | k86 v987-86 0 88 | k87 v115-87 0 89 | k88 v646-88 0 90 | k89 v496-89 0 91 | k9 v302-9 0 92 | k90 v120-90 1 93 | k91 v684-91 1 94 | k92 v374-92 1 95 | k93 v65-93 1 96 | k94 v370-94 1 97 | k95 v174-95 1 98 | k96 v828-96 1 99 | k97 v867-97 1 100 | k98 v759-98 1 101 | k99 v703-99 1 102 | -------------------------------------------------------------------------------- /regtest/test_01_lib/test23.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | 3 | # vim:sw=2:ai 4 | 5 | # test for 'IN', filters, and modifications 6 | 7 | BEGIN { 8 | push @INC, "../common/"; 9 | }; 10 | 11 | use strict; 12 | use warnings; 13 | use hstest; 14 | 15 | my $dbh = hstest::init_testdb(); 16 | my $table = 'hstesttbl'; 17 | my $tablesize = 100; 18 | $dbh->do( 19 | "create table $table (k varchar(30) primary key, " . 20 | "v varchar(30) not null, v2 int not null) " . 21 | "engine = innodb"); 22 | srand(999); 23 | 24 | my %valmap = (); 25 | 26 | my $sth = $dbh->prepare("insert into $table values (?,?,?)"); 27 | for (my $i = 0; $i < $tablesize; ++$i) { 28 | my $k = "k" . $i; 29 | my $v = "v" . int(rand(1000)) . "-" . $i; 30 | my $v2 = ($i / 10) % 2; 31 | $sth->execute($k, $v, $v2); 32 | $valmap{$k} = $v; 33 | } 34 | 35 | my $hs = hstest::get_hs_connection(undef, 9999); 36 | my $dbname = $hstest::conf{dbname}; 37 | $hs->open_index(1, $dbname, $table, '', 'k,v,v2', 'v2'); 38 | $hs->open_index(2, $dbname, $table, '', 'v', 'v2'); 39 | my $vs = [ 'k10', 'k20x', 'k30', 'k40', 'k50' ]; 40 | # update $table set v = 'MOD' where k in $vs and v2 = '1' 41 | my $r = $hs->execute_single(2, '=', [ '' ], 10000, 0, 'U', [ 'MOD' ], 42 | [['F', '=', 0, '1']], 0, $vs); 43 | $r = $hs->execute_single(1, '>=', [ '' ], 10000, 0); 44 | shift(@$r); 45 | print "HS\n"; 46 | my $len = scalar(@$r) / 3; 47 | for (my $i = 0; $i < $len; ++$i) { 48 | my $k = $r->[$i * 3]; 49 | my $v = $r->[$i * 3 + 1]; 50 | my $v2 = $r->[$i * 3 + 2]; 51 | print "$k $v $v2\n"; 52 | } 53 | 54 | -------------------------------------------------------------------------------- /regtest/test_01_lib/test24.expected: -------------------------------------------------------------------------------- 1 | HS 2 | 0 0 3 | -------------------------------------------------------------------------------- /regtest/test_01_lib/test24.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | 3 | # vim:sw=2:ai 4 | 5 | # test for issue #78 6 | 7 | BEGIN { 8 | push @INC, "../common/"; 9 | }; 10 | 11 | use strict; 12 | use warnings; 13 | use hstest; 14 | 15 | my $dbh = hstest::init_testdb(); 16 | my $table = 'hstesttbl'; 17 | my $tablesize = 100; 18 | $dbh->do( 19 | "create table $table (" . 20 | "id bigint(20) not null auto_increment, " . 21 | "t1 timestamp not null default current_timestamp, " . 22 | "primary key (id)" . 23 | ") engine = innodb"); 24 | srand(999); 25 | 26 | my %valmap = (); 27 | 28 | my $hs = hstest::get_hs_connection(undef, 9999); 29 | my $dbname = $hstest::conf{dbname}; 30 | $hs->open_index(0, $dbname, $table, 'PRIMARY', 'id,t1'); 31 | my $res = $hs->execute_single(0, '+', [ 321 ], 0, 0); 32 | die $hs->get_error() if $res->[0] != 0; 33 | print "HS\n"; 34 | print join(' ', @$res) . "\n"; 35 | 36 | --------------------------------------------------------------------------------