Merge lp:~percona-dev/percona-server/release-5.5.10-20.1 into lp:~percona-dev/percona-server/5.5.10

Proposed by Ignacio Nin
Status: Merged
Approved by: Alexey Kopytov
Approved revision: no longer in the source branch.
Merged at revision: 95
Proposed branch: lp:~percona-dev/percona-server/release-5.5.10-20.1
Merge into: lp:~percona-dev/percona-server/5.5.10
Diff against target: 41116 lines
To merge this branch: bzr merge lp:~percona-dev/percona-server/release-5.5.10-20.1
Reviewer Review Type Date Requested Status
Alexey Kopytov (community) Approve
Review via email: mp+57268@code.launchpad.net

Description of the change

Addition of scripts and fixes for building in all platforms. Includes HandlerSocket and the Maatkit UDF functions.

To post a comment you must log in.
Revision history for this message
Alexey Kopytov (akopytov) :
review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== added directory 'HandlerSocket-Plugin-for-MySQL'
=== added file 'HandlerSocket-Plugin-for-MySQL/AUTHORS'
--- HandlerSocket-Plugin-for-MySQL/AUTHORS 1970-01-01 00:00:00 +0000
+++ HandlerSocket-Plugin-for-MySQL/AUTHORS 2011-04-12 04:16:24 +0000
@@ -0,0 +1,19 @@
1Akira Higuchi (https://github.com/ahiguti)
2 - developed HanderSocket plugin, libhsclient, and perl-Net-HandlerSocket
3
4Yoshinori Matsunobu (https://github.com/yoshinorim)
5 - introduced autotools, added support for MySQL 5.5.6, added statistics
6 variables
7
8Jeff Hodges (https://github.com/jmhodges)
9 - fixed some autotools scripts
10
11Toru Yamaguchi (https://github.com/zigorou)
12 - ported to MacOS X
13
14Moriyoshi Koizumi (https://github.com/moriyoshi)
15 - fixed some autotools scripts
16
17takeda-at (https://github.com/takada-at)
18 - added simple authorization function
19
020
=== added file 'HandlerSocket-Plugin-for-MySQL/COPYING'
--- HandlerSocket-Plugin-for-MySQL/COPYING 1970-01-01 00:00:00 +0000
+++ HandlerSocket-Plugin-for-MySQL/COPYING 2011-04-12 04:16:24 +0000
@@ -0,0 +1,30 @@
1-----------------------------------------------------------------------------
2HandlerSocket 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
031
=== added file 'HandlerSocket-Plugin-for-MySQL/ChangeLog'
--- HandlerSocket-Plugin-for-MySQL/ChangeLog 1970-01-01 00:00:00 +0000
+++ HandlerSocket-Plugin-for-MySQL/ChangeLog 2011-04-12 04:16:24 +0000
@@ -0,0 +1,12 @@
11.0.6 - 2010-10-29
2 * Changed build instruction (autoreconf/configure/make), removed auto-generated files (Contributed by jmhodges)
3 *
4
51.0.5 - 2010-10-18
6 * Changed build procedures (using typical configure/make)
7 * Supported 5.5.6
8 * Added status variables
9
101.0.4 - 2010-08-15
11 * Initial public release
12
013
=== added file 'HandlerSocket-Plugin-for-MySQL/Makefile.am'
--- HandlerSocket-Plugin-for-MySQL/Makefile.am 1970-01-01 00:00:00 +0000
+++ HandlerSocket-Plugin-for-MySQL/Makefile.am 2011-04-12 04:16:24 +0000
@@ -0,0 +1,87 @@
1
2ACLOCAL_AMFLAGS = -I m4
3
4SUBDIRS = @HANDLERSOCKET_SUBDIRS@
5
6perl:
7 cd perl-Net-HandlerSocket && perl Makefile.PL && make
8
9install_perl:
10 cd perl-Net-HandlerSocket && make install
11
12rpms: rpm_cli rpm_perl rpm_c
13
14rpm_dir:
15 - mkdir dist
16 - mkdir dist/BUILD dist/RPMS dist/SOURCES dist/SPECS dist/SRPMS
17
18rpm_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
26rpm_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
36rpm_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
48install_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
55installrpms:
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
72clean_cli:
73 cd libhsclient && make clean
74 cd client && make clean
75
76clean_perl:
77 cd perl-Net-HandlerSocket && perl Makefile.PL && make clean && \
78 rm -f Makefile.old
79
80clean_c:
81 cd handlersocket && make clean
82
83clean_all: clean_cli clean_perl clean_c
84 cd regtest && make clean
85 rm -rf dist/*/*
86 rm -f dist/*.tar.gz
87
088
=== added file 'HandlerSocket-Plugin-for-MySQL/README'
--- HandlerSocket-Plugin-for-MySQL/README 1970-01-01 00:00:00 +0000
+++ HandlerSocket-Plugin-for-MySQL/README 2011-04-12 04:16:24 +0000
@@ -0,0 +1,76 @@
1
2-----------------------------------------------------------------------------
3HandlerSocket plugin for MySQL
4
5Copyright (c) 2010 DeNA Co.,Ltd.
6All rights reserved.
7
8Redistribution and use in source and binary forms, with or without
9modification, 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
20THIS SOFTWARE IS PROVIDED BY DeNA Co.,Ltd. "AS IS" AND ANY EXPRESS OR
21IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
22MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
23EVENT SHALL DeNA Co.,Ltd. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
25PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
26OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
27WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
28OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
29ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30
31
32-----------------------------------------------------------------------------
33About HandlerSocket
34
35HandlerSocket is a NoSQL plugin for MySQL. It works as a daemon inside the
36mysqld process, accept tcp connections, and execute requests from clients.
37HandlerSocket does not support SQL queries. Instead, it supports simple CRUD
38operations on tables.
39
40Because of the following reasons, HandlerSocket is much faster than the
41mysqld/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
50The current version of HandlerSocket only works with GNU/Linux. The source
51archive of HandlerSocket includes a C++ and a Perl client libraries.
52Here 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
72The home of HandlerSocket is here:
73 https://github.com/ahiguti/HandlerSocket-Plugin-for-MySQL
74
75More documents are available in docs-en/ and docs-ja/ directories.
76
077
=== added file 'HandlerSocket-Plugin-for-MySQL/autogen.sh'
--- HandlerSocket-Plugin-for-MySQL/autogen.sh 1970-01-01 00:00:00 +0000
+++ HandlerSocket-Plugin-for-MySQL/autogen.sh 2011-04-12 04:16:24 +0000
@@ -0,0 +1,117 @@
1#!/bin/sh
2
3warn() {
4echo -e "\tWARNING: $@" 1>&2
5}
6
7# init
8
9LIBTOOLIZE=libtoolize
10ACLOCAL=aclocal
11AUTOCONF=autoconf
12AUTOHEADER=autoheader
13AUTOMAKE=automake
14
15case `uname -s` in
16Darwin)
17LIBTOOLIZE=glibtoolize
18;;
19FreeBSD)
20ACLOCAL_ARGS="$ACLOCAL_ARGS -I /usr/local/share/aclocal/"
21;;
22esac
23
24
25# libtoolize
26echo "Searching libtoolize..."
27if [ `which $LIBTOOLIZE` ] ; then
28echo -e "\tFOUND: libtoolize -> $LIBTOOLIZE"
29else
30warn "Cannot Found libtoolize... input libtool command"
31 read LIBTOOLIZE
32 LIBTOOLIZE=`which $LIBTOOLIZE`
33 if [ `which $LIBTOOLIZE` ] ; then
34echo -e "\tSET: libtoolize -> $LIBTOOLIZE"
35 else
36warn "$LIBTOOLIZE: Command not found."
37 exit 1;
38 fi
39fi
40
41# aclocal
42echo "Searching aclocal..."
43if [ `which $ACLOCAL` ] ; then
44echo -e "\tFOUND: aclocal -> $ACLOCAL"
45else
46warn "Cannot Found aclocal... input aclocal command"
47 read ACLOCAL
48 ACLOCAL=`which $ACLOCAL`
49 if [ `which $ACLOCAL` ] ; then
50echo -e "\tSET: aclocal -> $ACLOCAL"
51 else
52warn "$ACLOCAL: Command not found."
53 exit 1;
54 fi
55fi
56
57# automake
58echo "Searching automake..."
59if [ `which $AUTOMAKE` ] ; then
60echo -e "\tFOUND: automake -> $AUTOMAKE"
61else
62warn "Cannot Found automake... input automake command"
63 read AUTOMAKE
64 ACLOCAL=`which $AUTOMAKE`
65 if [ `which $AUTOMAKE` ] ; then
66echo -e "\tSET: automake -> $AUTOMAKE"
67 else
68warn "$AUTOMAKE: Command not found."
69 exit 1;
70 fi
71fi
72
73# autoheader
74echo "Searching autoheader..."
75if [ `which $AUTOHEADER` ] ; then
76echo -e "\tFOUND: autoheader -> $AUTOHEADER"
77else
78warn "Cannot Found autoheader... input autoheader command"
79 read AUTOHEADER
80 ACLOCAL=`which $AUTOHEADER`
81 if [ `which $AUTOHEADER` ] ; then
82echo -e "\tSET: autoheader -> $AUTOHEADER"
83 else
84warn "$AUTOHEADER: Command not found."
85 exit 1;
86 fi
87fi
88
89# autoconf
90echo "Searching autoconf..."
91if [ `which $AUTOCONF` ] ; then
92echo -e "\tFOUND: autoconf -> $AUTOCONF"
93else
94warn "Cannot Found autoconf... input autoconf command"
95 read AUTOCONF
96 ACLOCAL=`which $AUTOCONF`
97 if [ `which $AUTOCONF` ] ; then
98echo -e "\tSET: autoconf -> $AUTOCONF"
99 else
100warn "$AUTOCONF: Command not found."
101 exit 1;
102 fi
103fi
104
105echo "Running libtoolize ..."
106$LIBTOOLIZE --force --copy
107echo "Running aclocal ..."
108$ACLOCAL ${ACLOCAL_ARGS} -I .
109echo "Running autoheader..."
110$AUTOHEADER
111echo "Running automake ..."
112$AUTOMAKE --add-missing --copy
113echo "Running autoconf ..."
114$AUTOCONF
115
116#mkdir m4 2> /dev/null
117
0118
=== added directory 'HandlerSocket-Plugin-for-MySQL/client'
=== added file 'HandlerSocket-Plugin-for-MySQL/client/Makefile.am'
--- HandlerSocket-Plugin-for-MySQL/client/Makefile.am 1970-01-01 00:00:00 +0000
+++ HandlerSocket-Plugin-for-MySQL/client/Makefile.am 2011-04-12 04:16:24 +0000
@@ -0,0 +1,13 @@
1AM_INCLUDES= -I../libhsclient
2bin_PROGRAMS=hsclient
3hsclient_SOURCES= hsclient.cpp
4hsclient_LDFLAGS= -static -L../libhsclient -lhsclient
5hsclient_CXXFLAGS= $(AM_INCLUDES)
6
7hstest: hstest.o
8 $(CXX) $(CXXFLAGS) $(LFLAGS) hstest.o \
9 -L../libhsclient/.libs -lhsclient $(MYSQL_LIB) -o hstest
10
11hstest.o: hstest.cpp
12 $(CXX) $(CXXFLAGS) $(MYSQL_INC) $(AM_INCLUDES) -c hstest.cpp
13
014
=== added file 'HandlerSocket-Plugin-for-MySQL/client/hsclient.cpp'
--- HandlerSocket-Plugin-for-MySQL/client/hsclient.cpp 1970-01-01 00:00:00 +0000
+++ HandlerSocket-Plugin-for-MySQL/client/hsclient.cpp 2011-04-12 04:16:24 +0000
@@ -0,0 +1,88 @@
1
2// vim:sw=2:ai
3
4#include "hstcpcli.hpp"
5#include "string_util.hpp"
6
7namespace dena {
8
9int
10hstcpcli_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<std::string> keys;
24 std::vector<string_ref> 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
83int
84main(int argc, char **argv)
85{
86 return dena::hstcpcli_main(argc, argv);
87}
88
089
=== added file 'HandlerSocket-Plugin-for-MySQL/client/hspool_test.pl'
--- HandlerSocket-Plugin-for-MySQL/client/hspool_test.pl 1970-01-01 00:00:00 +0000
+++ HandlerSocket-Plugin-for-MySQL/client/hspool_test.pl 2011-04-12 04:16:24 +0000
@@ -0,0 +1,224 @@
1#!/usr/bin/perl
2
3use strict;
4use warnings;
5use DB::HandlerSocket::Pool;
6use DBI;
7
8my %conf = ();
9for my $i (@ARGV) {
10 my ($k, $v) = split(/=/, $i);
11 $conf{$k} = $v;
12}
13
14my $verbose = get_conf("verbose", 0);
15my $actions_str = get_conf("actions",
16 "create,insert,verify,verify2,verify3,verify4,clean");
17my $tablesize = get_conf("tablesize", 1000);
18my $db = get_conf("db", "hstestdb");
19my $table = get_conf("table", "testtbl");
20my $table_schema = get_conf("table_schema", undef);
21my $engine = get_conf("engine", "innodb");
22my $host = get_conf("host", "localhost");
23my $mysqlport = get_conf("mysqlport", 3306);
24my $hsport_rd = get_conf("hsport_rd", 9998);
25my $hsport_wr = get_conf("hsport_wr", 9999);
26my $loop = get_conf("loop", 10000);
27my $op = get_conf("op", "=");
28my $ssps = get_conf("ssps", 0);
29my $num_moreflds = get_conf("moreflds", 0);
30my $moreflds_prefix = get_conf("moreflds_prefix", "f");
31my $mysql_user = 'root';
32my $mysql_password = '';
33
34my $dsn = "DBI:mysql:database=;host=$host;port=$mysqlport"
35 . ";mysql_server_prepare=$ssps";
36my $dbh = DBI->connect($dsn, $mysql_user, $mysql_password,
37 { RaiseError => 1 });
38my $hsargs = { 'host' => $host, 'port' => $hsport_rd };
39my $hspool = new DB::HandlerSocket::Pool({
40 hostmap => {
41 "$db.$table" => {
42 host => $host,
43 port => $hsport_rd,
44 },
45 },
46 resolve => undef,
47 error => undef,
48});
49$table_schema = "(k int primary key, fc30 varchar(30), ft text)"
50 if (!defined($table_schema));
51
52my @actions = split(/,/, $actions_str);
53for my $action (@actions) {
54 print "ACTION: $action\n";
55 eval "hstest_$action()";
56 if ($@) {
57 die $@;
58 }
59 print "ACTION: $action DONE\n";
60}
61
62sub get_conf {
63 my ($key, $def) = @_;
64 my $val = $conf{$key};
65 if ($val) {
66 print "$key=$val\n";
67 } else {
68 $val = $def;
69 my $defstr = $def || "(undef)";
70 print "$key=$defstr(default)\n";
71 }
72 return $val;
73}
74
75sub hstest_create {
76 $dbh->do("drop database if exists $db");
77 $dbh->do("create database $db");
78 $dbh->do("use $db");
79 $dbh->do("create table $table $table_schema engine=$engine");
80}
81
82sub hstest_dump {
83 $dbh->do("use $db");
84 my $sth = $dbh->prepare("select * from $table");
85 $sth->execute();
86 my $arr = $sth->fetchall_arrayref();
87 for my $rec (@$arr) {
88 print "REC:";
89 for my $row (@$rec) {
90 print " $row";
91 }
92 print "\n";
93 }
94}
95
96sub hstest_insert {
97 $dbh->do("use $db");
98 my $sth = $dbh->prepare("insert into $table values (?, ?, ?)");
99 for (my $k = 0; $k < $tablesize; ++$k) {
100 my $fc30 = "fc30_$k";
101 my $ft = "ft_$k";
102 $sth->execute($k, $fc30, $ft);
103 }
104}
105
106sub hstest_verify {
107 $dbh->do("use $db");
108 my $sth = $dbh->prepare("select * from $table order by k");
109 $sth->execute();
110 my $arr = $sth->fetchall_arrayref();
111 my $hsres = $hspool->index_find($db, $table, "PRIMARY", "k,fc30,ft",
112 ">=", [ 0 ], $tablesize, 0);
113 for (my $i = 0; $i < $tablesize; ++$i) {
114 my $rec = $arr->[$i];
115 my $differ = 0;
116 print "REC:" if $verbose;
117 for (my $j = 0; $j < 3; ++$j) {
118 my $fld = $rec->[$j];
119 my $hsidx = $i * 3 + $j;
120 my $hsfld = $hsres->[$hsidx];
121 if ($hsfld ne $fld) {
122 $differ = 1;
123 }
124 if ($differ) {
125 print " $fld:$hsfld" if $verbose;
126 } else {
127 print " $hsfld" if $verbose;
128 }
129 }
130 print "\n" if $verbose;
131 if ($differ) {
132 die "verification failed";
133 }
134 }
135}
136
137sub hstest_verify2 {
138 $dbh->do("use $db");
139 my $sth = $dbh->prepare("select * from $table order by k");
140 $sth->execute();
141 my $arr = $sth->fetchall_arrayref();
142 my $hsresa = $hspool->index_find_multi($db, $table, "PRIMARY",
143 "k,fc30,ft", [ [ -1, ">=", [ 0 ], $tablesize, 0 ] ]);
144 my $hsres = $hsresa->[0];
145 for (my $i = 0; $i < $tablesize; ++$i) {
146 my $rec = $arr->[$i];
147 my $differ = 0;
148 print "REC:" if $verbose;
149 for (my $j = 0; $j < 3; ++$j) {
150 my $fld = $rec->[$j];
151 my $hsidx = $i * 3 + $j;
152 my $hsfld = $hsres->[$hsidx];
153 if ($hsfld ne $fld) {
154 $differ = 1;
155 }
156 if ($differ) {
157 print " $fld:$hsfld" if $verbose;
158 } else {
159 print " $hsfld" if $verbose;
160 }
161 }
162 print "\n" if $verbose;
163 if ($differ) {
164 die "verification failed";
165 }
166 }
167}
168
169sub hashref_to_str {
170 my $href = $_[0];
171 my $r = '';
172 for my $k (sort keys %$href) {
173 my $v = $href->{$k};
174 $r .= "($k=>$v)";
175 }
176 return $r;
177}
178
179sub hstest_verify3 {
180 $dbh->do("use $db");
181 my $sth = $dbh->prepare("select * from $table order by k");
182 $sth->execute();
183 my $hsres_t = $hspool->index_find($db, $table, "PRIMARY", "k,fc30,ft",
184 ">=", [ 0 ], $tablesize, 0);
185 my $hsres = DB::HandlerSocket::Pool::result_single_to_hasharr(
186 [ 'k', 'fc30', 'ft' ], $hsres_t);
187 for (my $i = 0; $i < $tablesize; ++$i) {
188 my $mystr = hashref_to_str($sth->fetchrow_hashref());
189 my $hsstr = hashref_to_str($hsres->[$i]);
190 if ($mystr ne $hsstr) {
191 print "DIFF my=[$mystr] hs=[$hsstr]\n" if $verbose;
192 die "verification failed";
193 } else {
194 print "OK $hsstr\n" if $verbose;
195 }
196 }
197}
198
199sub hstest_verify4 {
200 $dbh->do("use $db");
201 my $sth = $dbh->prepare("select * from $table order by k");
202 $sth->execute();
203 my $hsres_t = $hspool->index_find($db, $table, "PRIMARY", "k,fc30,ft",
204 ">=", [ 0 ], $tablesize, 0);
205 my $hsres = DB::HandlerSocket::Pool::result_single_to_hashhash(
206 [ 'k', 'fc30', 'ft' ], 'k', $hsres_t);
207 my $rechash = $sth->fetchall_hashref('k');
208 while (my ($k, $href) = each (%$rechash)) {
209 my $mystr = hashref_to_str($href);
210 my $hsstr = hashref_to_str($hsres->{$k});
211 if ($mystr ne $hsstr) {
212 print "DIFF my=[$mystr] hs=[$hsstr]\n" if $verbose;
213 die "verification failed";
214 } else {
215 print "OK $hsstr\n" if $verbose;
216 }
217 }
218}
219
220sub hstest_clean {
221 $hspool->clear_pool();
222 $dbh->do("drop database if exists $db");
223}
224
0225
=== added file 'HandlerSocket-Plugin-for-MySQL/client/hstest.cpp'
--- HandlerSocket-Plugin-for-MySQL/client/hstest.cpp 1970-01-01 00:00:00 +0000
+++ HandlerSocket-Plugin-for-MySQL/client/hstest.cpp 2011-04-12 04:16:24 +0000
@@ -0,0 +1,1494 @@
1
2// vim:sw=2:ai
3
4#include <signal.h>
5#include <sys/time.h>
6#include <stdio.h>
7#include <string.h>
8#include <vector>
9#include <stdlib.h>
10#include <memory>
11#include <errno.h>
12#include <mysql.h>
13#include <time.h>
14#include <sys/types.h>
15#include <sys/stat.h>
16#include <fcntl.h>
17
18#include "util.hpp"
19#include "auto_ptrcontainer.hpp"
20#include "socket.hpp"
21#include "thread.hpp"
22#include "hstcpcli.hpp"
23
24#if __GNUC__ >= 4
25long atomic_exchange_and_add(volatile long *valp, long c)
26{
27 return __sync_fetch_and_add(valp, c);
28}
29#else
30#include <bits/atomicity.h>
31using namespace __gnu_cxx;
32long atomic_exchange_and_add(volatile long *valp, long c)
33{
34 return __exchange_and_add((volatile _Atomic_word *)valp, c);
35}
36#endif
37
38namespace dena {
39
40struct auto_mysql : private noncopyable {
41 auto_mysql() : db(0) {
42 reset();
43 }
44 ~auto_mysql() {
45 if (db) {
46 mysql_close(db);
47 }
48 }
49 void reset() {
50 if (db) {
51 mysql_close(db);
52 }
53 if ((db = mysql_init(0)) == 0) {
54 fatal_abort("failed to initialize mysql client");
55 }
56 }
57 operator MYSQL *() const { return db; }
58 private:
59 MYSQL *db;
60};
61
62struct auto_mysql_res : private noncopyable {
63 auto_mysql_res(MYSQL *db) {
64 res = mysql_store_result(db);
65 }
66 ~auto_mysql_res() {
67 if (res) {
68 mysql_free_result(res);
69 }
70 }
71 operator MYSQL_RES *() const { return res; }
72 private:
73 MYSQL_RES *res;
74};
75
76struct auto_mysql_stmt : private noncopyable {
77 auto_mysql_stmt(MYSQL *db) {
78 stmt = mysql_stmt_init(db);
79 }
80 ~auto_mysql_stmt() {
81 if (stmt) {
82 mysql_stmt_close(stmt);
83 }
84 }
85 operator MYSQL_STMT *() const { return stmt; }
86 private:
87 MYSQL_STMT *stmt;
88};
89
90namespace {
91
92double
93gettimeofday_double()
94{
95 struct timeval tv = { };
96 if (gettimeofday(&tv, 0) != 0) {
97 fatal_abort("gettimeofday");
98 }
99 return static_cast<double>(tv.tv_usec) / 1000000 + tv.tv_sec;
100}
101
102// unused
103void
104wait_close(int fd)
105{
106 char buf[1024];
107 while (true) {
108 int r = read(fd, buf, sizeof(buf));
109 if (r <= 0) {
110 break;
111 }
112 }
113}
114
115// unused
116void
117gentle_close(int fd)
118{
119 int r = shutdown(fd, SHUT_WR);
120 if (r != 0) {
121 return;
122 }
123 wait_close(fd);
124}
125
126};
127
128struct hstest_shared {
129 config conf;
130 socket_args arg;
131 int verbose;
132 size_t loop;
133 size_t pipe;
134 char op;
135 long num_threads;
136 mutable volatile long count;
137 mutable volatile long conn_count;
138 long wait_conn;
139 volatile char *keygen;
140 long keygen_size;
141 mutable volatile int enable_timing;
142 int usleep;
143 int dump;
144 hstest_shared() : verbose(0), loop(0), pipe(0), op('G'), num_threads(0),
145 count(0), conn_count(0), wait_conn(0), keygen(0), keygen_size(0),
146 enable_timing(0), usleep(0), dump(0) { }
147 void increment_count(unsigned int c = 1) const volatile {
148 atomic_exchange_and_add(&count, c);
149 }
150 void increment_conn(unsigned int c) const volatile {
151 atomic_exchange_and_add(&conn_count, c);
152 while (wait_conn != 0 && conn_count < wait_conn) {
153 sleep(1);
154 }
155 // fprintf(stderr, "wait_conn=%ld done\n", wait_conn);
156 }
157};
158
159struct hstest_thread {
160 struct arg_type {
161 size_t id;
162 const hstest_shared& sh;
163 bool watch_flag;
164 arg_type(size_t i, const hstest_shared& s, bool w)
165 : id(i), sh(s), watch_flag(w) { }
166 };
167 hstest_thread(const arg_type& a) : arg(a), io_success_count(0),
168 op_success_count(0), response_min(99999), response_max(0),
169 response_sum(0), response_avg(0) { }
170 void operator ()();
171 void test_1();
172 void test_2_3(int test_num);
173 void test_4_5(int test_num);
174 void test_6(int test_num);
175 void test_7(int test_num);
176 void test_8(int test_num);
177 void test_9(int test_num);
178 void test_10(int test_num);
179 void test_11(int test_num);
180 void test_12(int test_num);
181 void test_21(int test_num);
182 void test_22(int test_num);
183 void test_watch();
184 void sleep_if();
185 void set_timing(double time_spent);
186 arg_type arg;
187 auto_file fd;
188 size_t io_success_count;
189 size_t op_success_count;
190 double response_min, response_max, response_sum, response_avg;
191};
192
193void
194hstest_thread::test_1()
195{
196 char buf[1024];
197 unsigned int seed = arg.id;
198 seed ^= arg.sh.conf.get_int("seed_xor", 0);
199 std::string err;
200 if (socket_connect(fd, arg.sh.arg, err) != 0) {
201 fprintf(stderr, "connect: %d %s\n", errno, strerror(errno));
202 return;
203 }
204 const char op = arg.sh.op;
205 const int tablesize = arg.sh.conf.get_int("tablesize", 0);
206 for (size_t i = 0; i < arg.sh.loop; ++i) {
207 for (size_t j = 0; j < arg.sh.pipe; ++j) {
208 int k = 0, v = 0, len = 0;
209 if (op == 'G') {
210 k = rand_r(&seed);
211 v = rand_r(&seed); /* unused */
212 if (tablesize != 0) {
213 k &= tablesize;
214 }
215 len = snprintf(buf, sizeof(buf), "%c\tk%d\n", op, k);
216 } else {
217 k = rand_r(&seed);
218 v = rand_r(&seed);
219 if (tablesize != 0) {
220 k &= tablesize;
221 }
222 len = snprintf(buf, sizeof(buf), "%c\tk%d\tv%d\n", op, k, v);
223 }
224 const int wlen = write(fd.get(), buf, len);
225 if (wlen != len) {
226 return;
227 }
228 }
229 size_t read_cnt = 0;
230 size_t read_pos = 0;
231 while (read_cnt < arg.sh.pipe) {
232 const int rlen = read(fd.get(), buf + read_pos, sizeof(buf) - read_pos);
233 if (rlen <= 0) {
234 return;
235 }
236 read_pos += rlen;
237 while (true) {
238 const char *const p = static_cast<const char *>(memchr(buf, '\n',
239 read_pos));
240 if (p == 0) {
241 break;
242 }
243 ++read_cnt;
244 ++io_success_count;
245 arg.sh.increment_count();
246 if (p != buf && buf[0] == '=') {
247 ++op_success_count;
248 }
249 const size_t rest_size = buf + read_pos - (p + 1);
250 if (rest_size != 0) {
251 memmove(buf, p + 1, rest_size);
252 }
253 read_pos = rest_size;
254 }
255 }
256 }
257}
258
259void
260hstest_thread::test_2_3(int test_num)
261{
262#if 0
263 char buf_k[128], buf_v[128];
264 unsigned int seed = arg.id;
265 op_base_t op = static_cast<op_base_t>(arg.sh.op);
266 micli_ptr hnd;
267 if (test_num == 2) {
268 hnd = micli_i::create_remote(arg.sh.conf);
269 } else if (test_num == 3) {
270 // hnd = micli_i::create_inproc(arg.sh.localdb);
271 }
272 if (hnd.get() == 0) {
273 return;
274 }
275 for (size_t i = 0; i < arg.sh.loop; ++i) {
276 for (size_t j = 0; j < arg.sh.pipe; ++j) {
277 int k = 0, v = 0, klen = 0, vlen = 0;
278 k = rand_r(&seed);
279 klen = snprintf(buf_k, sizeof(buf_k), "k%d", k);
280 v = rand_r(&seed); /* unused */
281 vlen = snprintf(buf_v, sizeof(buf_v), "v%d", v);
282 string_ref arr[2];
283 arr[0] = string_ref(buf_k, klen);
284 arr[1] = string_ref(buf_v, vlen);
285 pstrarr_ptr rec(arr, 2);
286 if (hnd->execute(op, 0, 0, rec.get_const())) {
287 ++io_success_count;
288 arg.sh.increment_count();
289 const dataset& res = hnd->get_result_ref();
290 if (res.size() == 1) {
291 ++op_success_count;
292 }
293 }
294 }
295 }
296#endif
297}
298
299void
300hstest_thread::test_4_5(int test_num)
301{
302#if 0
303 char buf_k[128], buf_v[8192];
304 memset(buf_v, ' ', sizeof(buf_v));
305 unsigned int seed = arg.id;
306 op_base_t op = static_cast<op_base_t>(arg.sh.op);
307 micli_ptr hnd;
308 if (test_num == 4) {
309 hnd = micli_i::create_remote(arg.sh.conf);
310 } else if (test_num == 5) {
311 hnd = micli_i::create_inproc(arg.sh.localdb);
312 }
313 if (hnd.get() == 0) {
314 return;
315 }
316 for (size_t i = 0; i < arg.sh.loop; ++i) {
317 for (size_t j = 0; j < arg.sh.pipe; ++j) {
318 int k = 0, klen = 0, vlen = 0;
319 k = i & 0x0000ffffUL;
320 if (k == 0) {
321 fprintf(stderr, "k=0\n");
322 }
323 klen = snprintf(buf_k, sizeof(buf_k), "k%d", k);
324 vlen = rand_r(&seed) % 8192;
325 string_ref arr[2];
326 arr[0] = string_ref(buf_k, klen);
327 arr[1] = string_ref(buf_v, vlen);
328 pstrarr_ptr rec(arr, 2);
329 if (hnd->execute(op, 0, 0, rec.get_const())) {
330 ++io_success_count;
331 const dataset& res = hnd->get_result_ref();
332 if (res.size() == 1) {
333 ++op_success_count;
334 }
335 }
336 }
337 }
338#endif
339}
340
341void
342hstest_thread::test_6(int test_num)
343{
344 int count = arg.sh.conf.get_int("count", 1);
345 auto_file fds[count];
346 for (int i = 0; i < count; ++i) {
347 const double t1 = gettimeofday_double();
348 std::string err;
349 if (socket_connect(fds[i], arg.sh.arg, err) != 0) {
350 fprintf(stderr, "id=%zu i=%d err=%s\n", arg.id, i, err.c_str());
351 }
352 const double t2 = gettimeofday_double();
353 if (t2 - t1 > 1) {
354 fprintf(stderr, "id=%zu i=%d time %f\n", arg.id, i, t2 - t1);
355 }
356 }
357}
358
359void
360hstest_thread::test_7(int num)
361{
362 /*
363 set foo 0 0 10
364 0123456789
365 STORED
366 get foo
367 VALUE foo 0 10
368 0123456789
369 END
370 get var
371 END
372 */
373 char buf[1024];
374 const int keep_connection = arg.sh.conf.get_int("keep_connection", 1);
375 unsigned int seed = arg.id;
376 seed ^= arg.sh.conf.get_int("seed_xor", 0);
377 const int tablesize = arg.sh.conf.get_int("tablesize", 0);
378 const char op = arg.sh.op;
379 for (size_t i = 0; i < arg.sh.loop; ++i) {
380 const double tm1 = gettimeofday_double();
381 std::string err;
382 if (fd.get() < 0 && socket_connect(fd, arg.sh.arg, err) != 0) {
383 fprintf(stderr, "connect: %d %s\n", errno, strerror(errno));
384 return;
385 }
386 for (size_t j = 0; j < arg.sh.pipe; ++j) {
387 int k = 0, v = 0, len = 0;
388 if (op == 'G') {
389 k = rand_r(&seed);
390 v = rand_r(&seed); /* unused */
391 if (tablesize != 0) {
392 k &= tablesize;
393 }
394 len = snprintf(buf, sizeof(buf), "get k%d\r\n", k);
395 } else {
396 k = rand_r(&seed);
397 v = rand_r(&seed);
398 if (tablesize != 0) {
399 k &= tablesize;
400 }
401 char vbuf[1024];
402 int vlen = snprintf(vbuf, sizeof(vbuf),
403 "v%d"
404 // "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
405 // "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
406 // "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
407 // "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
408 // "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
409 , v);
410 len = snprintf(buf, sizeof(buf), "set k%d 0 0 %d\r\n%s\r\n",
411 k, vlen, vbuf);
412 }
413 const int wlen = write(fd.get(), buf, len);
414 if (wlen != len) {
415 return;
416 }
417 }
418 size_t read_cnt = 0;
419 size_t read_pos = 0;
420 bool read_response_done = false;
421 bool expect_value = false;
422 while (!read_response_done) {
423 const int rlen = read(fd.get(), buf + read_pos, sizeof(buf) - read_pos);
424 if (rlen <= 0) {
425 return;
426 }
427 read_pos += rlen;
428 while (true) {
429 const char *const p = static_cast<const char *>(memchr(buf, '\n',
430 read_pos));
431 if (p == 0) {
432 break;
433 }
434 ++read_cnt;
435 if (expect_value) {
436 expect_value = false;
437 } else if (p >= buf + 6 && memcmp(buf, "VALUE ", 6) == 0) {
438 expect_value = true;
439 ++op_success_count;
440 } else {
441 if (p == buf + 7 && memcmp(buf, "STORED\r", 7) == 0) {
442 ++op_success_count;
443 }
444 read_response_done = true;
445 }
446 const size_t rest_size = buf + read_pos - (p + 1);
447 if (rest_size != 0) {
448 memmove(buf, p + 1, rest_size);
449 }
450 read_pos = rest_size;
451 }
452 ++io_success_count;
453 }
454 arg.sh.increment_count();
455 if (!keep_connection) {
456 fd.close();
457 }
458 const double tm2 = gettimeofday_double();
459 set_timing(tm2 - tm1);
460 sleep_if();
461 }
462}
463
464struct rec {
465 std::string key;
466 std::string value;
467};
468
469void
470hstest_thread::test_8(int test_num)
471{
472#if 0
473 char buf_k[128], buf_v[128];
474 unsigned int seed = arg.id;
475 // op_base_t op = static_cast<op_base_t>(arg.sh.op);
476 using namespace boost::multi_index;
477 typedef member<rec, std::string, &rec::key> rec_get_key;
478 typedef ordered_unique<rec_get_key> oui;
479 typedef multi_index_container< rec, indexed_by<oui> > mic;
480 #if 0
481 typedef std::map<std::string, std::string> m_type;
482 m_type m;
483 #endif
484 mic m;
485 for (size_t i = 0; i < arg.sh.loop; ++i) {
486 for (size_t j = 0; j < arg.sh.pipe; ++j) {
487 int k = 0, v = 0, klen = 0, vlen = 0;
488 k = rand_r(&seed);
489 klen = snprintf(buf_k, sizeof(buf_k), "k%d", k);
490 v = rand_r(&seed); /* unused */
491 vlen = snprintf(buf_v, sizeof(buf_v), "v%d", v);
492 const std::string ks(buf_k, klen);
493 const std::string vs(buf_v, vlen);
494 rec r;
495 r.key = ks;
496 r.value = vs;
497 m.insert(r);
498 // m.insert(std::make_pair(ks, vs));
499 ++io_success_count;
500 ++op_success_count;
501 arg.sh.increment_count();
502 }
503 }
504#endif
505}
506
507struct mysqltest_thread_initobj : private noncopyable {
508 mysqltest_thread_initobj() {
509 mysql_thread_init();
510 }
511 ~mysqltest_thread_initobj() {
512 mysql_thread_end();
513 }
514};
515
516void
517hstest_thread::test_9(int test_num)
518{
519 /* create table hstest
520 * ( k varchar(255) not null, v varchar(255) not null, primary key(k))
521 * engine = innodb; */
522 auto_mysql db;
523 // mysqltest_thread_initobj initobj;
524 std::string err;
525 const char op = arg.sh.op;
526 const std::string suffix = arg.sh.conf.get_str("value_suffix", "upd");
527 unsigned long long err_cnt = 0;
528 unsigned long long query_cnt = 0;
529 #if 0
530 my_bool reconnect = 0;
531 if (mysql_options(db, MYSQL_OPT_RECONNECT, &reconnect) != 0) {
532 err = "mysql_options() failed";
533 ++err_cnt;
534 return;
535 }
536 #endif
537 unsigned int seed = time(0) + arg.id + 1;
538 seed ^= arg.sh.conf.get_int("seed_xor", 0);
539 drand48_data randbuf;
540 srand48_r(seed, &randbuf);
541 const std::string mysql_host = arg.sh.conf.get_str("host", "localhost");
542 const int mysql_port = arg.sh.conf.get_int("mysqlport", 3306);
543 const int num = arg.sh.loop;
544 const std::string mysql_user = arg.sh.conf.get_str("mysqluser", "root");
545 const std::string mysql_passwd = arg.sh.conf.get_str("mysqlpass", "");
546 const std::string mysql_dbname = arg.sh.conf.get_str("dbname", "hstest");
547 const int keep_connection = arg.sh.conf.get_int("keep_connection", 1);
548 const int verbose = arg.sh.conf.get_int("verbose", 1);
549 const int tablesize = arg.sh.conf.get_int("tablesize", 10000);
550 const int moreflds = arg.sh.conf.get_int("moreflds", 0);
551 const std::string moreflds_prefix = arg.sh.conf.get_str(
552 "moreflds_prefix", "column0123456789_");
553 const int use_handler = arg.sh.conf.get_int("handler", 0);
554 const int sched_flag = arg.sh.conf.get_int("sched", 0);
555 const int ssps = arg.sh.conf.get_int("ssps", 0);
556 std::string flds = "v";
557 for (int i = 0; i < moreflds; ++i) {
558 char buf[1024];
559 snprintf(buf, sizeof(buf), ",%s%d", moreflds_prefix.c_str(), i);
560 flds += std::string(buf);
561 }
562 int connected = 0;
563 std::auto_ptr<auto_mysql_stmt> stmt;
564 for (int i = 0; i < num; ++i) {
565 const double tm1 = gettimeofday_double();
566 const int flags = 0;
567 if (connected == 0) {
568 if (!mysql_real_connect(db, mysql_host.c_str(),
569 mysql_user.c_str(), mysql_user.empty() ? 0 : mysql_passwd.c_str(),
570 mysql_dbname.c_str(), mysql_port, 0, flags)) {
571 err = "failed to connect: " + std::string(mysql_error(db));
572 if (verbose >= 1) {
573 fprintf(stderr, "e=[%s]\n", err.c_str());
574 }
575 ++err_cnt;
576 return;
577 }
578 arg.sh.increment_conn(1);
579 }
580 int r = 0;
581 if (connected == 0 && use_handler) {
582 const char *const q = "handler hstest_table1 open";
583 r = mysql_real_query(db, q, strlen(q));
584 if (r != 0) {
585 err = 1;
586 }
587 }
588 if (connected == 0 && ssps) {
589 stmt.reset(new auto_mysql_stmt(db));
590 const char *const q = "select v from hstest_table1 where k = ?";
591 r = mysql_stmt_prepare(*stmt, q, strlen(q));
592 if (r != 0) {
593 fprintf(stderr, "ssps err\n");
594 ++err_cnt;
595 return;
596 }
597 }
598 connected = 1;
599 std::string result_str;
600 unsigned int err = 0;
601 unsigned int num_flds = 0, num_affected_rows = 0;
602 int got_data = 0;
603 char buf_query[16384];
604 int buf_query_len = 0;
605 int k = 0, v = 0;
606 {
607 double kf = 0, vf = 0;
608 drand48_r(&randbuf, &kf);
609 drand48_r(&randbuf, &vf);
610 k = int(kf * tablesize);
611 v = int(vf * tablesize);
612 #if 0
613 k = rand_r(&seed);
614 v = rand_r(&seed);
615 if (tablesize != 0) {
616 k %= tablesize;
617 }
618 #endif
619 if (op == 'G') {
620 if (use_handler) {
621 buf_query_len = snprintf(buf_query, sizeof(buf_query),
622 "handler hstest_table1 read `primary` = ( '%d' )", k);
623 // TODO: moreflds
624 } else if (ssps) {
625 //
626 } else {
627 buf_query_len = snprintf(buf_query, sizeof(buf_query),
628 "select %s from hstest_table1 where k = '%d'", flds.c_str(), k);
629 }
630 } else if (op == 'U') {
631 buf_query_len = snprintf(buf_query, sizeof(buf_query),
632 "update hstest_table1 set v = '%d_%d%s' where k = '%d'",
633 v, k, suffix.c_str(), k);
634 } else if (op == 'R') {
635 buf_query_len = snprintf(buf_query, sizeof(buf_query),
636 "replace into hstest_table1 values ('%d', 'v%d')", k, v);
637 // TODO: moreflds
638 }
639 }
640 if (r == 0) {
641 if (ssps) {
642 MYSQL_BIND bind[1] = { };
643 bind[0].buffer_type = MYSQL_TYPE_LONG;
644 bind[0].buffer = (char *)&k;
645 bind[0].is_null = 0;
646 bind[0].length = 0;
647 if (mysql_stmt_bind_param(*stmt, bind)) {
648 fprintf(stderr, "err: %s\n", mysql_stmt_error(*stmt));
649 ++err_cnt;
650 return;
651 }
652 r = mysql_stmt_execute(*stmt);
653 // fprintf(stderr, "stmt exec\n");
654 } else {
655 r = mysql_real_query(db, buf_query, buf_query_len);
656 // fprintf(stderr, "real query\n");
657 }
658 ++query_cnt;
659 }
660 if (r != 0) {
661 err = 1;
662 } else if (ssps) {
663 if (verbose >= 0) {
664 char resbuf[1024];
665 unsigned long res_len = 0;
666 MYSQL_BIND bind[1] = { };
667 bind[0].buffer_type = MYSQL_TYPE_STRING;
668 bind[0].buffer = resbuf;
669 bind[0].buffer_length = sizeof(resbuf);
670 bind[0].length = &res_len;
671 if (mysql_stmt_bind_result(*stmt, bind)) {
672 fprintf(stderr, "err: %s\n", mysql_stmt_error(*stmt));
673 ++err_cnt;
674 return;
675 }
676 if (mysql_stmt_fetch(*stmt)) {
677 fprintf(stderr, "err: %s\n", mysql_stmt_error(*stmt));
678 ++err_cnt;
679 return;
680 }
681 if (!result_str.empty()) {
682 result_str += " ";
683 }
684 result_str += std::string(resbuf, res_len);
685 // fprintf(stderr, "SSPS RES: %s\n", result_str.c_str());
686 got_data = 1;
687 } else {
688 got_data = 1;
689 }
690 } else {
691 auto_mysql_res res(db);
692 if (res != 0) {
693 if (verbose >= 0) {
694 num_flds = mysql_num_fields(res);
695 MYSQL_ROW row = 0;
696 while ((row = mysql_fetch_row(res)) != 0) {
697 got_data = 1;
698 unsigned long *const lengths = mysql_fetch_lengths(res);
699 if (verbose >= 2) {
700 for (unsigned int i = 0; i < num_flds; ++i) {
701 if (!result_str.empty()) {
702 result_str += " ";
703 }
704 result_str += std::string(row[i], lengths[i]);
705 }
706 }
707 }
708 } else {
709 got_data = 1;
710 }
711 } else {
712 if (mysql_field_count(db) == 0) {
713 num_affected_rows = mysql_affected_rows(db);
714 } else {
715 err = 1;
716 }
717 }
718 }
719 if (verbose >= 2 || (verbose >= 1 && err != 0)) {
720 if (err) {
721 ++err_cnt;
722 const char *const errstr = mysql_error(db);
723 fprintf(stderr, "e=[%s] a=%u q=[%s]\n", errstr,
724 num_affected_rows, buf_query);
725 } else {
726 fprintf(stderr, "a=%u q=[%s] r=[%s]\n", num_affected_rows, buf_query,
727 result_str.c_str());
728 }
729 }
730 if (err == 0) {
731 ++io_success_count;
732 if (num_affected_rows > 0 || got_data > 0) {
733 ++op_success_count;
734 } else {
735 if (verbose >= 1) {
736 fprintf(stderr, "k=%d numaff=%u gotdata=%d\n",
737 k, num_affected_rows, got_data);
738 }
739 }
740 arg.sh.increment_count();
741 }
742 if (!keep_connection) {
743 if (stmt.get() != 0) {
744 stmt.reset();
745 }
746 db.reset();
747 connected = 0;
748 }
749 const double tm2 = gettimeofday_double();
750 set_timing(tm2 - tm1);
751 sleep_if();
752 if (sched_flag) {
753 sched_yield();
754 }
755 }
756 if (verbose >= 1) {
757 fprintf(stderr, "thread finished (error_count=%llu)\n", err_cnt);
758 }
759}
760
761void
762hstest_thread::test_10(int test_num)
763{
764 const int keep_connection = arg.sh.conf.get_int("keep_connection", 1);
765 unsigned int seed = time(0) + arg.id + 1;
766 seed ^= arg.sh.conf.get_int("seed_xor", 0);
767 drand48_data randbuf;
768 srand48_r(seed, &randbuf);
769 std::string err;
770 int keepconn_count = 0;
771 const char op = arg.sh.op;
772 const int verbose = arg.sh.conf.get_int("verbose", 1);
773 const std::string suffix = arg.sh.conf.get_str("value_suffix", "upd");
774 const int tablesize = arg.sh.conf.get_int("tablesize", 10000);
775 const int firstkey = arg.sh.conf.get_int("firstkey", 0);
776 const int sched_flag = arg.sh.conf.get_int("sched", 0);
777 const int moreflds = arg.sh.conf.get_int("moreflds", 0);
778 const std::string dbname = arg.sh.conf.get_str("dbname", "hstest");
779 const std::string table = arg.sh.conf.get_str("table", "hstest_table1");
780 const std::string index = arg.sh.conf.get_str("index", "PRIMARY");
781 const std::string field = arg.sh.conf.get_str("field", "v");
782 const std::string moreflds_prefix = arg.sh.conf.get_str(
783 "moreflds_prefix", "column0123456789_");
784 const int dump = arg.sh.dump;
785 const int nodup = arg.sh.conf.get_int("nodup", 0);
786 std::string moreflds_str;
787 for (int i = 0; i < moreflds; ++i) {
788 char sbuf[1024];
789 snprintf(sbuf, sizeof(sbuf), ",%s%d", moreflds_prefix.c_str(), i);
790 moreflds_str += std::string(sbuf);
791 }
792 char wbuf[16384], rbuf[16384];
793 int wbuflen = 0;
794 for (size_t i = 0; i < arg.sh.loop; ++i) {
795 int len = 0, rlen = 0, wlen = 0;
796 #if 0
797 const double tm1 = gettimeofday_double();
798 #endif
799 if (fd.get() < 0) {
800 if (socket_connect(fd, arg.sh.arg, err) != 0) {
801 fprintf(stderr, "connect: %d %s\n", errno, strerror(errno));
802 return;
803 }
804 len = snprintf(wbuf, sizeof(wbuf),
805 "P\t1\t%s\t%s\tPRIMARY\t%s%s\n", dbname.c_str(), table.c_str(),
806 field.c_str(), moreflds_str.c_str());
807 /* pst_num, db, table, index, retflds */
808 wlen = write(fd.get(), wbuf, len);
809 if (len != wlen) {
810 fprintf(stderr, "write: %d %d\n", len, wlen);
811 return;
812 }
813 rlen = read(fd.get(), rbuf, sizeof(rbuf));
814 if (rlen <= 0 || rbuf[rlen - 1] != '\n') {
815 fprintf(stderr, "read: rlen=%d errno=%d\n", rlen, errno);
816 return;
817 }
818 if (rbuf[0] != '0') {
819 fprintf(stderr, "failed to open table\n");
820 return;
821 }
822 arg.sh.increment_conn(1);
823 }
824 const double tm1 = gettimeofday_double();
825 for (size_t j = 0; j < arg.sh.pipe; ++j) {
826 int k = 0, v = 0;
827 wbuflen = 0;
828 {
829 while (true) {
830 double kf = 0, vf = 0;
831 drand48_r(&randbuf, &kf);
832 drand48_r(&randbuf, &vf);
833 k = int(kf * tablesize) + firstkey;
834 v = int(vf * tablesize) + firstkey;
835 // k = rand_r(&seed);
836 // v = rand_r(&seed); /* unused */
837 #if 0
838 if (tablesize != 0) {
839 k &= tablesize;
840 }
841 #endif
842 if (op == 'G') {
843 wbuflen = snprintf(wbuf, sizeof(wbuf), "1\t=\t1\t%d\n", k);
844 } else if (op == 'U') {
845 wbuflen = snprintf(wbuf, sizeof(wbuf),
846 "1\t=\t1\t%d\t1\t0\tU\t%d_%d%s\n", k, v, k, suffix.c_str());
847 }
848 if (k - firstkey < arg.sh.keygen_size) {
849 volatile char *const ptr = arg.sh.keygen + (k - firstkey);
850 // int oldv = __sync_fetch_and_or(ptr, 1);
851 int oldv = *ptr;
852 *ptr += 1;
853 if (nodup && oldv != 0) {
854 if (dump) {
855 fprintf(stderr, "retry\n");
856 }
857 continue;
858 }
859 } else {
860 if (nodup) {
861 if (dump) {
862 fprintf(stderr, "retry2\n");
863 }
864 continue;
865 }
866 }
867 break;
868 }
869 }
870 wlen = write(fd.get(), wbuf, wbuflen);
871 if (wlen != wbuflen) {
872 fprintf(stderr, "write: %d %d\n", wbuflen, wlen);
873 return;
874 }
875 }
876 size_t read_cnt = 0;
877 size_t read_pos = 0;
878 while (read_cnt < arg.sh.pipe) {
879 rlen = read(fd.get(), rbuf + read_pos, sizeof(rbuf) - read_pos);
880 if (rlen <= 0) {
881 fprintf(stderr, "read: %d\n", rlen);
882 return;
883 }
884 read_pos += rlen;
885 while (true) {
886 const char *const nl = static_cast<const char *>(memchr(rbuf, '\n',
887 read_pos));
888 if (nl == 0) {
889 break;
890 }
891 ++read_cnt;
892 ++io_success_count;
893 const char *t1 = static_cast<const char *>(memchr(rbuf, '\t',
894 nl - rbuf));
895 if (t1 == 0) {
896 fprintf(stderr, "error \n");
897 break;
898 }
899 ++t1;
900 const char *t2 = static_cast<const char *>(memchr(t1, '\t',
901 nl - t1));
902 if (t2 == 0) {
903 if (verbose > 1) {
904 fprintf(stderr, "key: notfound \n");
905 }
906 break;
907 }
908 ++t2;
909 if (t1 == rbuf + 2 && rbuf[0] == '0') {
910 if (op == 'G') {
911 ++op_success_count;
912 arg.sh.increment_count();
913 } else if (op == 'U') {
914 const char *t3 = t2;
915 while (t3 != nl && t3[0] >= 0x10) {
916 ++t3;
917 }
918 if (t3 != t2 + 1 || t2[0] != '1') {
919 const std::string mess(t2, t3);
920 fprintf(stderr, "mod: %s\n", mess.c_str());
921 } else {
922 ++op_success_count;
923 arg.sh.increment_count();
924 if (arg.sh.dump && arg.sh.pipe == 1) {
925 fwrite(wbuf, wbuflen, 1, stderr);
926 }
927 }
928 }
929 } else {
930 const char *t3 = t2;
931 while (t3 != nl && t3[0] >= 0x10) {
932 ++t3;
933 }
934 const std::string mess(t2, t3);
935 fprintf(stderr, "err: %s\n", mess.c_str());
936 }
937 const size_t rest_size = rbuf + read_pos - (nl + 1);
938 if (rest_size != 0) {
939 memmove(rbuf, nl + 1, rest_size);
940 }
941 read_pos = rest_size;
942 }
943 }
944 if (!keep_connection) {
945 fd.reset();
946 arg.sh.increment_conn(-1);
947 } else if (keep_connection > 1 && ++keepconn_count > keep_connection) {
948 keepconn_count = 0;
949 fd.reset();
950 arg.sh.increment_conn(-1);
951 }
952 const double tm2 = gettimeofday_double();
953 set_timing(tm2 - tm1);
954 sleep_if();
955 if (sched_flag) {
956 sched_yield();
957 }
958 }
959 if (dump) {
960 fprintf(stderr, "done\n");
961 }
962}
963
964void
965hstest_thread::sleep_if()
966{
967 if (arg.sh.usleep) {
968 struct timespec ts = {
969 arg.sh.usleep / 1000000,
970 (arg.sh.usleep % 1000000) * 1000
971 };
972 nanosleep(&ts, 0);
973 }
974}
975
976void
977hstest_thread::set_timing(double time_spent)
978{
979 response_min = std::min(response_min, time_spent);
980 response_max = std::max(response_max, time_spent);
981 response_sum += time_spent;
982 if (op_success_count != 0) {
983 response_avg = response_sum / op_success_count;
984 }
985}
986
987void
988hstest_thread::test_11(int test_num)
989{
990 const int keep_connection = arg.sh.conf.get_int("keep_connection", 1);
991 const int tablesize = arg.sh.conf.get_int("tablesize", 0);
992 unsigned int seed = arg.id;
993 seed ^= arg.sh.conf.get_int("seed_xor", 0);
994 std::string err;
995 hstcpcli_ptr cli;
996 for (size_t i = 0; i < arg.sh.loop; ++i) {
997 if (cli.get() == 0) {
998 cli = hstcpcli_i::create(arg.sh.arg);
999 cli->request_buf_open_index(0, "hstest", "hstest_table1", "", "v");
1000 /* pst_num, db, table, index, retflds */
1001 if (cli->request_send() != 0) {
1002 fprintf(stderr, "reuqest_send: %s\n", cli->get_error().c_str());
1003 return;
1004 }
1005 size_t num_flds = 0;
1006 if (cli->response_recv(num_flds) != 0) {
1007 fprintf(stderr, "reuqest_recv: %s\n", cli->get_error().c_str());
1008 return;
1009 }
1010 cli->response_buf_remove();
1011 }
1012 for (size_t j = 0; j < arg.sh.pipe; ++j) {
1013 char buf[256];
1014 int k = 0, v = 0, len = 0;
1015 {
1016 k = rand_r(&seed);
1017 v = rand_r(&seed); /* unused */
1018 if (tablesize != 0) {
1019 k &= tablesize;
1020 }
1021 len = snprintf(buf, sizeof(buf), "%d", k);
1022 }
1023 const string_ref key(buf, len);
1024 const string_ref op("=", 1);
1025 cli->request_buf_exec_generic(0, op, &key, 1, 1, 0, string_ref(), 0, 0);
1026 }
1027 if (cli->request_send() != 0) {
1028 fprintf(stderr, "reuqest_send: %s\n", cli->get_error().c_str());
1029 return;
1030 }
1031 size_t read_cnt = 0;
1032 for (size_t j = 0; j < arg.sh.pipe; ++j) {
1033 size_t num_flds = 0;
1034 if (cli->response_recv(num_flds) != 0) {
1035 fprintf(stderr, "reuqest_recv: %s\n", cli->get_error().c_str());
1036 return;
1037 }
1038 {
1039 ++read_cnt;
1040 ++io_success_count;
1041 arg.sh.increment_count();
1042 {
1043 ++op_success_count;
1044 }
1045 }
1046 cli->response_buf_remove();
1047 }
1048 if (!keep_connection) {
1049 cli.reset();
1050 }
1051 }
1052}
1053
1054void
1055hstest_thread::test_watch()
1056{
1057 const int timelimit = arg.sh.conf.get_int("timelimit", 0);
1058 const int timelimit_offset = timelimit / 2;
1059 int loop = 0;
1060 double t1 = 0, t2 = 0;
1061 size_t cnt_t1 = 0, cnt_t2 = 0;
1062 size_t prev_cnt = 0;
1063 double now_f = 0;
1064 while (true) {
1065 sleep(1);
1066 const size_t cnt = arg.sh.count;
1067 const size_t df = cnt - prev_cnt;
1068 prev_cnt = cnt;
1069 const double now_prev = now_f;
1070 now_f = gettimeofday_double();
1071 if (now_prev != 0) {
1072 const double rps = static_cast<double>(df) / (now_f - now_prev);
1073 fprintf(stderr, "now: %zu cntdiff: %zu tdiff: %f rps: %f\n",
1074 static_cast<size_t>(now_f), df, now_f - now_prev, rps);
1075 }
1076 if (timelimit != 0) {
1077 if (arg.sh.wait_conn == 0 || arg.sh.conn_count >= arg.sh.wait_conn) {
1078 ++loop;
1079 }
1080 if (loop == timelimit_offset) {
1081 t1 = gettimeofday_double();
1082 cnt_t1 = cnt;
1083 arg.sh.enable_timing = 1;
1084 fprintf(stderr, "start timing\n");
1085 } else if (loop == timelimit_offset + timelimit) {
1086 t2 = gettimeofday_double();
1087 cnt_t2 = cnt;
1088 const size_t cnt_diff = cnt_t2 - cnt_t1;
1089 const double tdiff = t2 - t1;
1090 const double qps = cnt_diff / (tdiff != 0 ? tdiff : 1);
1091 fprintf(stderr, "(%f: %zu, %f: %zu), %10.5f qps\n",
1092 t1, cnt_t1, t2, cnt_t2, qps);
1093 size_t keycnt = 0;
1094 for (int i = 0; i < arg.sh.keygen_size; ++i) {
1095 if (arg.sh.keygen[i]) {
1096 ++keycnt;
1097 }
1098 }
1099 fprintf(stderr, "keygen=%zu\n", keycnt);
1100 break;
1101 }
1102 }
1103 }
1104#if 0
1105 int loop = 0;
1106 double t1 = 0, t2 = 0;
1107 size_t cnt_t1 = 0, cnt_t2 = 0;
1108 size_t prev_cnt = 0;
1109 while (true) {
1110 sleep(1);
1111 const size_t cnt = arg.sh.count;
1112 const size_t df = cnt - prev_cnt;
1113 prev_cnt = cnt;
1114 const size_t now = time(0);
1115 fprintf(stderr, "%zu %zu\n", now, df);
1116 if (timelimit != 0) {
1117 ++loop;
1118 if (loop == timelimit_offset) {
1119 t1 = gettimeofday_double();
1120 cnt_t1 = cnt;
1121 } else if (loop == timelimit_offset + timelimit) {
1122 t2 = gettimeofday_double();
1123 cnt_t2 = cnt;
1124 const size_t cnt_diff = cnt_t2 - cnt_t1;
1125 const double tdiff = t2 - t1;
1126 const double qps = cnt_diff / (tdiff != 0 ? tdiff : 1);
1127 fprintf(stderr, "(%f: %zu, %f: %zu), %10.5f qps\n",
1128 t1, cnt_t1, t2, cnt_t2, qps);
1129 size_t keycnt = 0;
1130 for (int i = 0; i < arg.sh.keygen_size; ++i) {
1131 if (arg.sh.keygen[i]) {
1132 ++keycnt;
1133 }
1134 }
1135 fprintf(stderr, "keygen=%zu\n", keycnt);
1136 _exit(0);
1137 }
1138 }
1139 }
1140#endif
1141}
1142
1143void
1144hstest_thread::test_12(int test_num)
1145{
1146 /* NOTE: num_threads should be 1 */
1147 /* create table hstest
1148 * ( k varchar(255) not null, v varchar(255) not null, primary key(k))
1149 * engine = innodb; */
1150 mysqltest_thread_initobj initobj;
1151 auto_mysql db;
1152 std::string err;
1153 unsigned long long err_cnt = 0;
1154 unsigned long long query_cnt = 0;
1155 #if 0
1156 my_bool reconnect = 0;
1157 if (mysql_options(db, MYSQL_OPT_RECONNECT, &reconnect) != 0) {
1158 err = "mysql_options() failed";
1159 ++err_cnt;
1160 return;
1161 }
1162 #endif
1163 const std::string mysql_host = arg.sh.conf.get_str("host", "localhost");
1164 const int mysql_port = arg.sh.conf.get_int("mysqlport", 3306);
1165 const unsigned int num = arg.sh.loop;
1166 const size_t pipe = arg.sh.pipe;
1167 const std::string mysql_user = arg.sh.conf.get_str("mysqluser", "root");
1168 const std::string mysql_passwd = arg.sh.conf.get_str("mysqlpass", "");
1169 const std::string mysql_dbname = arg.sh.conf.get_str("db", "hstest");
1170 const int keep_connection = arg.sh.conf.get_int("keep_connection", 1);
1171 const int verbose = arg.sh.conf.get_int("verbose", 1);
1172 const int use_handler = arg.sh.conf.get_int("handler", 0);
1173 int connected = 0;
1174 unsigned int k = 0;
1175 string_buffer buf;
1176 for (unsigned int i = 0; i < num; ++i) {
1177 const int flags = 0;
1178 if (connected == 0 && !mysql_real_connect(db, mysql_host.c_str(),
1179 mysql_user.c_str(), mysql_user.empty() ? 0 : mysql_passwd.c_str(),
1180 mysql_dbname.c_str(), mysql_port, 0, flags)) {
1181 err = "failed to connect: " + std::string(mysql_error(db));
1182 if (verbose >= 1) {
1183 fprintf(stderr, "e=[%s]\n", err.c_str());
1184 }
1185 ++err_cnt;
1186 return;
1187 }
1188 int r = 0;
1189 if (connected == 0 && use_handler) {
1190 const char *const q = "handler hstest open";
1191 r = mysql_real_query(db, q, strlen(q));
1192 if (r != 0) {
1193 err = 1;
1194 }
1195 }
1196 connected = 1;
1197 std::string result_str;
1198 unsigned int err = 0;
1199 unsigned int num_flds = 0, num_affected_rows = 0;
1200 int got_data = 0;
1201 buf.clear();
1202 buf.append_literal("insert into hstest values ");
1203 for (size_t j = 0; j < pipe; ++j) {
1204 const unsigned int v = ~k;
1205 if (j != 0) {
1206 buf.append_literal(",");
1207 }
1208 char *wp = buf.make_space(64);
1209 int buf_query_len = snprintf(wp, 64, "('k%u', 'v%u')", k, v);
1210 buf.space_wrote(buf_query_len);
1211 ++k;
1212 }
1213 if (r == 0) {
1214 r = mysql_real_query(db, buf.begin(), buf.size());
1215 ++query_cnt;
1216 }
1217 if (r != 0) {
1218 err = 1;
1219 } else {
1220 auto_mysql_res res(db);
1221 if (res != 0) {
1222 if (verbose >= 0) {
1223 num_flds = mysql_num_fields(res);
1224 MYSQL_ROW row = 0;
1225 while ((row = mysql_fetch_row(res)) != 0) {
1226 got_data = 1;
1227 unsigned long *const lengths = mysql_fetch_lengths(res);
1228 if (verbose >= 2) {
1229 for (unsigned int i = 0; i < num_flds; ++i) {
1230 if (!result_str.empty()) {
1231 result_str += " ";
1232 }
1233 result_str += std::string(row[i], lengths[i]);
1234 }
1235 }
1236 }
1237 }
1238 } else {
1239 if (mysql_field_count(db) == 0) {
1240 num_affected_rows = mysql_affected_rows(db);
1241 } else {
1242 err = 1;
1243 }
1244 }
1245 }
1246 if (verbose >= 2 || (verbose >= 1 && err != 0)) {
1247 if (err) {
1248 ++err_cnt;
1249 const char *const errstr = mysql_error(db);
1250 fprintf(stderr, "e=[%s] a=%u q=[%s]\n", errstr,
1251 num_affected_rows, std::string(buf.begin(), buf.size()).c_str());
1252 } else {
1253 fprintf(stderr, "a=%u q=[%s] r=[%s]\n", num_affected_rows,
1254 std::string(buf.begin(), buf.size()).c_str(),
1255 result_str.c_str());
1256 }
1257 }
1258 if (err == 0) {
1259 ++io_success_count;
1260 if (num_affected_rows > 0 || got_data > 0) {
1261 ++op_success_count;
1262 }
1263 arg.sh.increment_count(pipe);
1264 }
1265 if (!keep_connection) {
1266 db.reset();
1267 connected = 0;
1268 }
1269 }
1270 if (verbose >= 1) {
1271 fprintf(stderr, "thread finished (error_count=%llu)\n", err_cnt);
1272 }
1273}
1274
1275void
1276hstest_thread::test_21(int num)
1277{
1278 /* fsync test */
1279 unsigned int id = arg.id;
1280 std::string err;
1281 #if 0
1282 if (socket_connect(fd, arg.sh.arg, err) != 0) {
1283 fprintf(stderr, "connect: %d %s\n", errno, strerror(errno));
1284 return;
1285 }
1286 #endif
1287 auto_file logfd;
1288 char fname[1024];
1289 snprintf(fname, sizeof(fname), "synctest_%u", id);
1290 int open_flags = O_WRONLY | O_CREAT | O_TRUNC | O_APPEND;
1291 logfd.reset(open(fname, open_flags, 0644));
1292 if (logfd.get() < 0) {
1293 fprintf(stderr, "open: %s: %d %s\n", fname, errno, strerror(errno));
1294 return;
1295 }
1296 char buf[1024];
1297 unsigned long long count = 0;
1298 while (true) {
1299 snprintf(buf, sizeof(buf), "%u %llu\n", id, count);
1300 const size_t len = strlen(buf);
1301 if (write(logfd.get(), buf, len) != (ssize_t)len) {
1302 fprintf(stderr, "write: %s: %d %s\n", fname, errno, strerror(errno));
1303 return;
1304 }
1305 #if 0
1306 if (write(fd.get(), buf, len) != (ssize_t)len) {
1307 fprintf(stderr, "write(sock): %d %s\n", errno, strerror(errno));
1308 return;
1309 }
1310 #endif
1311 if (fdatasync(logfd.get()) != 0) {
1312 fprintf(stderr, "fsync: %s: %d %s\n", fname, errno, strerror(errno));
1313 return;
1314 }
1315 ++count;
1316 ++op_success_count;
1317 arg.sh.increment_count();
1318 }
1319}
1320
1321void
1322hstest_thread::test_22(int num)
1323{
1324 /* dd if=/dev/zero of=dummy.dat bs=1024M count=100 */
1325 unsigned int id = arg.id;
1326 std::string err;
1327 auto_file filefd;
1328 char fname[1024];
1329 snprintf(fname, sizeof(fname), "dummy.dat");
1330 int open_flags = O_RDONLY | O_DIRECT;
1331 filefd.reset(open(fname, open_flags, 0644));
1332 if (filefd.get() < 0) {
1333 fprintf(stderr, "open: %s: %d %s\n", fname, errno, strerror(errno));
1334 return;
1335 }
1336 char buf_x[4096 * 2];
1337 char *const buf = (char *)(size_t(buf_x + 4096) / 4096 * 4096);
1338 unsigned long long count = 0;
1339 drand48_data randbuf;
1340 unsigned long long seed = time(0);
1341 seed *= 10;
1342 seed += id;
1343 srand48_r(seed, &randbuf);
1344 for (unsigned int i = 0; i < arg.sh.loop; ++i) {
1345 double kf = 0;
1346 drand48_r(&randbuf, &kf);
1347 kf *= (209715200 / 1);
1348 // fprintf(stderr, "v=%f\n", kf);
1349 off_t v = static_cast<off_t>(kf);
1350 v %= (209715200 / 1);
1351 v *= (512 * 1);
1352 const double tm1 = gettimeofday_double();
1353 const ssize_t r = pread(filefd.get(), buf, (512 * 1), v);
1354 const double tm2 = gettimeofday_double();
1355 if (r < 0) {
1356 fprintf(stderr, "pread: %s: %d %s\n", fname, errno, strerror(errno));
1357 return;
1358 }
1359 ++count;
1360 ++op_success_count;
1361 arg.sh.increment_count();
1362 set_timing(tm2 - tm1);
1363 }
1364}
1365
1366void
1367hstest_thread::operator ()()
1368{
1369 if (arg.watch_flag) {
1370 return test_watch();
1371 }
1372 int test_num = arg.sh.conf.get_int("test", 1);
1373 if (test_num == 1) {
1374 test_1();
1375 } else if (test_num == 2 || test_num == 3) {
1376 test_2_3(test_num);
1377 } else if (test_num == 4 || test_num == 5) {
1378 test_4_5(test_num);
1379 } else if (test_num == 6) {
1380 test_6(test_num);
1381 } else if (test_num == 7) {
1382 test_7(test_num);
1383 } else if (test_num == 8) {
1384 test_8(test_num);
1385 } else if (test_num == 9) {
1386 test_9(test_num);
1387 } else if (test_num == 10) {
1388 test_10(test_num);
1389 } else if (test_num == 11) {
1390 test_11(test_num);
1391 } else if (test_num == 12) {
1392 test_12(test_num);
1393 } else if (test_num == 21) {
1394 test_21(test_num);
1395 } else if (test_num == 22) {
1396 test_22(test_num);
1397 }
1398 const int halt = arg.sh.conf.get_int("halt", 0);
1399 if (halt) {
1400 fprintf(stderr, "thread halted\n");
1401 while (true) {
1402 sleep(100000);
1403 }
1404 }
1405 fprintf(stderr, "thread finished\n");
1406}
1407
1408int
1409hstest_main(int argc, char **argv)
1410{
1411 ignore_sigpipe();
1412 hstest_shared shared;
1413 parse_args(argc, argv, shared.conf);
1414 shared.conf["port"] = shared.conf["hsport"];
1415 shared.arg.set(shared.conf);
1416 shared.loop = shared.conf.get_int("num", 1000);
1417 shared.pipe = shared.conf.get_int("pipe", 1);
1418 shared.verbose = shared.conf.get_int("verbose", 1);
1419 const int tablesize = shared.conf.get_int("tablesize", 0);
1420 std::vector<char> keygen(tablesize);
1421 shared.keygen = &keygen[0];
1422 shared.keygen_size = tablesize;
1423 shared.usleep = shared.conf.get_int("usleep", 0);
1424 shared.dump = shared.conf.get_int("dump", 0);
1425 shared.num_threads = shared.conf.get_int("num_threads", 10);
1426 shared.wait_conn = shared.conf.get_int("wait_conn", 0);
1427 const std::string op = shared.conf.get_str("op", "G");
1428 if (op.size() > 0) {
1429 shared.op = op[0];
1430 }
1431 #if 0
1432 const int localdb_flag = shared.conf.get_int("local", 0);
1433 if (localdb_flag) {
1434 shared.localdb = database_i::create(shared.conf);
1435 }
1436 #endif
1437 const int num_thrs = shared.num_threads;
1438 typedef thread<hstest_thread> thread_type;
1439 typedef std::auto_ptr<thread_type> thread_ptr;
1440 typedef auto_ptrcontainer< std::vector<thread_type *> > thrs_type;
1441 thrs_type thrs;
1442 for (int i = 0; i < num_thrs; ++i) {
1443 const hstest_thread::arg_type arg(i, shared, false);
1444 thread_ptr thr(new thread<hstest_thread>(arg));
1445 thrs.push_back_ptr(thr);
1446 }
1447 for (size_t i = 0; i < thrs.size(); ++i) {
1448 thrs[i]->start();
1449 }
1450 thread_ptr watch_thread;
1451 const int timelimit = shared.conf.get_int("timelimit", 0);
1452 {
1453 const hstest_thread::arg_type arg(0, shared, true);
1454 watch_thread = thread_ptr(new thread<hstest_thread>(arg));
1455 watch_thread->start();
1456 }
1457 size_t iocnt = 0, opcnt = 0;
1458 double respmin = 999999, respmax = 0;
1459 double respsum = 0;
1460 if (timelimit != 0) {
1461 watch_thread->join();
1462 }
1463 for (size_t i = 0; i < thrs.size(); ++i) {
1464 if (timelimit == 0) {
1465 thrs[i]->join();
1466 }
1467 iocnt += (*thrs[i])->io_success_count;
1468 opcnt += (*thrs[i])->op_success_count;
1469 respmin = std::min(respmin, (*thrs[i])->response_min);
1470 respmax = std::max(respmax, (*thrs[i])->response_max);
1471 respsum += (*thrs[i])->response_sum;
1472 }
1473 fprintf(stderr, "io_success_count=%zu op_success_count=%zu\n", iocnt, opcnt);
1474 fprintf(stderr, "respmin=%f respmax=%f respsum=%f respavg=%f\n",
1475 respmin, respmax, respsum, respsum / opcnt);
1476 size_t keycnt = 0;
1477 for (size_t i = 0; i < keygen.size(); ++i) {
1478 if (keygen[i]) {
1479 ++keycnt;
1480 }
1481 }
1482 fprintf(stderr, "keycnt=%zu\n", keycnt);
1483 _exit(0);
1484 return 0;
1485}
1486
1487};
1488
1489int
1490main(int argc, char **argv)
1491{
1492 return dena::hstest_main(argc, argv);
1493}
1494
01495
=== added file 'HandlerSocket-Plugin-for-MySQL/client/hstest.pl'
--- HandlerSocket-Plugin-for-MySQL/client/hstest.pl 1970-01-01 00:00:00 +0000
+++ HandlerSocket-Plugin-for-MySQL/client/hstest.pl 2011-04-12 04:16:24 +0000
@@ -0,0 +1,228 @@
1#!/usr/bin/perl
2
3# vim:sw=8:ai:ts=8
4
5use strict;
6use warnings;
7
8use DBI;
9use Net::HandlerSocket;
10
11my %conf = ();
12for my $i (@ARGV) {
13 my ($k, $v) = split(/=/, $i);
14 $conf{$k} = $v;
15}
16
17my $verbose = get_conf("verbose", 0);
18my $actions_str = get_conf("actions", "hsread");
19my $tablesize = get_conf("tablesize", 10000);
20my $db = get_conf("db", "hstest");
21my $table = get_conf("table", "hstest_table1");
22my $engine = get_conf("engine", "innodb");
23my $host = get_conf("host", "localhost");
24my $mysqlport = get_conf("mysqlport", 3306);
25my $mysqluser = get_conf("mysqluser", "root");
26my $mysqlpass = get_conf("mysqlpass", "");
27my $hsport = get_conf("hsport", 9999);
28my $loop = get_conf("loop", 10000);
29my $op = get_conf("op", "=");
30my $ssps = get_conf("ssps", 0);
31my $num_moreflds = get_conf("moreflds", 0);
32my $moreflds_prefix = get_conf("moreflds_prefix", "column0123456789_");
33my $keytype = get_conf("keytype", "varchar(32)");
34my $file = get_conf("file", undef);
35
36my $dsn = "DBI:mysql:database=;host=$host;port=$mysqlport"
37 . ";mysql_server_prepare=$ssps";
38my $dbh = DBI->connect($dsn, $mysqluser, $mysqlpass, { RaiseError => 1 });
39my $hsargs = { 'host' => $host, 'port' => $hsport };
40my $cli = new Net::HandlerSocket($hsargs);
41
42my @actions = split(/,/, $actions_str);
43for my $action (@actions) {
44 if ($action eq "table") {
45 print("TABLE $db.$table\n");
46 $dbh->do("drop database if exists $db");
47 $dbh->do("create database $db");
48 $dbh->do("use $db");
49 my $moreflds = get_createtbl_moreflds_str();
50 $dbh->do(
51 "create table $table (" .
52 "k $keytype primary key" .
53 ",v varchar(32) not null" .
54 $moreflds .
55 ") character set utf8 collate utf8_bin " .
56 "engine = $engine");
57 } elsif ($action eq "insert") {
58 print("INSERT $db.$table tablesize=$tablesize\n");
59 $dbh->do("use $db");
60 my $moreflds = get_insert_moreflds_str();
61 for (my $i = 0; $i < $tablesize; $i += 100) {
62 my $qstr = "insert into $db.$table values";
63 for (my $j = 0; $j < 100; ++$j) {
64 if ($j != 0) {
65 $qstr .= ",";
66 }
67 my $k = "" . ($i + $j);
68 my $v = "v" . int(rand(1000)) . ($i + $j);
69 $qstr .= "('$k', '$v'";
70 for (my $j = 0; $j < $num_moreflds; ++$j) {
71 $qstr .= ",'$j'";
72 }
73 $qstr .= ")";
74 }
75 $dbh->do($qstr);
76 print "$i/$tablesize\n" if $i % 1000 == 0;
77 }
78 } elsif ($action eq "read") {
79 print("READ $db.$table op=$op loop=$loop\n");
80 $dbh->do("use $db");
81 my $moreflds = get_select_moreflds_str();
82 my $sth = $dbh->prepare(
83 "select k,v$moreflds from $db.$table where k = ?");
84 for (my $i = 0; $i < $loop; ++$i) {
85 my $k = "" . int(rand($tablesize));
86 # print "k=$k\n";
87 $sth->execute($k);
88 if ($verbose >= 10) {
89 print "RET:";
90 while (my $ref = $sth->fetchrow_arrayref()) {
91 my $rk = $ref->[0];
92 my $rv = $ref->[1];
93 print " $rk $rv";
94 }
95 print "\n";
96 }
97 print "$i/$loop\n" if $i % 1000 == 0;
98 }
99 } elsif ($action eq "hsinsert") {
100 print("HSINSERT $db.$table tablesize=$tablesize\n");
101 $cli->open_index(1, $db, $table, '', 'k,v');
102 for (my $i = 0; $i < $tablesize; ++$i) {
103 my $k = "" . $i;
104 my $v = "v" . int(rand(1000)) . $i;
105 my $r = $cli->execute_insert(1, [ $k, $v ]);
106 if ($r->[0] != 0) {
107 die;
108 }
109 print "$i/$tablesize\n" if $i % 1000 == 0;
110 }
111 } elsif ($action eq "hsread") {
112 print("HSREAD $db.$table op=$op loop=$loop\n");
113 my $moreflds = get_select_moreflds_str();
114 $cli->open_index(1, $db, $table, '', "k,v$moreflds");
115 for (my $i = 0; $i < $loop; ++$i) {
116 my $k = "" . int(rand($tablesize));
117 # print "k=$k\n";
118 my $r = $cli->execute_find(1, $op, [ $k ], 1, 0);
119 if ($verbose >= 10) {
120 my $len = scalar(@{$r});
121 print "LEN=$len";
122 for my $e (@{$r}) {
123 print " [$e]";
124 }
125 print "\n";
126 }
127 print "$i/$loop\n" if $i % 1000 == 0;
128 }
129 } elsif ($action eq "hsupdate") {
130 my $vbase = "v" . int(rand(1000));
131 print("HSUPDATE $db.$table op=$op loop=$loop vbase=$vbase\n");
132 $cli->open_index(1, $db, $table, '', 'v');
133 for (my $i = 0; $i < $loop; ++$i) {
134 my $k = "" . int(rand($tablesize));
135 my $v = $vbase . $i;
136 print "k=$k v=$v\n";
137 my $r = $cli->execute_update(1, $op, [ $k ], 1, 0,
138 [ $v ]);
139 if ($verbose >= 10) {
140 print "UP k=$k v=$v\n";
141 }
142 print "$i/$loop\n" if $i % 1000 == 0;
143 }
144 } elsif ($action eq "hsdelete") {
145 print("HSDELETE $db.$table op=$op loop=$loop\n");
146 $cli->open_index(1, $db, $table, '', '');
147 for (my $i = 0; $i < $loop; ++$i) {
148 my $k = "" . int(rand($tablesize));
149 print "k=$k\n";
150 my $r = $cli->execute_delete(1, $op, [ $k ], 1, 0);
151 if ($verbose >= 10) {
152 print "DEL k=$k\n";
153 }
154 print "$i/$loop\n" if $i % 1000 == 0;
155 }
156 } elsif ($action eq "verify") {
157 verify_do();
158 }
159}
160
161sub verify_do {
162 my ($fail_cnt, $ok_cnt) = (0, 0);
163 my $sth = $dbh->prepare("select v from $db.$table where k = ?");
164 use FileHandle;
165 my $fh = new FileHandle($file, "r");
166 while (my $line = <$fh>) {
167 chomp($line);
168 my @vec = split(/\t/, $line);
169 my $k = $vec[3];
170 my $v = $vec[7];
171 next if (!defined($k) || !defined($v));
172 # print "$k $v\n";
173 $sth->execute($k);
174 my $aref = $sth->fetchrow_arrayref();
175 if (!defined($aref)) {
176 print "FAILED: $k notfound\n";
177 ++$fail_cnt;
178 } else {
179 my $gv = $aref->[0];
180 if ($gv ne $v) {
181 print "FAILED: $k got=$gv expected=$v\n";
182 ++$fail_cnt;
183 } else {
184 print "OK: $k $v $gv\n" if $verbose >= 10;
185 ++$ok_cnt;
186 }
187 }
188 }
189 print "OK=$ok_cnt FAIL=$fail_cnt\n";
190}
191
192sub get_conf {
193 my ($key, $def) = @_;
194 my $val = $conf{$key};
195 if ($val) {
196 print "$key=$val\n";
197 } else {
198 $val = $def;
199 $def ||= '';
200 print "$key=$def(default)\n";
201 }
202 return $val;
203}
204
205sub get_createtbl_moreflds_str {
206 my $s = "";
207 for (my $j = 0; $j < $num_moreflds; ++$j) {
208 $s .= ",$moreflds_prefix$j varchar(30)";
209 }
210 return $s;
211}
212
213sub get_select_moreflds_str {
214 my $s = "";
215 for (my $i = 0; $i < $num_moreflds; ++$i) {
216 $s .= ",$moreflds_prefix$i";
217 }
218 return $s;
219}
220
221sub get_insert_moreflds_str {
222 my $s = "";
223 for (my $i = 0; $i < $num_moreflds; ++$i) {
224 $s .= ",?";
225 }
226 return $s;
227}
228
0229
=== added file 'HandlerSocket-Plugin-for-MySQL/client/hstest_hs.sh'
--- HandlerSocket-Plugin-for-MySQL/client/hstest_hs.sh 1970-01-01 00:00:00 +0000
+++ HandlerSocket-Plugin-for-MySQL/client/hstest_hs.sh 2011-04-12 04:16:24 +0000
@@ -0,0 +1,4 @@
1#!/bin/bash
2
3exec ./hstest test=10 tablesize=10000 host=localhost hsport=9998 num=10000000 \
4 num_threads=100 timelimit=10 $@
05
=== added file 'HandlerSocket-Plugin-for-MySQL/client/hstest_hs_more50.sh'
--- HandlerSocket-Plugin-for-MySQL/client/hstest_hs_more50.sh 1970-01-01 00:00:00 +0000
+++ HandlerSocket-Plugin-for-MySQL/client/hstest_hs_more50.sh 2011-04-12 04:16:24 +0000
@@ -0,0 +1,4 @@
1#!/bin/bash
2
3exec ./hstest test=10 key_mask=9999 host=localhost port=9998 num=10000000 \
4 num_threads=100 timelimit=10 moreflds=50 $@
05
=== added file 'HandlerSocket-Plugin-for-MySQL/client/hstest_md.sh'
--- HandlerSocket-Plugin-for-MySQL/client/hstest_md.sh 1970-01-01 00:00:00 +0000
+++ HandlerSocket-Plugin-for-MySQL/client/hstest_md.sh 2011-04-12 04:16:24 +0000
@@ -0,0 +1,7 @@
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
08
=== added file 'HandlerSocket-Plugin-for-MySQL/client/hstest_my.sh'
--- HandlerSocket-Plugin-for-MySQL/client/hstest_my.sh 1970-01-01 00:00:00 +0000
+++ HandlerSocket-Plugin-for-MySQL/client/hstest_my.sh 2011-04-12 04:16:24 +0000
@@ -0,0 +1,3 @@
1#!/bin/bash
2exec ./hstest test=9 tablesize=9999 host=localhost mysqlport=3306 num=1000000 \
3 num_threads=100 verbose=1 timelimit=10 $@
04
=== added file 'HandlerSocket-Plugin-for-MySQL/client/hstest_my_more50.sh'
--- HandlerSocket-Plugin-for-MySQL/client/hstest_my_more50.sh 1970-01-01 00:00:00 +0000
+++ HandlerSocket-Plugin-for-MySQL/client/hstest_my_more50.sh 2011-04-12 04:16:24 +0000
@@ -0,0 +1,3 @@
1#!/bin/bash
2exec ./hstest test=9 key_mask=9999 host=localhost port=3306 num=1000000 \
3 num_threads=100 verbose=1 timelimit=10 moreflds=50 $@
04
=== added file 'HandlerSocket-Plugin-for-MySQL/configure.ac'
--- HandlerSocket-Plugin-for-MySQL/configure.ac 1970-01-01 00:00:00 +0000
+++ HandlerSocket-Plugin-for-MySQL/configure.ac 2011-04-12 04:16:24 +0000
@@ -0,0 +1,134 @@
1# -*- Autoconf -*-
2# Process this file with autoconf to produce a configure script.
3
4#AC_PREREQ([2.63b])
5AC_INIT([handlersocket-plugin], [1.0.6], [https://github.com/ahiguti/HandlerSocket-Plugin-for-MySQL/issues])
6AC_CONFIG_HEADERS([config.h])
7AM_INIT_AUTOMAKE([-Wall -Werror foreign])
8AC_CONFIG_SRCDIR([libhsclient/fatal.cpp])
9AC_CONFIG_MACRO_DIR([m4])
10
11AC_PROG_CC
12AC_PROG_CXX
13AC_PROG_CPP
14AC_PROG_LIBTOOL
15
16AC_DEFUN([CONFIG_OPTION_MYSQL],[
17 AC_MSG_CHECKING([mysql source])
18
19 MYSQL_SOURCE_VERSION=
20 MYSQL_INC=
21 ac_mysql_source_dir=
22 AC_ARG_WITH([mysql-source],
23 [AS_HELP_STRING([--with-mysql-source=PATH], [MySQL source directory PATH])],
24 [
25 ac_mysql_source_dir=`cd $withval && pwd`
26 if test -f "$ac_mysql_source_dir/sql/handler.h" ; then
27 MYSQL_INC="-I$ac_mysql_source_dir/sql"
28 MYSQL_INC="$MYSQL_INC -I$ac_mysql_source_dir/include"
29 MYSQL_INC="$MYSQL_INC -I$ac_mysql_source_dir/regex"
30 MYSQL_INC="$MYSQL_INC -I$ac_mysql_source_dir"
31 AC_SUBST(MYSQL_INC)
32 if test -f "$ac_mysql_source_dir/VERSION"; then
33 source "$ac_mysql_source_dir/VERSION"
34 MYSQL_SOURCE_VERSION="$MYSQL_VERSION_MAJOR.$MYSQL_VERSION_MINOR.$MYSQL_VERSION_PATCH"
35 else
36 if test -f "$ac_mysql_source_dir/configure.in"; then
37 MYSQL_SOURCE_VERSION=`cat $ac_mysql_source_dir/configure.in | grep "\[[MySQL Server\]]" | sed -e "s|.*\([[0-9]]\+\.[[0-9]]\+\.[[0-9]]\+[[0-9a-zA-Z\_\-]]*\).*|\1|"`
38 else
39 AC_MSG_ERROR([invalid MySQL source directory: $ac_mysql_source_dir])
40 fi
41 fi
42 AC_MSG_RESULT([yes: Using $ac_mysql_source_dir, version $MYSQL_SOURCE_VERSION])
43 else
44 AC_MSG_ERROR([invalid MySQL source directory: $ac_mysql_source_dir])
45 fi
46 ],
47 [AC_MSG_ERROR([--with-mysql-source=PATH is required for standalone build])]
48 )
49
50 MYSQL_BIN_VERSION=
51 ac_mysql_config=
52 AC_ARG_WITH([mysql-bindir],
53 [AS_HELP_STRING([--with-mysql-bindir=PATH], [MySQL binary directory PATH. This should be the directory where mysql_config is located.])],
54 [
55 mysql_bin_dir=`cd $withval 2> /dev/null && pwd || echo ""`
56 ac_mysql_config="$mysql_bin_dir/mysql_config"
57 ],
58 [
59 AC_PATH_PROG([ac_mysql_config], [mysql_config])
60 ]
61 )
62
63 AC_MSG_CHECKING([mysql binary])
64 if test ! -x "$ac_mysql_config" ; then
65 AC_MSG_ERROR([mysql_config not found! You have to specify the directory where mysql_config resides to --with-mysql-bindir=PATH.])
66 fi
67
68 MYSQL_CFLAGS_ADD=`"$ac_mysql_config" --cflags`
69 MYSQL_CFLAGS="$MYSQL_CFLAGS $MYSQL_CFLAGS_ADD -DFORCE_DBUG_OFF"
70 # FIXME
71 AC_SUBST(MYSQL_CFLAGS)
72
73 MYSQL_BIN_VERSION=`"$ac_mysql_config" --version`
74 AC_MSG_RESULT([yes: Using $ac_mysql_config, version $MYSQL_BIN_VERSION])
75
76 MYSQL_LIB=`"$ac_mysql_config" --libs_r`
77 LIB_DIR=`echo $MYSQL_LIB | sed -e "s|.*-L/|/|" | sed -e "s| .*||"`
78 # FIXME
79 if test a`basename "$LIB_DIR"` = amysql ; then
80 MYSQL_LIB="-L`dirname $LIB_DIR` $MYSQL_LIB"
81 # FIXME
82 fi
83 AC_SUBST(MYSQL_LIB)
84
85 if test a$MYSQL_SOURCE_VERSION != a$MYSQL_BIN_VERSION ; then
86 AC_MSG_ERROR([MySQL source version does not match MySQL binary version])
87 fi
88
89 AC_MSG_CHECKING([mysql plugin dir])
90 ac_mysql_plugin_dir=
91 AC_ARG_WITH([mysql-plugindir],
92 [AS_HELP_STRING([--with-mysql-plugindir=PATH], [MySQL plugin directory where handlersocket.so to be copied])],
93 [
94 ac_mysql_plugin_dir=`cd $withval && pwd`
95 if test -d "$ac_mysql_plugin_dir/" ; then
96 PLUGIN_DIR="$ac_mysql_plugin_dir"
97 AC_SUBST(PLUGIN_DIR)
98 AC_MSG_RESULT([yes: Using $ac_mysql_plugin_dir])
99 else
100 AC_MSG_ERROR([invalid MySQL plugin directory : $ac_mysql_plugin_dir])
101 fi
102 ],
103 [
104 LIB_DIR_TMP=`"$ac_mysql_config" --plugindir`
105 if test ! -d "$LIB_DIR_TMP"; then
106 LIB_DIR_TMP=`"$ac_mysql_config" --libs_r | sed -e "s|.*-L/|/|" | sed -e "s| .*||"`/plugin
107 # FIXME
108 fi
109 ac_mysql_plugin_dir=$LIB_DIR_TMP
110 PLUGIN_DIR="$ac_mysql_plugin_dir"
111 AC_SUBST(PLUGIN_DIR)
112 AC_MSG_RESULT([--with-mysql-plugindir was not set. Using $ac_mysql_plugin_dir])
113 ]
114 )
115])
116
117HANDLERSOCKET_SUBDIRS="libhsclient"
118AC_ARG_ENABLE(handlersocket_server,
119 [ --enable-handlersocket-server build HandlerSocket plugin (defalut=yes)])
120if test "$enable_handlersocket_server" != "no"; then
121 CONFIG_OPTION_MYSQL
122 HANDLERSOCKET_SUBDIRS="libhsclient handlersocket client"
123fi
124AC_SUBST(HANDLERSOCKET_SUBDIRS)
125
126CFLAGS="$CFLAGS -Werror"
127CXXFLAGS="$CXXFLAGS -Wall -g -fno-rtti -fno-exceptions -fPIC -DPIC"
128
129AC_CONFIG_FILES([Makefile
130 handlersocket/Makefile
131 libhsclient/Makefile
132 client/Makefile])
133
134AC_OUTPUT
0135
=== added directory 'HandlerSocket-Plugin-for-MySQL/docs-en'
=== added file 'HandlerSocket-Plugin-for-MySQL/docs-en/about-handlersocket.en.txt'
--- HandlerSocket-Plugin-for-MySQL/docs-en/about-handlersocket.en.txt 1970-01-01 00:00:00 +0000
+++ HandlerSocket-Plugin-for-MySQL/docs-en/about-handlersocket.en.txt 2011-04-12 04:16:24 +0000
@@ -0,0 +1,72 @@
1
2-----------------------------------------------------------------------------
3HandlerSocket plugin for MySQL
4
5Copyright (c) 2010 DeNA Co.,Ltd.
6All rights reserved.
7
8Redistribution and use in source and binary forms, with or without
9modification, 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
20THIS SOFTWARE IS PROVIDED BY DeNA Co.,Ltd. "AS IS" AND ANY EXPRESS OR
21IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
22MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
23EVENT SHALL DeNA Co.,Ltd. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
25PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
26OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
27WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
28OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
29ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30
31
32-----------------------------------------------------------------------------
33About HandlerSocket
34
35HandlerSocket is a NoSQL plugin for MySQL. It works as a daemon inside the
36mysqld process, accept tcp connections, and execute requests from clients.
37HandlerSocket does not support SQL queries. Instead, it supports simple CRUD
38operations on tables.
39
40Because of the following reasons, HandlerSocket is much faster than the
41mysqld/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
50The current version of HandlerSocket only works with GNU/Linux. The source
51archive of HandlerSocket includes a C++ and a Perl client libraries.
52Here 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
68The home of HandlerSocket is here:
69 https://github.com/ahiguti/HandlerSocket-Plugin-for-MySQL
70
71More documents are available in docs-en/ and docs-ja/ directories.
72
073
=== added file 'HandlerSocket-Plugin-for-MySQL/docs-en/configuration-options.en.txt'
--- HandlerSocket-Plugin-for-MySQL/docs-en/configuration-options.en.txt 1970-01-01 00:00:00 +0000
+++ HandlerSocket-Plugin-for-MySQL/docs-en/configuration-options.en.txt 2011-04-12 04:16:24 +0000
@@ -0,0 +1,87 @@
1
2-----------------------------------------------------------------
3handlersocket_verbose (default = 10, min = 0, max = 10000)
4
5 Specify the logging verboseness.
6
7-----------------------------------------------------------------
8handlersocket_address (default = '')
9
10 Specify the address to bind. If empty, it binds to 0.0.0.0.
11
12-----------------------------------------------------------------
13handlersocket_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-----------------------------------------------------------------
19handlersocket_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-----------------------------------------------------------------
25handlersocket_epoll (default = 1, min = 0, max = 1)
26
27 Specify whether handlersocket uses epoll for I/O multiplexing.
28
29-----------------------------------------------------------------
30handlersocket_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-----------------------------------------------------------------
37handlersocket_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-----------------------------------------------------------------
43handlersocket_timeout (default = 300, min = 30, max = 3600)
44
45 Specify the socket timeout in seconds.
46
47-----------------------------------------------------------------
48handlersocket_backlog (default = 32768, min = 5, max = 1000000)
49
50 Specify the length of the listen backlog.
51
52-----------------------------------------------------------------
53handlersocket_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-----------------------------------------------------------------
59handlersocket_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-----------------------------------------------------------------
65handlersocket_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-----------------------------------------------------------------
72handlersocket_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-----------------------------------------------------------------
80handlersocket_wrlock_timeout (default = 12, min = 0, max = 3600)
81
82 Specify the lock timeout in seconds. When a write request is
83 performed, handlersocket locks an advisory lock named
84 'handlersocket_wr'. This option sets the timeout for the
85 locking.
86
87
088
=== added file 'HandlerSocket-Plugin-for-MySQL/docs-en/installation.en.txt'
--- HandlerSocket-Plugin-for-MySQL/docs-en/installation.en.txt 1970-01-01 00:00:00 +0000
+++ HandlerSocket-Plugin-for-MySQL/docs-en/installation.en.txt 2011-04-12 04:16:24 +0000
@@ -0,0 +1,91 @@
11. 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,
6MySQL 5.1 or higher version is required.
7 Please make sure that you use identical MySQL version between MySQL source
8and MySQL binary. Otherwise you might encounter serious problems (i.e. server
9crash, 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,
21--with-mysql-bindir refers to where MySQL binary executables (i.e.
22mysql_config) are located, and --with-mysql-plugindir refers to a plugin
23directory where plugin libraries (*.so) are installed.
24
25 $ make
26 $ sudo make install
27
28 Both libhsclient and the handlersocket plugin will be installed.
29
30
312. Using Handlersocket
32
33Append configuration options for handlersocket to my.cnf.
34
35 [mysqld]
36 loose_handlersocket_port = 9998
37 # the port number to bind to (for read requests)
38 loose_handlersocket_port_wr = 9999
39 # the port number to bind to (for write requests)
40 loose_handlersocket_threads = 16
41 # the number of worker threads (for read requests)
42 loose_handlersocket_threads_wr = 1
43 # the number of worker threads (for write requests)
44 open_files_limit = 65535
45 # to allow handlersocket accept many concurrent
46 # connections, make open_files_limit as large as
47 # possible.
48
49Log in to mysql as root, and execute the following query.
50
51 mysql> install plugin handlersocket soname 'handlersocket.so';
52
53If handlersocket.so is successfully installed, it starts
54accepting connections on port 9998 and 9999. Running
55'show processlist' should show handlersocket worker threads.
56
57-----------------------------------------------------------------
58On the client side, you need to install libhsclient for c++ apps
59and perl-Net-HandlerSocket for perl apps. They do not require
60MySQL to compile.
61
62 $ ./autogen.sh
63 $ ./configure --disable-handlersocket-server
64 $ make
65 $ sudo make install
66 $ cd perl-Net-HandlerSocket
67 $ perl Makefile.PL
68 $ make
69 $ sudo make install
70
71-----------------------------------------------------------------
72Alternatively, you can use the rpm installation. If your OS
73supports rpms, you can use the following commands to build and
74install handlersocket rpm packages.
75
76(Server side, installs HandlerSocket plugin)
77 $ ./autogen.sh
78 $ ./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
79 $ make rpm_cli
80 $ sudo rpm -U dist/RPMS/*/libhsclient*.rpm
81 $ make rpm_c
82 $ sudo rpm -U dist/RPMS/*/handlersocket*.rpm
83
84(Client side, installs client libraries)
85 $ ./autogen.sh
86 $ ./configure --disable-handlersocket-server
87 $ make rpm_cli
88 $ sudo rpm -U dist/RPMS/*/libhsclient*.rpm
89 $ make rpm_perl
90 $ sudo rpm -U dist/RPMS/*/perl-Net-HandlerSocket*.rpm
91
092
=== added file 'HandlerSocket-Plugin-for-MySQL/docs-en/perl-client.en.txt'
--- HandlerSocket-Plugin-for-MySQL/docs-en/perl-client.en.txt 1970-01-01 00:00:00 +0000
+++ HandlerSocket-Plugin-for-MySQL/docs-en/perl-client.en.txt 2011-04-12 04:16:24 +0000
@@ -0,0 +1,126 @@
1
2-----------------------------------------------------------------
3To open a connection to the handlersocket plugin, you need to
4create 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-----------------------------------------------------------------
11Before executing table operations, you need to open an index to
12work 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
18The first argument for open_index is an integer value which is
19used to identify an open table, which is only valid within the
20same Net::HandlerSocket object. The 4th argument is the name of
21index to open. If 'PRIMARY' is specified, the primary index is
22open. The 5th argument is a comma-separated list of column names.
23
24-----------------------------------------------------------------
25To read a record from a table using an index, call the
26execute_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
32The first argument must be an integer which has specified as the
33first argument for open_index on the same Net::HandlerSocket
34object. The second argument specifies the search operation. The
35current version of handlersocket supports '=', '>=', '<=', '>',
36and '<'. The 3rd argument specifies the key to find, which must
37an arrayref whose length is equal to or smaller than the number
38of key columns of the index. The 4th and the 5th arguments
39specify the maximum number of records to be retrieved, and the
40number of records skipped before retrieving records. The columns
41to be retrieved are specified by the 5th argument for the
42corresponding open_index call.
43
44The execute_single method always returns an arrayref. The first
45element is the error code, which is 0 when no error is occured.
46The remaining are the field values. If more than one record is
47returned, it is flatten to an 1-dimensional array. For example,
48when 5 records that have 3 columns are returned, you can retrieve
49values 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-----------------------------------------------------------------
61To update or delete records, you need to specify more arguments
62for the execute_single method. Note that the Net::HandlerSocket
63object must be connected to a handlersocket worker for write
64operations, which is port 9999 by default.
65(For safety, the port 9998 only allows read operations, and the
66port 9999 allows write operations also. The port 9999 allows
67read operations too, but slower than 9998 because of record
68locking etc.. Port numbers can be changed using the
69'handlersocket_port' and the 'handlersocket_port_wr'
70configuration 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
84The 6th argument for execute_single specifies the modification
85operation. The current version supports 'U' and 'D'. For the 'U'
86operation, the 7th argument specifies the new value for the row.
87The columns to be modified are specified by the 5th argument for
88the corresponding open_index call. For the 'D' operation, the
897th argument can be omitted.
90
91-----------------------------------------------------------------
92The 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 my $num_inserted_rows = $res->[1];
97
98The 3rd argument must be an arrayref whose elements correspond to
99the 5th argument for the corresponding open_index call. If there
100is a column which is not appeared in the 5th argument for the
101open_index, the default value for the column is set.
102
103-----------------------------------------------------------------
104Multiple operations can be executed in a single call. Executing
105multiple operations in a single call is much faster than
106executing them separatedly.
107
108 my $rarr = $hs->execute_multi([
109 [ 0, '>=', [ 'foo' ], 5, 0 ],
110 [ 2, '=', [ 'bar' ], 1, 0 ],
111 [ 4, '<', [ 'baz' ], 10, 5 ],
112 ]);
113 for my $res (@$rarr) {
114 die $hs->get_error() if $res->[0] != 0;
115 shift(@$res);
116 # ...
117 }
118
119-----------------------------------------------------------------
120When an error is occured, the first element of the returned
121arrayref becomes a non-zero value. A negative value indicates
122that an I/O error is occured and the Net::HandlerSocket object
123should be disposed. A positive value means that the connection is
124still active and the Net::HandlerSocket object can be reused
125later.
126
0127
=== added file 'HandlerSocket-Plugin-for-MySQL/docs-en/protocol.en.txt'
--- HandlerSocket-Plugin-for-MySQL/docs-en/protocol.en.txt 1970-01-01 00:00:00 +0000
+++ HandlerSocket-Plugin-for-MySQL/docs-en/protocol.en.txt 2011-04-12 04:16:24 +0000
@@ -0,0 +1,148 @@
1
2----------------------------------------------------------------------------
3The HandlerSocket protocol
4
5----------------------------------------------------------------------------
6Basic syntax
7
8- The HandlerSocket protocol is line-based. Each line ends with LF(0x0a).
9- Each line consists a concatenation of tokens separated by HT(0x09).
10- A token is either NULL or an encoded string. Note that you need to
11 distinguish NULL from an empty string, as most DBMs does so.
12- NULL is expressed as a single NUL(0x00).
13- An encoded string is a string with the following encoding rules.
14 - Characters in the range [0x10 - 0xff] are not encoded.
15 - A character in the range [0x00 - 0x0f] is prefixed by 0x01 and
16 shifted by 0x40. For example, 0x03 is encoded as 0x01 0x43.
17- Note that a string can be empty. A continuation of 0x09 0x09 means that
18 there is an empty string between them. A continuation of 0x09 0x0a means
19 that there is an empty string at the end of the line.
20
21----------------------------------------------------------------------------
22Request and Response
23
24- The HandlerSocket protocol is a simple request/response protocol. After a
25 connection is established, the client side sends a request, and then the
26 server side sends a response.
27- A request/response consists of a single line.
28- Requests can be pipelined; That is, you can send multiple requests (ie.
29 lines) at one time, and receive responses for them at one time.
30
31----------------------------------------------------------------------------
32'open_index' request
33
34The 'open_index' request has the following syntax.
35
36 P <indexid> <dbname> <tablename> <indexname> <columns>
37
38- <indexid> is a number in decimal.
39- <dbname>, <tablename>, and <indexname> are strings. To open the primary
40 key, use PRIMARY as <indexname>.
41- <columns> is a comma-separated list of column names.
42
43Once an 'open_index' request is issued, the HandlerSocket plugin opens the
44specified index and keep it open until the client connection is closed. Each
45open index is identified by <indexid>. If <indexid> is already open, the old
46open index is closed. You can open the same combination of <dbname>
47<tablename> <indexname> multple times, possibly with different <columns>.
48For efficiency, keep <indexid> small as far as possible.
49
50----------------------------------------------------------------------------
51Getting data
52
53The 'find' request has the following syntax.
54
55 <indexid> <op> <vlen> <v1> ... <vn> <limit> <offset>
56
57- <indexid> is a number. This number must be an <indexid> specified by a
58 'open_index' request executed previously on the same connection.
59- <op> specifies the comparison operation to use. The current version of
60 HandlerSocket supports '=', '>', '>=', '<', and '<='.
61- <vlen> indicates the length of the trailing parameters <v1> ... <vn>. This
62 must be smaller than or equal to the number of index columns specified by
63 specified by the corresponding 'open_index' request.
64- <v1> ... <vn> specify the index column values to fetch.
65- <limit> and <offset> are numbers. These parameters can be omitted. When
66 omitted, it works as if 1 and 0 are specified.
67
68----------------------------------------------------------------------------
69Updating/Deleting data
70
71The 'find_modify' request has the following syntax.
72
73 <indexid> <op> <vlen> <v1> ... <vn> <limit> <offset> <mop> <m1> ... <mk>
74
75- <mop> is either 'U' (update) or 'D' (delete).
76- <m1> ... <mk> specifies the column values to set. The length of <m1> ...
77 <mk> must be smaller than or equal to the length of <columns> specified by
78 the corresponding 'open_index' request. If <mop> is 'D', these parameters
79 are ignored.
80
81----------------------------------------------------------------------------
82Inserting data
83
84The 'insert' request has the following syntax.
85
86 <indexid> '+' <vlen> <v1> ... <vn>
87
88- <vlen> indicates the length of the trailing parameters <v1> ... <vn>. This
89 must be smaller than or equal to the length of <columns> specified by the
90 corresponding 'open_index' request.
91- <v1> ... <vn> specify the column values to set. For columns not in
92 <columns>, the default values for each column are set.
93
94----------------------------------------------------------------------------
95Response syntax
96
97HandlerSocket returns a response of the following syntax for each request.
98
99 <errorcode> <numcolumns> <r1> ... <rn>
100
101- <errorcode> indicates whether the request has successfully executed or not.
102 '0' means success. Non-zero means an error.
103- <numcolumns> indicates the number of columns of the result set.
104- <r1> ... <rn> is the result set. The length of <r1> ... <rn> is always a
105 multiple of <numcolumns>. It is possible that <r1> ... <rn> is empty.
106
107If <errorcode> is non-zero, <numcolumns> is always 1 and <r1> indicates a
108human-readable error message, though sometimes <r1> is not provided.
109
110----------------------------------------------------------------------------
111Response for 'open_index'
112
113If 'open_index' is succeeded, HandlerSocket returns a line of the following
114syntax.
115
116 0 1
117
118----------------------------------------------------------------------------
119Response for 'find'
120
121If 'find' is succeeded, HandlerSocket returns a line of the following
122syntax.
123
124 0 <numcolumns> <r1> ... <rn>
125
126- <numcolumns> always equals to the length of <columns> of the corresponding
127 'open_index' request.
128- <r1> ... <rn> is the result set. If N rows are found, the length of <r1>
129 ... <rn> becomes ( <numcolumns> * N ).
130
131----------------------------------------------------------------------------
132Response for 'find_modify'
133
134If 'find_modify' is succeeded, HandlerSocket returns a line of the following
135syntax.
136
137 0 1 <nummod>
138
139- <nummod> is the number of modified rows.
140
141----------------------------------------------------------------------------
142Response for 'insert'
143
144If 'insert' is succeeded, HanderSocket returns a line of the following
145syntax.
146
147 0 1
148
0149
=== added directory 'HandlerSocket-Plugin-for-MySQL/docs-ja'
=== added file 'HandlerSocket-Plugin-for-MySQL/docs-ja/about-handlersocket.ja.txt'
--- HandlerSocket-Plugin-for-MySQL/docs-ja/about-handlersocket.ja.txt 1970-01-01 00:00:00 +0000
+++ HandlerSocket-Plugin-for-MySQL/docs-ja/about-handlersocket.ja.txt 2011-04-12 04:16:24 +0000
@@ -0,0 +1,51 @@
1
2
3-----------------------------------------------------------------
4ソースコード�利用�������責事項
5
6本ソフトウェア�開発者�よ�株�会社ディー・エヌ・エー��本フト
7ウェア��稼動�稼動�良を�む法律上�瑕疵担�責任���他�証責
8任を負���も�����。���本ソフトウエア�開発者�よ�株�
9会社ディー・エヌ・エー��本ソフトウェア�商�性�����客様�
10特定�目的�対�る��性��������る�証も負���も���
11��。
12
13-----------------------------------------------------------------
14handlersocket plugin����
15
16mysqlサー��常���innodb等�ストレージエンジン��直接�アクセ
17スを�供�るプラグイン��。handlersocketプラグイン�自��リス
18ナーを���専用�クライアントライブラリ(libhsclient)を使���れ
19�アクセス���。
20
21mysql�標準クライアントライブラリ(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
052
=== added file 'HandlerSocket-Plugin-for-MySQL/docs-ja/installation.ja.txt'
--- HandlerSocket-Plugin-for-MySQL/docs-ja/installation.ja.txt 1970-01-01 00:00:00 +0000
+++ HandlerSocket-Plugin-for-MySQL/docs-ja/installation.ja.txt 2011-04-12 04:16:24 +0000
@@ -0,0 +1,87 @@
1
2-----------------------------------------------------------------
3HandlerSocketプラグイン�ビルド方法(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トリを指定���。--with-mysql-bindir��インストール済��MySQL
12�mysql_configコマンド�有るディレクトリを指定���。
13��後以下�よ��ビルド・インストール���。
14
15 $ make
16 $ sudo make install
17
18-----------------------------------------------------------------
19クライアントライブラリ�ビルド方法(RPMを使���方法)
20
21クライアントライブラリをビルド�る際���MySQL�ソースコード�
22必��り��ん。��MySQL�インストール�れ��る必�も�り��ん。
23
24 $ ./autogen.sh
25 $ ./configure --disable-handlersocket-server
26 $ make
27 $ sudo make install
28 $ cd perl-Net-HandlerSocket
29 $ perl Makefile.PL
30 $ make
31 $ sudo make install
32
33-----------------------------------------------------------------
34ビルド方法(RPM)
35
36以下�よ��実行�れ��rpmパッケージ�ビルド&インストール�れ�
37�。
38
39(MySQLサー���HandlerSocketプラグインをインストール�る)
40 $ ./autogen.sh
41 $ ./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
42 $ make rpm_cli
43 $ sudo rpm -U dist/RPMS/*/libhsclient*.rpm
44 $ make rpm_c
45 $ sudo rpm -U dist/RPMS/*/handlersocket*.rpm
46
47(クライアント��クライアントライブラリをインストール�る)
48 $ ./autogen.sh
49 $ ./configure --disable-handlersocket-server
50 $ make rpm_cli
51 $ sudo rpm -U dist/RPMS/*/libhsclient*.rpm
52 $ make rpm_perl
53 $ sudo rpm -U dist/RPMS/*/perl-Net-HandlerSocket*.rpm
54
55-----------------------------------------------------------------
56èµ·å‹•
57
58mysqlを起動��状態��mysql�設定ファイル(my.cnf等)�以下�内容を
59追加���。
60
61 [mysqld]
62 handlersocket_port = 9998
63 # handlersocket�接続を��付�る�ート(�照系リクエスト用)
64 handlersocket_port_wr = 9999
65 # handlersocket�接続を��付�る�ート(更新系リクエスト用)
66 handlersocket_address =
67 # handlersocket��インド�るアドレス(空����OK)
68 handlersocket_verbose = 0
69 # デ�ッグ用
70 handlersocket_timeout = 300
71 # 通信タイムアウト(秒)
72 handlersocket_threads = 16
73 # handlersocket�ワーカースレッド数
74 thread_concurrency = 128
75 # handlersocket�幾���スレッドを�有�る���大���
76 # 値を指定������
77 open_files_limit = 65535
78 # ソケットを大��開�るよ���る���大���値を指定�
79 # �����
80
81以下�クエリを実行���。
82
83 mysql> install plugin handlersocket soname 'handlersocket.so';
84 Query OK, 0 rows affected (0.06 sec)
85
86以上�handlersocket�クライアント�らアクセス��るよ���り��。
87
088
=== added file 'HandlerSocket-Plugin-for-MySQL/docs-ja/perl-client.ja.txt'
--- HandlerSocket-Plugin-for-MySQL/docs-ja/perl-client.ja.txt 1970-01-01 00:00:00 +0000
+++ HandlerSocket-Plugin-for-MySQL/docs-ja/perl-client.ja.txt 2011-04-12 04:16:24 +0000
@@ -0,0 +1,118 @@
1
2-----------------------------------------------------------------
3handlersocketプラグイン��接続を開����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最��引数�開�索引�付�る番���。付��番���一�
19Net::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オブジェクト�
32open_index�付��も����れ��り��ん。第2引数���作を指定
33���。�在��ージョン���「=��「>=��「<=��「>��「<�
34��作�利用�能��。第3引数��列���照���れ�探���行�
35キー値を指定���。�列�長��索引�キー�個数����少��数
36���れ��り��ん。第4引数�第5引数��れ�れ��得�る最大行
37数��得��読�飛��行数を指定���。�得�れる列�対応�る
38open_index呼�出��第5引数�指定�れ�も���り��。
39
40execute_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行を更新���削除�る���更�多��引数を指定��
57execute_singleメソッドを呼�出���。書�込�処�を�る���
58対象�Net::HandlerSocketオブジェクト�更新用handlersocketワーカ(既
59定���ート9999)�接続�れ�も�������り��ん。
60(安全�����ート9998��照処���を��付���ート9999�更新
61処�も��付�るよ��������。�ート9999��照処�も��付
62�����レコードロック等�影響����り��。�ート番��
63mysqld�「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
78execute_single�第6引数�変更処��種類を指定���。�在��ー
79ジョン��「U��「D��利用�能��。「U�������第7引数�
80新��値を指定���。更新�れる列��対応�るopen_index呼�出�
81�第5引数�指定�れ�も���り��。「D������第7引数��
82略����。
83
84-----------------------------------------------------------------
85execute_singleメソッド�列�挿入�も使用����。
86
87 my $res = $hs->execute_single(3, '+', [ 'foo', 'bar', 'baz' ]);
88 die $hs->get_error() if $res->[0] != 0;
89 my $num_inserted_rows = $res->[1];
90
91第3引数��対応�るopen_index呼�出��第5引数�列リスト����
92��長���列���照���れ��り��ん。open_index呼�出��
93第5引数�指定�れ����列��������列�既定値�セット�れ
94��。
95
96-----------------------------------------------------------------
97execute_multiメソッドを使���複数�リクエストを一��呼�出��
98実行�る�������。�れ�リクエストを個別�実行�るより高速
99��。
100
101 my $rarr = $hs->execute_multi([
102 [ 0, '>=', [ 'foo' ], 5, 0 ],
103 [ 2, '=', [ 'bar' ], 1, 0 ],
104 [ 4, '<', [ 'baz' ], 10, 5 ],
105 ]);
106 for my $res (@$rarr) {
107 die $hs->get_error() if $res->[0] != 0;
108 shift(@$res);
109 # ...
110 }
111
112-----------------------------------------------------------------
113エラー�起�る�返値��列�照�最���素�0以外��り��。負�
114数�場��I/Oエラー�起�����を示����場����
115Net::HandlerSocketオブジェクト�破棄�る����。正�値�場��
116接続�維��れ��る�����オブジェクト��れ以後も�利用��
117��。
118
0119
=== added file 'HandlerSocket-Plugin-for-MySQL/docs-ja/protocol.ja.txt'
--- HandlerSocket-Plugin-for-MySQL/docs-ja/protocol.ja.txt 1970-01-01 00:00:00 +0000
+++ HandlerSocket-Plugin-for-MySQL/docs-ja/protocol.ja.txt 2011-04-12 04:16:24 +0000
@@ -0,0 +1,94 @@
1
2-----------------------------------------------------------------
3handlersocket�通信プロトコル
4
5-----------------------------------------------------------------
6構文
7
8・コマンド行�改行(LF)�終�る。
9・コマンド行�複数�トークン�ら�り�トークン間�TAB�区切られる。
10・トークン�NULLトークン��文字列トークン���れ�。
11・NULLトークン��一�NUL文字��ら��れる。
12・文字列トークン��0�イト以上�文字列��ら��れる。���0x10
13 未満�文字�����0x01を�置��0x40を加��コード��ら��
14 れる。�れ以外�文字���文字自身�コード��ら��れる。
15
16-----------------------------------------------------------------
17リクエスト�レス�ンス
18
19・接続�確立��直後�状態�����クライアント�コマンド行を�
20 る。(リクエスト)
21・サー��クライアント����リクエスト��度��数�コマンド行
22 を返�。(レス�ンス)
23・リクエスト�パイプライン化��よ�。��りクライアント���
24 ���リクエスト�対�る返事を待���次�リクエストを���も
25 よ�。
26
27-----------------------------------------------------------------
28リクエスト
29
30・open_index命令�次�よ��構文を��。
31 'P' indexid dbname tablename indexname fieldlist
32 indexid�開���る索引�付�られる番����一接続上�後�実行
33 �る命令��対象索引を指定�る���使�れる。dbname�tablename�
34 indexname��れ�れ開���DB�テーブル�索引���。索引���
35 ���"PRIMARY"を指定�る�プライマリキー�開�れる。fieldlist
36 �カンマ区切り�列��リスト。
37・find命令�次�よ��構文を��。
38 indexid op nflds v1 ... vn limit offset
39 indexid�実行対象�索引を指定�る。op�索引検索�演算�(後述)。
40 v1�らvn��変長����個数�nflds。nflds�indexid�指定�れ�
41 open_index命令�indexname�索引�fieldlist�フィールド数�等�
42 ����������ら��。m2�らmk��変長����個数�
43 indexid�指定�れ�open_index命令�発行�れ�際�fieldlist�一
44 致���れ��ら��。コマンド行�limit以���略��る。limit
45 �offset��検索�件��致�る列���レス�ンス�返�列数�上
46 ���スキップ�る列数。limit�offsetを�略��場���れ�れ1
47 �0�指定�れ������動作を�る。find命令�レス�ンス����
48 �件��致��列�リストを返�。op���指定��る演算��次�
49 ��り。
50 '=' - v1 ... vn�一致�るも�を�得
51 '>' - v1 ... vnより大��も�を昇順��得
52 '>=' - v1 ... vn�一致�る�大��も�を昇順��得
53 '<' - v1 ... vnより���も�を�順��得
54 '<=' - v1 ... vn�一致�る�等��も�を�順��得
55 nflds�1より大��(v1 ... vn�2個以上)���辞書�順��比較�
56 れる。
57・find_modify命令�次�よ��構文を��。
58 indexid op nflds v1 ... vn limit offset modop m1 ... mk
59 modopより��部分�find命令��等���れ�よ���作対象�行を
60 指定�る。���作対象�行�対�modop�指定�れ�変更処�を実行
61 �る。m1 ... mk��変長���略��る。modop�次��れ�。
62 'U' - indexid�指定�れ�open_index命令�fieldlist列
63 �内容を�m1 ... mk�値�更新�る。
64 'D' - 対象�行を削除�る。m1 ... mk�値�無視�れる。
65・insert命令��よ��構文を��。
66 indexid '+' nflds v1 ... vn
67 indexid�指定�れ�テーブル��列を挿入�る。v1 ... vn��変長
68 ����個数�nflds。nflds�indexid�指定�れ�open_index命令�
69 indexname�索引�fieldlist�フィールド数�等���������
70 ��ら��。
71
72-----------------------------------------------------------------
73レス�ンス
74
75・open_index命令��功�����レス�ンス�次�構文を��。
76 '0' '1'
77・find命令��功�����レス�ンス�次�構文を��。
78 '0' nflds v1 ... vn
79 nflds��果セット�列�数を�ら��。v1 ... vn��変長����
80 長��nflds�整数�。v1 ... vn�空���も�り��れ��件��
81 致�るレコード�存在�������を�ら��。�果セット�複数
82 行�������v1 ... vn�長��nflds�2�以上��り�最��
83 行�ら順�v1 ... vn�セット�れる。
84・modify命令��功�����レス�ンス�次�構文を��。
85 '0' '1' nummod
86 nummod�変更�施�れ�行数。nummod�0����変更�れ�行�無
87 �����を�ら��。
88・insert命令��功�����レス�ンス�次�構文を��。
89 '0' '1'
90・命令�失敗�����レス�ンス�命令�関�ら�次�構文を��。
91 err '1' message
92 err�0以外�数値��エラーコードを�ら��。message�人間�読�
93 エラーメッセージ。���message�無���も�る。
94
095
=== added directory 'HandlerSocket-Plugin-for-MySQL/handlersocket'
=== added file 'HandlerSocket-Plugin-for-MySQL/handlersocket/COPYRIGHT.txt'
--- HandlerSocket-Plugin-for-MySQL/handlersocket/COPYRIGHT.txt 1970-01-01 00:00:00 +0000
+++ HandlerSocket-Plugin-for-MySQL/handlersocket/COPYRIGHT.txt 2011-04-12 04:16:24 +0000
@@ -0,0 +1,27 @@
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
028
=== added file 'HandlerSocket-Plugin-for-MySQL/handlersocket/Makefile.am'
--- HandlerSocket-Plugin-for-MySQL/handlersocket/Makefile.am 1970-01-01 00:00:00 +0000
+++ HandlerSocket-Plugin-for-MySQL/handlersocket/Makefile.am 2011-04-12 04:16:24 +0000
@@ -0,0 +1,10 @@
1pkgplugindir = $(PLUGIN_DIR)
2noinst_HEADERS = database.hpp hstcpsvr.hpp hstcpsvr_worker.hpp mysql_incl.hpp
3pkgplugin_LTLIBRARIES = handlersocket.la
4handlersocket_la_LDFLAGS = -module ../libhsclient/libhsclient.la
5handlersocket_la_CFLAGS = $(MYSQL_INC) $(MYSQL_CFLAGS) $(AM_CFLAGS) \
6 -I../libhsclient
7handlersocket_la_CXXFLAGS = $(MYSQL_INC) $(MYSQL_CFLAGS) $(AM_CFLAGS) \
8 -I../libhsclient
9handlersocket_la_SOURCES = database.cpp handlersocket.cpp \
10 hstcpsvr_worker.cpp hstcpsvr.cpp
011
=== added file 'HandlerSocket-Plugin-for-MySQL/handlersocket/Makefile.plain.template'
--- HandlerSocket-Plugin-for-MySQL/handlersocket/Makefile.plain.template 1970-01-01 00:00:00 +0000
+++ HandlerSocket-Plugin-for-MySQL/handlersocket/Makefile.plain.template 2011-04-12 04:16:24 +0000
@@ -0,0 +1,31 @@
1
2MYSQL_INC = HANDLERSOCKET_MYSQL_INC
3MYSQL_LIB = HANDLERSOCKET_MYSQL_LIB
4
5CXX = g++ -Wall -g -fno-rtti -fno-exceptions -fPIC -DPIC
6LIBS = $(MYSQL_LIB) -lhsclient -lpthread -lz
7CXXFLAGS = -I/usr/include/handlersocket $(MYSQL_INC)
8LDFLAGS =
9
10CXXFLAGS += -O3 -DNDEBUG
11
12HANDLERSOCKET_OBJS = database.o hstcpsvr.o hstcpsvr_worker.o
13
14all: handlersocket.so
15
16handlersocket.so: $(HANDLERSOCKET_OBJS) handlersocket.cpp
17 $(CXX) $(CXXFLAGS) -fno-strict-aliasing -shared $^ -o $@ $(LDFLAGS) \
18 -Wl,-soname -Wl,$@ $(LIBS)
19clean:
20 rm -f *.a *.so *.o
21
22LIBDIR = $(shell \
23 if [ -e /usr/lib64/mysql ]; then echo /usr/lib64; else echo /usr/lib; fi)
24
25install: 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
032
=== added file 'HandlerSocket-Plugin-for-MySQL/handlersocket/database.cpp'
--- HandlerSocket-Plugin-for-MySQL/handlersocket/database.cpp 1970-01-01 00:00:00 +0000
+++ HandlerSocket-Plugin-for-MySQL/handlersocket/database.cpp 2011-04-12 04:16:24 +0000
@@ -0,0 +1,1143 @@
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 <stdlib.h>
10#include <stdio.h>
11#include <string.h>
12
13#include "database.hpp"
14#include "string_util.hpp"
15#include "escape.hpp"
16#include "mysql_incl.hpp"
17
18#define DBG_KEY(x)
19#define DBG_SHUT(x)
20#define DBG_LOCK(x)
21#define DBG_THR(x)
22#define DBG_CMP(x)
23#define DBG_FLD(x)
24#define DBG_FILTER(x)
25#define DBG_REFCNT(x)
26#define DBG_DELETED
27
28/* status variables */
29unsigned long long int open_tables_count;
30unsigned long long int close_tables_count;
31unsigned long long int lock_tables_count;
32unsigned long long int unlock_tables_count;
33unsigned long long int index_exec_count;
34
35namespace dena {
36
37prep_stmt::prep_stmt()
38 : dbctx(0), table_id(static_cast<size_t>(-1)),
39 idxnum(static_cast<size_t>(-1))
40{
41}
42prep_stmt::prep_stmt(dbcontext_i *c, size_t tbl, size_t idx,
43 const fields_type& rf, const fields_type& ff)
44 : dbctx(c), table_id(tbl), idxnum(idx), ret_fields(rf), filter_fields(ff)
45{
46 if (dbctx) {
47 dbctx->table_addref(table_id);
48 }
49}
50prep_stmt::~prep_stmt()
51{
52 if (dbctx) {
53 dbctx->table_release(table_id);
54 }
55}
56
57prep_stmt::prep_stmt(const prep_stmt& x)
58 : dbctx(x.dbctx), table_id(x.table_id), idxnum(x.idxnum),
59 ret_fields(x.ret_fields), filter_fields(x.filter_fields)
60{
61 if (dbctx) {
62 dbctx->table_addref(table_id);
63 }
64}
65
66prep_stmt&
67prep_stmt::operator =(const prep_stmt& x)
68{
69 if (this != &x) {
70 if (dbctx) {
71 dbctx->table_release(table_id);
72 }
73 dbctx = x.dbctx;
74 table_id = x.table_id;
75 idxnum = x.idxnum;
76 ret_fields = x.ret_fields;
77 filter_fields = x.filter_fields;
78 if (dbctx) {
79 dbctx->table_addref(table_id);
80 }
81 }
82 return *this;
83}
84
85struct database : public database_i, private noncopyable {
86 database(const config& c);
87 virtual ~database();
88 virtual dbcontext_ptr create_context(bool for_write) volatile;
89 virtual void stop() volatile;
90 virtual const config& get_conf() const volatile;
91 public:
92 int child_running;
93 private:
94 config conf;
95};
96
97struct tablevec_entry {
98 TABLE *table;
99 size_t refcount;
100 bool modified;
101 tablevec_entry() : table(0), refcount(0), modified(false) { }
102};
103
104struct expr_user_lock : private noncopyable {
105 expr_user_lock(THD *thd, int timeout)
106 : lck_key("handlersocket_wr", 16, &my_charset_latin1),
107 lck_timeout(timeout),
108 lck_func_get_lock(&lck_key, &lck_timeout),
109 lck_func_release_lock(&lck_key)
110 {
111 lck_key.fix_fields(thd, 0);
112 lck_timeout.fix_fields(thd, 0);
113 lck_func_get_lock.fix_fields(thd, 0);
114 lck_func_release_lock.fix_fields(thd, 0);
115 }
116 long long get_lock() {
117 return lck_func_get_lock.val_int();
118 }
119 long long release_lock() {
120 return lck_func_release_lock.val_int();
121 }
122 private:
123 Item_string lck_key;
124 Item_int lck_timeout;
125 Item_func_get_lock lck_func_get_lock;
126 Item_func_release_lock lck_func_release_lock;
127};
128
129struct dbcontext : public dbcontext_i, private noncopyable {
130 dbcontext(volatile database *d, bool for_write);
131 virtual ~dbcontext();
132 virtual void init_thread(const void *stack_botton,
133 volatile int& shutdown_flag);
134 virtual void term_thread();
135 virtual bool check_alive();
136 virtual void lock_tables_if();
137 virtual void unlock_tables_if();
138 virtual bool get_commit_error();
139 virtual void clear_error();
140 virtual void close_tables_if();
141 virtual void table_addref(size_t tbl_id);
142 virtual void table_release(size_t tbl_id);
143 virtual void cmd_open_index(dbcallback_i& cb, size_t pst_id, const char *dbn,
144 const char *tbl, const char *idx, const char *retflds,
145 const char *filflds);
146 virtual void cmd_exec_on_index(dbcallback_i& cb, const cmd_exec_args& args);
147 virtual void set_statistics(size_t num_conns, size_t num_active);
148 private:
149 int set_thread_message(const char *fmt, ...)
150 __attribute__((format (printf, 2, 3)));
151 bool parse_fields(TABLE *const table, const char *str,
152 prep_stmt::fields_type& flds);
153 void cmd_insert_internal(dbcallback_i& cb, const prep_stmt& pst,
154 const string_ref *fvals, size_t fvalslen);
155 void cmd_sql_internal(dbcallback_i& cb, const prep_stmt& pst,
156 const string_ref *fvals, size_t fvalslen);
157 void cmd_find_internal(dbcallback_i& cb, const prep_stmt& pst,
158 ha_rkey_function find_flag, const cmd_exec_args& args);
159 size_t calc_filter_buf_size(TABLE *table, const prep_stmt& pst,
160 const record_filter *filters);
161 bool fill_filter_buf(TABLE *table, const prep_stmt& pst,
162 const record_filter *filters, uchar *filter_buf, size_t len);
163 int check_filter(dbcallback_i& cb, TABLE *table, const prep_stmt& pst,
164 const record_filter *filters, const uchar *filter_buf);
165 void resp_record(dbcallback_i& cb, TABLE *const table, const prep_stmt& pst);
166 void dump_record(dbcallback_i& cb, TABLE *const table, const prep_stmt& pst);
167 int modify_record(dbcallback_i& cb, TABLE *const table,
168 const prep_stmt& pst, const cmd_exec_args& args, char mod_op,
169 size_t& modified_count);
170 private:
171 typedef std::vector<tablevec_entry> table_vec_type;
172 typedef std::pair<std::string, std::string> table_name_type;
173 typedef std::map<table_name_type, size_t> table_map_type;
174 private:
175 volatile database *const dbref;
176 bool for_write_flag;
177 THD *thd;
178 MYSQL_LOCK *lock;
179 bool lock_failed;
180 std::auto_ptr<expr_user_lock> user_lock;
181 int user_level_lock_timeout;
182 bool user_level_lock_locked;
183 bool commit_error;
184 std::vector<char> info_message_buf;
185 table_vec_type table_vec;
186 table_map_type table_map;
187 #if MYSQL_VERSION_ID >= 50505
188 MDL_request *mdl_request;
189 #else
190 void *mdl_request;
191 #endif
192};
193
194database::database(const config& c)
195 : child_running(1), conf(c)
196{
197}
198
199database::~database()
200{
201}
202
203dbcontext_ptr
204database::create_context(bool for_write) volatile
205{
206 return dbcontext_ptr(new dbcontext(this, for_write));
207}
208
209void
210database::stop() volatile
211{
212 child_running = false;
213}
214
215const config&
216database::get_conf() const volatile
217{
218 return const_cast<const config&>(conf);
219}
220
221database_ptr
222database_i::create(const config& conf)
223{
224 return database_ptr(new database(conf));
225}
226
227dbcontext::dbcontext(volatile database *d, bool for_write)
228 : dbref(d), for_write_flag(for_write), thd(0), lock(0), lock_failed(false),
229 user_level_lock_timeout(0), user_level_lock_locked(false),
230 commit_error(false), mdl_request(0)
231{
232 info_message_buf.resize(8192);
233 user_level_lock_timeout = d->get_conf().get_int("wrlock_timeout", 12);
234}
235
236dbcontext::~dbcontext()
237{
238}
239
240namespace {
241
242int
243wait_server_to_start(THD *thd, volatile int& shutdown_flag)
244{
245 int r = 0;
246 DBG_SHUT(fprintf(stderr, "HNDSOCK wsts\n"));
247 pthread_mutex_lock(&LOCK_server_started);
248 while (!mysqld_server_started) {
249 timespec abstime = { };
250 set_timespec(abstime, 1);
251 pthread_cond_timedwait(&COND_server_started, &LOCK_server_started,
252 &abstime);
253 pthread_mutex_unlock(&LOCK_server_started);
254 pthread_mutex_lock(&thd->mysys_var->mutex);
255 THD::killed_state st = thd->killed;
256 pthread_mutex_unlock(&thd->mysys_var->mutex);
257 DBG_SHUT(fprintf(stderr, "HNDSOCK wsts kst %d\n", (int)st));
258 pthread_mutex_lock(&LOCK_server_started);
259 if (st != THD::NOT_KILLED) {
260 DBG_SHUT(fprintf(stderr, "HNDSOCK wsts kst %d break\n", (int)st));
261 r = -1;
262 break;
263 }
264 if (shutdown_flag) {
265 DBG_SHUT(fprintf(stderr, "HNDSOCK wsts kst shut break\n"));
266 r = -1;
267 break;
268 }
269 }
270 pthread_mutex_unlock(&LOCK_server_started);
271 DBG_SHUT(fprintf(stderr, "HNDSOCK wsts done\n"));
272 return r;
273}
274
275}; // namespace
276
277void
278dbcontext::init_thread(const void *stack_bottom, volatile int& shutdown_flag)
279{
280 DBG_THR(fprintf(stderr, "HNDSOCK init thread\n"));
281 {
282 my_thread_init();
283 thd = new THD;
284 thd->thread_stack = (char *)stack_bottom;
285 DBG_THR(const size_t of = (char *)(&thd->thread_stack) - (char *)thd);
286 DBG_THR(fprintf(stderr, "thread_stack = %p sz=%zu of=%zu\n",
287 thd->thread_stack, sizeof(THD), of));
288 thd->store_globals();
289 thd->system_thread = static_cast<enum_thread_type>(1<<30UL);
290 const NET v = { 0 };
291 thd->net = v;
292 if (for_write_flag) {
293 #if MYSQL_VERSION_ID >= 50505
294 thd->variables.option_bits |= OPTION_BIN_LOG;
295 #else
296 thd->options |= OPTION_BIN_LOG;
297 #endif
298 safeFree(thd->db);
299 thd->db = 0;
300 thd->db = my_strdup("handlersocket", MYF(0));
301 }
302 my_pthread_setspecific_ptr(THR_THD, thd);
303 DBG_THR(fprintf(stderr, "HNDSOCK x0 %p\n", thd));
304 }
305 {
306 pthread_mutex_lock(&LOCK_thread_count);
307 thd->thread_id = thread_id++;
308 threads.append(thd);
309 ++thread_count;
310 pthread_mutex_unlock(&LOCK_thread_count);
311 }
312
313 DBG_THR(fprintf(stderr, "HNDSOCK init thread wsts\n"));
314 wait_server_to_start(thd, shutdown_flag);
315 DBG_THR(fprintf(stderr, "HNDSOCK init thread done\n"));
316
317 thd_proc_info(thd, &info_message_buf[0]);
318 set_thread_message("hs:listening");
319 DBG_THR(fprintf(stderr, "HNDSOCK x1 %p\n", thd));
320
321 #if MYSQL_VERSION_ID >= 50508
322 mdl_request = new(thd->mem_root) MDL_request;
323 mdl_request->init(MDL_key::TABLE, "", "",
324 for_write_flag ? MDL_SHARED_WRITE : MDL_SHARED_READ, MDL_STATEMENT);
325 #elif MYSQL_VERSION_ID >= 50505
326 mdl_request = MDL_request::create(MDL_key::TABLE, "", "",
327 for_write_flag ? MDL_SHARED_WRITE : MDL_SHARED_READ, thd->mem_root);
328 #endif
329
330 lex_start(thd);
331
332 user_lock.reset(new expr_user_lock(thd, user_level_lock_timeout));
333}
334
335int
336dbcontext::set_thread_message(const char *fmt, ...)
337{
338 va_list ap;
339 va_start(ap, fmt);
340 const int n = vsnprintf(&info_message_buf[0], info_message_buf.size(),
341 fmt, ap);
342 va_end(ap);
343 return n;
344}
345
346void
347dbcontext::term_thread()
348{
349 DBG_THR(fprintf(stderr, "HNDSOCK thread end %p\n", thd));
350 unlock_tables_if();
351 my_pthread_setspecific_ptr(THR_THD, 0);
352 {
353 pthread_mutex_lock(&LOCK_thread_count);
354 delete thd;
355 thd = 0;
356 --thread_count;
357 pthread_mutex_unlock(&LOCK_thread_count);
358 my_thread_end();
359 }
360}
361
362bool
363dbcontext::check_alive()
364{
365 pthread_mutex_lock(&thd->mysys_var->mutex);
366 THD::killed_state st = thd->killed;
367 pthread_mutex_unlock(&thd->mysys_var->mutex);
368 DBG_SHUT(fprintf(stderr, "chk HNDSOCK kst %p %p %d %zu\n", thd, &thd->killed,
369 (int)st, sizeof(*thd)));
370 if (st != THD::NOT_KILLED) {
371 DBG_SHUT(fprintf(stderr, "chk HNDSOCK kst %d break\n", (int)st));
372 return false;
373 }
374 return true;
375}
376
377void
378dbcontext::lock_tables_if()
379{
380 if (lock_failed) {
381 return;
382 }
383 if (for_write_flag && !user_level_lock_locked) {
384 if (user_lock->get_lock()) {
385 user_level_lock_locked = true;
386 } else {
387 lock_failed = true;
388 return;
389 }
390 }
391 if (lock == 0) {
392 const size_t num_max = table_vec.size();
393 TABLE *tables[num_max ? num_max : 1]; /* GNU */
394 size_t num_open = 0;
395 for (size_t i = 0; i < num_max; ++i) {
396 if (table_vec[i].refcount > 0) {
397 tables[num_open++] = table_vec[i].table;
398 }
399 table_vec[i].modified = false;
400 }
401 #if MYSQL_VERSION_ID >= 50505
402 lock = thd->lock = mysql_lock_tables(thd, &tables[0], num_open, 0);
403 #else
404 bool need_reopen= false;
405 lock = thd->lock = mysql_lock_tables(thd, &tables[0], num_open,
406 MYSQL_LOCK_NOTIFY_IF_NEED_REOPEN, &need_reopen);
407 #endif
408 statistic_increment(lock_tables_count, &LOCK_status);
409 thd_proc_info(thd, &info_message_buf[0]);
410 DENA_VERBOSE(100, fprintf(stderr, "HNDSOCK lock tables %p %p %zu %zu\n",
411 thd, lock, num_max, num_open));
412 if (lock == 0) {
413 lock_failed = true;
414 DENA_VERBOSE(10, fprintf(stderr, "HNDSOCK failed to lock tables %p\n",
415 thd));
416 }
417 if (for_write_flag) {
418 #if MYSQL_VERSION_ID >= 50505
419 thd->set_current_stmt_binlog_format_row();
420 #else
421 thd->current_stmt_binlog_row_based = 1;
422 #endif
423 }
424 }
425 DBG_LOCK(fprintf(stderr, "HNDSOCK tblnum=%d\n", (int)tblnum));
426}
427
428void
429dbcontext::unlock_tables_if()
430{
431 if (lock != 0) {
432 DENA_VERBOSE(100, fprintf(stderr, "HNDSOCK unlock tables\n"));
433 if (for_write_flag) {
434 for (size_t i = 0; i < table_vec.size(); ++i) {
435 if (table_vec[i].modified) {
436 query_cache_invalidate3(thd, table_vec[i].table, 0);
437 /* invalidate immediately */
438 }
439 }
440 bool suc = true;
441 #if MYSQL_VERSION_ID >= 50505
442 suc = (trans_commit_stmt(thd) == 0);
443 #else
444 suc = (ha_autocommit_or_rollback(thd, 0) == 0);
445 #endif
446 if (!suc) {
447 commit_error = true;
448 DENA_VERBOSE(10, fprintf(stderr,
449 "HNDSOCK unlock tables: commit failed\n"));
450 }
451 }
452 mysql_unlock_tables(thd, lock);
453 lock = thd->lock = 0;
454 statistic_increment(unlock_tables_count, &LOCK_status);
455 }
456 if (user_level_lock_locked) {
457 if (user_lock->release_lock()) {
458 user_level_lock_locked = false;
459 }
460 }
461}
462
463bool
464dbcontext::get_commit_error()
465{
466 return commit_error;
467}
468
469void
470dbcontext::clear_error()
471{
472 lock_failed = false;
473 commit_error = false;
474}
475
476void
477dbcontext::close_tables_if()
478{
479 unlock_tables_if();
480 if (!table_vec.empty()) {
481 DENA_VERBOSE(100, fprintf(stderr, "HNDSOCK close tables\n"));
482 close_thread_tables(thd);
483 statistic_increment(close_tables_count, &LOCK_status);
484 table_vec.clear();
485 table_map.clear();
486 }
487}
488
489void
490dbcontext::table_addref(size_t tbl_id)
491{
492 table_vec[tbl_id].refcount += 1;
493 DBG_REFCNT(fprintf(stderr, "%p %zu %zu addref\n", this, tbl_id,
494 table_vec[tbl_id].refcount));
495}
496
497void
498dbcontext::table_release(size_t tbl_id)
499{
500 table_vec[tbl_id].refcount -= 1;
501 DBG_REFCNT(fprintf(stderr, "%p %zu %zu release\n", this, tbl_id,
502 table_vec[tbl_id].refcount));
503}
504
505void
506dbcontext::resp_record(dbcallback_i& cb, TABLE *const table,
507 const prep_stmt& pst)
508{
509 char rwpstr_buf[64];
510 String rwpstr(rwpstr_buf, sizeof(rwpstr_buf), &my_charset_bin);
511 const prep_stmt::fields_type& rf = pst.get_ret_fields();
512 const size_t n = rf.size();
513 for (size_t i = 0; i < n; ++i) {
514 uint32_t fn = rf[i];
515 Field *const fld = table->field[fn];
516 DBG_FLD(fprintf(stderr, "fld=%p %zu\n", fld, fn));
517 if (fld->is_null()) {
518 /* null */
519 cb.dbcb_resp_entry(0, 0);
520 } else {
521 fld->val_str(&rwpstr, &rwpstr);
522 const size_t len = rwpstr.length();
523 if (len != 0) {
524 /* non-empty */
525 cb.dbcb_resp_entry(rwpstr.ptr(), rwpstr.length());
526 } else {
527 /* empty */
528 static const char empty_str[] = "";
529 cb.dbcb_resp_entry(empty_str, 0);
530 }
531 }
532 }
533}
534
535void
536dbcontext::dump_record(dbcallback_i& cb, TABLE *const table,
537 const prep_stmt& pst)
538{
539 char rwpstr_buf[64];
540 String rwpstr(rwpstr_buf, sizeof(rwpstr_buf), &my_charset_bin);
541 const prep_stmt::fields_type& rf = pst.get_ret_fields();
542 const size_t n = rf.size();
543 for (size_t i = 0; i < n; ++i) {
544 uint32_t fn = rf[i];
545 Field *const fld = table->field[fn];
546 if (fld->is_null()) {
547 /* null */
548 cb.dbcb_resp_entry(0, 0);
549 fprintf(stderr, "NULL");
550 } else {
551 fld->val_str(&rwpstr, &rwpstr);
552 const std::string s(rwpstr.ptr(), rwpstr.length());
553 fprintf(stderr, "[%s]", s.c_str());
554 }
555 }
556 fprintf(stderr, "\n");
557}
558
559int
560dbcontext::modify_record(dbcallback_i& cb, TABLE *const table,
561 const prep_stmt& pst, const cmd_exec_args& args, char mod_op,
562 size_t& modified_count)
563{
564 if (mod_op == 'U') {
565 /* update */
566 handler *const hnd = table->file;
567 uchar *const buf = table->record[0];
568 store_record(table, record[1]);
569 const prep_stmt::fields_type& rf = pst.get_ret_fields();
570 const size_t n = rf.size();
571 for (size_t i = 0; i < n; ++i) {
572 const string_ref& nv = args.uvals[i];
573 uint32_t fn = rf[i];
574 Field *const fld = table->field[fn];
575 if (nv.begin() == 0) {
576 fld->set_null();
577 } else {
578 fld->set_notnull();
579 fld->store(nv.begin(), nv.size(), &my_charset_bin);
580 }
581 }
582 table_vec[pst.get_table_id()].modified = true;
583 const int r = hnd->ha_update_row(table->record[1], buf);
584 if (r != 0 && r != HA_ERR_RECORD_IS_THE_SAME) {
585 return r;
586 }
587 ++modified_count; /* TODO: HA_ERR_RECORD_IS_THE_SAME? */
588 } else if (mod_op == 'D') {
589 /* delete */
590 handler *const hnd = table->file;
591 table_vec[pst.get_table_id()].modified = true;
592 const int r = hnd->ha_delete_row(table->record[0]);
593 if (r != 0) {
594 return r;
595 }
596 ++modified_count;
597 } else if (mod_op == '+' || mod_op == '-') {
598 /* increment/decrement */
599 handler *const hnd = table->file;
600 uchar *const buf = table->record[0];
601 store_record(table, record[1]);
602 const prep_stmt::fields_type& rf = pst.get_ret_fields();
603 const size_t n = rf.size();
604 size_t i = 0;
605 for (i = 0; i < n; ++i) {
606 const string_ref& nv = args.uvals[i];
607 uint32_t fn = rf[i];
608 Field *const fld = table->field[fn];
609 if (fld->is_null() || nv.begin() == 0) {
610 continue;
611 }
612 const long long pval = fld->val_int();
613 const long long llv = atoll_nocheck(nv.begin(), nv.end());
614 /* TODO: llv == 0? */
615 long long nval = 0;
616 if (mod_op == '+') {
617 /* increment */
618 nval = pval + llv;
619 } else {
620 /* decrement */
621 nval = pval - llv;
622 if ((pval < 0 && nval > 0) || (pval > 0 && nval < 0)) {
623 break; /* don't modify */
624 }
625 if ((pval < 0) != (nval < 0)) {
626 nval = 0; /* crip */
627 }
628 }
629 fld->store(nval, false);
630 }
631 if (i == n) {
632 /* modify */
633 table_vec[pst.get_table_id()].modified = true;
634 const int r = hnd->ha_update_row(table->record[1], buf);
635 if (r != 0 && r != HA_ERR_RECORD_IS_THE_SAME) {
636 return r;
637 }
638 ++modified_count;
639 }
640 }
641 return 0;
642}
643
644void
645dbcontext::cmd_insert_internal(dbcallback_i& cb, const prep_stmt& pst,
646 const string_ref *fvals, size_t fvalslen)
647{
648 if (!for_write_flag) {
649 return cb.dbcb_resp_short(2, "readonly");
650 }
651 lock_tables_if();
652 if (lock == 0) {
653 return cb.dbcb_resp_short(2, "lock_tables");
654 }
655 if (pst.get_table_id() >= table_vec.size()) {
656 return cb.dbcb_resp_short(2, "tblnum");
657 }
658 TABLE *const table = table_vec[pst.get_table_id()].table;
659 handler *const hnd = table->file;
660 uchar *const buf = table->record[0];
661 empty_record(table);
662 memset(buf, 0, table->s->null_bytes); /* clear null flags */
663 Field **fld = table->field;
664 size_t i = 0;
665 for (; *fld && i < fvalslen; ++fld, ++i) {
666 if (fvals[i].begin() == 0) {
667 (*fld)->set_null();
668 } else {
669 (*fld)->store(fvals[i].begin(), fvals[i].size(), &my_charset_bin);
670 }
671 }
672 table->next_number_field = table->found_next_number_field;
673 const int r = hnd->ha_write_row(buf);
674 table->next_number_field = 0;
675 table_vec[pst.get_table_id()].modified = true;
676 return cb.dbcb_resp_short(r != 0 ? 1 : 0, "");
677}
678
679void
680dbcontext::cmd_sql_internal(dbcallback_i& cb, const prep_stmt& pst,
681 const string_ref *fvals, size_t fvalslen)
682{
683 if (fvalslen < 1) {
684 return cb.dbcb_resp_short(2, "syntax");
685 }
686 return cb.dbcb_resp_short(2, "notimpl");
687}
688
689void
690dbcontext::cmd_find_internal(dbcallback_i& cb, const prep_stmt& pst,
691 ha_rkey_function find_flag, const cmd_exec_args& args)
692{
693 const bool debug_out = (verbose_level >= 100);
694 bool need_resp_record = true;
695 char mod_op = 0;
696 const string_ref& mod_op_str = args.mod_op;
697 if (mod_op_str.size() != 0) {
698 if (!for_write_flag) {
699 return cb.dbcb_resp_short(2, "readonly");
700 }
701 mod_op = mod_op_str.begin()[0];
702 need_resp_record = mod_op_str.size() > 1 && mod_op_str.begin()[1] == '?';
703 switch (mod_op) {
704 case 'U': /* update */
705 case 'D': /* delete */
706 case '+': /* increment */
707 case '-': /* decrement */
708 break;
709 default:
710 if (debug_out) {
711 fprintf(stderr, "unknown modop: %c\n", mod_op);
712 }
713 return cb.dbcb_resp_short(2, "modop");
714 }
715 }
716 lock_tables_if();
717 if (lock == 0) {
718 return cb.dbcb_resp_short(2, "lock_tables");
719 }
720 if (pst.get_table_id() >= table_vec.size()) {
721 return cb.dbcb_resp_short(2, "tblnum");
722 }
723 TABLE *const table = table_vec[pst.get_table_id()].table;
724 /* keys */
725 if (pst.get_idxnum() >= table->s->keys) {
726 return cb.dbcb_resp_short(2, "idxnum");
727 }
728 KEY& kinfo = table->key_info[pst.get_idxnum()];
729 if (args.kvalslen > kinfo.key_parts) {
730 return cb.dbcb_resp_short(2, "kpnum");
731 }
732 uchar key_buf[kinfo.key_length]; /* GNU */
733 size_t kplen_sum = 0;
734 {
735 DBG_KEY(fprintf(stderr, "SLOW\n"));
736 for (size_t i = 0; i < args.kvalslen; ++i) {
737 const KEY_PART_INFO & kpt = kinfo.key_part[i];
738 const string_ref& kval = args.kvals[i];
739 if (kval.begin() == 0) {
740 kpt.field->set_null();
741 } else {
742 kpt.field->set_notnull();
743 }
744 kpt.field->store(kval.begin(), kval.size(), &my_charset_bin);
745 kplen_sum += kpt.store_length;
746 }
747 key_copy(key_buf, table->record[0], &kinfo, kplen_sum);
748 }
749 /* filters */
750 uchar *filter_buf = 0;
751 if (args.filters != 0) {
752 const size_t filter_buf_len = calc_filter_buf_size(table, pst,
753 args.filters);
754 filter_buf = reinterpret_cast<uchar *>(alloca(filter_buf_len));
755 /* FIXME: TEST */
756 if (!fill_filter_buf(table, pst, args.filters, filter_buf,
757 filter_buf_len)) {
758 return cb.dbcb_resp_short(2, "filterblob");
759 }
760 }
761 /* handler */
762 table->read_set = &table->s->all_set;
763 handler *const hnd = table->file;
764 if (!for_write_flag) {
765 hnd->init_table_handle_for_HANDLER();
766 }
767 hnd->ha_index_or_rnd_end();
768 hnd->ha_index_init(pst.get_idxnum(), 1);
769 #if 0
770 statistic_increment(index_exec_count, &LOCK_status);
771 #endif
772 if (need_resp_record) {
773 cb.dbcb_resp_begin(pst.get_ret_fields().size());
774 }
775 const uint32_t limit = args.limit ? args.limit : 1;
776 uint32_t skip = args.skip;
777 size_t modified_count = 0;
778 int r = 0;
779 for (uint32_t i = 0; i < limit + skip; ++i) {
780 if (i == 0) {
781 const key_part_map kpm = (1U << args.kvalslen) - 1;
782 r = hnd->index_read_map(table->record[0], key_buf, kpm, find_flag);
783 } else {
784 switch (find_flag) {
785 case HA_READ_BEFORE_KEY:
786 case HA_READ_KEY_OR_PREV:
787 r = hnd->index_prev(table->record[0]);
788 break;
789 case HA_READ_AFTER_KEY:
790 case HA_READ_KEY_OR_NEXT:
791 r = hnd->index_next(table->record[0]);
792 break;
793 case HA_READ_KEY_EXACT:
794 r = hnd->index_next_same(table->record[0], key_buf, kplen_sum);
795 break;
796 default:
797 r = HA_ERR_END_OF_FILE; /* to finish the loop */
798 break;
799 }
800 }
801 if (debug_out) {
802 fprintf(stderr, "r=%d\n", r);
803 if (r == 0 || r == HA_ERR_RECORD_DELETED) {
804 dump_record(cb, table, pst);
805 }
806 }
807 int filter_res = 0;
808 if (r != 0) {
809 /* no-count */
810 } else if (args.filters != 0 && (filter_res = check_filter(cb, table,
811 pst, args.filters, filter_buf)) != 0) {
812 if (filter_res < 0) {
813 break;
814 }
815 } else if (skip > 0) {
816 --skip;
817 } else {
818 if (need_resp_record) {
819 resp_record(cb, table, pst);
820 }
821 if (mod_op != 0) {
822 r = modify_record(cb, table, pst, args, mod_op, modified_count);
823 }
824 }
825 if (r != 0 && r != HA_ERR_RECORD_DELETED) {
826 break;
827 }
828 }
829 hnd->ha_index_or_rnd_end();
830 if (r != 0 && r != HA_ERR_RECORD_DELETED && r != HA_ERR_KEY_NOT_FOUND &&
831 r != HA_ERR_END_OF_FILE) {
832 /* failed */
833 if (need_resp_record) {
834 /* revert dbcb_resp_begin() and dbcb_resp_entry() */
835 cb.dbcb_resp_cancel();
836 }
837 cb.dbcb_resp_short_num(2, r);
838 } else {
839 /* succeeded */
840 if (need_resp_record) {
841 cb.dbcb_resp_end();
842 } else {
843 cb.dbcb_resp_short_num(0, modified_count);
844 }
845 }
846}
847
848size_t
849dbcontext::calc_filter_buf_size(TABLE *table, const prep_stmt& pst,
850 const record_filter *filters)
851{
852 size_t filter_buf_len = 0;
853 for (const record_filter *f = filters; f->op.begin() != 0; ++f) {
854 if (f->val.begin() == 0) {
855 continue;
856 }
857 const uint32_t fn = pst.get_filter_fields()[f->ff_offset];
858 filter_buf_len += table->field[fn]->pack_length();
859 }
860 return filter_buf_len;
861}
862
863bool
864dbcontext::fill_filter_buf(TABLE *table, const prep_stmt& pst,
865 const record_filter *filters, uchar *filter_buf, size_t len)
866{
867 memset(filter_buf, 0, len);
868 size_t pos = 0;
869 for (const record_filter *f = filters; f->op.begin() != 0; ++f) {
870 if (f->val.begin() == 0) {
871 continue;
872 }
873 const uint32_t fn = pst.get_filter_fields()[f->ff_offset];
874 Field *const fld = table->field[fn];
875 if ((fld->flags & BLOB_FLAG) != 0) {
876 return false;
877 }
878 fld->store(f->val.begin(), f->val.size(), &my_charset_bin);
879 const size_t packlen = fld->pack_length();
880 memcpy(filter_buf + pos, fld->ptr, packlen);
881 pos += packlen;
882 }
883 return true;
884}
885
886int
887dbcontext::check_filter(dbcallback_i& cb, TABLE *table, const prep_stmt& pst,
888 const record_filter *filters, const uchar *filter_buf)
889{
890 DBG_FILTER(fprintf(stderr, "check_filter\n"));
891 size_t pos = 0;
892 for (const record_filter *f = filters; f->op.begin() != 0; ++f) {
893 const string_ref& op = f->op;
894 const string_ref& val = f->val;
895 const uint32_t fn = pst.get_filter_fields()[f->ff_offset];
896 Field *const fld = table->field[fn];
897 const size_t packlen = fld->pack_length();
898 const uchar *const bval = filter_buf + pos;
899 int cv = 0;
900 if (fld->is_null()) {
901 cv = (val.begin() == 0) ? 0 : -1;
902 } else {
903 cv = (val.begin() == 0) ? 1 : fld->cmp(bval);
904 }
905 DBG_FILTER(fprintf(stderr, "check_filter cv=%d\n", cv));
906 bool cond = true;
907 if (op.size() == 1) {
908 switch (op.begin()[0]) {
909 case '>':
910 DBG_FILTER(fprintf(stderr, "check_filter op: >\n"));
911 cond = (cv > 0);
912 break;
913 case '<':
914 DBG_FILTER(fprintf(stderr, "check_filter op: <\n"));
915 cond = (cv < 0);
916 break;
917 case '=':
918 DBG_FILTER(fprintf(stderr, "check_filter op: =\n"));
919 cond = (cv == 0);
920 break;
921 default:
922 DBG_FILTER(fprintf(stderr, "check_filter op: unknown\n"));
923 cond = false; /* FIXME: error */
924 break;
925 }
926 } else if (op.size() == 2 && op.begin()[1] == '=') {
927 switch (op.begin()[0]) {
928 case '>':
929 DBG_FILTER(fprintf(stderr, "check_filter op: >=\n"));
930 cond = (cv >= 0);
931 break;
932 case '<':
933 DBG_FILTER(fprintf(stderr, "check_filter op: <=\n"));
934 cond = (cv <= 0);
935 break;
936 case '!':
937 DBG_FILTER(fprintf(stderr, "check_filter op: !=\n"));
938 cond = (cv != 0);
939 break;
940 default:
941 DBG_FILTER(fprintf(stderr, "check_filter op: unknown\n"));
942 cond = false; /* FIXME: error */
943 break;
944 }
945 }
946 DBG_FILTER(fprintf(stderr, "check_filter cond: %d\n", (int)cond));
947 if (!cond) {
948 return (f->filter_type == record_filter_type_skip) ? 1 : -1;
949 }
950 if (val.begin() != 0) {
951 pos += packlen;
952 }
953 }
954 return 0;
955}
956
957void
958dbcontext::cmd_open_index(dbcallback_i& cb, size_t pst_id, const char *dbn,
959 const char *tbl, const char *idx, const char *retflds, const char *filflds)
960{
961 unlock_tables_if();
962 const table_name_type k = std::make_pair(std::string(dbn), std::string(tbl));
963 const table_map_type::const_iterator iter = table_map.find(k);
964 uint32_t tblnum = 0;
965 if (iter != table_map.end()) {
966 tblnum = iter->second;
967 DBG_CMP(fprintf(stderr, "HNDSOCK k=%s tblnum=%d\n", k.c_str(),
968 (int)tblnum));
969 } else {
970 TABLE_LIST tables;
971 TABLE *table = 0;
972 bool refresh = true;
973 const thr_lock_type lock_type = for_write_flag ? TL_WRITE : TL_READ;
974 #if MYSQL_VERSION_ID >= 50505
975 tables.init_one_table(dbn, strlen(dbn), tbl, strlen(tbl), tbl,
976 lock_type);
977 tables.mdl_request = mdl_request;
978 Open_table_context ot_act(thd, MYSQL_OPEN_REOPEN);
979 if (!open_table(thd, &tables, thd->mem_root, &ot_act)) {
980 table = tables.table;
981 }
982 #else
983 tables.init_one_table(dbn, tbl, lock_type);
984 table = open_table(thd, &tables, thd->mem_root, &refresh,
985 OPEN_VIEW_NO_PARSE);
986 #endif
987 if (table == 0) {
988 DENA_VERBOSE(10, fprintf(stderr,
989 "HNDSOCK failed to open %p [%s] [%s] [%d]\n",
990 thd, dbn, tbl, static_cast<int>(refresh)));
991 return cb.dbcb_resp_short(2, "open_table");
992 }
993 statistic_increment(open_tables_count, &LOCK_status);
994 table->reginfo.lock_type = lock_type;
995 table->use_all_columns();
996 tblnum = table_vec.size();
997 tablevec_entry e;
998 e.table = table;
999 table_vec.push_back(e);
1000 table_map[k] = tblnum;
1001 }
1002 size_t idxnum = static_cast<size_t>(-1);
1003 if (idx[0] >= '0' && idx[0] <= '9') {
1004 /* numeric */
1005 TABLE *const table = table_vec[tblnum].table;
1006 idxnum = atoi(idx);
1007 if (idxnum >= table->s->keys) {
1008 return cb.dbcb_resp_short(2, "idxnum");
1009 }
1010 } else {
1011 const char *const idx_name_to_open = idx[0] == '\0' ? "PRIMARY" : idx;
1012 TABLE *const table = table_vec[tblnum].table;
1013 for (uint i = 0; i < table->s->keys; ++i) {
1014 KEY& kinfo = table->key_info[i];
1015 if (strcmp(kinfo.name, idx_name_to_open) == 0) {
1016 idxnum = i;
1017 break;
1018 }
1019 }
1020 }
1021 if (idxnum == size_t(-1)) {
1022 return cb.dbcb_resp_short(2, "idxnum");
1023 }
1024 prep_stmt::fields_type rf;
1025 prep_stmt::fields_type ff;
1026 if (!parse_fields(table_vec[tblnum].table, retflds, rf)) {
1027 return cb.dbcb_resp_short(2, "fld");
1028 }
1029 if (!parse_fields(table_vec[tblnum].table, filflds, ff)) {
1030 return cb.dbcb_resp_short(2, "fld");
1031 }
1032 prep_stmt p(this, tblnum, idxnum, rf, ff);
1033 cb.dbcb_set_prep_stmt(pst_id, p);
1034 return cb.dbcb_resp_short(0, "");
1035}
1036
1037bool
1038dbcontext::parse_fields(TABLE *const table, const char *str,
1039 prep_stmt::fields_type& flds)
1040{
1041 string_ref flds_sr(str, strlen(str));
1042 std::vector<string_ref> fldnms;
1043 if (flds_sr.size() != 0) {
1044 split(',', flds_sr, fldnms);
1045 }
1046 for (size_t i = 0; i < fldnms.size(); ++i) {
1047 Field **fld = 0;
1048 size_t j = 0;
1049 for (fld = table->field; *fld; ++fld, ++j) {
1050 DBG_FLD(fprintf(stderr, "f %s\n", (*fld)->field_name));
1051 string_ref fn((*fld)->field_name, strlen((*fld)->field_name));
1052 if (fn == fldnms[i]) {
1053 break;
1054 }
1055 }
1056 if (*fld == 0) {
1057 DBG_FLD(fprintf(stderr, "UNKNOWN FLD %s [%s]\n", retflds,
1058 std::string(fldnms[i].begin(), fldnms[i].size()).c_str()));
1059 return false;
1060 }
1061 DBG_FLD(fprintf(stderr, "FLD %s %zu\n", (*fld)->field_name, j));
1062 flds.push_back(j);
1063 }
1064 return true;
1065}
1066
1067enum db_write_op {
1068 db_write_op_none = 0,
1069 db_write_op_insert = 1,
1070 db_write_op_sql = 2,
1071};
1072
1073void
1074dbcontext::cmd_exec_on_index(dbcallback_i& cb, const cmd_exec_args& args)
1075{
1076 const prep_stmt& p = *args.pst;
1077 if (p.get_table_id() == static_cast<size_t>(-1)) {
1078 return cb.dbcb_resp_short(2, "stmtnum");
1079 }
1080 ha_rkey_function find_flag = HA_READ_KEY_EXACT;
1081 db_write_op wrop = db_write_op_none;
1082 if (args.op.size() == 1) {
1083 switch (args.op.begin()[0]) {
1084 case '=':
1085 find_flag = HA_READ_KEY_EXACT;
1086 break;
1087 case '>':
1088 find_flag = HA_READ_AFTER_KEY;
1089 break;
1090 case '<':
1091 find_flag = HA_READ_BEFORE_KEY;
1092 break;
1093 case '+':
1094 wrop = db_write_op_insert;
1095 break;
1096 case 'S':
1097 wrop = db_write_op_sql;
1098 break;
1099 default:
1100 return cb.dbcb_resp_short(1, "op");
1101 }
1102 } else if (args.op.size() == 2 && args.op.begin()[1] == '=') {
1103 switch (args.op.begin()[0]) {
1104 case '>':
1105 find_flag = HA_READ_KEY_OR_NEXT;
1106 break;
1107 case '<':
1108 find_flag = HA_READ_KEY_OR_PREV;
1109 break;
1110 default:
1111 return cb.dbcb_resp_short(1, "op");
1112 }
1113 } else {
1114 return cb.dbcb_resp_short(1, "op");
1115 }
1116 if (args.kvalslen <= 0) {
1117 return cb.dbcb_resp_short(2, "klen");
1118 }
1119 switch (wrop) {
1120 case db_write_op_none:
1121 return cmd_find_internal(cb, p, find_flag, args);
1122 case db_write_op_insert:
1123 return cmd_insert_internal(cb, p, args.kvals, args.kvalslen);
1124 case db_write_op_sql:
1125 return cmd_sql_internal(cb, p, args.kvals, args.kvalslen);
1126 }
1127}
1128
1129void
1130dbcontext::set_statistics(size_t num_conns, size_t num_active)
1131{
1132 thd_proc_info(thd, &info_message_buf[0]);
1133 if (for_write_flag) {
1134 set_thread_message("handlersocket: mode=wr, %zu conns, %zu active",
1135 num_conns, num_active);
1136 } else {
1137 set_thread_message("handlersocket: mode=rd, %zu conns, %zu active",
1138 num_conns, num_active);
1139 }
1140}
1141
1142};
1143
01144
=== added file 'HandlerSocket-Plugin-for-MySQL/handlersocket/database.hpp'
--- HandlerSocket-Plugin-for-MySQL/handlersocket/database.hpp 1970-01-01 00:00:00 +0000
+++ HandlerSocket-Plugin-for-MySQL/handlersocket/database.hpp 2011-04-12 04:16:24 +0000
@@ -0,0 +1,130 @@
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 <string>
13#include <memory>
14#include <vector>
15#include <stdint.h>
16
17#include "string_buffer.hpp"
18#include "string_ref.hpp"
19#include "config.hpp"
20
21namespace dena {
22
23struct database_i;
24typedef std::auto_ptr<volatile database_i> database_ptr;
25
26struct dbcontext_i;
27typedef std::auto_ptr<dbcontext_i> dbcontext_ptr;
28
29struct 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
37struct prep_stmt {
38 typedef std::vector<uint32_t> 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
59struct 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_begin(size_t num_flds) = 0;
66 virtual void dbcb_resp_entry(const char *fld, size_t fldlen) = 0;
67 virtual void dbcb_resp_end() = 0;
68 virtual void dbcb_resp_cancel() = 0;
69};
70
71enum record_filter_type {
72 record_filter_type_skip = 0,
73 record_filter_type_break = 1,
74};
75
76struct record_filter {
77 record_filter_type filter_type;
78 string_ref op;
79 uint32_t ff_offset; /* offset in filter_fields */
80 string_ref val;
81 record_filter() : filter_type(record_filter_type_skip), ff_offset(0) { }
82};
83
84struct cmd_exec_args {
85 const prep_stmt *pst;
86 string_ref op;
87 const string_ref *kvals;
88 size_t kvalslen;
89 uint32_t limit;
90 uint32_t skip;
91 string_ref mod_op;
92 const string_ref *uvals; /* size must be pst->retfieelds.size() */
93 const record_filter *filters;
94 cmd_exec_args() : pst(0), kvals(0), kvalslen(0), limit(0), skip(0),
95 uvals(0), filters(0) { }
96};
97
98struct dbcontext_i {
99 virtual ~dbcontext_i() { }
100 virtual void init_thread(const void *stack_bottom,
101 volatile int& shutdown_flag) = 0;
102 virtual void term_thread() = 0;
103 virtual bool check_alive() = 0;
104 virtual void lock_tables_if() = 0;
105 virtual void unlock_tables_if() = 0;
106 virtual bool get_commit_error() = 0;
107 virtual void clear_error() = 0;
108 virtual void close_tables_if() = 0;
109 virtual void table_addref(size_t tbl_id) = 0; /* TODO: hide */
110 virtual void table_release(size_t tbl_id) = 0; /* TODO: hide */
111 virtual void cmd_open_index(dbcallback_i& cb, size_t pst_id, const char *dbn,
112 const char *tbl, const char *idx, const char *retflds,
113 const char *filflds) = 0;
114 virtual void cmd_exec_on_index(dbcallback_i& cb, const cmd_exec_args& args)
115 = 0;
116 virtual void set_statistics(size_t num_conns, size_t num_active) = 0;
117};
118
119};
120
121extern unsigned long long int open_tables_count;
122extern unsigned long long int close_tables_count;
123extern unsigned long long int lock_tables_count;
124extern unsigned long long int unlock_tables_count;
125#if 0
126extern unsigned long long int index_exec_count;
127#endif
128
129#endif
130
0131
=== added file 'HandlerSocket-Plugin-for-MySQL/handlersocket/handlersocket.cpp'
--- HandlerSocket-Plugin-for-MySQL/handlersocket/handlersocket.cpp 1970-01-01 00:00:00 +0000
+++ HandlerSocket-Plugin-for-MySQL/handlersocket/handlersocket.cpp 2011-04-12 04:16:24 +0000
@@ -0,0 +1,216 @@
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 <memory>
10#include <string>
11#include <stdio.h>
12
13#include "config.hpp"
14#include "hstcpsvr.hpp"
15#include "string_util.hpp"
16#include "mysql_incl.hpp"
17
18#define DBG_LOG \
19 if (dena::verbose_level >= 100) { \
20 fprintf(stderr, "%s %p\n", __PRETTY_FUNCTION__, this); \
21 }
22#define DBG_DO(x) if (dena::verbose_level >= 100) { x; }
23
24#define DBG_DIR(x)
25
26using namespace dena;
27
28static char *handlersocket_address = 0;
29static char *handlersocket_port = 0;
30static char *handlersocket_port_wr = 0;
31static unsigned int handlersocket_epoll = 1;
32static unsigned int handlersocket_threads = 32;
33static unsigned int handlersocket_threads_wr = 1;
34static unsigned int handlersocket_timeout = 30;
35static unsigned int handlersocket_backlog = 32768;
36static unsigned int handlersocket_sndbuf = 0;
37static unsigned int handlersocket_rcvbuf = 0;
38static unsigned int handlersocket_readsize = 0;
39static unsigned int handlersocket_accept_balance = 0;
40static unsigned int handlersocket_wrlock_timeout = 0;
41static char *handlersocket_plain_secret = 0;
42static char *handlersocket_plain_secret_wr = 0;
43
44struct daemon_handlersocket_data {
45 hstcpsvr_ptr hssvr_rd;
46 hstcpsvr_ptr hssvr_wr;
47};
48
49static int
50daemon_handlersocket_init(void *p)
51{
52 DENA_VERBOSE(10, fprintf(stderr, "handlersocket: initialized\n"));
53 config conf;
54 conf["use_epoll"] = handlersocket_epoll ? "1" : "0";
55 if (handlersocket_address) {
56 conf["host"] = handlersocket_address;
57 }
58 if (handlersocket_port) {
59 conf["port"] = handlersocket_port;
60 }
61 /*
62 * unix domain socket
63 * conf["host"] = "/";
64 * conf["port"] = "/tmp/handlersocket";
65 */
66 if (handlersocket_threads > 0) {
67 conf["num_threads"] = to_stdstring(handlersocket_threads);
68 } else {
69 conf["num_threads"] = "1";
70 }
71 conf["timeout"] = to_stdstring(handlersocket_timeout);
72 conf["listen_backlog"] = to_stdstring(handlersocket_backlog);
73 conf["sndbuf"] = to_stdstring(handlersocket_sndbuf);
74 conf["rcvbuf"] = to_stdstring(handlersocket_rcvbuf);
75 conf["readsize"] = to_stdstring(handlersocket_readsize);
76 conf["accept_balance"] = to_stdstring(handlersocket_accept_balance);
77 conf["wrlock_timeout"] = to_stdstring(handlersocket_wrlock_timeout);
78 std::auto_ptr<daemon_handlersocket_data> ap(new daemon_handlersocket_data);
The diff has been truncated for viewing.

Subscribers

People subscribed via source and target branches