Merge lp:~percona-dev/percona-server/release-5.5.10-20.1 into lp:~percona-dev/percona-server/5.5.10
- release-5.5.10-20.1
- Merge into 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 |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Alexey Kopytov (community) | Approve | ||
Review via email: mp+57268@code.launchpad.net |
Commit message
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
1 | === added directory 'HandlerSocket-Plugin-for-MySQL' |
2 | === added file 'HandlerSocket-Plugin-for-MySQL/AUTHORS' |
3 | --- HandlerSocket-Plugin-for-MySQL/AUTHORS 1970-01-01 00:00:00 +0000 |
4 | +++ HandlerSocket-Plugin-for-MySQL/AUTHORS 2011-04-12 04:16:24 +0000 |
5 | @@ -0,0 +1,19 @@ |
6 | +Akira Higuchi (https://github.com/ahiguti) |
7 | + - developed HanderSocket plugin, libhsclient, and perl-Net-HandlerSocket |
8 | + |
9 | +Yoshinori Matsunobu (https://github.com/yoshinorim) |
10 | + - introduced autotools, added support for MySQL 5.5.6, added statistics |
11 | + variables |
12 | + |
13 | +Jeff Hodges (https://github.com/jmhodges) |
14 | + - fixed some autotools scripts |
15 | + |
16 | +Toru Yamaguchi (https://github.com/zigorou) |
17 | + - ported to MacOS X |
18 | + |
19 | +Moriyoshi Koizumi (https://github.com/moriyoshi) |
20 | + - fixed some autotools scripts |
21 | + |
22 | +takeda-at (https://github.com/takada-at) |
23 | + - added simple authorization function |
24 | + |
25 | |
26 | === added file 'HandlerSocket-Plugin-for-MySQL/COPYING' |
27 | --- HandlerSocket-Plugin-for-MySQL/COPYING 1970-01-01 00:00:00 +0000 |
28 | +++ HandlerSocket-Plugin-for-MySQL/COPYING 2011-04-12 04:16:24 +0000 |
29 | @@ -0,0 +1,30 @@ |
30 | +----------------------------------------------------------------------------- |
31 | +HandlerSocket plugin for MySQL |
32 | + |
33 | + Copyright (c) 2010 DeNA Co.,Ltd. |
34 | + All rights reserved. |
35 | + |
36 | + Redistribution and use in source and binary forms, with or without |
37 | + modification, are permitted provided that the following conditions are met: |
38 | + |
39 | + * Redistributions of source code must retain the above copyright |
40 | + notice, this list of conditions and the following disclaimer. |
41 | + * Redistributions in binary form must reproduce the above copyright |
42 | + notice, this list of conditions and the following disclaimer in the |
43 | + documentation and/or other materials provided with the distribution. |
44 | + * Neither the name of DeNA Co.,Ltd. nor the names of its contributors |
45 | + may be used to endorse or promote products derived from this software |
46 | + without specific prior written permission. |
47 | + |
48 | + THIS SOFTWARE IS PROVIDED BY DeNA Co.,Ltd. "AS IS" AND ANY EXPRESS OR |
49 | + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF |
50 | + MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO |
51 | + EVENT SHALL DeNA Co.,Ltd. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
52 | + SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
53 | + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; |
54 | + OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, |
55 | + WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR |
56 | + OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF |
57 | + ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
58 | + |
59 | + |
60 | |
61 | === added file 'HandlerSocket-Plugin-for-MySQL/ChangeLog' |
62 | --- HandlerSocket-Plugin-for-MySQL/ChangeLog 1970-01-01 00:00:00 +0000 |
63 | +++ HandlerSocket-Plugin-for-MySQL/ChangeLog 2011-04-12 04:16:24 +0000 |
64 | @@ -0,0 +1,12 @@ |
65 | +1.0.6 - 2010-10-29 |
66 | + * Changed build instruction (autoreconf/configure/make), removed auto-generated files (Contributed by jmhodges) |
67 | + * |
68 | + |
69 | +1.0.5 - 2010-10-18 |
70 | + * Changed build procedures (using typical configure/make) |
71 | + * Supported 5.5.6 |
72 | + * Added status variables |
73 | + |
74 | +1.0.4 - 2010-08-15 |
75 | + * Initial public release |
76 | + |
77 | |
78 | === added file 'HandlerSocket-Plugin-for-MySQL/Makefile.am' |
79 | --- HandlerSocket-Plugin-for-MySQL/Makefile.am 1970-01-01 00:00:00 +0000 |
80 | +++ HandlerSocket-Plugin-for-MySQL/Makefile.am 2011-04-12 04:16:24 +0000 |
81 | @@ -0,0 +1,87 @@ |
82 | + |
83 | +ACLOCAL_AMFLAGS = -I m4 |
84 | + |
85 | +SUBDIRS = @HANDLERSOCKET_SUBDIRS@ |
86 | + |
87 | +perl: |
88 | + cd perl-Net-HandlerSocket && perl Makefile.PL && make |
89 | + |
90 | +install_perl: |
91 | + cd perl-Net-HandlerSocket && make install |
92 | + |
93 | +rpms: rpm_cli rpm_perl rpm_c |
94 | + |
95 | +rpm_dir: |
96 | + - mkdir dist |
97 | + - mkdir dist/BUILD dist/RPMS dist/SOURCES dist/SPECS dist/SRPMS |
98 | + |
99 | +rpm_cli: clean_cli rpm_dir |
100 | + sed -e "s/HANDLERSOCKET_VERSION/$(VERSION)/" \ |
101 | + libhsclient/libhsclient.spec.template \ |
102 | + > libhsclient/libhsclient.spec |
103 | + tar cvfz dist/libhsclient.tar.gz libhsclient |
104 | + rpmbuild --define "_topdir `pwd`/dist" -ta \ |
105 | + dist/libhsclient.tar.gz |
106 | + |
107 | +rpm_perl: clean_perl rpm_dir |
108 | + sed -e "s/HANDLERSOCKET_VERSION/$(VERSION)/" \ |
109 | + perl-Net-HandlerSocket/perl-Net-HandlerSocket.spec.template \ |
110 | + > perl-Net-HandlerSocket/perl-Net-HandlerSocket.spec |
111 | + cd perl-Net-HandlerSocket && perl Makefile.PL && make clean && \ |
112 | + rm -f Makefile.old |
113 | + tar cvfz dist/perl-Net-HandlerSocket.tar.gz perl-Net-HandlerSocket |
114 | + rpmbuild --define "_topdir `pwd`/dist" -ta \ |
115 | + dist/perl-Net-HandlerSocket.tar.gz |
116 | + |
117 | +rpm_c: clean_c rpm_dir |
118 | + sed -e "s/HANDLERSOCKET_VERSION/$(VERSION)/" \ |
119 | + handlersocket/handlersocket.spec.template \ |
120 | + > handlersocket/handlersocket.spec |
121 | + sed -e "s|HANDLERSOCKET_MYSQL_INC|$(MYSQL_CFLAGS) $(MYSQL_INC)|" \ |
122 | + -e "s|HANDLERSOCKET_MYSQL_LIB|$(MYSQL_LIB)|" \ |
123 | + handlersocket/Makefile.plain.template \ |
124 | + > handlersocket/Makefile.plain |
125 | + tar cvfz dist/handlersocket.tar.gz handlersocket |
126 | + rpmbuild --define "_topdir `pwd`/dist" -ta \ |
127 | + dist/handlersocket.tar.gz |
128 | + |
129 | +install_rpm_pl: |
130 | + - sudo rpm -e perl-Net-HandlerSocket |
131 | + - sudo rpm -e perl-Net-HandlerSocket-debuginfo |
132 | + make clean |
133 | + make rpm_perl |
134 | + - sudo rpm -U dist/RPMS/*/perl*.rpm |
135 | + |
136 | +installrpms: |
137 | + - sudo rpm -e handlersocket |
138 | + - sudo rpm -e handlersocket-debuginfo |
139 | + - sudo rpm -e perl-Net-HandlerSocket |
140 | + - sudo rpm -e perl-Net-HandlerSocket-debuginfo |
141 | + - sudo rpm -e libhsclient |
142 | + - sudo rpm -e libhsclient-debuginfo |
143 | + make clean |
144 | + make rpm_cli |
145 | + - sudo rpm -U dist/RPMS/*/libhsclient*.rpm |
146 | + make clean |
147 | + make rpm_perl |
148 | + - sudo rpm -U dist/RPMS/*/perl*.rpm |
149 | + make clean |
150 | + make rpm_c |
151 | + - sudo rpm -U dist/RPMS/*/handlersocket*.rpm |
152 | + |
153 | +clean_cli: |
154 | + cd libhsclient && make clean |
155 | + cd client && make clean |
156 | + |
157 | +clean_perl: |
158 | + cd perl-Net-HandlerSocket && perl Makefile.PL && make clean && \ |
159 | + rm -f Makefile.old |
160 | + |
161 | +clean_c: |
162 | + cd handlersocket && make clean |
163 | + |
164 | +clean_all: clean_cli clean_perl clean_c |
165 | + cd regtest && make clean |
166 | + rm -rf dist/*/* |
167 | + rm -f dist/*.tar.gz |
168 | + |
169 | |
170 | === added file 'HandlerSocket-Plugin-for-MySQL/README' |
171 | --- HandlerSocket-Plugin-for-MySQL/README 1970-01-01 00:00:00 +0000 |
172 | +++ HandlerSocket-Plugin-for-MySQL/README 2011-04-12 04:16:24 +0000 |
173 | @@ -0,0 +1,76 @@ |
174 | + |
175 | +----------------------------------------------------------------------------- |
176 | +HandlerSocket plugin for MySQL |
177 | + |
178 | +Copyright (c) 2010 DeNA Co.,Ltd. |
179 | +All rights reserved. |
180 | + |
181 | +Redistribution and use in source and binary forms, with or without |
182 | +modification, are permitted provided that the following conditions are met: |
183 | + |
184 | + * Redistributions of source code must retain the above copyright |
185 | + notice, this list of conditions and the following disclaimer. |
186 | + * Redistributions in binary form must reproduce the above copyright |
187 | + notice, this list of conditions and the following disclaimer in the |
188 | + documentation and/or other materials provided with the distribution. |
189 | + * Neither the name of DeNA Co.,Ltd. nor the names of its contributors |
190 | + may be used to endorse or promote products derived from this software |
191 | + without specific prior written permission. |
192 | + |
193 | +THIS SOFTWARE IS PROVIDED BY DeNA Co.,Ltd. "AS IS" AND ANY EXPRESS OR |
194 | +IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF |
195 | +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO |
196 | +EVENT SHALL DeNA Co.,Ltd. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
197 | +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
198 | +PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; |
199 | +OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, |
200 | +WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR |
201 | +OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF |
202 | +ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
203 | + |
204 | + |
205 | +----------------------------------------------------------------------------- |
206 | +About HandlerSocket |
207 | + |
208 | +HandlerSocket is a NoSQL plugin for MySQL. It works as a daemon inside the |
209 | +mysqld process, accept tcp connections, and execute requests from clients. |
210 | +HandlerSocket does not support SQL queries. Instead, it supports simple CRUD |
211 | +operations on tables. |
212 | + |
213 | +Because of the following reasons, HandlerSocket is much faster than the |
214 | +mysqld/libmysql pair in some circumstances: |
215 | + |
216 | + - HandlerSocket manipulates data without parsing SQL, which causes less |
217 | + CPU usage. |
218 | + - HandlerSocket reads many requests from clients and executes their |
219 | + requests in bulk, which causes less CPU and disk usage. |
220 | + - HandlerSocket client/server protocol is more compact than the |
221 | + mysql/libmysql pair, which causes less network usage. |
222 | + |
223 | +The current version of HandlerSocket only works with GNU/Linux. The source |
224 | +archive of HandlerSocket includes a C++ and a Perl client libraries. |
225 | +Here is a list of client libraries for other languages: |
226 | + |
227 | + - PHP |
228 | + http://openpear.org/package/Net_HandlerSocket |
229 | + http://github.com/tz-lom/HSPHP |
230 | + http://code.google.com/p/php-handlersocket/ |
231 | + - Java |
232 | + http://code.google.com/p/hs4j/ |
233 | + http://code.google.com/p/handlersocketforjava/ |
234 | + - Python |
235 | + http://pypi.python.org/pypi/python-handler-socket |
236 | + https://code.launchpad.net/~songofacandy/+junk/pyhandlersocket |
237 | + - Ruby |
238 | + https://github.com/winebarrel/ruby-handlersocket |
239 | + https://github.com/miyucy/handlersocket |
240 | + - JavaScript |
241 | + https://github.com/koichik/node-handlersocket |
242 | + - Scala |
243 | + https://github.com/fujohnwang/hs2client |
244 | + |
245 | +The home of HandlerSocket is here: |
246 | + https://github.com/ahiguti/HandlerSocket-Plugin-for-MySQL |
247 | + |
248 | +More documents are available in docs-en/ and docs-ja/ directories. |
249 | + |
250 | |
251 | === added file 'HandlerSocket-Plugin-for-MySQL/autogen.sh' |
252 | --- HandlerSocket-Plugin-for-MySQL/autogen.sh 1970-01-01 00:00:00 +0000 |
253 | +++ HandlerSocket-Plugin-for-MySQL/autogen.sh 2011-04-12 04:16:24 +0000 |
254 | @@ -0,0 +1,117 @@ |
255 | +#!/bin/sh |
256 | + |
257 | +warn() { |
258 | +echo -e "\tWARNING: $@" 1>&2 |
259 | +} |
260 | + |
261 | +# init |
262 | + |
263 | +LIBTOOLIZE=libtoolize |
264 | +ACLOCAL=aclocal |
265 | +AUTOCONF=autoconf |
266 | +AUTOHEADER=autoheader |
267 | +AUTOMAKE=automake |
268 | + |
269 | +case `uname -s` in |
270 | +Darwin) |
271 | +LIBTOOLIZE=glibtoolize |
272 | +;; |
273 | +FreeBSD) |
274 | +ACLOCAL_ARGS="$ACLOCAL_ARGS -I /usr/local/share/aclocal/" |
275 | +;; |
276 | +esac |
277 | + |
278 | + |
279 | +# libtoolize |
280 | +echo "Searching libtoolize..." |
281 | +if [ `which $LIBTOOLIZE` ] ; then |
282 | +echo -e "\tFOUND: libtoolize -> $LIBTOOLIZE" |
283 | +else |
284 | +warn "Cannot Found libtoolize... input libtool command" |
285 | + read LIBTOOLIZE |
286 | + LIBTOOLIZE=`which $LIBTOOLIZE` |
287 | + if [ `which $LIBTOOLIZE` ] ; then |
288 | +echo -e "\tSET: libtoolize -> $LIBTOOLIZE" |
289 | + else |
290 | +warn "$LIBTOOLIZE: Command not found." |
291 | + exit 1; |
292 | + fi |
293 | +fi |
294 | + |
295 | +# aclocal |
296 | +echo "Searching aclocal..." |
297 | +if [ `which $ACLOCAL` ] ; then |
298 | +echo -e "\tFOUND: aclocal -> $ACLOCAL" |
299 | +else |
300 | +warn "Cannot Found aclocal... input aclocal command" |
301 | + read ACLOCAL |
302 | + ACLOCAL=`which $ACLOCAL` |
303 | + if [ `which $ACLOCAL` ] ; then |
304 | +echo -e "\tSET: aclocal -> $ACLOCAL" |
305 | + else |
306 | +warn "$ACLOCAL: Command not found." |
307 | + exit 1; |
308 | + fi |
309 | +fi |
310 | + |
311 | +# automake |
312 | +echo "Searching automake..." |
313 | +if [ `which $AUTOMAKE` ] ; then |
314 | +echo -e "\tFOUND: automake -> $AUTOMAKE" |
315 | +else |
316 | +warn "Cannot Found automake... input automake command" |
317 | + read AUTOMAKE |
318 | + ACLOCAL=`which $AUTOMAKE` |
319 | + if [ `which $AUTOMAKE` ] ; then |
320 | +echo -e "\tSET: automake -> $AUTOMAKE" |
321 | + else |
322 | +warn "$AUTOMAKE: Command not found." |
323 | + exit 1; |
324 | + fi |
325 | +fi |
326 | + |
327 | +# autoheader |
328 | +echo "Searching autoheader..." |
329 | +if [ `which $AUTOHEADER` ] ; then |
330 | +echo -e "\tFOUND: autoheader -> $AUTOHEADER" |
331 | +else |
332 | +warn "Cannot Found autoheader... input autoheader command" |
333 | + read AUTOHEADER |
334 | + ACLOCAL=`which $AUTOHEADER` |
335 | + if [ `which $AUTOHEADER` ] ; then |
336 | +echo -e "\tSET: autoheader -> $AUTOHEADER" |
337 | + else |
338 | +warn "$AUTOHEADER: Command not found." |
339 | + exit 1; |
340 | + fi |
341 | +fi |
342 | + |
343 | +# autoconf |
344 | +echo "Searching autoconf..." |
345 | +if [ `which $AUTOCONF` ] ; then |
346 | +echo -e "\tFOUND: autoconf -> $AUTOCONF" |
347 | +else |
348 | +warn "Cannot Found autoconf... input autoconf command" |
349 | + read AUTOCONF |
350 | + ACLOCAL=`which $AUTOCONF` |
351 | + if [ `which $AUTOCONF` ] ; then |
352 | +echo -e "\tSET: autoconf -> $AUTOCONF" |
353 | + else |
354 | +warn "$AUTOCONF: Command not found." |
355 | + exit 1; |
356 | + fi |
357 | +fi |
358 | + |
359 | +echo "Running libtoolize ..." |
360 | +$LIBTOOLIZE --force --copy |
361 | +echo "Running aclocal ..." |
362 | +$ACLOCAL ${ACLOCAL_ARGS} -I . |
363 | +echo "Running autoheader..." |
364 | +$AUTOHEADER |
365 | +echo "Running automake ..." |
366 | +$AUTOMAKE --add-missing --copy |
367 | +echo "Running autoconf ..." |
368 | +$AUTOCONF |
369 | + |
370 | +#mkdir m4 2> /dev/null |
371 | + |
372 | |
373 | === added directory 'HandlerSocket-Plugin-for-MySQL/client' |
374 | === added file 'HandlerSocket-Plugin-for-MySQL/client/Makefile.am' |
375 | --- HandlerSocket-Plugin-for-MySQL/client/Makefile.am 1970-01-01 00:00:00 +0000 |
376 | +++ HandlerSocket-Plugin-for-MySQL/client/Makefile.am 2011-04-12 04:16:24 +0000 |
377 | @@ -0,0 +1,13 @@ |
378 | +AM_INCLUDES= -I../libhsclient |
379 | +bin_PROGRAMS=hsclient |
380 | +hsclient_SOURCES= hsclient.cpp |
381 | +hsclient_LDFLAGS= -static -L../libhsclient -lhsclient |
382 | +hsclient_CXXFLAGS= $(AM_INCLUDES) |
383 | + |
384 | +hstest: hstest.o |
385 | + $(CXX) $(CXXFLAGS) $(LFLAGS) hstest.o \ |
386 | + -L../libhsclient/.libs -lhsclient $(MYSQL_LIB) -o hstest |
387 | + |
388 | +hstest.o: hstest.cpp |
389 | + $(CXX) $(CXXFLAGS) $(MYSQL_INC) $(AM_INCLUDES) -c hstest.cpp |
390 | + |
391 | |
392 | === added file 'HandlerSocket-Plugin-for-MySQL/client/hsclient.cpp' |
393 | --- HandlerSocket-Plugin-for-MySQL/client/hsclient.cpp 1970-01-01 00:00:00 +0000 |
394 | +++ HandlerSocket-Plugin-for-MySQL/client/hsclient.cpp 2011-04-12 04:16:24 +0000 |
395 | @@ -0,0 +1,88 @@ |
396 | + |
397 | +// vim:sw=2:ai |
398 | + |
399 | +#include "hstcpcli.hpp" |
400 | +#include "string_util.hpp" |
401 | + |
402 | +namespace dena { |
403 | + |
404 | +int |
405 | +hstcpcli_main(int argc, char **argv) |
406 | +{ |
407 | + config conf; |
408 | + parse_args(argc, argv, conf); |
409 | + socket_args sockargs; |
410 | + sockargs.set(conf); |
411 | + hstcpcli_ptr cli = hstcpcli_i::create(sockargs); |
412 | + const std::string dbname = conf.get_str("dbname", "hstest"); |
413 | + const std::string table = conf.get_str("table", "hstest_table1"); |
414 | + const std::string index = conf.get_str("index", "PRIMARY"); |
415 | + const std::string fields = conf.get_str("fields", "k,v"); |
416 | + const int limit = conf.get_int("limit", 0); |
417 | + const int skip = conf.get_int("skip", 0); |
418 | + std::vector<std::string> keys; |
419 | + std::vector<string_ref> keyrefs; |
420 | + size_t num_keys = 0; |
421 | + while (true) { |
422 | + const std::string conf_key = std::string("k") + to_stdstring(num_keys); |
423 | + const std::string k = conf.get_str(conf_key, ""); |
424 | + const std::string kx = conf.get_str(conf_key, "x"); |
425 | + if (k.empty() && kx == "x") { |
426 | + break; |
427 | + } |
428 | + ++num_keys; |
429 | + keys.push_back(k); |
430 | + } |
431 | + for (size_t i = 0; i < keys.size(); ++i) { |
432 | + const string_ref ref(keys[i].data(), keys[i].size()); |
433 | + keyrefs.push_back(ref); |
434 | + } |
435 | + const std::string op = conf.get_str("op", "="); |
436 | + const string_ref op_ref(op.data(), op.size()); |
437 | + cli->request_buf_open_index(0, dbname.c_str(), table.c_str(), |
438 | + index.c_str(), fields.c_str()); |
439 | + cli->request_buf_exec_generic(0, op_ref, num_keys == 0 ? 0 : &keyrefs[0], |
440 | + num_keys, limit, skip, string_ref(), 0, 0); |
441 | + int code = 0; |
442 | + size_t numflds = 0; |
443 | + do { |
444 | + if (cli->request_send() != 0) { |
445 | + fprintf(stderr, "request_send: %s\n", cli->get_error().c_str()); |
446 | + break; |
447 | + } |
448 | + if ((code = cli->response_recv(numflds)) != 0) { |
449 | + fprintf(stderr, "response_recv: %s\n", cli->get_error().c_str()); |
450 | + break; |
451 | + } |
452 | + } while (false); |
453 | + cli->response_buf_remove(); |
454 | + do { |
455 | + if ((code = cli->response_recv(numflds)) != 0) { |
456 | + fprintf(stderr, "response_recv: %s\n", cli->get_error().c_str()); |
457 | + break; |
458 | + } |
459 | + while (true) { |
460 | + const string_ref *const row = cli->get_next_row(); |
461 | + if (row == 0) { |
462 | + break; |
463 | + } |
464 | + printf("REC:"); |
465 | + for (size_t i = 0; i < numflds; ++i) { |
466 | + const std::string val(row[i].begin(), row[i].size()); |
467 | + printf(" %s", val.c_str()); |
468 | + } |
469 | + printf("\n"); |
470 | + } |
471 | + } while (false); |
472 | + cli->response_buf_remove(); |
473 | + return 0; |
474 | +} |
475 | + |
476 | +}; |
477 | + |
478 | +int |
479 | +main(int argc, char **argv) |
480 | +{ |
481 | + return dena::hstcpcli_main(argc, argv); |
482 | +} |
483 | + |
484 | |
485 | === added file 'HandlerSocket-Plugin-for-MySQL/client/hspool_test.pl' |
486 | --- HandlerSocket-Plugin-for-MySQL/client/hspool_test.pl 1970-01-01 00:00:00 +0000 |
487 | +++ HandlerSocket-Plugin-for-MySQL/client/hspool_test.pl 2011-04-12 04:16:24 +0000 |
488 | @@ -0,0 +1,224 @@ |
489 | +#!/usr/bin/perl |
490 | + |
491 | +use strict; |
492 | +use warnings; |
493 | +use DB::HandlerSocket::Pool; |
494 | +use DBI; |
495 | + |
496 | +my %conf = (); |
497 | +for my $i (@ARGV) { |
498 | + my ($k, $v) = split(/=/, $i); |
499 | + $conf{$k} = $v; |
500 | +} |
501 | + |
502 | +my $verbose = get_conf("verbose", 0); |
503 | +my $actions_str = get_conf("actions", |
504 | + "create,insert,verify,verify2,verify3,verify4,clean"); |
505 | +my $tablesize = get_conf("tablesize", 1000); |
506 | +my $db = get_conf("db", "hstestdb"); |
507 | +my $table = get_conf("table", "testtbl"); |
508 | +my $table_schema = get_conf("table_schema", undef); |
509 | +my $engine = get_conf("engine", "innodb"); |
510 | +my $host = get_conf("host", "localhost"); |
511 | +my $mysqlport = get_conf("mysqlport", 3306); |
512 | +my $hsport_rd = get_conf("hsport_rd", 9998); |
513 | +my $hsport_wr = get_conf("hsport_wr", 9999); |
514 | +my $loop = get_conf("loop", 10000); |
515 | +my $op = get_conf("op", "="); |
516 | +my $ssps = get_conf("ssps", 0); |
517 | +my $num_moreflds = get_conf("moreflds", 0); |
518 | +my $moreflds_prefix = get_conf("moreflds_prefix", "f"); |
519 | +my $mysql_user = 'root'; |
520 | +my $mysql_password = ''; |
521 | + |
522 | +my $dsn = "DBI:mysql:database=;host=$host;port=$mysqlport" |
523 | + . ";mysql_server_prepare=$ssps"; |
524 | +my $dbh = DBI->connect($dsn, $mysql_user, $mysql_password, |
525 | + { RaiseError => 1 }); |
526 | +my $hsargs = { 'host' => $host, 'port' => $hsport_rd }; |
527 | +my $hspool = new DB::HandlerSocket::Pool({ |
528 | + hostmap => { |
529 | + "$db.$table" => { |
530 | + host => $host, |
531 | + port => $hsport_rd, |
532 | + }, |
533 | + }, |
534 | + resolve => undef, |
535 | + error => undef, |
536 | +}); |
537 | +$table_schema = "(k int primary key, fc30 varchar(30), ft text)" |
538 | + if (!defined($table_schema)); |
539 | + |
540 | +my @actions = split(/,/, $actions_str); |
541 | +for my $action (@actions) { |
542 | + print "ACTION: $action\n"; |
543 | + eval "hstest_$action()"; |
544 | + if ($@) { |
545 | + die $@; |
546 | + } |
547 | + print "ACTION: $action DONE\n"; |
548 | +} |
549 | + |
550 | +sub get_conf { |
551 | + my ($key, $def) = @_; |
552 | + my $val = $conf{$key}; |
553 | + if ($val) { |
554 | + print "$key=$val\n"; |
555 | + } else { |
556 | + $val = $def; |
557 | + my $defstr = $def || "(undef)"; |
558 | + print "$key=$defstr(default)\n"; |
559 | + } |
560 | + return $val; |
561 | +} |
562 | + |
563 | +sub hstest_create { |
564 | + $dbh->do("drop database if exists $db"); |
565 | + $dbh->do("create database $db"); |
566 | + $dbh->do("use $db"); |
567 | + $dbh->do("create table $table $table_schema engine=$engine"); |
568 | +} |
569 | + |
570 | +sub hstest_dump { |
571 | + $dbh->do("use $db"); |
572 | + my $sth = $dbh->prepare("select * from $table"); |
573 | + $sth->execute(); |
574 | + my $arr = $sth->fetchall_arrayref(); |
575 | + for my $rec (@$arr) { |
576 | + print "REC:"; |
577 | + for my $row (@$rec) { |
578 | + print " $row"; |
579 | + } |
580 | + print "\n"; |
581 | + } |
582 | +} |
583 | + |
584 | +sub hstest_insert { |
585 | + $dbh->do("use $db"); |
586 | + my $sth = $dbh->prepare("insert into $table values (?, ?, ?)"); |
587 | + for (my $k = 0; $k < $tablesize; ++$k) { |
588 | + my $fc30 = "fc30_$k"; |
589 | + my $ft = "ft_$k"; |
590 | + $sth->execute($k, $fc30, $ft); |
591 | + } |
592 | +} |
593 | + |
594 | +sub hstest_verify { |
595 | + $dbh->do("use $db"); |
596 | + my $sth = $dbh->prepare("select * from $table order by k"); |
597 | + $sth->execute(); |
598 | + my $arr = $sth->fetchall_arrayref(); |
599 | + my $hsres = $hspool->index_find($db, $table, "PRIMARY", "k,fc30,ft", |
600 | + ">=", [ 0 ], $tablesize, 0); |
601 | + for (my $i = 0; $i < $tablesize; ++$i) { |
602 | + my $rec = $arr->[$i]; |
603 | + my $differ = 0; |
604 | + print "REC:" if $verbose; |
605 | + for (my $j = 0; $j < 3; ++$j) { |
606 | + my $fld = $rec->[$j]; |
607 | + my $hsidx = $i * 3 + $j; |
608 | + my $hsfld = $hsres->[$hsidx]; |
609 | + if ($hsfld ne $fld) { |
610 | + $differ = 1; |
611 | + } |
612 | + if ($differ) { |
613 | + print " $fld:$hsfld" if $verbose; |
614 | + } else { |
615 | + print " $hsfld" if $verbose; |
616 | + } |
617 | + } |
618 | + print "\n" if $verbose; |
619 | + if ($differ) { |
620 | + die "verification failed"; |
621 | + } |
622 | + } |
623 | +} |
624 | + |
625 | +sub hstest_verify2 { |
626 | + $dbh->do("use $db"); |
627 | + my $sth = $dbh->prepare("select * from $table order by k"); |
628 | + $sth->execute(); |
629 | + my $arr = $sth->fetchall_arrayref(); |
630 | + my $hsresa = $hspool->index_find_multi($db, $table, "PRIMARY", |
631 | + "k,fc30,ft", [ [ -1, ">=", [ 0 ], $tablesize, 0 ] ]); |
632 | + my $hsres = $hsresa->[0]; |
633 | + for (my $i = 0; $i < $tablesize; ++$i) { |
634 | + my $rec = $arr->[$i]; |
635 | + my $differ = 0; |
636 | + print "REC:" if $verbose; |
637 | + for (my $j = 0; $j < 3; ++$j) { |
638 | + my $fld = $rec->[$j]; |
639 | + my $hsidx = $i * 3 + $j; |
640 | + my $hsfld = $hsres->[$hsidx]; |
641 | + if ($hsfld ne $fld) { |
642 | + $differ = 1; |
643 | + } |
644 | + if ($differ) { |
645 | + print " $fld:$hsfld" if $verbose; |
646 | + } else { |
647 | + print " $hsfld" if $verbose; |
648 | + } |
649 | + } |
650 | + print "\n" if $verbose; |
651 | + if ($differ) { |
652 | + die "verification failed"; |
653 | + } |
654 | + } |
655 | +} |
656 | + |
657 | +sub hashref_to_str { |
658 | + my $href = $_[0]; |
659 | + my $r = ''; |
660 | + for my $k (sort keys %$href) { |
661 | + my $v = $href->{$k}; |
662 | + $r .= "($k=>$v)"; |
663 | + } |
664 | + return $r; |
665 | +} |
666 | + |
667 | +sub hstest_verify3 { |
668 | + $dbh->do("use $db"); |
669 | + my $sth = $dbh->prepare("select * from $table order by k"); |
670 | + $sth->execute(); |
671 | + my $hsres_t = $hspool->index_find($db, $table, "PRIMARY", "k,fc30,ft", |
672 | + ">=", [ 0 ], $tablesize, 0); |
673 | + my $hsres = DB::HandlerSocket::Pool::result_single_to_hasharr( |
674 | + [ 'k', 'fc30', 'ft' ], $hsres_t); |
675 | + for (my $i = 0; $i < $tablesize; ++$i) { |
676 | + my $mystr = hashref_to_str($sth->fetchrow_hashref()); |
677 | + my $hsstr = hashref_to_str($hsres->[$i]); |
678 | + if ($mystr ne $hsstr) { |
679 | + print "DIFF my=[$mystr] hs=[$hsstr]\n" if $verbose; |
680 | + die "verification failed"; |
681 | + } else { |
682 | + print "OK $hsstr\n" if $verbose; |
683 | + } |
684 | + } |
685 | +} |
686 | + |
687 | +sub hstest_verify4 { |
688 | + $dbh->do("use $db"); |
689 | + my $sth = $dbh->prepare("select * from $table order by k"); |
690 | + $sth->execute(); |
691 | + my $hsres_t = $hspool->index_find($db, $table, "PRIMARY", "k,fc30,ft", |
692 | + ">=", [ 0 ], $tablesize, 0); |
693 | + my $hsres = DB::HandlerSocket::Pool::result_single_to_hashhash( |
694 | + [ 'k', 'fc30', 'ft' ], 'k', $hsres_t); |
695 | + my $rechash = $sth->fetchall_hashref('k'); |
696 | + while (my ($k, $href) = each (%$rechash)) { |
697 | + my $mystr = hashref_to_str($href); |
698 | + my $hsstr = hashref_to_str($hsres->{$k}); |
699 | + if ($mystr ne $hsstr) { |
700 | + print "DIFF my=[$mystr] hs=[$hsstr]\n" if $verbose; |
701 | + die "verification failed"; |
702 | + } else { |
703 | + print "OK $hsstr\n" if $verbose; |
704 | + } |
705 | + } |
706 | +} |
707 | + |
708 | +sub hstest_clean { |
709 | + $hspool->clear_pool(); |
710 | + $dbh->do("drop database if exists $db"); |
711 | +} |
712 | + |
713 | |
714 | === added file 'HandlerSocket-Plugin-for-MySQL/client/hstest.cpp' |
715 | --- HandlerSocket-Plugin-for-MySQL/client/hstest.cpp 1970-01-01 00:00:00 +0000 |
716 | +++ HandlerSocket-Plugin-for-MySQL/client/hstest.cpp 2011-04-12 04:16:24 +0000 |
717 | @@ -0,0 +1,1494 @@ |
718 | + |
719 | +// vim:sw=2:ai |
720 | + |
721 | +#include <signal.h> |
722 | +#include <sys/time.h> |
723 | +#include <stdio.h> |
724 | +#include <string.h> |
725 | +#include <vector> |
726 | +#include <stdlib.h> |
727 | +#include <memory> |
728 | +#include <errno.h> |
729 | +#include <mysql.h> |
730 | +#include <time.h> |
731 | +#include <sys/types.h> |
732 | +#include <sys/stat.h> |
733 | +#include <fcntl.h> |
734 | + |
735 | +#include "util.hpp" |
736 | +#include "auto_ptrcontainer.hpp" |
737 | +#include "socket.hpp" |
738 | +#include "thread.hpp" |
739 | +#include "hstcpcli.hpp" |
740 | + |
741 | +#if __GNUC__ >= 4 |
742 | +long atomic_exchange_and_add(volatile long *valp, long c) |
743 | +{ |
744 | + return __sync_fetch_and_add(valp, c); |
745 | +} |
746 | +#else |
747 | +#include <bits/atomicity.h> |
748 | +using namespace __gnu_cxx; |
749 | +long atomic_exchange_and_add(volatile long *valp, long c) |
750 | +{ |
751 | + return __exchange_and_add((volatile _Atomic_word *)valp, c); |
752 | +} |
753 | +#endif |
754 | + |
755 | +namespace dena { |
756 | + |
757 | +struct auto_mysql : private noncopyable { |
758 | + auto_mysql() : db(0) { |
759 | + reset(); |
760 | + } |
761 | + ~auto_mysql() { |
762 | + if (db) { |
763 | + mysql_close(db); |
764 | + } |
765 | + } |
766 | + void reset() { |
767 | + if (db) { |
768 | + mysql_close(db); |
769 | + } |
770 | + if ((db = mysql_init(0)) == 0) { |
771 | + fatal_abort("failed to initialize mysql client"); |
772 | + } |
773 | + } |
774 | + operator MYSQL *() const { return db; } |
775 | + private: |
776 | + MYSQL *db; |
777 | +}; |
778 | + |
779 | +struct auto_mysql_res : private noncopyable { |
780 | + auto_mysql_res(MYSQL *db) { |
781 | + res = mysql_store_result(db); |
782 | + } |
783 | + ~auto_mysql_res() { |
784 | + if (res) { |
785 | + mysql_free_result(res); |
786 | + } |
787 | + } |
788 | + operator MYSQL_RES *() const { return res; } |
789 | + private: |
790 | + MYSQL_RES *res; |
791 | +}; |
792 | + |
793 | +struct auto_mysql_stmt : private noncopyable { |
794 | + auto_mysql_stmt(MYSQL *db) { |
795 | + stmt = mysql_stmt_init(db); |
796 | + } |
797 | + ~auto_mysql_stmt() { |
798 | + if (stmt) { |
799 | + mysql_stmt_close(stmt); |
800 | + } |
801 | + } |
802 | + operator MYSQL_STMT *() const { return stmt; } |
803 | + private: |
804 | + MYSQL_STMT *stmt; |
805 | +}; |
806 | + |
807 | +namespace { |
808 | + |
809 | +double |
810 | +gettimeofday_double() |
811 | +{ |
812 | + struct timeval tv = { }; |
813 | + if (gettimeofday(&tv, 0) != 0) { |
814 | + fatal_abort("gettimeofday"); |
815 | + } |
816 | + return static_cast<double>(tv.tv_usec) / 1000000 + tv.tv_sec; |
817 | +} |
818 | + |
819 | +// unused |
820 | +void |
821 | +wait_close(int fd) |
822 | +{ |
823 | + char buf[1024]; |
824 | + while (true) { |
825 | + int r = read(fd, buf, sizeof(buf)); |
826 | + if (r <= 0) { |
827 | + break; |
828 | + } |
829 | + } |
830 | +} |
831 | + |
832 | +// unused |
833 | +void |
834 | +gentle_close(int fd) |
835 | +{ |
836 | + int r = shutdown(fd, SHUT_WR); |
837 | + if (r != 0) { |
838 | + return; |
839 | + } |
840 | + wait_close(fd); |
841 | +} |
842 | + |
843 | +}; |
844 | + |
845 | +struct hstest_shared { |
846 | + config conf; |
847 | + socket_args arg; |
848 | + int verbose; |
849 | + size_t loop; |
850 | + size_t pipe; |
851 | + char op; |
852 | + long num_threads; |
853 | + mutable volatile long count; |
854 | + mutable volatile long conn_count; |
855 | + long wait_conn; |
856 | + volatile char *keygen; |
857 | + long keygen_size; |
858 | + mutable volatile int enable_timing; |
859 | + int usleep; |
860 | + int dump; |
861 | + hstest_shared() : verbose(0), loop(0), pipe(0), op('G'), num_threads(0), |
862 | + count(0), conn_count(0), wait_conn(0), keygen(0), keygen_size(0), |
863 | + enable_timing(0), usleep(0), dump(0) { } |
864 | + void increment_count(unsigned int c = 1) const volatile { |
865 | + atomic_exchange_and_add(&count, c); |
866 | + } |
867 | + void increment_conn(unsigned int c) const volatile { |
868 | + atomic_exchange_and_add(&conn_count, c); |
869 | + while (wait_conn != 0 && conn_count < wait_conn) { |
870 | + sleep(1); |
871 | + } |
872 | + // fprintf(stderr, "wait_conn=%ld done\n", wait_conn); |
873 | + } |
874 | +}; |
875 | + |
876 | +struct hstest_thread { |
877 | + struct arg_type { |
878 | + size_t id; |
879 | + const hstest_shared& sh; |
880 | + bool watch_flag; |
881 | + arg_type(size_t i, const hstest_shared& s, bool w) |
882 | + : id(i), sh(s), watch_flag(w) { } |
883 | + }; |
884 | + hstest_thread(const arg_type& a) : arg(a), io_success_count(0), |
885 | + op_success_count(0), response_min(99999), response_max(0), |
886 | + response_sum(0), response_avg(0) { } |
887 | + void operator ()(); |
888 | + void test_1(); |
889 | + void test_2_3(int test_num); |
890 | + void test_4_5(int test_num); |
891 | + void test_6(int test_num); |
892 | + void test_7(int test_num); |
893 | + void test_8(int test_num); |
894 | + void test_9(int test_num); |
895 | + void test_10(int test_num); |
896 | + void test_11(int test_num); |
897 | + void test_12(int test_num); |
898 | + void test_21(int test_num); |
899 | + void test_22(int test_num); |
900 | + void test_watch(); |
901 | + void sleep_if(); |
902 | + void set_timing(double time_spent); |
903 | + arg_type arg; |
904 | + auto_file fd; |
905 | + size_t io_success_count; |
906 | + size_t op_success_count; |
907 | + double response_min, response_max, response_sum, response_avg; |
908 | +}; |
909 | + |
910 | +void |
911 | +hstest_thread::test_1() |
912 | +{ |
913 | + char buf[1024]; |
914 | + unsigned int seed = arg.id; |
915 | + seed ^= arg.sh.conf.get_int("seed_xor", 0); |
916 | + std::string err; |
917 | + if (socket_connect(fd, arg.sh.arg, err) != 0) { |
918 | + fprintf(stderr, "connect: %d %s\n", errno, strerror(errno)); |
919 | + return; |
920 | + } |
921 | + const char op = arg.sh.op; |
922 | + const int tablesize = arg.sh.conf.get_int("tablesize", 0); |
923 | + for (size_t i = 0; i < arg.sh.loop; ++i) { |
924 | + for (size_t j = 0; j < arg.sh.pipe; ++j) { |
925 | + int k = 0, v = 0, len = 0; |
926 | + if (op == 'G') { |
927 | + k = rand_r(&seed); |
928 | + v = rand_r(&seed); /* unused */ |
929 | + if (tablesize != 0) { |
930 | + k &= tablesize; |
931 | + } |
932 | + len = snprintf(buf, sizeof(buf), "%c\tk%d\n", op, k); |
933 | + } else { |
934 | + k = rand_r(&seed); |
935 | + v = rand_r(&seed); |
936 | + if (tablesize != 0) { |
937 | + k &= tablesize; |
938 | + } |
939 | + len = snprintf(buf, sizeof(buf), "%c\tk%d\tv%d\n", op, k, v); |
940 | + } |
941 | + const int wlen = write(fd.get(), buf, len); |
942 | + if (wlen != len) { |
943 | + return; |
944 | + } |
945 | + } |
946 | + size_t read_cnt = 0; |
947 | + size_t read_pos = 0; |
948 | + while (read_cnt < arg.sh.pipe) { |
949 | + const int rlen = read(fd.get(), buf + read_pos, sizeof(buf) - read_pos); |
950 | + if (rlen <= 0) { |
951 | + return; |
952 | + } |
953 | + read_pos += rlen; |
954 | + while (true) { |
955 | + const char *const p = static_cast<const char *>(memchr(buf, '\n', |
956 | + read_pos)); |
957 | + if (p == 0) { |
958 | + break; |
959 | + } |
960 | + ++read_cnt; |
961 | + ++io_success_count; |
962 | + arg.sh.increment_count(); |
963 | + if (p != buf && buf[0] == '=') { |
964 | + ++op_success_count; |
965 | + } |
966 | + const size_t rest_size = buf + read_pos - (p + 1); |
967 | + if (rest_size != 0) { |
968 | + memmove(buf, p + 1, rest_size); |
969 | + } |
970 | + read_pos = rest_size; |
971 | + } |
972 | + } |
973 | + } |
974 | +} |
975 | + |
976 | +void |
977 | +hstest_thread::test_2_3(int test_num) |
978 | +{ |
979 | +#if 0 |
980 | + char buf_k[128], buf_v[128]; |
981 | + unsigned int seed = arg.id; |
982 | + op_base_t op = static_cast<op_base_t>(arg.sh.op); |
983 | + micli_ptr hnd; |
984 | + if (test_num == 2) { |
985 | + hnd = micli_i::create_remote(arg.sh.conf); |
986 | + } else if (test_num == 3) { |
987 | + // hnd = micli_i::create_inproc(arg.sh.localdb); |
988 | + } |
989 | + if (hnd.get() == 0) { |
990 | + return; |
991 | + } |
992 | + for (size_t i = 0; i < arg.sh.loop; ++i) { |
993 | + for (size_t j = 0; j < arg.sh.pipe; ++j) { |
994 | + int k = 0, v = 0, klen = 0, vlen = 0; |
995 | + k = rand_r(&seed); |
996 | + klen = snprintf(buf_k, sizeof(buf_k), "k%d", k); |
997 | + v = rand_r(&seed); /* unused */ |
998 | + vlen = snprintf(buf_v, sizeof(buf_v), "v%d", v); |
999 | + string_ref arr[2]; |
1000 | + arr[0] = string_ref(buf_k, klen); |
1001 | + arr[1] = string_ref(buf_v, vlen); |
1002 | + pstrarr_ptr rec(arr, 2); |
1003 | + if (hnd->execute(op, 0, 0, rec.get_const())) { |
1004 | + ++io_success_count; |
1005 | + arg.sh.increment_count(); |
1006 | + const dataset& res = hnd->get_result_ref(); |
1007 | + if (res.size() == 1) { |
1008 | + ++op_success_count; |
1009 | + } |
1010 | + } |
1011 | + } |
1012 | + } |
1013 | +#endif |
1014 | +} |
1015 | + |
1016 | +void |
1017 | +hstest_thread::test_4_5(int test_num) |
1018 | +{ |
1019 | +#if 0 |
1020 | + char buf_k[128], buf_v[8192]; |
1021 | + memset(buf_v, ' ', sizeof(buf_v)); |
1022 | + unsigned int seed = arg.id; |
1023 | + op_base_t op = static_cast<op_base_t>(arg.sh.op); |
1024 | + micli_ptr hnd; |
1025 | + if (test_num == 4) { |
1026 | + hnd = micli_i::create_remote(arg.sh.conf); |
1027 | + } else if (test_num == 5) { |
1028 | + hnd = micli_i::create_inproc(arg.sh.localdb); |
1029 | + } |
1030 | + if (hnd.get() == 0) { |
1031 | + return; |
1032 | + } |
1033 | + for (size_t i = 0; i < arg.sh.loop; ++i) { |
1034 | + for (size_t j = 0; j < arg.sh.pipe; ++j) { |
1035 | + int k = 0, klen = 0, vlen = 0; |
1036 | + k = i & 0x0000ffffUL; |
1037 | + if (k == 0) { |
1038 | + fprintf(stderr, "k=0\n"); |
1039 | + } |
1040 | + klen = snprintf(buf_k, sizeof(buf_k), "k%d", k); |
1041 | + vlen = rand_r(&seed) % 8192; |
1042 | + string_ref arr[2]; |
1043 | + arr[0] = string_ref(buf_k, klen); |
1044 | + arr[1] = string_ref(buf_v, vlen); |
1045 | + pstrarr_ptr rec(arr, 2); |
1046 | + if (hnd->execute(op, 0, 0, rec.get_const())) { |
1047 | + ++io_success_count; |
1048 | + const dataset& res = hnd->get_result_ref(); |
1049 | + if (res.size() == 1) { |
1050 | + ++op_success_count; |
1051 | + } |
1052 | + } |
1053 | + } |
1054 | + } |
1055 | +#endif |
1056 | +} |
1057 | + |
1058 | +void |
1059 | +hstest_thread::test_6(int test_num) |
1060 | +{ |
1061 | + int count = arg.sh.conf.get_int("count", 1); |
1062 | + auto_file fds[count]; |
1063 | + for (int i = 0; i < count; ++i) { |
1064 | + const double t1 = gettimeofday_double(); |
1065 | + std::string err; |
1066 | + if (socket_connect(fds[i], arg.sh.arg, err) != 0) { |
1067 | + fprintf(stderr, "id=%zu i=%d err=%s\n", arg.id, i, err.c_str()); |
1068 | + } |
1069 | + const double t2 = gettimeofday_double(); |
1070 | + if (t2 - t1 > 1) { |
1071 | + fprintf(stderr, "id=%zu i=%d time %f\n", arg.id, i, t2 - t1); |
1072 | + } |
1073 | + } |
1074 | +} |
1075 | + |
1076 | +void |
1077 | +hstest_thread::test_7(int num) |
1078 | +{ |
1079 | + /* |
1080 | + set foo 0 0 10 |
1081 | + 0123456789 |
1082 | + STORED |
1083 | + get foo |
1084 | + VALUE foo 0 10 |
1085 | + 0123456789 |
1086 | + END |
1087 | + get var |
1088 | + END |
1089 | + */ |
1090 | + char buf[1024]; |
1091 | + const int keep_connection = arg.sh.conf.get_int("keep_connection", 1); |
1092 | + unsigned int seed = arg.id; |
1093 | + seed ^= arg.sh.conf.get_int("seed_xor", 0); |
1094 | + const int tablesize = arg.sh.conf.get_int("tablesize", 0); |
1095 | + const char op = arg.sh.op; |
1096 | + for (size_t i = 0; i < arg.sh.loop; ++i) { |
1097 | + const double tm1 = gettimeofday_double(); |
1098 | + std::string err; |
1099 | + if (fd.get() < 0 && socket_connect(fd, arg.sh.arg, err) != 0) { |
1100 | + fprintf(stderr, "connect: %d %s\n", errno, strerror(errno)); |
1101 | + return; |
1102 | + } |
1103 | + for (size_t j = 0; j < arg.sh.pipe; ++j) { |
1104 | + int k = 0, v = 0, len = 0; |
1105 | + if (op == 'G') { |
1106 | + k = rand_r(&seed); |
1107 | + v = rand_r(&seed); /* unused */ |
1108 | + if (tablesize != 0) { |
1109 | + k &= tablesize; |
1110 | + } |
1111 | + len = snprintf(buf, sizeof(buf), "get k%d\r\n", k); |
1112 | + } else { |
1113 | + k = rand_r(&seed); |
1114 | + v = rand_r(&seed); |
1115 | + if (tablesize != 0) { |
1116 | + k &= tablesize; |
1117 | + } |
1118 | + char vbuf[1024]; |
1119 | + int vlen = snprintf(vbuf, sizeof(vbuf), |
1120 | + "v%d" |
1121 | + // "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" |
1122 | + // "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" |
1123 | + // "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" |
1124 | + // "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" |
1125 | + // "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" |
1126 | + , v); |
1127 | + len = snprintf(buf, sizeof(buf), "set k%d 0 0 %d\r\n%s\r\n", |
1128 | + k, vlen, vbuf); |
1129 | + } |
1130 | + const int wlen = write(fd.get(), buf, len); |
1131 | + if (wlen != len) { |
1132 | + return; |
1133 | + } |
1134 | + } |
1135 | + size_t read_cnt = 0; |
1136 | + size_t read_pos = 0; |
1137 | + bool read_response_done = false; |
1138 | + bool expect_value = false; |
1139 | + while (!read_response_done) { |
1140 | + const int rlen = read(fd.get(), buf + read_pos, sizeof(buf) - read_pos); |
1141 | + if (rlen <= 0) { |
1142 | + return; |
1143 | + } |
1144 | + read_pos += rlen; |
1145 | + while (true) { |
1146 | + const char *const p = static_cast<const char *>(memchr(buf, '\n', |
1147 | + read_pos)); |
1148 | + if (p == 0) { |
1149 | + break; |
1150 | + } |
1151 | + ++read_cnt; |
1152 | + if (expect_value) { |
1153 | + expect_value = false; |
1154 | + } else if (p >= buf + 6 && memcmp(buf, "VALUE ", 6) == 0) { |
1155 | + expect_value = true; |
1156 | + ++op_success_count; |
1157 | + } else { |
1158 | + if (p == buf + 7 && memcmp(buf, "STORED\r", 7) == 0) { |
1159 | + ++op_success_count; |
1160 | + } |
1161 | + read_response_done = true; |
1162 | + } |
1163 | + const size_t rest_size = buf + read_pos - (p + 1); |
1164 | + if (rest_size != 0) { |
1165 | + memmove(buf, p + 1, rest_size); |
1166 | + } |
1167 | + read_pos = rest_size; |
1168 | + } |
1169 | + ++io_success_count; |
1170 | + } |
1171 | + arg.sh.increment_count(); |
1172 | + if (!keep_connection) { |
1173 | + fd.close(); |
1174 | + } |
1175 | + const double tm2 = gettimeofday_double(); |
1176 | + set_timing(tm2 - tm1); |
1177 | + sleep_if(); |
1178 | + } |
1179 | +} |
1180 | + |
1181 | +struct rec { |
1182 | + std::string key; |
1183 | + std::string value; |
1184 | +}; |
1185 | + |
1186 | +void |
1187 | +hstest_thread::test_8(int test_num) |
1188 | +{ |
1189 | +#if 0 |
1190 | + char buf_k[128], buf_v[128]; |
1191 | + unsigned int seed = arg.id; |
1192 | + // op_base_t op = static_cast<op_base_t>(arg.sh.op); |
1193 | + using namespace boost::multi_index; |
1194 | + typedef member<rec, std::string, &rec::key> rec_get_key; |
1195 | + typedef ordered_unique<rec_get_key> oui; |
1196 | + typedef multi_index_container< rec, indexed_by<oui> > mic; |
1197 | + #if 0 |
1198 | + typedef std::map<std::string, std::string> m_type; |
1199 | + m_type m; |
1200 | + #endif |
1201 | + mic m; |
1202 | + for (size_t i = 0; i < arg.sh.loop; ++i) { |
1203 | + for (size_t j = 0; j < arg.sh.pipe; ++j) { |
1204 | + int k = 0, v = 0, klen = 0, vlen = 0; |
1205 | + k = rand_r(&seed); |
1206 | + klen = snprintf(buf_k, sizeof(buf_k), "k%d", k); |
1207 | + v = rand_r(&seed); /* unused */ |
1208 | + vlen = snprintf(buf_v, sizeof(buf_v), "v%d", v); |
1209 | + const std::string ks(buf_k, klen); |
1210 | + const std::string vs(buf_v, vlen); |
1211 | + rec r; |
1212 | + r.key = ks; |
1213 | + r.value = vs; |
1214 | + m.insert(r); |
1215 | + // m.insert(std::make_pair(ks, vs)); |
1216 | + ++io_success_count; |
1217 | + ++op_success_count; |
1218 | + arg.sh.increment_count(); |
1219 | + } |
1220 | + } |
1221 | +#endif |
1222 | +} |
1223 | + |
1224 | +struct mysqltest_thread_initobj : private noncopyable { |
1225 | + mysqltest_thread_initobj() { |
1226 | + mysql_thread_init(); |
1227 | + } |
1228 | + ~mysqltest_thread_initobj() { |
1229 | + mysql_thread_end(); |
1230 | + } |
1231 | +}; |
1232 | + |
1233 | +void |
1234 | +hstest_thread::test_9(int test_num) |
1235 | +{ |
1236 | + /* create table hstest |
1237 | + * ( k varchar(255) not null, v varchar(255) not null, primary key(k)) |
1238 | + * engine = innodb; */ |
1239 | + auto_mysql db; |
1240 | + // mysqltest_thread_initobj initobj; |
1241 | + std::string err; |
1242 | + const char op = arg.sh.op; |
1243 | + const std::string suffix = arg.sh.conf.get_str("value_suffix", "upd"); |
1244 | + unsigned long long err_cnt = 0; |
1245 | + unsigned long long query_cnt = 0; |
1246 | + #if 0 |
1247 | + my_bool reconnect = 0; |
1248 | + if (mysql_options(db, MYSQL_OPT_RECONNECT, &reconnect) != 0) { |
1249 | + err = "mysql_options() failed"; |
1250 | + ++err_cnt; |
1251 | + return; |
1252 | + } |
1253 | + #endif |
1254 | + unsigned int seed = time(0) + arg.id + 1; |
1255 | + seed ^= arg.sh.conf.get_int("seed_xor", 0); |
1256 | + drand48_data randbuf; |
1257 | + srand48_r(seed, &randbuf); |
1258 | + const std::string mysql_host = arg.sh.conf.get_str("host", "localhost"); |
1259 | + const int mysql_port = arg.sh.conf.get_int("mysqlport", 3306); |
1260 | + const int num = arg.sh.loop; |
1261 | + const std::string mysql_user = arg.sh.conf.get_str("mysqluser", "root"); |
1262 | + const std::string mysql_passwd = arg.sh.conf.get_str("mysqlpass", ""); |
1263 | + const std::string mysql_dbname = arg.sh.conf.get_str("dbname", "hstest"); |
1264 | + const int keep_connection = arg.sh.conf.get_int("keep_connection", 1); |
1265 | + const int verbose = arg.sh.conf.get_int("verbose", 1); |
1266 | + const int tablesize = arg.sh.conf.get_int("tablesize", 10000); |
1267 | + const int moreflds = arg.sh.conf.get_int("moreflds", 0); |
1268 | + const std::string moreflds_prefix = arg.sh.conf.get_str( |
1269 | + "moreflds_prefix", "column0123456789_"); |
1270 | + const int use_handler = arg.sh.conf.get_int("handler", 0); |
1271 | + const int sched_flag = arg.sh.conf.get_int("sched", 0); |
1272 | + const int ssps = arg.sh.conf.get_int("ssps", 0); |
1273 | + std::string flds = "v"; |
1274 | + for (int i = 0; i < moreflds; ++i) { |
1275 | + char buf[1024]; |
1276 | + snprintf(buf, sizeof(buf), ",%s%d", moreflds_prefix.c_str(), i); |
1277 | + flds += std::string(buf); |
1278 | + } |
1279 | + int connected = 0; |
1280 | + std::auto_ptr<auto_mysql_stmt> stmt; |
1281 | + for (int i = 0; i < num; ++i) { |
1282 | + const double tm1 = gettimeofday_double(); |
1283 | + const int flags = 0; |
1284 | + if (connected == 0) { |
1285 | + if (!mysql_real_connect(db, mysql_host.c_str(), |
1286 | + mysql_user.c_str(), mysql_user.empty() ? 0 : mysql_passwd.c_str(), |
1287 | + mysql_dbname.c_str(), mysql_port, 0, flags)) { |
1288 | + err = "failed to connect: " + std::string(mysql_error(db)); |
1289 | + if (verbose >= 1) { |
1290 | + fprintf(stderr, "e=[%s]\n", err.c_str()); |
1291 | + } |
1292 | + ++err_cnt; |
1293 | + return; |
1294 | + } |
1295 | + arg.sh.increment_conn(1); |
1296 | + } |
1297 | + int r = 0; |
1298 | + if (connected == 0 && use_handler) { |
1299 | + const char *const q = "handler hstest_table1 open"; |
1300 | + r = mysql_real_query(db, q, strlen(q)); |
1301 | + if (r != 0) { |
1302 | + err = 1; |
1303 | + } |
1304 | + } |
1305 | + if (connected == 0 && ssps) { |
1306 | + stmt.reset(new auto_mysql_stmt(db)); |
1307 | + const char *const q = "select v from hstest_table1 where k = ?"; |
1308 | + r = mysql_stmt_prepare(*stmt, q, strlen(q)); |
1309 | + if (r != 0) { |
1310 | + fprintf(stderr, "ssps err\n"); |
1311 | + ++err_cnt; |
1312 | + return; |
1313 | + } |
1314 | + } |
1315 | + connected = 1; |
1316 | + std::string result_str; |
1317 | + unsigned int err = 0; |
1318 | + unsigned int num_flds = 0, num_affected_rows = 0; |
1319 | + int got_data = 0; |
1320 | + char buf_query[16384]; |
1321 | + int buf_query_len = 0; |
1322 | + int k = 0, v = 0; |
1323 | + { |
1324 | + double kf = 0, vf = 0; |
1325 | + drand48_r(&randbuf, &kf); |
1326 | + drand48_r(&randbuf, &vf); |
1327 | + k = int(kf * tablesize); |
1328 | + v = int(vf * tablesize); |
1329 | + #if 0 |
1330 | + k = rand_r(&seed); |
1331 | + v = rand_r(&seed); |
1332 | + if (tablesize != 0) { |
1333 | + k %= tablesize; |
1334 | + } |
1335 | + #endif |
1336 | + if (op == 'G') { |
1337 | + if (use_handler) { |
1338 | + buf_query_len = snprintf(buf_query, sizeof(buf_query), |
1339 | + "handler hstest_table1 read `primary` = ( '%d' )", k); |
1340 | + // TODO: moreflds |
1341 | + } else if (ssps) { |
1342 | + // |
1343 | + } else { |
1344 | + buf_query_len = snprintf(buf_query, sizeof(buf_query), |
1345 | + "select %s from hstest_table1 where k = '%d'", flds.c_str(), k); |
1346 | + } |
1347 | + } else if (op == 'U') { |
1348 | + buf_query_len = snprintf(buf_query, sizeof(buf_query), |
1349 | + "update hstest_table1 set v = '%d_%d%s' where k = '%d'", |
1350 | + v, k, suffix.c_str(), k); |
1351 | + } else if (op == 'R') { |
1352 | + buf_query_len = snprintf(buf_query, sizeof(buf_query), |
1353 | + "replace into hstest_table1 values ('%d', 'v%d')", k, v); |
1354 | + // TODO: moreflds |
1355 | + } |
1356 | + } |
1357 | + if (r == 0) { |
1358 | + if (ssps) { |
1359 | + MYSQL_BIND bind[1] = { }; |
1360 | + bind[0].buffer_type = MYSQL_TYPE_LONG; |
1361 | + bind[0].buffer = (char *)&k; |
1362 | + bind[0].is_null = 0; |
1363 | + bind[0].length = 0; |
1364 | + if (mysql_stmt_bind_param(*stmt, bind)) { |
1365 | + fprintf(stderr, "err: %s\n", mysql_stmt_error(*stmt)); |
1366 | + ++err_cnt; |
1367 | + return; |
1368 | + } |
1369 | + r = mysql_stmt_execute(*stmt); |
1370 | + // fprintf(stderr, "stmt exec\n"); |
1371 | + } else { |
1372 | + r = mysql_real_query(db, buf_query, buf_query_len); |
1373 | + // fprintf(stderr, "real query\n"); |
1374 | + } |
1375 | + ++query_cnt; |
1376 | + } |
1377 | + if (r != 0) { |
1378 | + err = 1; |
1379 | + } else if (ssps) { |
1380 | + if (verbose >= 0) { |
1381 | + char resbuf[1024]; |
1382 | + unsigned long res_len = 0; |
1383 | + MYSQL_BIND bind[1] = { }; |
1384 | + bind[0].buffer_type = MYSQL_TYPE_STRING; |
1385 | + bind[0].buffer = resbuf; |
1386 | + bind[0].buffer_length = sizeof(resbuf); |
1387 | + bind[0].length = &res_len; |
1388 | + if (mysql_stmt_bind_result(*stmt, bind)) { |
1389 | + fprintf(stderr, "err: %s\n", mysql_stmt_error(*stmt)); |
1390 | + ++err_cnt; |
1391 | + return; |
1392 | + } |
1393 | + if (mysql_stmt_fetch(*stmt)) { |
1394 | + fprintf(stderr, "err: %s\n", mysql_stmt_error(*stmt)); |
1395 | + ++err_cnt; |
1396 | + return; |
1397 | + } |
1398 | + if (!result_str.empty()) { |
1399 | + result_str += " "; |
1400 | + } |
1401 | + result_str += std::string(resbuf, res_len); |
1402 | + // fprintf(stderr, "SSPS RES: %s\n", result_str.c_str()); |
1403 | + got_data = 1; |
1404 | + } else { |
1405 | + got_data = 1; |
1406 | + } |
1407 | + } else { |
1408 | + auto_mysql_res res(db); |
1409 | + if (res != 0) { |
1410 | + if (verbose >= 0) { |
1411 | + num_flds = mysql_num_fields(res); |
1412 | + MYSQL_ROW row = 0; |
1413 | + while ((row = mysql_fetch_row(res)) != 0) { |
1414 | + got_data = 1; |
1415 | + unsigned long *const lengths = mysql_fetch_lengths(res); |
1416 | + if (verbose >= 2) { |
1417 | + for (unsigned int i = 0; i < num_flds; ++i) { |
1418 | + if (!result_str.empty()) { |
1419 | + result_str += " "; |
1420 | + } |
1421 | + result_str += std::string(row[i], lengths[i]); |
1422 | + } |
1423 | + } |
1424 | + } |
1425 | + } else { |
1426 | + got_data = 1; |
1427 | + } |
1428 | + } else { |
1429 | + if (mysql_field_count(db) == 0) { |
1430 | + num_affected_rows = mysql_affected_rows(db); |
1431 | + } else { |
1432 | + err = 1; |
1433 | + } |
1434 | + } |
1435 | + } |
1436 | + if (verbose >= 2 || (verbose >= 1 && err != 0)) { |
1437 | + if (err) { |
1438 | + ++err_cnt; |
1439 | + const char *const errstr = mysql_error(db); |
1440 | + fprintf(stderr, "e=[%s] a=%u q=[%s]\n", errstr, |
1441 | + num_affected_rows, buf_query); |
1442 | + } else { |
1443 | + fprintf(stderr, "a=%u q=[%s] r=[%s]\n", num_affected_rows, buf_query, |
1444 | + result_str.c_str()); |
1445 | + } |
1446 | + } |
1447 | + if (err == 0) { |
1448 | + ++io_success_count; |
1449 | + if (num_affected_rows > 0 || got_data > 0) { |
1450 | + ++op_success_count; |
1451 | + } else { |
1452 | + if (verbose >= 1) { |
1453 | + fprintf(stderr, "k=%d numaff=%u gotdata=%d\n", |
1454 | + k, num_affected_rows, got_data); |
1455 | + } |
1456 | + } |
1457 | + arg.sh.increment_count(); |
1458 | + } |
1459 | + if (!keep_connection) { |
1460 | + if (stmt.get() != 0) { |
1461 | + stmt.reset(); |
1462 | + } |
1463 | + db.reset(); |
1464 | + connected = 0; |
1465 | + } |
1466 | + const double tm2 = gettimeofday_double(); |
1467 | + set_timing(tm2 - tm1); |
1468 | + sleep_if(); |
1469 | + if (sched_flag) { |
1470 | + sched_yield(); |
1471 | + } |
1472 | + } |
1473 | + if (verbose >= 1) { |
1474 | + fprintf(stderr, "thread finished (error_count=%llu)\n", err_cnt); |
1475 | + } |
1476 | +} |
1477 | + |
1478 | +void |
1479 | +hstest_thread::test_10(int test_num) |
1480 | +{ |
1481 | + const int keep_connection = arg.sh.conf.get_int("keep_connection", 1); |
1482 | + unsigned int seed = time(0) + arg.id + 1; |
1483 | + seed ^= arg.sh.conf.get_int("seed_xor", 0); |
1484 | + drand48_data randbuf; |
1485 | + srand48_r(seed, &randbuf); |
1486 | + std::string err; |
1487 | + int keepconn_count = 0; |
1488 | + const char op = arg.sh.op; |
1489 | + const int verbose = arg.sh.conf.get_int("verbose", 1); |
1490 | + const std::string suffix = arg.sh.conf.get_str("value_suffix", "upd"); |
1491 | + const int tablesize = arg.sh.conf.get_int("tablesize", 10000); |
1492 | + const int firstkey = arg.sh.conf.get_int("firstkey", 0); |
1493 | + const int sched_flag = arg.sh.conf.get_int("sched", 0); |
1494 | + const int moreflds = arg.sh.conf.get_int("moreflds", 0); |
1495 | + const std::string dbname = arg.sh.conf.get_str("dbname", "hstest"); |
1496 | + const std::string table = arg.sh.conf.get_str("table", "hstest_table1"); |
1497 | + const std::string index = arg.sh.conf.get_str("index", "PRIMARY"); |
1498 | + const std::string field = arg.sh.conf.get_str("field", "v"); |
1499 | + const std::string moreflds_prefix = arg.sh.conf.get_str( |
1500 | + "moreflds_prefix", "column0123456789_"); |
1501 | + const int dump = arg.sh.dump; |
1502 | + const int nodup = arg.sh.conf.get_int("nodup", 0); |
1503 | + std::string moreflds_str; |
1504 | + for (int i = 0; i < moreflds; ++i) { |
1505 | + char sbuf[1024]; |
1506 | + snprintf(sbuf, sizeof(sbuf), ",%s%d", moreflds_prefix.c_str(), i); |
1507 | + moreflds_str += std::string(sbuf); |
1508 | + } |
1509 | + char wbuf[16384], rbuf[16384]; |
1510 | + int wbuflen = 0; |
1511 | + for (size_t i = 0; i < arg.sh.loop; ++i) { |
1512 | + int len = 0, rlen = 0, wlen = 0; |
1513 | + #if 0 |
1514 | + const double tm1 = gettimeofday_double(); |
1515 | + #endif |
1516 | + if (fd.get() < 0) { |
1517 | + if (socket_connect(fd, arg.sh.arg, err) != 0) { |
1518 | + fprintf(stderr, "connect: %d %s\n", errno, strerror(errno)); |
1519 | + return; |
1520 | + } |
1521 | + len = snprintf(wbuf, sizeof(wbuf), |
1522 | + "P\t1\t%s\t%s\tPRIMARY\t%s%s\n", dbname.c_str(), table.c_str(), |
1523 | + field.c_str(), moreflds_str.c_str()); |
1524 | + /* pst_num, db, table, index, retflds */ |
1525 | + wlen = write(fd.get(), wbuf, len); |
1526 | + if (len != wlen) { |
1527 | + fprintf(stderr, "write: %d %d\n", len, wlen); |
1528 | + return; |
1529 | + } |
1530 | + rlen = read(fd.get(), rbuf, sizeof(rbuf)); |
1531 | + if (rlen <= 0 || rbuf[rlen - 1] != '\n') { |
1532 | + fprintf(stderr, "read: rlen=%d errno=%d\n", rlen, errno); |
1533 | + return; |
1534 | + } |
1535 | + if (rbuf[0] != '0') { |
1536 | + fprintf(stderr, "failed to open table\n"); |
1537 | + return; |
1538 | + } |
1539 | + arg.sh.increment_conn(1); |
1540 | + } |
1541 | + const double tm1 = gettimeofday_double(); |
1542 | + for (size_t j = 0; j < arg.sh.pipe; ++j) { |
1543 | + int k = 0, v = 0; |
1544 | + wbuflen = 0; |
1545 | + { |
1546 | + while (true) { |
1547 | + double kf = 0, vf = 0; |
1548 | + drand48_r(&randbuf, &kf); |
1549 | + drand48_r(&randbuf, &vf); |
1550 | + k = int(kf * tablesize) + firstkey; |
1551 | + v = int(vf * tablesize) + firstkey; |
1552 | + // k = rand_r(&seed); |
1553 | + // v = rand_r(&seed); /* unused */ |
1554 | + #if 0 |
1555 | + if (tablesize != 0) { |
1556 | + k &= tablesize; |
1557 | + } |
1558 | + #endif |
1559 | + if (op == 'G') { |
1560 | + wbuflen = snprintf(wbuf, sizeof(wbuf), "1\t=\t1\t%d\n", k); |
1561 | + } else if (op == 'U') { |
1562 | + wbuflen = snprintf(wbuf, sizeof(wbuf), |
1563 | + "1\t=\t1\t%d\t1\t0\tU\t%d_%d%s\n", k, v, k, suffix.c_str()); |
1564 | + } |
1565 | + if (k - firstkey < arg.sh.keygen_size) { |
1566 | + volatile char *const ptr = arg.sh.keygen + (k - firstkey); |
1567 | + // int oldv = __sync_fetch_and_or(ptr, 1); |
1568 | + int oldv = *ptr; |
1569 | + *ptr += 1; |
1570 | + if (nodup && oldv != 0) { |
1571 | + if (dump) { |
1572 | + fprintf(stderr, "retry\n"); |
1573 | + } |
1574 | + continue; |
1575 | + } |
1576 | + } else { |
1577 | + if (nodup) { |
1578 | + if (dump) { |
1579 | + fprintf(stderr, "retry2\n"); |
1580 | + } |
1581 | + continue; |
1582 | + } |
1583 | + } |
1584 | + break; |
1585 | + } |
1586 | + } |
1587 | + wlen = write(fd.get(), wbuf, wbuflen); |
1588 | + if (wlen != wbuflen) { |
1589 | + fprintf(stderr, "write: %d %d\n", wbuflen, wlen); |
1590 | + return; |
1591 | + } |
1592 | + } |
1593 | + size_t read_cnt = 0; |
1594 | + size_t read_pos = 0; |
1595 | + while (read_cnt < arg.sh.pipe) { |
1596 | + rlen = read(fd.get(), rbuf + read_pos, sizeof(rbuf) - read_pos); |
1597 | + if (rlen <= 0) { |
1598 | + fprintf(stderr, "read: %d\n", rlen); |
1599 | + return; |
1600 | + } |
1601 | + read_pos += rlen; |
1602 | + while (true) { |
1603 | + const char *const nl = static_cast<const char *>(memchr(rbuf, '\n', |
1604 | + read_pos)); |
1605 | + if (nl == 0) { |
1606 | + break; |
1607 | + } |
1608 | + ++read_cnt; |
1609 | + ++io_success_count; |
1610 | + const char *t1 = static_cast<const char *>(memchr(rbuf, '\t', |
1611 | + nl - rbuf)); |
1612 | + if (t1 == 0) { |
1613 | + fprintf(stderr, "error \n"); |
1614 | + break; |
1615 | + } |
1616 | + ++t1; |
1617 | + const char *t2 = static_cast<const char *>(memchr(t1, '\t', |
1618 | + nl - t1)); |
1619 | + if (t2 == 0) { |
1620 | + if (verbose > 1) { |
1621 | + fprintf(stderr, "key: notfound \n"); |
1622 | + } |
1623 | + break; |
1624 | + } |
1625 | + ++t2; |
1626 | + if (t1 == rbuf + 2 && rbuf[0] == '0') { |
1627 | + if (op == 'G') { |
1628 | + ++op_success_count; |
1629 | + arg.sh.increment_count(); |
1630 | + } else if (op == 'U') { |
1631 | + const char *t3 = t2; |
1632 | + while (t3 != nl && t3[0] >= 0x10) { |
1633 | + ++t3; |
1634 | + } |
1635 | + if (t3 != t2 + 1 || t2[0] != '1') { |
1636 | + const std::string mess(t2, t3); |
1637 | + fprintf(stderr, "mod: %s\n", mess.c_str()); |
1638 | + } else { |
1639 | + ++op_success_count; |
1640 | + arg.sh.increment_count(); |
1641 | + if (arg.sh.dump && arg.sh.pipe == 1) { |
1642 | + fwrite(wbuf, wbuflen, 1, stderr); |
1643 | + } |
1644 | + } |
1645 | + } |
1646 | + } else { |
1647 | + const char *t3 = t2; |
1648 | + while (t3 != nl && t3[0] >= 0x10) { |
1649 | + ++t3; |
1650 | + } |
1651 | + const std::string mess(t2, t3); |
1652 | + fprintf(stderr, "err: %s\n", mess.c_str()); |
1653 | + } |
1654 | + const size_t rest_size = rbuf + read_pos - (nl + 1); |
1655 | + if (rest_size != 0) { |
1656 | + memmove(rbuf, nl + 1, rest_size); |
1657 | + } |
1658 | + read_pos = rest_size; |
1659 | + } |
1660 | + } |
1661 | + if (!keep_connection) { |
1662 | + fd.reset(); |
1663 | + arg.sh.increment_conn(-1); |
1664 | + } else if (keep_connection > 1 && ++keepconn_count > keep_connection) { |
1665 | + keepconn_count = 0; |
1666 | + fd.reset(); |
1667 | + arg.sh.increment_conn(-1); |
1668 | + } |
1669 | + const double tm2 = gettimeofday_double(); |
1670 | + set_timing(tm2 - tm1); |
1671 | + sleep_if(); |
1672 | + if (sched_flag) { |
1673 | + sched_yield(); |
1674 | + } |
1675 | + } |
1676 | + if (dump) { |
1677 | + fprintf(stderr, "done\n"); |
1678 | + } |
1679 | +} |
1680 | + |
1681 | +void |
1682 | +hstest_thread::sleep_if() |
1683 | +{ |
1684 | + if (arg.sh.usleep) { |
1685 | + struct timespec ts = { |
1686 | + arg.sh.usleep / 1000000, |
1687 | + (arg.sh.usleep % 1000000) * 1000 |
1688 | + }; |
1689 | + nanosleep(&ts, 0); |
1690 | + } |
1691 | +} |
1692 | + |
1693 | +void |
1694 | +hstest_thread::set_timing(double time_spent) |
1695 | +{ |
1696 | + response_min = std::min(response_min, time_spent); |
1697 | + response_max = std::max(response_max, time_spent); |
1698 | + response_sum += time_spent; |
1699 | + if (op_success_count != 0) { |
1700 | + response_avg = response_sum / op_success_count; |
1701 | + } |
1702 | +} |
1703 | + |
1704 | +void |
1705 | +hstest_thread::test_11(int test_num) |
1706 | +{ |
1707 | + const int keep_connection = arg.sh.conf.get_int("keep_connection", 1); |
1708 | + const int tablesize = arg.sh.conf.get_int("tablesize", 0); |
1709 | + unsigned int seed = arg.id; |
1710 | + seed ^= arg.sh.conf.get_int("seed_xor", 0); |
1711 | + std::string err; |
1712 | + hstcpcli_ptr cli; |
1713 | + for (size_t i = 0; i < arg.sh.loop; ++i) { |
1714 | + if (cli.get() == 0) { |
1715 | + cli = hstcpcli_i::create(arg.sh.arg); |
1716 | + cli->request_buf_open_index(0, "hstest", "hstest_table1", "", "v"); |
1717 | + /* pst_num, db, table, index, retflds */ |
1718 | + if (cli->request_send() != 0) { |
1719 | + fprintf(stderr, "reuqest_send: %s\n", cli->get_error().c_str()); |
1720 | + return; |
1721 | + } |
1722 | + size_t num_flds = 0; |
1723 | + if (cli->response_recv(num_flds) != 0) { |
1724 | + fprintf(stderr, "reuqest_recv: %s\n", cli->get_error().c_str()); |
1725 | + return; |
1726 | + } |
1727 | + cli->response_buf_remove(); |
1728 | + } |
1729 | + for (size_t j = 0; j < arg.sh.pipe; ++j) { |
1730 | + char buf[256]; |
1731 | + int k = 0, v = 0, len = 0; |
1732 | + { |
1733 | + k = rand_r(&seed); |
1734 | + v = rand_r(&seed); /* unused */ |
1735 | + if (tablesize != 0) { |
1736 | + k &= tablesize; |
1737 | + } |
1738 | + len = snprintf(buf, sizeof(buf), "%d", k); |
1739 | + } |
1740 | + const string_ref key(buf, len); |
1741 | + const string_ref op("=", 1); |
1742 | + cli->request_buf_exec_generic(0, op, &key, 1, 1, 0, string_ref(), 0, 0); |
1743 | + } |
1744 | + if (cli->request_send() != 0) { |
1745 | + fprintf(stderr, "reuqest_send: %s\n", cli->get_error().c_str()); |
1746 | + return; |
1747 | + } |
1748 | + size_t read_cnt = 0; |
1749 | + for (size_t j = 0; j < arg.sh.pipe; ++j) { |
1750 | + size_t num_flds = 0; |
1751 | + if (cli->response_recv(num_flds) != 0) { |
1752 | + fprintf(stderr, "reuqest_recv: %s\n", cli->get_error().c_str()); |
1753 | + return; |
1754 | + } |
1755 | + { |
1756 | + ++read_cnt; |
1757 | + ++io_success_count; |
1758 | + arg.sh.increment_count(); |
1759 | + { |
1760 | + ++op_success_count; |
1761 | + } |
1762 | + } |
1763 | + cli->response_buf_remove(); |
1764 | + } |
1765 | + if (!keep_connection) { |
1766 | + cli.reset(); |
1767 | + } |
1768 | + } |
1769 | +} |
1770 | + |
1771 | +void |
1772 | +hstest_thread::test_watch() |
1773 | +{ |
1774 | + const int timelimit = arg.sh.conf.get_int("timelimit", 0); |
1775 | + const int timelimit_offset = timelimit / 2; |
1776 | + int loop = 0; |
1777 | + double t1 = 0, t2 = 0; |
1778 | + size_t cnt_t1 = 0, cnt_t2 = 0; |
1779 | + size_t prev_cnt = 0; |
1780 | + double now_f = 0; |
1781 | + while (true) { |
1782 | + sleep(1); |
1783 | + const size_t cnt = arg.sh.count; |
1784 | + const size_t df = cnt - prev_cnt; |
1785 | + prev_cnt = cnt; |
1786 | + const double now_prev = now_f; |
1787 | + now_f = gettimeofday_double(); |
1788 | + if (now_prev != 0) { |
1789 | + const double rps = static_cast<double>(df) / (now_f - now_prev); |
1790 | + fprintf(stderr, "now: %zu cntdiff: %zu tdiff: %f rps: %f\n", |
1791 | + static_cast<size_t>(now_f), df, now_f - now_prev, rps); |
1792 | + } |
1793 | + if (timelimit != 0) { |
1794 | + if (arg.sh.wait_conn == 0 || arg.sh.conn_count >= arg.sh.wait_conn) { |
1795 | + ++loop; |
1796 | + } |
1797 | + if (loop == timelimit_offset) { |
1798 | + t1 = gettimeofday_double(); |
1799 | + cnt_t1 = cnt; |
1800 | + arg.sh.enable_timing = 1; |
1801 | + fprintf(stderr, "start timing\n"); |
1802 | + } else if (loop == timelimit_offset + timelimit) { |
1803 | + t2 = gettimeofday_double(); |
1804 | + cnt_t2 = cnt; |
1805 | + const size_t cnt_diff = cnt_t2 - cnt_t1; |
1806 | + const double tdiff = t2 - t1; |
1807 | + const double qps = cnt_diff / (tdiff != 0 ? tdiff : 1); |
1808 | + fprintf(stderr, "(%f: %zu, %f: %zu), %10.5f qps\n", |
1809 | + t1, cnt_t1, t2, cnt_t2, qps); |
1810 | + size_t keycnt = 0; |
1811 | + for (int i = 0; i < arg.sh.keygen_size; ++i) { |
1812 | + if (arg.sh.keygen[i]) { |
1813 | + ++keycnt; |
1814 | + } |
1815 | + } |
1816 | + fprintf(stderr, "keygen=%zu\n", keycnt); |
1817 | + break; |
1818 | + } |
1819 | + } |
1820 | + } |
1821 | +#if 0 |
1822 | + int loop = 0; |
1823 | + double t1 = 0, t2 = 0; |
1824 | + size_t cnt_t1 = 0, cnt_t2 = 0; |
1825 | + size_t prev_cnt = 0; |
1826 | + while (true) { |
1827 | + sleep(1); |
1828 | + const size_t cnt = arg.sh.count; |
1829 | + const size_t df = cnt - prev_cnt; |
1830 | + prev_cnt = cnt; |
1831 | + const size_t now = time(0); |
1832 | + fprintf(stderr, "%zu %zu\n", now, df); |
1833 | + if (timelimit != 0) { |
1834 | + ++loop; |
1835 | + if (loop == timelimit_offset) { |
1836 | + t1 = gettimeofday_double(); |
1837 | + cnt_t1 = cnt; |
1838 | + } else if (loop == timelimit_offset + timelimit) { |
1839 | + t2 = gettimeofday_double(); |
1840 | + cnt_t2 = cnt; |
1841 | + const size_t cnt_diff = cnt_t2 - cnt_t1; |
1842 | + const double tdiff = t2 - t1; |
1843 | + const double qps = cnt_diff / (tdiff != 0 ? tdiff : 1); |
1844 | + fprintf(stderr, "(%f: %zu, %f: %zu), %10.5f qps\n", |
1845 | + t1, cnt_t1, t2, cnt_t2, qps); |
1846 | + size_t keycnt = 0; |
1847 | + for (int i = 0; i < arg.sh.keygen_size; ++i) { |
1848 | + if (arg.sh.keygen[i]) { |
1849 | + ++keycnt; |
1850 | + } |
1851 | + } |
1852 | + fprintf(stderr, "keygen=%zu\n", keycnt); |
1853 | + _exit(0); |
1854 | + } |
1855 | + } |
1856 | + } |
1857 | +#endif |
1858 | +} |
1859 | + |
1860 | +void |
1861 | +hstest_thread::test_12(int test_num) |
1862 | +{ |
1863 | + /* NOTE: num_threads should be 1 */ |
1864 | + /* create table hstest |
1865 | + * ( k varchar(255) not null, v varchar(255) not null, primary key(k)) |
1866 | + * engine = innodb; */ |
1867 | + mysqltest_thread_initobj initobj; |
1868 | + auto_mysql db; |
1869 | + std::string err; |
1870 | + unsigned long long err_cnt = 0; |
1871 | + unsigned long long query_cnt = 0; |
1872 | + #if 0 |
1873 | + my_bool reconnect = 0; |
1874 | + if (mysql_options(db, MYSQL_OPT_RECONNECT, &reconnect) != 0) { |
1875 | + err = "mysql_options() failed"; |
1876 | + ++err_cnt; |
1877 | + return; |
1878 | + } |
1879 | + #endif |
1880 | + const std::string mysql_host = arg.sh.conf.get_str("host", "localhost"); |
1881 | + const int mysql_port = arg.sh.conf.get_int("mysqlport", 3306); |
1882 | + const unsigned int num = arg.sh.loop; |
1883 | + const size_t pipe = arg.sh.pipe; |
1884 | + const std::string mysql_user = arg.sh.conf.get_str("mysqluser", "root"); |
1885 | + const std::string mysql_passwd = arg.sh.conf.get_str("mysqlpass", ""); |
1886 | + const std::string mysql_dbname = arg.sh.conf.get_str("db", "hstest"); |
1887 | + const int keep_connection = arg.sh.conf.get_int("keep_connection", 1); |
1888 | + const int verbose = arg.sh.conf.get_int("verbose", 1); |
1889 | + const int use_handler = arg.sh.conf.get_int("handler", 0); |
1890 | + int connected = 0; |
1891 | + unsigned int k = 0; |
1892 | + string_buffer buf; |
1893 | + for (unsigned int i = 0; i < num; ++i) { |
1894 | + const int flags = 0; |
1895 | + if (connected == 0 && !mysql_real_connect(db, mysql_host.c_str(), |
1896 | + mysql_user.c_str(), mysql_user.empty() ? 0 : mysql_passwd.c_str(), |
1897 | + mysql_dbname.c_str(), mysql_port, 0, flags)) { |
1898 | + err = "failed to connect: " + std::string(mysql_error(db)); |
1899 | + if (verbose >= 1) { |
1900 | + fprintf(stderr, "e=[%s]\n", err.c_str()); |
1901 | + } |
1902 | + ++err_cnt; |
1903 | + return; |
1904 | + } |
1905 | + int r = 0; |
1906 | + if (connected == 0 && use_handler) { |
1907 | + const char *const q = "handler hstest open"; |
1908 | + r = mysql_real_query(db, q, strlen(q)); |
1909 | + if (r != 0) { |
1910 | + err = 1; |
1911 | + } |
1912 | + } |
1913 | + connected = 1; |
1914 | + std::string result_str; |
1915 | + unsigned int err = 0; |
1916 | + unsigned int num_flds = 0, num_affected_rows = 0; |
1917 | + int got_data = 0; |
1918 | + buf.clear(); |
1919 | + buf.append_literal("insert into hstest values "); |
1920 | + for (size_t j = 0; j < pipe; ++j) { |
1921 | + const unsigned int v = ~k; |
1922 | + if (j != 0) { |
1923 | + buf.append_literal(","); |
1924 | + } |
1925 | + char *wp = buf.make_space(64); |
1926 | + int buf_query_len = snprintf(wp, 64, "('k%u', 'v%u')", k, v); |
1927 | + buf.space_wrote(buf_query_len); |
1928 | + ++k; |
1929 | + } |
1930 | + if (r == 0) { |
1931 | + r = mysql_real_query(db, buf.begin(), buf.size()); |
1932 | + ++query_cnt; |
1933 | + } |
1934 | + if (r != 0) { |
1935 | + err = 1; |
1936 | + } else { |
1937 | + auto_mysql_res res(db); |
1938 | + if (res != 0) { |
1939 | + if (verbose >= 0) { |
1940 | + num_flds = mysql_num_fields(res); |
1941 | + MYSQL_ROW row = 0; |
1942 | + while ((row = mysql_fetch_row(res)) != 0) { |
1943 | + got_data = 1; |
1944 | + unsigned long *const lengths = mysql_fetch_lengths(res); |
1945 | + if (verbose >= 2) { |
1946 | + for (unsigned int i = 0; i < num_flds; ++i) { |
1947 | + if (!result_str.empty()) { |
1948 | + result_str += " "; |
1949 | + } |
1950 | + result_str += std::string(row[i], lengths[i]); |
1951 | + } |
1952 | + } |
1953 | + } |
1954 | + } |
1955 | + } else { |
1956 | + if (mysql_field_count(db) == 0) { |
1957 | + num_affected_rows = mysql_affected_rows(db); |
1958 | + } else { |
1959 | + err = 1; |
1960 | + } |
1961 | + } |
1962 | + } |
1963 | + if (verbose >= 2 || (verbose >= 1 && err != 0)) { |
1964 | + if (err) { |
1965 | + ++err_cnt; |
1966 | + const char *const errstr = mysql_error(db); |
1967 | + fprintf(stderr, "e=[%s] a=%u q=[%s]\n", errstr, |
1968 | + num_affected_rows, std::string(buf.begin(), buf.size()).c_str()); |
1969 | + } else { |
1970 | + fprintf(stderr, "a=%u q=[%s] r=[%s]\n", num_affected_rows, |
1971 | + std::string(buf.begin(), buf.size()).c_str(), |
1972 | + result_str.c_str()); |
1973 | + } |
1974 | + } |
1975 | + if (err == 0) { |
1976 | + ++io_success_count; |
1977 | + if (num_affected_rows > 0 || got_data > 0) { |
1978 | + ++op_success_count; |
1979 | + } |
1980 | + arg.sh.increment_count(pipe); |
1981 | + } |
1982 | + if (!keep_connection) { |
1983 | + db.reset(); |
1984 | + connected = 0; |
1985 | + } |
1986 | + } |
1987 | + if (verbose >= 1) { |
1988 | + fprintf(stderr, "thread finished (error_count=%llu)\n", err_cnt); |
1989 | + } |
1990 | +} |
1991 | + |
1992 | +void |
1993 | +hstest_thread::test_21(int num) |
1994 | +{ |
1995 | + /* fsync test */ |
1996 | + unsigned int id = arg.id; |
1997 | + std::string err; |
1998 | + #if 0 |
1999 | + if (socket_connect(fd, arg.sh.arg, err) != 0) { |
2000 | + fprintf(stderr, "connect: %d %s\n", errno, strerror(errno)); |
2001 | + return; |
2002 | + } |
2003 | + #endif |
2004 | + auto_file logfd; |
2005 | + char fname[1024]; |
2006 | + snprintf(fname, sizeof(fname), "synctest_%u", id); |
2007 | + int open_flags = O_WRONLY | O_CREAT | O_TRUNC | O_APPEND; |
2008 | + logfd.reset(open(fname, open_flags, 0644)); |
2009 | + if (logfd.get() < 0) { |
2010 | + fprintf(stderr, "open: %s: %d %s\n", fname, errno, strerror(errno)); |
2011 | + return; |
2012 | + } |
2013 | + char buf[1024]; |
2014 | + unsigned long long count = 0; |
2015 | + while (true) { |
2016 | + snprintf(buf, sizeof(buf), "%u %llu\n", id, count); |
2017 | + const size_t len = strlen(buf); |
2018 | + if (write(logfd.get(), buf, len) != (ssize_t)len) { |
2019 | + fprintf(stderr, "write: %s: %d %s\n", fname, errno, strerror(errno)); |
2020 | + return; |
2021 | + } |
2022 | + #if 0 |
2023 | + if (write(fd.get(), buf, len) != (ssize_t)len) { |
2024 | + fprintf(stderr, "write(sock): %d %s\n", errno, strerror(errno)); |
2025 | + return; |
2026 | + } |
2027 | + #endif |
2028 | + if (fdatasync(logfd.get()) != 0) { |
2029 | + fprintf(stderr, "fsync: %s: %d %s\n", fname, errno, strerror(errno)); |
2030 | + return; |
2031 | + } |
2032 | + ++count; |
2033 | + ++op_success_count; |
2034 | + arg.sh.increment_count(); |
2035 | + } |
2036 | +} |
2037 | + |
2038 | +void |
2039 | +hstest_thread::test_22(int num) |
2040 | +{ |
2041 | + /* dd if=/dev/zero of=dummy.dat bs=1024M count=100 */ |
2042 | + unsigned int id = arg.id; |
2043 | + std::string err; |
2044 | + auto_file filefd; |
2045 | + char fname[1024]; |
2046 | + snprintf(fname, sizeof(fname), "dummy.dat"); |
2047 | + int open_flags = O_RDONLY | O_DIRECT; |
2048 | + filefd.reset(open(fname, open_flags, 0644)); |
2049 | + if (filefd.get() < 0) { |
2050 | + fprintf(stderr, "open: %s: %d %s\n", fname, errno, strerror(errno)); |
2051 | + return; |
2052 | + } |
2053 | + char buf_x[4096 * 2]; |
2054 | + char *const buf = (char *)(size_t(buf_x + 4096) / 4096 * 4096); |
2055 | + unsigned long long count = 0; |
2056 | + drand48_data randbuf; |
2057 | + unsigned long long seed = time(0); |
2058 | + seed *= 10; |
2059 | + seed += id; |
2060 | + srand48_r(seed, &randbuf); |
2061 | + for (unsigned int i = 0; i < arg.sh.loop; ++i) { |
2062 | + double kf = 0; |
2063 | + drand48_r(&randbuf, &kf); |
2064 | + kf *= (209715200 / 1); |
2065 | + // fprintf(stderr, "v=%f\n", kf); |
2066 | + off_t v = static_cast<off_t>(kf); |
2067 | + v %= (209715200 / 1); |
2068 | + v *= (512 * 1); |
2069 | + const double tm1 = gettimeofday_double(); |
2070 | + const ssize_t r = pread(filefd.get(), buf, (512 * 1), v); |
2071 | + const double tm2 = gettimeofday_double(); |
2072 | + if (r < 0) { |
2073 | + fprintf(stderr, "pread: %s: %d %s\n", fname, errno, strerror(errno)); |
2074 | + return; |
2075 | + } |
2076 | + ++count; |
2077 | + ++op_success_count; |
2078 | + arg.sh.increment_count(); |
2079 | + set_timing(tm2 - tm1); |
2080 | + } |
2081 | +} |
2082 | + |
2083 | +void |
2084 | +hstest_thread::operator ()() |
2085 | +{ |
2086 | + if (arg.watch_flag) { |
2087 | + return test_watch(); |
2088 | + } |
2089 | + int test_num = arg.sh.conf.get_int("test", 1); |
2090 | + if (test_num == 1) { |
2091 | + test_1(); |
2092 | + } else if (test_num == 2 || test_num == 3) { |
2093 | + test_2_3(test_num); |
2094 | + } else if (test_num == 4 || test_num == 5) { |
2095 | + test_4_5(test_num); |
2096 | + } else if (test_num == 6) { |
2097 | + test_6(test_num); |
2098 | + } else if (test_num == 7) { |
2099 | + test_7(test_num); |
2100 | + } else if (test_num == 8) { |
2101 | + test_8(test_num); |
2102 | + } else if (test_num == 9) { |
2103 | + test_9(test_num); |
2104 | + } else if (test_num == 10) { |
2105 | + test_10(test_num); |
2106 | + } else if (test_num == 11) { |
2107 | + test_11(test_num); |
2108 | + } else if (test_num == 12) { |
2109 | + test_12(test_num); |
2110 | + } else if (test_num == 21) { |
2111 | + test_21(test_num); |
2112 | + } else if (test_num == 22) { |
2113 | + test_22(test_num); |
2114 | + } |
2115 | + const int halt = arg.sh.conf.get_int("halt", 0); |
2116 | + if (halt) { |
2117 | + fprintf(stderr, "thread halted\n"); |
2118 | + while (true) { |
2119 | + sleep(100000); |
2120 | + } |
2121 | + } |
2122 | + fprintf(stderr, "thread finished\n"); |
2123 | +} |
2124 | + |
2125 | +int |
2126 | +hstest_main(int argc, char **argv) |
2127 | +{ |
2128 | + ignore_sigpipe(); |
2129 | + hstest_shared shared; |
2130 | + parse_args(argc, argv, shared.conf); |
2131 | + shared.conf["port"] = shared.conf["hsport"]; |
2132 | + shared.arg.set(shared.conf); |
2133 | + shared.loop = shared.conf.get_int("num", 1000); |
2134 | + shared.pipe = shared.conf.get_int("pipe", 1); |
2135 | + shared.verbose = shared.conf.get_int("verbose", 1); |
2136 | + const int tablesize = shared.conf.get_int("tablesize", 0); |
2137 | + std::vector<char> keygen(tablesize); |
2138 | + shared.keygen = &keygen[0]; |
2139 | + shared.keygen_size = tablesize; |
2140 | + shared.usleep = shared.conf.get_int("usleep", 0); |
2141 | + shared.dump = shared.conf.get_int("dump", 0); |
2142 | + shared.num_threads = shared.conf.get_int("num_threads", 10); |
2143 | + shared.wait_conn = shared.conf.get_int("wait_conn", 0); |
2144 | + const std::string op = shared.conf.get_str("op", "G"); |
2145 | + if (op.size() > 0) { |
2146 | + shared.op = op[0]; |
2147 | + } |
2148 | + #if 0 |
2149 | + const int localdb_flag = shared.conf.get_int("local", 0); |
2150 | + if (localdb_flag) { |
2151 | + shared.localdb = database_i::create(shared.conf); |
2152 | + } |
2153 | + #endif |
2154 | + const int num_thrs = shared.num_threads; |
2155 | + typedef thread<hstest_thread> thread_type; |
2156 | + typedef std::auto_ptr<thread_type> thread_ptr; |
2157 | + typedef auto_ptrcontainer< std::vector<thread_type *> > thrs_type; |
2158 | + thrs_type thrs; |
2159 | + for (int i = 0; i < num_thrs; ++i) { |
2160 | + const hstest_thread::arg_type arg(i, shared, false); |
2161 | + thread_ptr thr(new thread<hstest_thread>(arg)); |
2162 | + thrs.push_back_ptr(thr); |
2163 | + } |
2164 | + for (size_t i = 0; i < thrs.size(); ++i) { |
2165 | + thrs[i]->start(); |
2166 | + } |
2167 | + thread_ptr watch_thread; |
2168 | + const int timelimit = shared.conf.get_int("timelimit", 0); |
2169 | + { |
2170 | + const hstest_thread::arg_type arg(0, shared, true); |
2171 | + watch_thread = thread_ptr(new thread<hstest_thread>(arg)); |
2172 | + watch_thread->start(); |
2173 | + } |
2174 | + size_t iocnt = 0, opcnt = 0; |
2175 | + double respmin = 999999, respmax = 0; |
2176 | + double respsum = 0; |
2177 | + if (timelimit != 0) { |
2178 | + watch_thread->join(); |
2179 | + } |
2180 | + for (size_t i = 0; i < thrs.size(); ++i) { |
2181 | + if (timelimit == 0) { |
2182 | + thrs[i]->join(); |
2183 | + } |
2184 | + iocnt += (*thrs[i])->io_success_count; |
2185 | + opcnt += (*thrs[i])->op_success_count; |
2186 | + respmin = std::min(respmin, (*thrs[i])->response_min); |
2187 | + respmax = std::max(respmax, (*thrs[i])->response_max); |
2188 | + respsum += (*thrs[i])->response_sum; |
2189 | + } |
2190 | + fprintf(stderr, "io_success_count=%zu op_success_count=%zu\n", iocnt, opcnt); |
2191 | + fprintf(stderr, "respmin=%f respmax=%f respsum=%f respavg=%f\n", |
2192 | + respmin, respmax, respsum, respsum / opcnt); |
2193 | + size_t keycnt = 0; |
2194 | + for (size_t i = 0; i < keygen.size(); ++i) { |
2195 | + if (keygen[i]) { |
2196 | + ++keycnt; |
2197 | + } |
2198 | + } |
2199 | + fprintf(stderr, "keycnt=%zu\n", keycnt); |
2200 | + _exit(0); |
2201 | + return 0; |
2202 | +} |
2203 | + |
2204 | +}; |
2205 | + |
2206 | +int |
2207 | +main(int argc, char **argv) |
2208 | +{ |
2209 | + return dena::hstest_main(argc, argv); |
2210 | +} |
2211 | + |
2212 | |
2213 | === added file 'HandlerSocket-Plugin-for-MySQL/client/hstest.pl' |
2214 | --- HandlerSocket-Plugin-for-MySQL/client/hstest.pl 1970-01-01 00:00:00 +0000 |
2215 | +++ HandlerSocket-Plugin-for-MySQL/client/hstest.pl 2011-04-12 04:16:24 +0000 |
2216 | @@ -0,0 +1,228 @@ |
2217 | +#!/usr/bin/perl |
2218 | + |
2219 | +# vim:sw=8:ai:ts=8 |
2220 | + |
2221 | +use strict; |
2222 | +use warnings; |
2223 | + |
2224 | +use DBI; |
2225 | +use Net::HandlerSocket; |
2226 | + |
2227 | +my %conf = (); |
2228 | +for my $i (@ARGV) { |
2229 | + my ($k, $v) = split(/=/, $i); |
2230 | + $conf{$k} = $v; |
2231 | +} |
2232 | + |
2233 | +my $verbose = get_conf("verbose", 0); |
2234 | +my $actions_str = get_conf("actions", "hsread"); |
2235 | +my $tablesize = get_conf("tablesize", 10000); |
2236 | +my $db = get_conf("db", "hstest"); |
2237 | +my $table = get_conf("table", "hstest_table1"); |
2238 | +my $engine = get_conf("engine", "innodb"); |
2239 | +my $host = get_conf("host", "localhost"); |
2240 | +my $mysqlport = get_conf("mysqlport", 3306); |
2241 | +my $mysqluser = get_conf("mysqluser", "root"); |
2242 | +my $mysqlpass = get_conf("mysqlpass", ""); |
2243 | +my $hsport = get_conf("hsport", 9999); |
2244 | +my $loop = get_conf("loop", 10000); |
2245 | +my $op = get_conf("op", "="); |
2246 | +my $ssps = get_conf("ssps", 0); |
2247 | +my $num_moreflds = get_conf("moreflds", 0); |
2248 | +my $moreflds_prefix = get_conf("moreflds_prefix", "column0123456789_"); |
2249 | +my $keytype = get_conf("keytype", "varchar(32)"); |
2250 | +my $file = get_conf("file", undef); |
2251 | + |
2252 | +my $dsn = "DBI:mysql:database=;host=$host;port=$mysqlport" |
2253 | + . ";mysql_server_prepare=$ssps"; |
2254 | +my $dbh = DBI->connect($dsn, $mysqluser, $mysqlpass, { RaiseError => 1 }); |
2255 | +my $hsargs = { 'host' => $host, 'port' => $hsport }; |
2256 | +my $cli = new Net::HandlerSocket($hsargs); |
2257 | + |
2258 | +my @actions = split(/,/, $actions_str); |
2259 | +for my $action (@actions) { |
2260 | + if ($action eq "table") { |
2261 | + print("TABLE $db.$table\n"); |
2262 | + $dbh->do("drop database if exists $db"); |
2263 | + $dbh->do("create database $db"); |
2264 | + $dbh->do("use $db"); |
2265 | + my $moreflds = get_createtbl_moreflds_str(); |
2266 | + $dbh->do( |
2267 | + "create table $table (" . |
2268 | + "k $keytype primary key" . |
2269 | + ",v varchar(32) not null" . |
2270 | + $moreflds . |
2271 | + ") character set utf8 collate utf8_bin " . |
2272 | + "engine = $engine"); |
2273 | + } elsif ($action eq "insert") { |
2274 | + print("INSERT $db.$table tablesize=$tablesize\n"); |
2275 | + $dbh->do("use $db"); |
2276 | + my $moreflds = get_insert_moreflds_str(); |
2277 | + for (my $i = 0; $i < $tablesize; $i += 100) { |
2278 | + my $qstr = "insert into $db.$table values"; |
2279 | + for (my $j = 0; $j < 100; ++$j) { |
2280 | + if ($j != 0) { |
2281 | + $qstr .= ","; |
2282 | + } |
2283 | + my $k = "" . ($i + $j); |
2284 | + my $v = "v" . int(rand(1000)) . ($i + $j); |
2285 | + $qstr .= "('$k', '$v'"; |
2286 | + for (my $j = 0; $j < $num_moreflds; ++$j) { |
2287 | + $qstr .= ",'$j'"; |
2288 | + } |
2289 | + $qstr .= ")"; |
2290 | + } |
2291 | + $dbh->do($qstr); |
2292 | + print "$i/$tablesize\n" if $i % 1000 == 0; |
2293 | + } |
2294 | + } elsif ($action eq "read") { |
2295 | + print("READ $db.$table op=$op loop=$loop\n"); |
2296 | + $dbh->do("use $db"); |
2297 | + my $moreflds = get_select_moreflds_str(); |
2298 | + my $sth = $dbh->prepare( |
2299 | + "select k,v$moreflds from $db.$table where k = ?"); |
2300 | + for (my $i = 0; $i < $loop; ++$i) { |
2301 | + my $k = "" . int(rand($tablesize)); |
2302 | + # print "k=$k\n"; |
2303 | + $sth->execute($k); |
2304 | + if ($verbose >= 10) { |
2305 | + print "RET:"; |
2306 | + while (my $ref = $sth->fetchrow_arrayref()) { |
2307 | + my $rk = $ref->[0]; |
2308 | + my $rv = $ref->[1]; |
2309 | + print " $rk $rv"; |
2310 | + } |
2311 | + print "\n"; |
2312 | + } |
2313 | + print "$i/$loop\n" if $i % 1000 == 0; |
2314 | + } |
2315 | + } elsif ($action eq "hsinsert") { |
2316 | + print("HSINSERT $db.$table tablesize=$tablesize\n"); |
2317 | + $cli->open_index(1, $db, $table, '', 'k,v'); |
2318 | + for (my $i = 0; $i < $tablesize; ++$i) { |
2319 | + my $k = "" . $i; |
2320 | + my $v = "v" . int(rand(1000)) . $i; |
2321 | + my $r = $cli->execute_insert(1, [ $k, $v ]); |
2322 | + if ($r->[0] != 0) { |
2323 | + die; |
2324 | + } |
2325 | + print "$i/$tablesize\n" if $i % 1000 == 0; |
2326 | + } |
2327 | + } elsif ($action eq "hsread") { |
2328 | + print("HSREAD $db.$table op=$op loop=$loop\n"); |
2329 | + my $moreflds = get_select_moreflds_str(); |
2330 | + $cli->open_index(1, $db, $table, '', "k,v$moreflds"); |
2331 | + for (my $i = 0; $i < $loop; ++$i) { |
2332 | + my $k = "" . int(rand($tablesize)); |
2333 | + # print "k=$k\n"; |
2334 | + my $r = $cli->execute_find(1, $op, [ $k ], 1, 0); |
2335 | + if ($verbose >= 10) { |
2336 | + my $len = scalar(@{$r}); |
2337 | + print "LEN=$len"; |
2338 | + for my $e (@{$r}) { |
2339 | + print " [$e]"; |
2340 | + } |
2341 | + print "\n"; |
2342 | + } |
2343 | + print "$i/$loop\n" if $i % 1000 == 0; |
2344 | + } |
2345 | + } elsif ($action eq "hsupdate") { |
2346 | + my $vbase = "v" . int(rand(1000)); |
2347 | + print("HSUPDATE $db.$table op=$op loop=$loop vbase=$vbase\n"); |
2348 | + $cli->open_index(1, $db, $table, '', 'v'); |
2349 | + for (my $i = 0; $i < $loop; ++$i) { |
2350 | + my $k = "" . int(rand($tablesize)); |
2351 | + my $v = $vbase . $i; |
2352 | + print "k=$k v=$v\n"; |
2353 | + my $r = $cli->execute_update(1, $op, [ $k ], 1, 0, |
2354 | + [ $v ]); |
2355 | + if ($verbose >= 10) { |
2356 | + print "UP k=$k v=$v\n"; |
2357 | + } |
2358 | + print "$i/$loop\n" if $i % 1000 == 0; |
2359 | + } |
2360 | + } elsif ($action eq "hsdelete") { |
2361 | + print("HSDELETE $db.$table op=$op loop=$loop\n"); |
2362 | + $cli->open_index(1, $db, $table, '', ''); |
2363 | + for (my $i = 0; $i < $loop; ++$i) { |
2364 | + my $k = "" . int(rand($tablesize)); |
2365 | + print "k=$k\n"; |
2366 | + my $r = $cli->execute_delete(1, $op, [ $k ], 1, 0); |
2367 | + if ($verbose >= 10) { |
2368 | + print "DEL k=$k\n"; |
2369 | + } |
2370 | + print "$i/$loop\n" if $i % 1000 == 0; |
2371 | + } |
2372 | + } elsif ($action eq "verify") { |
2373 | + verify_do(); |
2374 | + } |
2375 | +} |
2376 | + |
2377 | +sub verify_do { |
2378 | + my ($fail_cnt, $ok_cnt) = (0, 0); |
2379 | + my $sth = $dbh->prepare("select v from $db.$table where k = ?"); |
2380 | + use FileHandle; |
2381 | + my $fh = new FileHandle($file, "r"); |
2382 | + while (my $line = <$fh>) { |
2383 | + chomp($line); |
2384 | + my @vec = split(/\t/, $line); |
2385 | + my $k = $vec[3]; |
2386 | + my $v = $vec[7]; |
2387 | + next if (!defined($k) || !defined($v)); |
2388 | + # print "$k $v\n"; |
2389 | + $sth->execute($k); |
2390 | + my $aref = $sth->fetchrow_arrayref(); |
2391 | + if (!defined($aref)) { |
2392 | + print "FAILED: $k notfound\n"; |
2393 | + ++$fail_cnt; |
2394 | + } else { |
2395 | + my $gv = $aref->[0]; |
2396 | + if ($gv ne $v) { |
2397 | + print "FAILED: $k got=$gv expected=$v\n"; |
2398 | + ++$fail_cnt; |
2399 | + } else { |
2400 | + print "OK: $k $v $gv\n" if $verbose >= 10; |
2401 | + ++$ok_cnt; |
2402 | + } |
2403 | + } |
2404 | + } |
2405 | + print "OK=$ok_cnt FAIL=$fail_cnt\n"; |
2406 | +} |
2407 | + |
2408 | +sub get_conf { |
2409 | + my ($key, $def) = @_; |
2410 | + my $val = $conf{$key}; |
2411 | + if ($val) { |
2412 | + print "$key=$val\n"; |
2413 | + } else { |
2414 | + $val = $def; |
2415 | + $def ||= ''; |
2416 | + print "$key=$def(default)\n"; |
2417 | + } |
2418 | + return $val; |
2419 | +} |
2420 | + |
2421 | +sub get_createtbl_moreflds_str { |
2422 | + my $s = ""; |
2423 | + for (my $j = 0; $j < $num_moreflds; ++$j) { |
2424 | + $s .= ",$moreflds_prefix$j varchar(30)"; |
2425 | + } |
2426 | + return $s; |
2427 | +} |
2428 | + |
2429 | +sub get_select_moreflds_str { |
2430 | + my $s = ""; |
2431 | + for (my $i = 0; $i < $num_moreflds; ++$i) { |
2432 | + $s .= ",$moreflds_prefix$i"; |
2433 | + } |
2434 | + return $s; |
2435 | +} |
2436 | + |
2437 | +sub get_insert_moreflds_str { |
2438 | + my $s = ""; |
2439 | + for (my $i = 0; $i < $num_moreflds; ++$i) { |
2440 | + $s .= ",?"; |
2441 | + } |
2442 | + return $s; |
2443 | +} |
2444 | + |
2445 | |
2446 | === added file 'HandlerSocket-Plugin-for-MySQL/client/hstest_hs.sh' |
2447 | --- HandlerSocket-Plugin-for-MySQL/client/hstest_hs.sh 1970-01-01 00:00:00 +0000 |
2448 | +++ HandlerSocket-Plugin-for-MySQL/client/hstest_hs.sh 2011-04-12 04:16:24 +0000 |
2449 | @@ -0,0 +1,4 @@ |
2450 | +#!/bin/bash |
2451 | + |
2452 | +exec ./hstest test=10 tablesize=10000 host=localhost hsport=9998 num=10000000 \ |
2453 | + num_threads=100 timelimit=10 $@ |
2454 | |
2455 | === added file 'HandlerSocket-Plugin-for-MySQL/client/hstest_hs_more50.sh' |
2456 | --- HandlerSocket-Plugin-for-MySQL/client/hstest_hs_more50.sh 1970-01-01 00:00:00 +0000 |
2457 | +++ HandlerSocket-Plugin-for-MySQL/client/hstest_hs_more50.sh 2011-04-12 04:16:24 +0000 |
2458 | @@ -0,0 +1,4 @@ |
2459 | +#!/bin/bash |
2460 | + |
2461 | +exec ./hstest test=10 key_mask=9999 host=localhost port=9998 num=10000000 \ |
2462 | + num_threads=100 timelimit=10 moreflds=50 $@ |
2463 | |
2464 | === added file 'HandlerSocket-Plugin-for-MySQL/client/hstest_md.sh' |
2465 | --- HandlerSocket-Plugin-for-MySQL/client/hstest_md.sh 1970-01-01 00:00:00 +0000 |
2466 | +++ HandlerSocket-Plugin-for-MySQL/client/hstest_md.sh 2011-04-12 04:16:24 +0000 |
2467 | @@ -0,0 +1,7 @@ |
2468 | +#!/bin/bash |
2469 | + |
2470 | +./hstest test=7 key_mask=9999 host=localhost port=11211 num=10000 \ |
2471 | + num_threads=10 timelimit=10 op=R $@ |
2472 | +./hstest test=7 key_mask=9999 host=localhost port=11211 num=1000000 \ |
2473 | + num_threads=100 timelimit=10 op=G $@ |
2474 | + |
2475 | |
2476 | === added file 'HandlerSocket-Plugin-for-MySQL/client/hstest_my.sh' |
2477 | --- HandlerSocket-Plugin-for-MySQL/client/hstest_my.sh 1970-01-01 00:00:00 +0000 |
2478 | +++ HandlerSocket-Plugin-for-MySQL/client/hstest_my.sh 2011-04-12 04:16:24 +0000 |
2479 | @@ -0,0 +1,3 @@ |
2480 | +#!/bin/bash |
2481 | +exec ./hstest test=9 tablesize=9999 host=localhost mysqlport=3306 num=1000000 \ |
2482 | + num_threads=100 verbose=1 timelimit=10 $@ |
2483 | |
2484 | === added file 'HandlerSocket-Plugin-for-MySQL/client/hstest_my_more50.sh' |
2485 | --- HandlerSocket-Plugin-for-MySQL/client/hstest_my_more50.sh 1970-01-01 00:00:00 +0000 |
2486 | +++ HandlerSocket-Plugin-for-MySQL/client/hstest_my_more50.sh 2011-04-12 04:16:24 +0000 |
2487 | @@ -0,0 +1,3 @@ |
2488 | +#!/bin/bash |
2489 | +exec ./hstest test=9 key_mask=9999 host=localhost port=3306 num=1000000 \ |
2490 | + num_threads=100 verbose=1 timelimit=10 moreflds=50 $@ |
2491 | |
2492 | === added file 'HandlerSocket-Plugin-for-MySQL/configure.ac' |
2493 | --- HandlerSocket-Plugin-for-MySQL/configure.ac 1970-01-01 00:00:00 +0000 |
2494 | +++ HandlerSocket-Plugin-for-MySQL/configure.ac 2011-04-12 04:16:24 +0000 |
2495 | @@ -0,0 +1,134 @@ |
2496 | +# -*- Autoconf -*- |
2497 | +# Process this file with autoconf to produce a configure script. |
2498 | + |
2499 | +#AC_PREREQ([2.63b]) |
2500 | +AC_INIT([handlersocket-plugin], [1.0.6], [https://github.com/ahiguti/HandlerSocket-Plugin-for-MySQL/issues]) |
2501 | +AC_CONFIG_HEADERS([config.h]) |
2502 | +AM_INIT_AUTOMAKE([-Wall -Werror foreign]) |
2503 | +AC_CONFIG_SRCDIR([libhsclient/fatal.cpp]) |
2504 | +AC_CONFIG_MACRO_DIR([m4]) |
2505 | + |
2506 | +AC_PROG_CC |
2507 | +AC_PROG_CXX |
2508 | +AC_PROG_CPP |
2509 | +AC_PROG_LIBTOOL |
2510 | + |
2511 | +AC_DEFUN([CONFIG_OPTION_MYSQL],[ |
2512 | + AC_MSG_CHECKING([mysql source]) |
2513 | + |
2514 | + MYSQL_SOURCE_VERSION= |
2515 | + MYSQL_INC= |
2516 | + ac_mysql_source_dir= |
2517 | + AC_ARG_WITH([mysql-source], |
2518 | + [AS_HELP_STRING([--with-mysql-source=PATH], [MySQL source directory PATH])], |
2519 | + [ |
2520 | + ac_mysql_source_dir=`cd $withval && pwd` |
2521 | + if test -f "$ac_mysql_source_dir/sql/handler.h" ; then |
2522 | + MYSQL_INC="-I$ac_mysql_source_dir/sql" |
2523 | + MYSQL_INC="$MYSQL_INC -I$ac_mysql_source_dir/include" |
2524 | + MYSQL_INC="$MYSQL_INC -I$ac_mysql_source_dir/regex" |
2525 | + MYSQL_INC="$MYSQL_INC -I$ac_mysql_source_dir" |
2526 | + AC_SUBST(MYSQL_INC) |
2527 | + if test -f "$ac_mysql_source_dir/VERSION"; then |
2528 | + source "$ac_mysql_source_dir/VERSION" |
2529 | + MYSQL_SOURCE_VERSION="$MYSQL_VERSION_MAJOR.$MYSQL_VERSION_MINOR.$MYSQL_VERSION_PATCH" |
2530 | + else |
2531 | + if test -f "$ac_mysql_source_dir/configure.in"; then |
2532 | + 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|"` |
2533 | + else |
2534 | + AC_MSG_ERROR([invalid MySQL source directory: $ac_mysql_source_dir]) |
2535 | + fi |
2536 | + fi |
2537 | + AC_MSG_RESULT([yes: Using $ac_mysql_source_dir, version $MYSQL_SOURCE_VERSION]) |
2538 | + else |
2539 | + AC_MSG_ERROR([invalid MySQL source directory: $ac_mysql_source_dir]) |
2540 | + fi |
2541 | + ], |
2542 | + [AC_MSG_ERROR([--with-mysql-source=PATH is required for standalone build])] |
2543 | + ) |
2544 | + |
2545 | + MYSQL_BIN_VERSION= |
2546 | + ac_mysql_config= |
2547 | + AC_ARG_WITH([mysql-bindir], |
2548 | + [AS_HELP_STRING([--with-mysql-bindir=PATH], [MySQL binary directory PATH. This should be the directory where mysql_config is located.])], |
2549 | + [ |
2550 | + mysql_bin_dir=`cd $withval 2> /dev/null && pwd || echo ""` |
2551 | + ac_mysql_config="$mysql_bin_dir/mysql_config" |
2552 | + ], |
2553 | + [ |
2554 | + AC_PATH_PROG([ac_mysql_config], [mysql_config]) |
2555 | + ] |
2556 | + ) |
2557 | + |
2558 | + AC_MSG_CHECKING([mysql binary]) |
2559 | + if test ! -x "$ac_mysql_config" ; then |
2560 | + AC_MSG_ERROR([mysql_config not found! You have to specify the directory where mysql_config resides to --with-mysql-bindir=PATH.]) |
2561 | + fi |
2562 | + |
2563 | + MYSQL_CFLAGS_ADD=`"$ac_mysql_config" --cflags` |
2564 | + MYSQL_CFLAGS="$MYSQL_CFLAGS $MYSQL_CFLAGS_ADD -DFORCE_DBUG_OFF" |
2565 | + # FIXME |
2566 | + AC_SUBST(MYSQL_CFLAGS) |
2567 | + |
2568 | + MYSQL_BIN_VERSION=`"$ac_mysql_config" --version` |
2569 | + AC_MSG_RESULT([yes: Using $ac_mysql_config, version $MYSQL_BIN_VERSION]) |
2570 | + |
2571 | + MYSQL_LIB=`"$ac_mysql_config" --libs_r` |
2572 | + LIB_DIR=`echo $MYSQL_LIB | sed -e "s|.*-L/|/|" | sed -e "s| .*||"` |
2573 | + # FIXME |
2574 | + if test a`basename "$LIB_DIR"` = amysql ; then |
2575 | + MYSQL_LIB="-L`dirname $LIB_DIR` $MYSQL_LIB" |
2576 | + # FIXME |
2577 | + fi |
2578 | + AC_SUBST(MYSQL_LIB) |
2579 | + |
2580 | + if test a$MYSQL_SOURCE_VERSION != a$MYSQL_BIN_VERSION ; then |
2581 | + AC_MSG_ERROR([MySQL source version does not match MySQL binary version]) |
2582 | + fi |
2583 | + |
2584 | + AC_MSG_CHECKING([mysql plugin dir]) |
2585 | + ac_mysql_plugin_dir= |
2586 | + AC_ARG_WITH([mysql-plugindir], |
2587 | + [AS_HELP_STRING([--with-mysql-plugindir=PATH], [MySQL plugin directory where handlersocket.so to be copied])], |
2588 | + [ |
2589 | + ac_mysql_plugin_dir=`cd $withval && pwd` |
2590 | + if test -d "$ac_mysql_plugin_dir/" ; then |
2591 | + PLUGIN_DIR="$ac_mysql_plugin_dir" |
2592 | + AC_SUBST(PLUGIN_DIR) |
2593 | + AC_MSG_RESULT([yes: Using $ac_mysql_plugin_dir]) |
2594 | + else |
2595 | + AC_MSG_ERROR([invalid MySQL plugin directory : $ac_mysql_plugin_dir]) |
2596 | + fi |
2597 | + ], |
2598 | + [ |
2599 | + LIB_DIR_TMP=`"$ac_mysql_config" --plugindir` |
2600 | + if test ! -d "$LIB_DIR_TMP"; then |
2601 | + LIB_DIR_TMP=`"$ac_mysql_config" --libs_r | sed -e "s|.*-L/|/|" | sed -e "s| .*||"`/plugin |
2602 | + # FIXME |
2603 | + fi |
2604 | + ac_mysql_plugin_dir=$LIB_DIR_TMP |
2605 | + PLUGIN_DIR="$ac_mysql_plugin_dir" |
2606 | + AC_SUBST(PLUGIN_DIR) |
2607 | + AC_MSG_RESULT([--with-mysql-plugindir was not set. Using $ac_mysql_plugin_dir]) |
2608 | + ] |
2609 | + ) |
2610 | +]) |
2611 | + |
2612 | +HANDLERSOCKET_SUBDIRS="libhsclient" |
2613 | +AC_ARG_ENABLE(handlersocket_server, |
2614 | + [ --enable-handlersocket-server build HandlerSocket plugin (defalut=yes)]) |
2615 | +if test "$enable_handlersocket_server" != "no"; then |
2616 | + CONFIG_OPTION_MYSQL |
2617 | + HANDLERSOCKET_SUBDIRS="libhsclient handlersocket client" |
2618 | +fi |
2619 | +AC_SUBST(HANDLERSOCKET_SUBDIRS) |
2620 | + |
2621 | +CFLAGS="$CFLAGS -Werror" |
2622 | +CXXFLAGS="$CXXFLAGS -Wall -g -fno-rtti -fno-exceptions -fPIC -DPIC" |
2623 | + |
2624 | +AC_CONFIG_FILES([Makefile |
2625 | + handlersocket/Makefile |
2626 | + libhsclient/Makefile |
2627 | + client/Makefile]) |
2628 | + |
2629 | +AC_OUTPUT |
2630 | |
2631 | === added directory 'HandlerSocket-Plugin-for-MySQL/docs-en' |
2632 | === added file 'HandlerSocket-Plugin-for-MySQL/docs-en/about-handlersocket.en.txt' |
2633 | --- HandlerSocket-Plugin-for-MySQL/docs-en/about-handlersocket.en.txt 1970-01-01 00:00:00 +0000 |
2634 | +++ HandlerSocket-Plugin-for-MySQL/docs-en/about-handlersocket.en.txt 2011-04-12 04:16:24 +0000 |
2635 | @@ -0,0 +1,72 @@ |
2636 | + |
2637 | +----------------------------------------------------------------------------- |
2638 | +HandlerSocket plugin for MySQL |
2639 | + |
2640 | +Copyright (c) 2010 DeNA Co.,Ltd. |
2641 | +All rights reserved. |
2642 | + |
2643 | +Redistribution and use in source and binary forms, with or without |
2644 | +modification, are permitted provided that the following conditions are met: |
2645 | + |
2646 | + * Redistributions of source code must retain the above copyright |
2647 | + notice, this list of conditions and the following disclaimer. |
2648 | + * Redistributions in binary form must reproduce the above copyright |
2649 | + notice, this list of conditions and the following disclaimer in the |
2650 | + documentation and/or other materials provided with the distribution. |
2651 | + * Neither the name of DeNA Co.,Ltd. nor the names of its contributors |
2652 | + may be used to endorse or promote products derived from this software |
2653 | + without specific prior written permission. |
2654 | + |
2655 | +THIS SOFTWARE IS PROVIDED BY DeNA Co.,Ltd. "AS IS" AND ANY EXPRESS OR |
2656 | +IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF |
2657 | +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO |
2658 | +EVENT SHALL DeNA Co.,Ltd. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
2659 | +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
2660 | +PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; |
2661 | +OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, |
2662 | +WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR |
2663 | +OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF |
2664 | +ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
2665 | + |
2666 | + |
2667 | +----------------------------------------------------------------------------- |
2668 | +About HandlerSocket |
2669 | + |
2670 | +HandlerSocket is a NoSQL plugin for MySQL. It works as a daemon inside the |
2671 | +mysqld process, accept tcp connections, and execute requests from clients. |
2672 | +HandlerSocket does not support SQL queries. Instead, it supports simple CRUD |
2673 | +operations on tables. |
2674 | + |
2675 | +Because of the following reasons, HandlerSocket is much faster than the |
2676 | +mysqld/libmysql pair in some circumstances: |
2677 | + |
2678 | + - HandlerSocket manipulates data without parsing SQL, which causes less |
2679 | + CPU usage. |
2680 | + - HandlerSocket reads many requests from clients and executes their |
2681 | + requests in bulk, which causes less CPU and disk usage. |
2682 | + - HandlerSocket client/server protocol is more compact than the |
2683 | + mysql/libmysql pair, which causes less network usage. |
2684 | + |
2685 | +The current version of HandlerSocket only works with GNU/Linux. The source |
2686 | +archive of HandlerSocket includes a C++ and a Perl client libraries. |
2687 | +Here is a list of other language bindings: |
2688 | + |
2689 | + - PHP |
2690 | + http://openpear.org/package/Net_HandlerSocket |
2691 | + http://github.com/tz-lom/HSPHP |
2692 | + http://code.google.com/p/php-handlersocket/ |
2693 | + - Java |
2694 | + http://code.google.com/p/handlersocketforjava/ |
2695 | + - Python |
2696 | + https://code.launchpad.net/~songofacandy/+junk/pyhandlersocket |
2697 | + - Ruby |
2698 | + https://github.com/winebarrel/ruby-handlersocket |
2699 | + https://github.com/miyucy/handlersocket |
2700 | + - JavaScript(Node.js) |
2701 | + https://github.com/koichik/node-handlersocket |
2702 | + |
2703 | +The home of HandlerSocket is here: |
2704 | + https://github.com/ahiguti/HandlerSocket-Plugin-for-MySQL |
2705 | + |
2706 | +More documents are available in docs-en/ and docs-ja/ directories. |
2707 | + |
2708 | |
2709 | === added file 'HandlerSocket-Plugin-for-MySQL/docs-en/configuration-options.en.txt' |
2710 | --- HandlerSocket-Plugin-for-MySQL/docs-en/configuration-options.en.txt 1970-01-01 00:00:00 +0000 |
2711 | +++ HandlerSocket-Plugin-for-MySQL/docs-en/configuration-options.en.txt 2011-04-12 04:16:24 +0000 |
2712 | @@ -0,0 +1,87 @@ |
2713 | + |
2714 | +----------------------------------------------------------------- |
2715 | +handlersocket_verbose (default = 10, min = 0, max = 10000) |
2716 | + |
2717 | + Specify the logging verboseness. |
2718 | + |
2719 | +----------------------------------------------------------------- |
2720 | +handlersocket_address (default = '') |
2721 | + |
2722 | + Specify the address to bind. If empty, it binds to 0.0.0.0. |
2723 | + |
2724 | +----------------------------------------------------------------- |
2725 | +handlersocket_port (default = '9998') |
2726 | + |
2727 | + Specify the port to bind. This option is for the listener for |
2728 | + read requests. If empty, the listener is disabled. |
2729 | + |
2730 | +----------------------------------------------------------------- |
2731 | +handlersocket_port_wr (default = '9999') |
2732 | + |
2733 | + Specify the port to bind. This option is for the listener for |
2734 | + write requests. If empty, the listener is disabled. |
2735 | + |
2736 | +----------------------------------------------------------------- |
2737 | +handlersocket_epoll (default = 1, min = 0, max = 1) |
2738 | + |
2739 | + Specify whether handlersocket uses epoll for I/O multiplexing. |
2740 | + |
2741 | +----------------------------------------------------------------- |
2742 | +handlersocket_threads (default = 16, min = 1, max = 3000) |
2743 | + |
2744 | + Specify the number of handlersocket worker threads. This option |
2745 | + is for the listener for read requests. Recommended value is |
2746 | + (the number of CPU cores * 2). |
2747 | + |
2748 | +----------------------------------------------------------------- |
2749 | +handlersocket_threads_wr (default = 1, min = 1, max = 3000) |
2750 | + |
2751 | + Specify the number of handlersocket worker threads. This option |
2752 | + is for the listener for write requests. Recommended value is 1. |
2753 | + |
2754 | +----------------------------------------------------------------- |
2755 | +handlersocket_timeout (default = 300, min = 30, max = 3600) |
2756 | + |
2757 | + Specify the socket timeout in seconds. |
2758 | + |
2759 | +----------------------------------------------------------------- |
2760 | +handlersocket_backlog (default = 32768, min = 5, max = 1000000) |
2761 | + |
2762 | + Specify the length of the listen backlog. |
2763 | + |
2764 | +----------------------------------------------------------------- |
2765 | +handlersocket_sndbuf (default = 0, min = 0, max = 1677216) |
2766 | + |
2767 | + Specify the maximum socket send buffer in bytes. If 0, the |
2768 | + system-wide default value is set. |
2769 | + |
2770 | +----------------------------------------------------------------- |
2771 | +handlersocket_rcvbuf (default = 0, min = 0, max = 1677216) |
2772 | + |
2773 | + Specify the maximum socket receive buffer in bytes. If 0, the |
2774 | + system-wide default value is set. |
2775 | + |
2776 | +----------------------------------------------------------------- |
2777 | +handlersocket_readsize (default = 0, min = 0, max = 1677216) |
2778 | + |
2779 | + Specify the minimum length of the handlersocket request buffer. |
2780 | + Larger value can make handlersocket faster for large requests, |
2781 | + but can consume memory. The default value is possibly 4096. |
2782 | + |
2783 | +----------------------------------------------------------------- |
2784 | +handlersocket_accept_balance (default = 0, min = 0, max = 10000) |
2785 | + |
2786 | + When this option is set to non-zero, handlersocket tries to |
2787 | + balance accepted connections among threads. Non-zero is |
2788 | + recommended if you use persistent connections (i.e., connection |
2789 | + pooling on the client side). |
2790 | + |
2791 | +----------------------------------------------------------------- |
2792 | +handlersocket_wrlock_timeout (default = 12, min = 0, max = 3600) |
2793 | + |
2794 | + Specify the lock timeout in seconds. When a write request is |
2795 | + performed, handlersocket locks an advisory lock named |
2796 | + 'handlersocket_wr'. This option sets the timeout for the |
2797 | + locking. |
2798 | + |
2799 | + |
2800 | |
2801 | === added file 'HandlerSocket-Plugin-for-MySQL/docs-en/installation.en.txt' |
2802 | --- HandlerSocket-Plugin-for-MySQL/docs-en/installation.en.txt 1970-01-01 00:00:00 +0000 |
2803 | +++ HandlerSocket-Plugin-for-MySQL/docs-en/installation.en.txt 2011-04-12 04:16:24 +0000 |
2804 | @@ -0,0 +1,91 @@ |
2805 | +1. Building Handlersocket |
2806 | + |
2807 | + 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. |
2808 | + 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. |
2809 | + Since Handlersocket uses daemon plugin interface supported from MySQL 5.1, |
2810 | +MySQL 5.1 or higher version is required. |
2811 | + Please make sure that you use identical MySQL version between MySQL source |
2812 | +and MySQL binary. Otherwise you might encounter serious problems (i.e. server |
2813 | +crash, etc). |
2814 | + Here are steps to build Handlersocket. |
2815 | + |
2816 | +* Get MySQL source code |
2817 | + |
2818 | +* Get MySQL binary |
2819 | + |
2820 | +* Build Handlersocket |
2821 | + $ ./autogen.sh |
2822 | + $ ./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 |
2823 | + |
2824 | + --with-mysql-source refers to the top of MySQL source directory, |
2825 | +--with-mysql-bindir refers to where MySQL binary executables (i.e. |
2826 | +mysql_config) are located, and --with-mysql-plugindir refers to a plugin |
2827 | +directory where plugin libraries (*.so) are installed. |
2828 | + |
2829 | + $ make |
2830 | + $ sudo make install |
2831 | + |
2832 | + Both libhsclient and the handlersocket plugin will be installed. |
2833 | + |
2834 | + |
2835 | +2. Using Handlersocket |
2836 | + |
2837 | +Append configuration options for handlersocket to my.cnf. |
2838 | + |
2839 | + [mysqld] |
2840 | + loose_handlersocket_port = 9998 |
2841 | + # the port number to bind to (for read requests) |
2842 | + loose_handlersocket_port_wr = 9999 |
2843 | + # the port number to bind to (for write requests) |
2844 | + loose_handlersocket_threads = 16 |
2845 | + # the number of worker threads (for read requests) |
2846 | + loose_handlersocket_threads_wr = 1 |
2847 | + # the number of worker threads (for write requests) |
2848 | + open_files_limit = 65535 |
2849 | + # to allow handlersocket accept many concurrent |
2850 | + # connections, make open_files_limit as large as |
2851 | + # possible. |
2852 | + |
2853 | +Log in to mysql as root, and execute the following query. |
2854 | + |
2855 | + mysql> install plugin handlersocket soname 'handlersocket.so'; |
2856 | + |
2857 | +If handlersocket.so is successfully installed, it starts |
2858 | +accepting connections on port 9998 and 9999. Running |
2859 | +'show processlist' should show handlersocket worker threads. |
2860 | + |
2861 | +----------------------------------------------------------------- |
2862 | +On the client side, you need to install libhsclient for c++ apps |
2863 | +and perl-Net-HandlerSocket for perl apps. They do not require |
2864 | +MySQL to compile. |
2865 | + |
2866 | + $ ./autogen.sh |
2867 | + $ ./configure --disable-handlersocket-server |
2868 | + $ make |
2869 | + $ sudo make install |
2870 | + $ cd perl-Net-HandlerSocket |
2871 | + $ perl Makefile.PL |
2872 | + $ make |
2873 | + $ sudo make install |
2874 | + |
2875 | +----------------------------------------------------------------- |
2876 | +Alternatively, you can use the rpm installation. If your OS |
2877 | +supports rpms, you can use the following commands to build and |
2878 | +install handlersocket rpm packages. |
2879 | + |
2880 | +(Server side, installs HandlerSocket plugin) |
2881 | + $ ./autogen.sh |
2882 | + $ ./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 |
2883 | + $ make rpm_cli |
2884 | + $ sudo rpm -U dist/RPMS/*/libhsclient*.rpm |
2885 | + $ make rpm_c |
2886 | + $ sudo rpm -U dist/RPMS/*/handlersocket*.rpm |
2887 | + |
2888 | +(Client side, installs client libraries) |
2889 | + $ ./autogen.sh |
2890 | + $ ./configure --disable-handlersocket-server |
2891 | + $ make rpm_cli |
2892 | + $ sudo rpm -U dist/RPMS/*/libhsclient*.rpm |
2893 | + $ make rpm_perl |
2894 | + $ sudo rpm -U dist/RPMS/*/perl-Net-HandlerSocket*.rpm |
2895 | + |
2896 | |
2897 | === added file 'HandlerSocket-Plugin-for-MySQL/docs-en/perl-client.en.txt' |
2898 | --- HandlerSocket-Plugin-for-MySQL/docs-en/perl-client.en.txt 1970-01-01 00:00:00 +0000 |
2899 | +++ HandlerSocket-Plugin-for-MySQL/docs-en/perl-client.en.txt 2011-04-12 04:16:24 +0000 |
2900 | @@ -0,0 +1,126 @@ |
2901 | + |
2902 | +----------------------------------------------------------------- |
2903 | +To open a connection to the handlersocket plugin, you need to |
2904 | +create a Net::HandlerSocket object. |
2905 | + |
2906 | + use Net::HandlerSocket; |
2907 | + my $args = { host => 'localhost', port => 9998 }; |
2908 | + my $hs = new Net::HandlerSocket($args); |
2909 | + |
2910 | +----------------------------------------------------------------- |
2911 | +Before executing table operations, you need to open an index to |
2912 | +work with. |
2913 | + |
2914 | + my $err = $hs->open_index(3, 'database1', 'table1', 'PRIMARY', |
2915 | + 'f1,f2'); |
2916 | + die $hs->get_error() if $res->[0] != 0; |
2917 | + |
2918 | +The first argument for open_index is an integer value which is |
2919 | +used to identify an open table, which is only valid within the |
2920 | +same Net::HandlerSocket object. The 4th argument is the name of |
2921 | +index to open. If 'PRIMARY' is specified, the primary index is |
2922 | +open. The 5th argument is a comma-separated list of column names. |
2923 | + |
2924 | +----------------------------------------------------------------- |
2925 | +To read a record from a table using an index, call the |
2926 | +execute_single method. |
2927 | + |
2928 | + my $res = $hs->execute_single(3, '=', [ 'foo' ], 1, 0); |
2929 | + die $hs->get_error() if $res->[0] != 0; |
2930 | + shift(@$res); |
2931 | + |
2932 | +The first argument must be an integer which has specified as the |
2933 | +first argument for open_index on the same Net::HandlerSocket |
2934 | +object. The second argument specifies the search operation. The |
2935 | +current version of handlersocket supports '=', '>=', '<=', '>', |
2936 | +and '<'. The 3rd argument specifies the key to find, which must |
2937 | +an arrayref whose length is equal to or smaller than the number |
2938 | +of key columns of the index. The 4th and the 5th arguments |
2939 | +specify the maximum number of records to be retrieved, and the |
2940 | +number of records skipped before retrieving records. The columns |
2941 | +to be retrieved are specified by the 5th argument for the |
2942 | +corresponding open_index call. |
2943 | + |
2944 | +The execute_single method always returns an arrayref. The first |
2945 | +element is the error code, which is 0 when no error is occured. |
2946 | +The remaining are the field values. If more than one record is |
2947 | +returned, it is flatten to an 1-dimensional array. For example, |
2948 | +when 5 records that have 3 columns are returned, you can retrieve |
2949 | +values using the following code. |
2950 | + |
2951 | + die $hs->get_error() if $res->[0] != 0; |
2952 | + shift(@$res); |
2953 | + for (my $row = 0; $row < 5; ++$row) { |
2954 | + for (my $col = 0; $col < 3; ++$col) { |
2955 | + my $value = $res->[$row * 5 + $col]; |
2956 | + # ... |
2957 | + } |
2958 | + } |
2959 | + |
2960 | +----------------------------------------------------------------- |
2961 | +To update or delete records, you need to specify more arguments |
2962 | +for the execute_single method. Note that the Net::HandlerSocket |
2963 | +object must be connected to a handlersocket worker for write |
2964 | +operations, which is port 9999 by default. |
2965 | +(For safety, the port 9998 only allows read operations, and the |
2966 | +port 9999 allows write operations also. The port 9999 allows |
2967 | +read operations too, but slower than 9998 because of record |
2968 | +locking etc.. Port numbers can be changed using the |
2969 | +'handlersocket_port' and the 'handlersocket_port_wr' |
2970 | +configuration options of mysqld.) |
2971 | + |
2972 | + my $args = { host => 'localhost', port => 9999 }; |
2973 | + my $hs = new Net::HandlerSocket($args); |
2974 | + |
2975 | + my $res = $hs->execute_single(3, '=', [ 'bar' ], 1, 0, 'U', |
2976 | + [ 'fubar', 'hoge' ]); |
2977 | + die $hs->get_error() if $res->[0] != 0; |
2978 | + my $num_updated_rows = $res->[1]; |
2979 | + |
2980 | + my $res = $hs->execute_single(3, '=', [ 'baz' ], 1, 0, 'D'); |
2981 | + die $hs->get_error() if $res->[0] != 0; |
2982 | + my $num_deleted_rows = $res->[1]; |
2983 | + |
2984 | +The 6th argument for execute_single specifies the modification |
2985 | +operation. The current version supports 'U' and 'D'. For the 'U' |
2986 | +operation, the 7th argument specifies the new value for the row. |
2987 | +The columns to be modified are specified by the 5th argument for |
2988 | +the corresponding open_index call. For the 'D' operation, the |
2989 | +7th argument can be omitted. |
2990 | + |
2991 | +----------------------------------------------------------------- |
2992 | +The execute_single method can be used for inserting records also. |
2993 | + |
2994 | + my $res = $hs->execute_single(3, '+', [ 'foo', 'bar', 'baz' ]); |
2995 | + die $hs->get_error() if $res->[0] != 0; |
2996 | + my $num_inserted_rows = $res->[1]; |
2997 | + |
2998 | +The 3rd argument must be an arrayref whose elements correspond to |
2999 | +the 5th argument for the corresponding open_index call. If there |
3000 | +is a column which is not appeared in the 5th argument for the |
3001 | +open_index, the default value for the column is set. |
3002 | + |
3003 | +----------------------------------------------------------------- |
3004 | +Multiple operations can be executed in a single call. Executing |
3005 | +multiple operations in a single call is much faster than |
3006 | +executing them separatedly. |
3007 | + |
3008 | + my $rarr = $hs->execute_multi([ |
3009 | + [ 0, '>=', [ 'foo' ], 5, 0 ], |
3010 | + [ 2, '=', [ 'bar' ], 1, 0 ], |
3011 | + [ 4, '<', [ 'baz' ], 10, 5 ], |
3012 | + ]); |
3013 | + for my $res (@$rarr) { |
3014 | + die $hs->get_error() if $res->[0] != 0; |
3015 | + shift(@$res); |
3016 | + # ... |
3017 | + } |
3018 | + |
3019 | +----------------------------------------------------------------- |
3020 | +When an error is occured, the first element of the returned |
3021 | +arrayref becomes a non-zero value. A negative value indicates |
3022 | +that an I/O error is occured and the Net::HandlerSocket object |
3023 | +should be disposed. A positive value means that the connection is |
3024 | +still active and the Net::HandlerSocket object can be reused |
3025 | +later. |
3026 | + |
3027 | |
3028 | === added file 'HandlerSocket-Plugin-for-MySQL/docs-en/protocol.en.txt' |
3029 | --- HandlerSocket-Plugin-for-MySQL/docs-en/protocol.en.txt 1970-01-01 00:00:00 +0000 |
3030 | +++ HandlerSocket-Plugin-for-MySQL/docs-en/protocol.en.txt 2011-04-12 04:16:24 +0000 |
3031 | @@ -0,0 +1,148 @@ |
3032 | + |
3033 | +---------------------------------------------------------------------------- |
3034 | +The HandlerSocket protocol |
3035 | + |
3036 | +---------------------------------------------------------------------------- |
3037 | +Basic syntax |
3038 | + |
3039 | +- The HandlerSocket protocol is line-based. Each line ends with LF(0x0a). |
3040 | +- Each line consists a concatenation of tokens separated by HT(0x09). |
3041 | +- A token is either NULL or an encoded string. Note that you need to |
3042 | + distinguish NULL from an empty string, as most DBMs does so. |
3043 | +- NULL is expressed as a single NUL(0x00). |
3044 | +- An encoded string is a string with the following encoding rules. |
3045 | + - Characters in the range [0x10 - 0xff] are not encoded. |
3046 | + - A character in the range [0x00 - 0x0f] is prefixed by 0x01 and |
3047 | + shifted by 0x40. For example, 0x03 is encoded as 0x01 0x43. |
3048 | +- Note that a string can be empty. A continuation of 0x09 0x09 means that |
3049 | + there is an empty string between them. A continuation of 0x09 0x0a means |
3050 | + that there is an empty string at the end of the line. |
3051 | + |
3052 | +---------------------------------------------------------------------------- |
3053 | +Request and Response |
3054 | + |
3055 | +- The HandlerSocket protocol is a simple request/response protocol. After a |
3056 | + connection is established, the client side sends a request, and then the |
3057 | + server side sends a response. |
3058 | +- A request/response consists of a single line. |
3059 | +- Requests can be pipelined; That is, you can send multiple requests (ie. |
3060 | + lines) at one time, and receive responses for them at one time. |
3061 | + |
3062 | +---------------------------------------------------------------------------- |
3063 | +'open_index' request |
3064 | + |
3065 | +The 'open_index' request has the following syntax. |
3066 | + |
3067 | + P <indexid> <dbname> <tablename> <indexname> <columns> |
3068 | + |
3069 | +- <indexid> is a number in decimal. |
3070 | +- <dbname>, <tablename>, and <indexname> are strings. To open the primary |
3071 | + key, use PRIMARY as <indexname>. |
3072 | +- <columns> is a comma-separated list of column names. |
3073 | + |
3074 | +Once an 'open_index' request is issued, the HandlerSocket plugin opens the |
3075 | +specified index and keep it open until the client connection is closed. Each |
3076 | +open index is identified by <indexid>. If <indexid> is already open, the old |
3077 | +open index is closed. You can open the same combination of <dbname> |
3078 | +<tablename> <indexname> multple times, possibly with different <columns>. |
3079 | +For efficiency, keep <indexid> small as far as possible. |
3080 | + |
3081 | +---------------------------------------------------------------------------- |
3082 | +Getting data |
3083 | + |
3084 | +The 'find' request has the following syntax. |
3085 | + |
3086 | + <indexid> <op> <vlen> <v1> ... <vn> <limit> <offset> |
3087 | + |
3088 | +- <indexid> is a number. This number must be an <indexid> specified by a |
3089 | + 'open_index' request executed previously on the same connection. |
3090 | +- <op> specifies the comparison operation to use. The current version of |
3091 | + HandlerSocket supports '=', '>', '>=', '<', and '<='. |
3092 | +- <vlen> indicates the length of the trailing parameters <v1> ... <vn>. This |
3093 | + must be smaller than or equal to the number of index columns specified by |
3094 | + specified by the corresponding 'open_index' request. |
3095 | +- <v1> ... <vn> specify the index column values to fetch. |
3096 | +- <limit> and <offset> are numbers. These parameters can be omitted. When |
3097 | + omitted, it works as if 1 and 0 are specified. |
3098 | + |
3099 | +---------------------------------------------------------------------------- |
3100 | +Updating/Deleting data |
3101 | + |
3102 | +The 'find_modify' request has the following syntax. |
3103 | + |
3104 | + <indexid> <op> <vlen> <v1> ... <vn> <limit> <offset> <mop> <m1> ... <mk> |
3105 | + |
3106 | +- <mop> is either 'U' (update) or 'D' (delete). |
3107 | +- <m1> ... <mk> specifies the column values to set. The length of <m1> ... |
3108 | + <mk> must be smaller than or equal to the length of <columns> specified by |
3109 | + the corresponding 'open_index' request. If <mop> is 'D', these parameters |
3110 | + are ignored. |
3111 | + |
3112 | +---------------------------------------------------------------------------- |
3113 | +Inserting data |
3114 | + |
3115 | +The 'insert' request has the following syntax. |
3116 | + |
3117 | + <indexid> '+' <vlen> <v1> ... <vn> |
3118 | + |
3119 | +- <vlen> indicates the length of the trailing parameters <v1> ... <vn>. This |
3120 | + must be smaller than or equal to the length of <columns> specified by the |
3121 | + corresponding 'open_index' request. |
3122 | +- <v1> ... <vn> specify the column values to set. For columns not in |
3123 | + <columns>, the default values for each column are set. |
3124 | + |
3125 | +---------------------------------------------------------------------------- |
3126 | +Response syntax |
3127 | + |
3128 | +HandlerSocket returns a response of the following syntax for each request. |
3129 | + |
3130 | + <errorcode> <numcolumns> <r1> ... <rn> |
3131 | + |
3132 | +- <errorcode> indicates whether the request has successfully executed or not. |
3133 | + '0' means success. Non-zero means an error. |
3134 | +- <numcolumns> indicates the number of columns of the result set. |
3135 | +- <r1> ... <rn> is the result set. The length of <r1> ... <rn> is always a |
3136 | + multiple of <numcolumns>. It is possible that <r1> ... <rn> is empty. |
3137 | + |
3138 | +If <errorcode> is non-zero, <numcolumns> is always 1 and <r1> indicates a |
3139 | +human-readable error message, though sometimes <r1> is not provided. |
3140 | + |
3141 | +---------------------------------------------------------------------------- |
3142 | +Response for 'open_index' |
3143 | + |
3144 | +If 'open_index' is succeeded, HandlerSocket returns a line of the following |
3145 | +syntax. |
3146 | + |
3147 | + 0 1 |
3148 | + |
3149 | +---------------------------------------------------------------------------- |
3150 | +Response for 'find' |
3151 | + |
3152 | +If 'find' is succeeded, HandlerSocket returns a line of the following |
3153 | +syntax. |
3154 | + |
3155 | + 0 <numcolumns> <r1> ... <rn> |
3156 | + |
3157 | +- <numcolumns> always equals to the length of <columns> of the corresponding |
3158 | + 'open_index' request. |
3159 | +- <r1> ... <rn> is the result set. If N rows are found, the length of <r1> |
3160 | + ... <rn> becomes ( <numcolumns> * N ). |
3161 | + |
3162 | +---------------------------------------------------------------------------- |
3163 | +Response for 'find_modify' |
3164 | + |
3165 | +If 'find_modify' is succeeded, HandlerSocket returns a line of the following |
3166 | +syntax. |
3167 | + |
3168 | + 0 1 <nummod> |
3169 | + |
3170 | +- <nummod> is the number of modified rows. |
3171 | + |
3172 | +---------------------------------------------------------------------------- |
3173 | +Response for 'insert' |
3174 | + |
3175 | +If 'insert' is succeeded, HanderSocket returns a line of the following |
3176 | +syntax. |
3177 | + |
3178 | + 0 1 |
3179 | + |
3180 | |
3181 | === added directory 'HandlerSocket-Plugin-for-MySQL/docs-ja' |
3182 | === added file 'HandlerSocket-Plugin-for-MySQL/docs-ja/about-handlersocket.ja.txt' |
3183 | --- HandlerSocket-Plugin-for-MySQL/docs-ja/about-handlersocket.ja.txt 1970-01-01 00:00:00 +0000 |
3184 | +++ HandlerSocket-Plugin-for-MySQL/docs-ja/about-handlersocket.ja.txt 2011-04-12 04:16:24 +0000 |
3185 | @@ -0,0 +1,51 @@ |
3186 | + |
3187 | + |
3188 | +----------------------------------------------------------------- |
3189 | +ソースコードã�®åˆ©ç”¨ã�«ã�‚ã�Ÿã�£ã�¦ã�®å…�è²¬äº‹é … |
3190 | + |
3191 | +本ソフトウェアã�®é–‹ç™ºè€…ã�Šã‚ˆã�³æ ªå¼�会社ディー・エヌ・エーã�¯ã€�本フト |
3192 | +ウェア��稼動�稼動�良を�む法律上�瑕疵担�責任���他�証責 |
3193 | +ä»»ã‚’è² ã‚�ã�ªã�„ã‚‚ã�®ã�¨ã�—ã�¾ã�™ã€‚ã�¾ã�Ÿã€�本ソフトウエアã�®é–‹ç™ºè€…ã�Šã‚ˆã�³æ ªå¼� |
3194 | +会社ディー・エヌ・エー��本ソフトウェア�商�性�����客様� |
3195 | +特定ã�®ç›®çš„ã�«å¯¾ã�™ã‚‹é�©å�ˆæ€§ã�«ã�¤ã�„ã�¦ã€�ã�„ã�‹ã�ªã‚‹ä¿�è¨¼ã‚‚è² ã‚�ã�ªã�„ã‚‚ã�®ã�¨ã�— |
3196 | +��。 |
3197 | + |
3198 | +----------------------------------------------------------------- |
3199 | +handlersocket plugin���� |
3200 | + |
3201 | +mysqlサーãƒ�ã�«å¸¸é§�ã�—ã€�innodbç‰ã�®ã‚¹ãƒˆãƒ¬ãƒ¼ã‚¸ã‚¨ãƒ³ã‚¸ãƒ³ã�¸ã�®ç›´æŽ¥ã�®ã‚¢ã‚¯ã‚» |
3202 | +スを�供�るプラグイン��。handlersocketプラグイン�自��リス |
3203 | +ナーを���専用�クライアントライブラリ(libhsclient)を使���れ |
3204 | +�アクセス���。 |
3205 | + |
3206 | +mysql�標準クライアントライブラリ(libmysql)を使��アクセス�比� |
3207 | +��以下�よ��利点��り��。 |
3208 | +・接続��り�消費�るリソース�少������時接続数�事実上無 |
3209 | + 制�。�����接続数を気����続接続を使���。 |
3210 | +・高速(�純��照クエリ�3�〜10�程度)。 |
3211 | +・通信プãƒãƒˆã‚³ãƒ«ã�Œã‚³ãƒ³ãƒ‘クト。libmysqlを使ã�†ã�¨ãƒ‡ãƒ¼ã‚¿è»¢é€�時ã�«ãƒ¬ |
3212 | + コード����付��る���通信内容�冗長����libhsclient� |
3213 | + ã�¯ãƒ‡ãƒ¼ã‚¿ã�®ã�¿ã�Œè»¢é€�ã�•ã‚Œã‚‹ã�Ÿã‚�ã€�帯域消費ã�Œå°‘ã�ªã��ã�ªã‚Šã�¾ã�™ã€‚å ´å�ˆã�« |
3214 | + よ���10�以上libmysql����冗長��り��。 |
3215 | + |
3216 | +�在��ージョン��以下�よ��処�をサ�ート�����。 |
3217 | +・指定�れ�索引�����指定�れ�値�完全一致�るよ��レコー |
3218 | + ドを�得。(SELECT ??? FROM tbl WHERE k1 = v1 AND k2 = v2...)。 |
3219 | + 索引を使���検索�サ�ート�����ん。 |
3220 | +・指定�れ�索引�����指定�れ�値��置��後�レコードを� |
3221 | + 得。(SELECT ??? FROM tbl WHERE k1 >= v1 LIMIT 100) |
3222 | +・�述�よ��手段��得��レコード�対�るUPDATE�DELETE |
3223 | +・レコード�INSERT |
3224 | + |
3225 | +以下�よ��言語をサ�ート���。 |
3226 | +・C++。libhsclientをリンク���。 |
3227 | +・Perl。Net::HandlerSocketをuse���。 |
3228 | + |
3229 | +�在��ージョン��GNU/Linux���動作���。 |
3230 | + |
3231 | +----------------------------------------------------------------- |
3232 | +既知��題 |
3233 | + |
3234 | +・kill�handlersocketスレッドを殺���スレッド数�減����回復 |
3235 | + ���ん。 |
3236 | + |
3237 | |
3238 | === added file 'HandlerSocket-Plugin-for-MySQL/docs-ja/installation.ja.txt' |
3239 | --- HandlerSocket-Plugin-for-MySQL/docs-ja/installation.ja.txt 1970-01-01 00:00:00 +0000 |
3240 | +++ HandlerSocket-Plugin-for-MySQL/docs-ja/installation.ja.txt 2011-04-12 04:16:24 +0000 |
3241 | @@ -0,0 +1,87 @@ |
3242 | + |
3243 | +----------------------------------------------------------------- |
3244 | +HandlerSocketプラグイン�ビルド方法(RPMを使���方法) |
3245 | + |
3246 | +以下�よ����configureを実行���。 |
3247 | + |
3248 | + $ ./autogen.sh |
3249 | + $ ./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 |
3250 | + |
3251 | +���--with-mysql-source��MySQL�ソースコード�トップディレク |
3252 | +トリを指定���。--with-mysql-bindir��インストール済��MySQL |
3253 | +�mysql_configコマンド�有るディレクトリを指定���。 |
3254 | +��後以下�よ��ビルド・インストール���。 |
3255 | + |
3256 | + $ make |
3257 | + $ sudo make install |
3258 | + |
3259 | +----------------------------------------------------------------- |
3260 | +クライアントライブラリ�ビルド方法(RPMを使���方法) |
3261 | + |
3262 | +クライアントライブラリをビルド�る際���MySQL�ソースコード� |
3263 | +必��り��ん。��MySQL�インストール�れ��る必�も�り��ん。 |
3264 | + |
3265 | + $ ./autogen.sh |
3266 | + $ ./configure --disable-handlersocket-server |
3267 | + $ make |
3268 | + $ sudo make install |
3269 | + $ cd perl-Net-HandlerSocket |
3270 | + $ perl Makefile.PL |
3271 | + $ make |
3272 | + $ sudo make install |
3273 | + |
3274 | +----------------------------------------------------------------- |
3275 | +ビルド方法(RPM) |
3276 | + |
3277 | +以下�よ��実行�れ��rpmパッケージ�ビルド&インストール�れ� |
3278 | +�。 |
3279 | + |
3280 | +(MySQLサー���HandlerSocketプラグインをインストール�る) |
3281 | + $ ./autogen.sh |
3282 | + $ ./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 |
3283 | + $ make rpm_cli |
3284 | + $ sudo rpm -U dist/RPMS/*/libhsclient*.rpm |
3285 | + $ make rpm_c |
3286 | + $ sudo rpm -U dist/RPMS/*/handlersocket*.rpm |
3287 | + |
3288 | +(クライアント��クライアントライブラリをインストール�る) |
3289 | + $ ./autogen.sh |
3290 | + $ ./configure --disable-handlersocket-server |
3291 | + $ make rpm_cli |
3292 | + $ sudo rpm -U dist/RPMS/*/libhsclient*.rpm |
3293 | + $ make rpm_perl |
3294 | + $ sudo rpm -U dist/RPMS/*/perl-Net-HandlerSocket*.rpm |
3295 | + |
3296 | +----------------------------------------------------------------- |
3297 | +èµ·å‹• |
3298 | + |
3299 | +mysqlã‚’èµ·å‹•ã�—ã�ŸçŠ¶æ…‹ã�§ã€�mysqlã�®è¨å®šãƒ•ã‚¡ã‚¤ãƒ«(my.cnfç‰)ã�«ä»¥ä¸‹ã�®å†…容を |
3300 | +è¿½åŠ ã�—ã�¾ã�™ã€‚ |
3301 | + |
3302 | + [mysqld] |
3303 | + handlersocket_port = 9998 |
3304 | + # handlersocket�接続を��付�る�ート(�照系リクエスト用) |
3305 | + handlersocket_port_wr = 9999 |
3306 | + # handlersocket�接続を��付�る�ート(更新系リクエスト用) |
3307 | + handlersocket_address = |
3308 | + # handlersocket��インド�るアドレス(空����OK) |
3309 | + handlersocket_verbose = 0 |
3310 | + # デ�ッグ用 |
3311 | + handlersocket_timeout = 300 |
3312 | + # 通信タイムアウト(秒) |
3313 | + handlersocket_threads = 16 |
3314 | + # handlersocket�ワーカースレッド数 |
3315 | + thread_concurrency = 128 |
3316 | + # handlersocketã�Œå¹¾ã�¤ã�‹ã�®ã‚¹ãƒ¬ãƒƒãƒ‰ã‚’å� 有ã�™ã‚‹ã�Ÿã‚�ã€�大ã��ã‚�ã�® |
3317 | + # 値を指定ã�—ã�¦ã��ã� ã�•ã�„ |
3318 | + open_files_limit = 65535 |
3319 | + # ソケットを大��開�るよ���る���大���値を指定� |
3320 | + # ã�¦ã��ã� ã�•ã�„ |
3321 | + |
3322 | +以下�クエリを実行���。 |
3323 | + |
3324 | + mysql> install plugin handlersocket soname 'handlersocket.so'; |
3325 | + Query OK, 0 rows affected (0.06 sec) |
3326 | + |
3327 | +以上�handlersocket�クライアント�らアクセス��るよ���り��。 |
3328 | + |
3329 | |
3330 | === added file 'HandlerSocket-Plugin-for-MySQL/docs-ja/perl-client.ja.txt' |
3331 | --- HandlerSocket-Plugin-for-MySQL/docs-ja/perl-client.ja.txt 1970-01-01 00:00:00 +0000 |
3332 | +++ HandlerSocket-Plugin-for-MySQL/docs-ja/perl-client.ja.txt 2011-04-12 04:16:24 +0000 |
3333 | @@ -0,0 +1,118 @@ |
3334 | + |
3335 | +----------------------------------------------------------------- |
3336 | +handlersocketプラグイン��接続を開����Net::HandlerSocketオブ |
3337 | +ジェクトを作����。 |
3338 | + |
3339 | + use Net::HandlerSocket; |
3340 | + my $args = { host => 'localhost', port => 9998 }; |
3341 | + my $hs = new Net::HandlerSocket($args); |
3342 | + |
3343 | +----------------------------------------------------------------- |
3344 | +検索���命令を実行�る���処�対象��る索引を開�必���り |
3345 | +��。 |
3346 | + |
3347 | + my $err = $hs->open_index(3, 'database1', 'table1', 'PRIMARY', |
3348 | + 'f1,f2'); |
3349 | + die $hs->get_error() if $res->[0] != 0; |
3350 | + |
3351 | +最��引数�開�索引�付�る番���。付��番���一� |
3352 | +Net::HandlerSocketオブジェクト������有効��。第4引数�開� |
3353 | +索引ã�®å��å‰�ã�§ã€�「PRIMARYã€�ã�ŒæŒ‡å®šã�•ã‚Œå ´å�ˆã�¯ãƒ—ライマリã‚ーã�Œé–‹ã�‹ã‚Œã�¾ |
3354 | +�。第5引数�「,��区切られ�列��リスト��。 |
3355 | + |
3356 | +----------------------------------------------------------------- |
3357 | +テーブル�ら索引を使��行を�得�る���execute_singleメソッド |
3358 | +を呼���。 |
3359 | + |
3360 | + my $res = $hs->execute_single(3, '=', [ 'foo' ], 1, 0); |
3361 | + die $hs->get_error() if $res->[0] != 0; |
3362 | + shift(@$res); |
3363 | + |
3364 | +最��引数�索引�番�����Net::HandlerSocketオブジェクト� |
3365 | +open_index�付��も����れ��り��ん。第2引数���作を指定 |
3366 | +���。�在��ージョン���「=��「>=��「<=��「>��「<� |
3367 | +��作�利用�能��。第3引数��列���照���れ�探���行� |
3368 | +ã‚ー値を指定ã�—ã�¾ã�™ã€‚é…�列ã�®é•·ã�•ã�¯ç´¢å¼•ã�®ã‚ーã�®å€‹æ•°ã�¨å�Œã�˜ã�‹å°‘ã�ªã�„æ•° |
3369 | +���れ��り��ん。第4引数�第5引数��れ�れ��得�る最大行 |
3370 | +æ•°ã€�å�–å¾—å‰�ã�«èªã�¿é£›ã�°ã�™è¡Œæ•°ã‚’指定ã�—ã�¾ã�™ã€‚å�–å¾—ã�•ã‚Œã‚‹åˆ—ã�¯å¯¾å¿œã�™ã‚‹ |
3371 | +open_index呼�出��第5引数�指定�れ�も���り��。 |
3372 | + |
3373 | +execute_singleメソッドã�¯å¸¸ã�«é…�列ã�¸ã�®å�‚照を返ã�—ã�¾ã�™ã€‚最åˆ�ã�®è¦�ç´ ã�¯ |
3374 | +エラーコードã�§ã€�ã�“ã‚Œã�Œ0ã�ªã‚‰ã�°æˆ�功を表ã�—ã�¾ã�™ã€‚残りã�®è¦�ç´ ã�¯åˆ—ã�®å€¤ã�§ |
3375 | +ã�™ã€‚ã‚‚ã�—å�–å¾—ã�•ã‚Œã�Ÿãƒ‡ãƒ¼ã‚¿ã�Œè¤‡æ•°è¡Œã�®å ´å�ˆã�¯ã€�ã��ã‚Œã�Œä¸€ã�¤ã�®é…�列ã�¸é€£çµ� |
3376 | +ã�•ã‚Œã�Ÿå½¢ã�§æ ¼ç´�ã�•ã‚Œã�¦ã�„ã�¾ã�™ã€‚例ã�ˆã�°ã€�5è¡Œ3列ã�®ãƒ‡ãƒ¼ã‚¿ã�®å ´å�ˆã€�次ã�®ã‚ˆ |
3377 | +��コード�よ����内容を�得����。 |
3378 | + |
3379 | + die $hs->get_error() if $res->[0] != 0; |
3380 | + shift(@$res); |
3381 | + for (my $row = 0; $row < 5; ++$row) { |
3382 | + for (my $col = 0; $col < 3; ++$col) { |
3383 | + my $value = $res->[$row * 5 + $col]; |
3384 | + # ... |
3385 | + } |
3386 | + } |
3387 | + |
3388 | +----------------------------------------------------------------- |
3389 | +行を更新���削除�る���更�多��引数を指定�� |
3390 | +execute_singleメソッドを呼�出���。書�込�処�を�る��� |
3391 | +対象�Net::HandlerSocketオブジェクト�更新用handlersocketワーカ(既 |
3392 | +定���ート9999)�接続�れ�も�������り��ん。 |
3393 | +(安全ã�®ã�Ÿã‚�ã€�ãƒ�ート9998ã�¯å�‚照処ç�†ã� ã�‘ã‚’å�—ã�‘付ã�‘ã€�ãƒ�ート9999ã�¯æ›´æ–° |
3394 | +処�も��付�るよ��������。�ート9999��照処�も��付 |
3395 | +ã�‘ã�¾ã�™ã�Œã€�レコードãƒãƒƒã‚¯ç‰ã�®å½±éŸ¿ã�§é�…ã��ã�ªã‚Šã�¾ã�™ã€‚ãƒ�ート番å�·ã�¯ |
3396 | +mysqldã�®ã€Œhandlersocket_portã€�ã�¨ã€Œhandlersocket_port_wrã€�ã�®è¨å®šé … |
3397 | +目�変更����。) |
3398 | + |
3399 | + my $args = { host => 'localhost', port => 9999 }; |
3400 | + my $hs = new Net::HandlerSocket($args); |
3401 | + |
3402 | + my $res = $hs->execute_single(3, '=', [ 'bar' ], 1, 0, 'U', |
3403 | + [ 'fubar', 'hoge' ]); |
3404 | + die $hs->get_error() if $res->[0] != 0; |
3405 | + my $num_updated_rows = $res->[1]; |
3406 | + |
3407 | + my $res = $hs->execute_single(3, '=', [ 'baz' ], 1, 0, 'D'); |
3408 | + die $hs->get_error() if $res->[0] != 0; |
3409 | + my $num_deleted_rows = $res->[1]; |
3410 | + |
3411 | +execute_single�第6引数�変更処��種類を指定���。�在��ー |
3412 | +ジョン��「U��「D��利用�能��。「U�������第7引数� |
3413 | +新��値を指定���。更新�れる列��対応�るopen_index呼�出� |
3414 | +�第5引数�指定�れ�も���り��。「D������第7引数�� |
3415 | +略����。 |
3416 | + |
3417 | +----------------------------------------------------------------- |
3418 | +execute_singleメソッド�列�挿入�も使用����。 |
3419 | + |
3420 | + my $res = $hs->execute_single(3, '+', [ 'foo', 'bar', 'baz' ]); |
3421 | + die $hs->get_error() if $res->[0] != 0; |
3422 | + my $num_inserted_rows = $res->[1]; |
3423 | + |
3424 | +第3引数ã�¯ã€�対応ã�™ã‚‹open_index呼ã�³å‡ºã�—ã�®ç¬¬5引数ã�®åˆ—リストã�¨å�Œã�˜ã� |
3425 | +��長���列���照���れ��り��ん。open_index呼�出�� |
3426 | +第5引数�指定�れ����列��������列�既定値�セット�れ |
3427 | +��。 |
3428 | + |
3429 | +----------------------------------------------------------------- |
3430 | +execute_multiメソッドを使���複数�リクエストを一��呼�出�� |
3431 | +実行�る�������。�れ�リクエストを個別�実行�るより高速 |
3432 | +��。 |
3433 | + |
3434 | + my $rarr = $hs->execute_multi([ |
3435 | + [ 0, '>=', [ 'foo' ], 5, 0 ], |
3436 | + [ 2, '=', [ 'bar' ], 1, 0 ], |
3437 | + [ 4, '<', [ 'baz' ], 10, 5 ], |
3438 | + ]); |
3439 | + for my $res (@$rarr) { |
3440 | + die $hs->get_error() if $res->[0] != 0; |
3441 | + shift(@$res); |
3442 | + # ... |
3443 | + } |
3444 | + |
3445 | +----------------------------------------------------------------- |
3446 | +エラーã�Œèµ·ã�“ã‚‹ã�¨è¿”値ã�®é…�列å�‚ç…§ã�®æœ€åˆ�ã�®è¦�ç´ ã�Œ0以外ã�«ã�ªã‚Šã�¾ã�™ã€‚è² ã�® |
3447 | +æ•°ã�®å ´å�ˆã�¯I/Oエラーã�Œèµ·ã�“ã�£ã�Ÿã�“ã�¨ã‚’示ã�—ã€�ã��ã�®å ´å�ˆã�¯ã��ã�® |
3448 | +Net::HandlerSocketオブジェクトã�¯ç ´æ£„ã�™ã‚‹ã�¹ã��ã�§ã�™ã€‚æ£ã�®å€¤ã�®å ´å�ˆã�¯ |
3449 | +接続ã�¯ç¶æŒ�ã�•ã‚Œã�¦ã�„ã‚‹ã�Ÿã‚�ã€�ã��ã�®ã‚ªãƒ–ジェクトã�¯ã��れ以後もå†�利用ã�§ã�� |
3450 | +��。 |
3451 | + |
3452 | |
3453 | === added file 'HandlerSocket-Plugin-for-MySQL/docs-ja/protocol.ja.txt' |
3454 | --- HandlerSocket-Plugin-for-MySQL/docs-ja/protocol.ja.txt 1970-01-01 00:00:00 +0000 |
3455 | +++ HandlerSocket-Plugin-for-MySQL/docs-ja/protocol.ja.txt 2011-04-12 04:16:24 +0000 |
3456 | @@ -0,0 +1,94 @@ |
3457 | + |
3458 | +----------------------------------------------------------------- |
3459 | +handlersocketã�®é€šä¿¡ãƒ—ãƒãƒˆã‚³ãƒ« |
3460 | + |
3461 | +----------------------------------------------------------------- |
3462 | +構文 |
3463 | + |
3464 | +・コマンド行�改行(LF)�終�る。 |
3465 | +・コマンド行�複数�トークン�ら�り�トークン間�TAB�区切られる。 |
3466 | +・トークンã�¯NULLトークンã�‹ã€�æ–‡å—列トークンã�®ã�„ã�šã‚Œã�‹ã€‚ |
3467 | +・NULLトークンã�¯å�˜ä¸€ã�®NULæ–‡å—ã�§ã�‚らã‚�ã�•ã‚Œã‚‹ã€‚ |
3468 | +・文å—列トークンã�¯ã€�0ãƒ�イト以上ã�®æ–‡å—列ã�§ã�‚らã‚�ã�•ã‚Œã‚‹ã€‚ã�Ÿã� ã�—0x10 |
3469 | + 未満ã�®æ–‡å—ã�«ã�¤ã�„ã�¦ã�¯0x01ã‚’å‰�ç½®ã�—ã€�0x40ã‚’åŠ ã�ˆã�Ÿã‚³ãƒ¼ãƒ‰ã�§ã�‚らã‚�ã�• |
3470 | + れる。ã��れ以外ã�®æ–‡å—ã�¯ã��ã�®æ–‡å—自身ã�®ã‚³ãƒ¼ãƒ‰ã�§ã�‚らã‚�ã�•ã‚Œã‚‹ã€‚ |
3471 | + |
3472 | +----------------------------------------------------------------- |
3473 | +リクエスト�レス�ンス |
3474 | + |
3475 | +・接続�確立��直後�状態�����クライアント�コマンド行を� |
3476 | + る。(リクエスト) |
3477 | +・サー��クライアント����リクエスト��度��数�コマンド行 |
3478 | + を返�。(レス�ンス) |
3479 | +・リクエスト�パイプライン化��よ�。��りクライアント��� |
3480 | + ���リクエスト�対�る返事を待���次�リクエストを���も |
3481 | + よ�。 |
3482 | + |
3483 | +----------------------------------------------------------------- |
3484 | +リクエスト |
3485 | + |
3486 | +・open_index命令�次�よ��構文を��。 |
3487 | + 'P' indexid dbname tablename indexname fieldlist |
3488 | + indexid�開���る索引�付�られる番����一接続上�後�実行 |
3489 | + �る命令��対象索引を指定�る���使�れる。dbname�tablename� |
3490 | + indexname��れ�れ開���DB�テーブル�索引���。索引��� |
3491 | + ã�¨ã�—ã�¦"PRIMARY"を指定ã�™ã‚‹ã�¨ãƒ—ライマリã‚ーã�Œé–‹ã�‹ã‚Œã‚‹ã€‚fieldlist |
3492 | + �カンマ区切り�列��リスト。 |
3493 | +・find命令�次�よ��構文を��。 |
3494 | + indexid op nflds v1 ... vn limit offset |
3495 | + indexidã�¯å®Ÿè¡Œå¯¾è±¡ã�®ç´¢å¼•ã‚’指定ã�™ã‚‹ã€‚opã�¯ç´¢å¼•æ¤œç´¢ã�®æ¼”ç®—å�(後述)。 |
3496 | + v1�らvn��変長����個数�nflds。nflds�indexid�指定�れ� |
3497 | + open_index命令ã�®indexnameã�®ç´¢å¼•ã�®fieldlistã�®ãƒ•ã‚£ãƒ¼ãƒ«ãƒ‰æ•°ã�«ç‰ã�— |
3498 | + ����������ら��。m2�らmk��変長����個数� |
3499 | + indexid�指定�れ�open_index命令�発行�れ�際�fieldlist�一 |
3500 | + 致���れ��ら��。コマンド行�limit以���略��る。limit |
3501 | + �offset��検索�件��致�る列���レス�ンス�返�列数�上 |
3502 | + é™�ã�¨ã€�スã‚ップã�™ã‚‹åˆ—数。limitã�¨offsetã‚’çœ�ç•¥ã�—ã�Ÿå ´å�ˆã�¯ã��ã‚Œã�žã‚Œ1 |
3503 | + �0�指定�れ������動作を�る。find命令�レス�ンス���� |
3504 | + æ�¡ä»¶ã�«å�ˆè‡´ã�—ã�Ÿåˆ—ã�®ãƒªã‚¹ãƒˆã‚’è¿”ã�™ã€‚opã�¨ã�—ã�¦æŒ‡å®šã�§ã��る演算å�ã�¯æ¬¡ã�® |
3505 | + ��り。 |
3506 | + '=' - v1 ... vn�一致�るも�を�得 |
3507 | + '>' - v1 ... vnより大ã��ã�„ã‚‚ã�®ã‚’æ˜‡é †ã�«å�–å¾— |
3508 | + '>=' - v1 ... vnã�«ä¸€è‡´ã�™ã‚‹ã�‹å¤§ã��ã�„ã‚‚ã�®ã‚’æ˜‡é †ã�«å�–å¾— |
3509 | + '<' - v1 ... vnよりå°�ã�•ã�„ã‚‚ã�®ã‚’é™�é †ã�«å�–å¾— |
3510 | + '<=' - v1 ... vnã�«ä¸€è‡´ã�™ã‚‹ã�‹ç‰ã�—ã�„ã‚‚ã�®ã‚’é™�é †ã�«å�–å¾— |
3511 | + nfldsã�Œ1より大ã��ã�„(v1 ... vnã�Œ2個以上)ã�¨ã��ã�¯è¾žæ›¸å¼�é †åº�ã�§æ¯”較ã�• |
3512 | + れる。 |
3513 | +・find_modify命令�次�よ��構文を��。 |
3514 | + indexid op nflds v1 ... vn limit offset modop m1 ... mk |
3515 | + modopよりå‰�ã�®éƒ¨åˆ†ã�¯find命令ã�¨å�Œç‰ã�§ã€�ã�“ã‚Œã�«ã‚ˆã�£ã�¦æ“�作対象ã�®è¡Œã‚’ |
3516 | + 指定�る。���作対象�行�対�modop�指定�れ�変更処�を実行 |
3517 | + �る。m1 ... mk��変長���略��る。modop�次��れ�。 |
3518 | + 'U' - indexid�指定�れ�open_index命令�fieldlist列 |
3519 | + �内容を�m1 ... mk�値�更新�る。 |
3520 | + 'D' - 対象�行を削除�る。m1 ... mk�値�無視�れる。 |
3521 | +・insert命令��よ��構文を��。 |
3522 | + indexid '+' nflds v1 ... vn |
3523 | + indexid�指定�れ�テーブル��列を挿入�る。v1 ... vn��変長 |
3524 | + ����個数�nflds。nflds�indexid�指定�れ�open_index命令� |
3525 | + indexnameã�®ç´¢å¼•ã�®fieldlistã�®ãƒ•ã‚£ãƒ¼ãƒ«ãƒ‰æ•°ã�«ç‰ã�—ã�„ã�‹å°�ã�•ã��ã�ªã��ã�¦ |
3526 | + ��ら��。 |
3527 | + |
3528 | +----------------------------------------------------------------- |
3529 | +レス�ンス |
3530 | + |
3531 | +・open_index命令��功�����レス�ンス�次�構文を��。 |
3532 | + '0' '1' |
3533 | +・find命令��功�����レス�ンス�次�構文を��。 |
3534 | + '0' nflds v1 ... vn |
3535 | + nflds��果セット�列�数を�ら��。v1 ... vn��変長���� |
3536 | + 長��nflds�整数�。v1 ... vn�空���も�り��れ��件�� |
3537 | + 致ã�™ã‚‹ãƒ¬ã‚³ãƒ¼ãƒ‰ã�Œå˜åœ¨ã�—ã�ªã�‹ã�£ã�Ÿã�“ã�¨ã‚’ã�‚らã‚�ã�™ã€‚çµ�果セットã�Œè¤‡æ•° |
3538 | + 行�������v1 ... vn�長��nflds�2�以上��り�最�� |
3539 | + è¡Œã�‹ã‚‰é †ã�«v1 ... vnã�«ã‚»ãƒƒãƒˆã�•ã‚Œã‚‹ã€‚ |
3540 | +・modify命令��功�����レス�ンス�次�構文を��。 |
3541 | + '0' '1' nummod |
3542 | + nummod�変更�施�れ�行数。nummod�0����変更�れ�行�無 |
3543 | + �����を�ら��。 |
3544 | +・insert命令��功�����レス�ンス�次�構文を��。 |
3545 | + '0' '1' |
3546 | +・命令�失敗�����レス�ンス�命令�関�ら�次�構文を��。 |
3547 | + err '1' message |
3548 | + errã�¯0以外ã�®æ•°å€¤ã�§ã€�エラーコードをã�‚らã‚�ã�™ã€‚messageã�¯äººé–“å�¯èªã�ª |
3549 | + エラーメッセージ。ã�Ÿã� ã�—messageã�Œç„¡ã�„ã�“ã�¨ã‚‚ã�‚る。 |
3550 | + |
3551 | |
3552 | === added directory 'HandlerSocket-Plugin-for-MySQL/handlersocket' |
3553 | === added file 'HandlerSocket-Plugin-for-MySQL/handlersocket/COPYRIGHT.txt' |
3554 | --- HandlerSocket-Plugin-for-MySQL/handlersocket/COPYRIGHT.txt 1970-01-01 00:00:00 +0000 |
3555 | +++ HandlerSocket-Plugin-for-MySQL/handlersocket/COPYRIGHT.txt 2011-04-12 04:16:24 +0000 |
3556 | @@ -0,0 +1,27 @@ |
3557 | + |
3558 | + Copyright (c) 2010 DeNA Co.,Ltd. |
3559 | + All rights reserved. |
3560 | + |
3561 | + Redistribution and use in source and binary forms, with or without |
3562 | + modification, are permitted provided that the following conditions are met: |
3563 | + |
3564 | + * Redistributions of source code must retain the above copyright |
3565 | + notice, this list of conditions and the following disclaimer. |
3566 | + * Redistributions in binary form must reproduce the above copyright |
3567 | + notice, this list of conditions and the following disclaimer in the |
3568 | + documentation and/or other materials provided with the distribution. |
3569 | + * Neither the name of DeNA Co.,Ltd. nor the names of its contributors |
3570 | + may be used to endorse or promote products derived from this software |
3571 | + without specific prior written permission. |
3572 | + |
3573 | + THIS SOFTWARE IS PROVIDED BY DeNA Co.,Ltd. "AS IS" AND ANY EXPRESS OR |
3574 | + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF |
3575 | + MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO |
3576 | + EVENT SHALL DeNA Co.,Ltd. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
3577 | + SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
3578 | + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; |
3579 | + OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, |
3580 | + WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR |
3581 | + OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF |
3582 | + ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
3583 | + |
3584 | |
3585 | === added file 'HandlerSocket-Plugin-for-MySQL/handlersocket/Makefile.am' |
3586 | --- HandlerSocket-Plugin-for-MySQL/handlersocket/Makefile.am 1970-01-01 00:00:00 +0000 |
3587 | +++ HandlerSocket-Plugin-for-MySQL/handlersocket/Makefile.am 2011-04-12 04:16:24 +0000 |
3588 | @@ -0,0 +1,10 @@ |
3589 | +pkgplugindir = $(PLUGIN_DIR) |
3590 | +noinst_HEADERS = database.hpp hstcpsvr.hpp hstcpsvr_worker.hpp mysql_incl.hpp |
3591 | +pkgplugin_LTLIBRARIES = handlersocket.la |
3592 | +handlersocket_la_LDFLAGS = -module ../libhsclient/libhsclient.la |
3593 | +handlersocket_la_CFLAGS = $(MYSQL_INC) $(MYSQL_CFLAGS) $(AM_CFLAGS) \ |
3594 | + -I../libhsclient |
3595 | +handlersocket_la_CXXFLAGS = $(MYSQL_INC) $(MYSQL_CFLAGS) $(AM_CFLAGS) \ |
3596 | + -I../libhsclient |
3597 | +handlersocket_la_SOURCES = database.cpp handlersocket.cpp \ |
3598 | + hstcpsvr_worker.cpp hstcpsvr.cpp |
3599 | |
3600 | === added file 'HandlerSocket-Plugin-for-MySQL/handlersocket/Makefile.plain.template' |
3601 | --- HandlerSocket-Plugin-for-MySQL/handlersocket/Makefile.plain.template 1970-01-01 00:00:00 +0000 |
3602 | +++ HandlerSocket-Plugin-for-MySQL/handlersocket/Makefile.plain.template 2011-04-12 04:16:24 +0000 |
3603 | @@ -0,0 +1,31 @@ |
3604 | + |
3605 | +MYSQL_INC = HANDLERSOCKET_MYSQL_INC |
3606 | +MYSQL_LIB = HANDLERSOCKET_MYSQL_LIB |
3607 | + |
3608 | +CXX = g++ -Wall -g -fno-rtti -fno-exceptions -fPIC -DPIC |
3609 | +LIBS = $(MYSQL_LIB) -lhsclient -lpthread -lz |
3610 | +CXXFLAGS = -I/usr/include/handlersocket $(MYSQL_INC) |
3611 | +LDFLAGS = |
3612 | + |
3613 | +CXXFLAGS += -O3 -DNDEBUG |
3614 | + |
3615 | +HANDLERSOCKET_OBJS = database.o hstcpsvr.o hstcpsvr_worker.o |
3616 | + |
3617 | +all: handlersocket.so |
3618 | + |
3619 | +handlersocket.so: $(HANDLERSOCKET_OBJS) handlersocket.cpp |
3620 | + $(CXX) $(CXXFLAGS) -fno-strict-aliasing -shared $^ -o $@ $(LDFLAGS) \ |
3621 | + -Wl,-soname -Wl,$@ $(LIBS) |
3622 | +clean: |
3623 | + rm -f *.a *.so *.o |
3624 | + |
3625 | +LIBDIR = $(shell \ |
3626 | + if [ -e /usr/lib64/mysql ]; then echo /usr/lib64; else echo /usr/lib; fi) |
3627 | + |
3628 | +install: handlersocket.so |
3629 | + sudo sh -c 'ulimit -c unlimited ; /etc/init.d/mysql stop ; \ |
3630 | + cp handlersocket.so handlersocket.so.cpy && \ |
3631 | + mv handlersocket.so.cpy \ |
3632 | + $(LIBDIR)/mysql/plugin/handlersocket.so && \ |
3633 | + /etc/init.d/mysql start' |
3634 | + |
3635 | |
3636 | === added file 'HandlerSocket-Plugin-for-MySQL/handlersocket/database.cpp' |
3637 | --- HandlerSocket-Plugin-for-MySQL/handlersocket/database.cpp 1970-01-01 00:00:00 +0000 |
3638 | +++ HandlerSocket-Plugin-for-MySQL/handlersocket/database.cpp 2011-04-12 04:16:24 +0000 |
3639 | @@ -0,0 +1,1143 @@ |
3640 | + |
3641 | +// vim:sw=2:ai |
3642 | + |
3643 | +/* |
3644 | + * Copyright (C) 2010 DeNA Co.,Ltd.. All rights reserved. |
3645 | + * See COPYRIGHT.txt for details. |
3646 | + */ |
3647 | + |
3648 | +#include <stdlib.h> |
3649 | +#include <stdio.h> |
3650 | +#include <string.h> |
3651 | + |
3652 | +#include "database.hpp" |
3653 | +#include "string_util.hpp" |
3654 | +#include "escape.hpp" |
3655 | +#include "mysql_incl.hpp" |
3656 | + |
3657 | +#define DBG_KEY(x) |
3658 | +#define DBG_SHUT(x) |
3659 | +#define DBG_LOCK(x) |
3660 | +#define DBG_THR(x) |
3661 | +#define DBG_CMP(x) |
3662 | +#define DBG_FLD(x) |
3663 | +#define DBG_FILTER(x) |
3664 | +#define DBG_REFCNT(x) |
3665 | +#define DBG_DELETED |
3666 | + |
3667 | +/* status variables */ |
3668 | +unsigned long long int open_tables_count; |
3669 | +unsigned long long int close_tables_count; |
3670 | +unsigned long long int lock_tables_count; |
3671 | +unsigned long long int unlock_tables_count; |
3672 | +unsigned long long int index_exec_count; |
3673 | + |
3674 | +namespace dena { |
3675 | + |
3676 | +prep_stmt::prep_stmt() |
3677 | + : dbctx(0), table_id(static_cast<size_t>(-1)), |
3678 | + idxnum(static_cast<size_t>(-1)) |
3679 | +{ |
3680 | +} |
3681 | +prep_stmt::prep_stmt(dbcontext_i *c, size_t tbl, size_t idx, |
3682 | + const fields_type& rf, const fields_type& ff) |
3683 | + : dbctx(c), table_id(tbl), idxnum(idx), ret_fields(rf), filter_fields(ff) |
3684 | +{ |
3685 | + if (dbctx) { |
3686 | + dbctx->table_addref(table_id); |
3687 | + } |
3688 | +} |
3689 | +prep_stmt::~prep_stmt() |
3690 | +{ |
3691 | + if (dbctx) { |
3692 | + dbctx->table_release(table_id); |
3693 | + } |
3694 | +} |
3695 | + |
3696 | +prep_stmt::prep_stmt(const prep_stmt& x) |
3697 | + : dbctx(x.dbctx), table_id(x.table_id), idxnum(x.idxnum), |
3698 | + ret_fields(x.ret_fields), filter_fields(x.filter_fields) |
3699 | +{ |
3700 | + if (dbctx) { |
3701 | + dbctx->table_addref(table_id); |
3702 | + } |
3703 | +} |
3704 | + |
3705 | +prep_stmt& |
3706 | +prep_stmt::operator =(const prep_stmt& x) |
3707 | +{ |
3708 | + if (this != &x) { |
3709 | + if (dbctx) { |
3710 | + dbctx->table_release(table_id); |
3711 | + } |
3712 | + dbctx = x.dbctx; |
3713 | + table_id = x.table_id; |
3714 | + idxnum = x.idxnum; |
3715 | + ret_fields = x.ret_fields; |
3716 | + filter_fields = x.filter_fields; |
3717 | + if (dbctx) { |
3718 | + dbctx->table_addref(table_id); |
3719 | + } |
3720 | + } |
3721 | + return *this; |
3722 | +} |
3723 | + |
3724 | +struct database : public database_i, private noncopyable { |
3725 | + database(const config& c); |
3726 | + virtual ~database(); |
3727 | + virtual dbcontext_ptr create_context(bool for_write) volatile; |
3728 | + virtual void stop() volatile; |
3729 | + virtual const config& get_conf() const volatile; |
3730 | + public: |
3731 | + int child_running; |
3732 | + private: |
3733 | + config conf; |
3734 | +}; |
3735 | + |
3736 | +struct tablevec_entry { |
3737 | + TABLE *table; |
3738 | + size_t refcount; |
3739 | + bool modified; |
3740 | + tablevec_entry() : table(0), refcount(0), modified(false) { } |
3741 | +}; |
3742 | + |
3743 | +struct expr_user_lock : private noncopyable { |
3744 | + expr_user_lock(THD *thd, int timeout) |
3745 | + : lck_key("handlersocket_wr", 16, &my_charset_latin1), |
3746 | + lck_timeout(timeout), |
3747 | + lck_func_get_lock(&lck_key, &lck_timeout), |
3748 | + lck_func_release_lock(&lck_key) |
3749 | + { |
3750 | + lck_key.fix_fields(thd, 0); |
3751 | + lck_timeout.fix_fields(thd, 0); |
3752 | + lck_func_get_lock.fix_fields(thd, 0); |
3753 | + lck_func_release_lock.fix_fields(thd, 0); |
3754 | + } |
3755 | + long long get_lock() { |
3756 | + return lck_func_get_lock.val_int(); |
3757 | + } |
3758 | + long long release_lock() { |
3759 | + return lck_func_release_lock.val_int(); |
3760 | + } |
3761 | + private: |
3762 | + Item_string lck_key; |
3763 | + Item_int lck_timeout; |
3764 | + Item_func_get_lock lck_func_get_lock; |
3765 | + Item_func_release_lock lck_func_release_lock; |
3766 | +}; |
3767 | + |
3768 | +struct dbcontext : public dbcontext_i, private noncopyable { |
3769 | + dbcontext(volatile database *d, bool for_write); |
3770 | + virtual ~dbcontext(); |
3771 | + virtual void init_thread(const void *stack_botton, |
3772 | + volatile int& shutdown_flag); |
3773 | + virtual void term_thread(); |
3774 | + virtual bool check_alive(); |
3775 | + virtual void lock_tables_if(); |
3776 | + virtual void unlock_tables_if(); |
3777 | + virtual bool get_commit_error(); |
3778 | + virtual void clear_error(); |
3779 | + virtual void close_tables_if(); |
3780 | + virtual void table_addref(size_t tbl_id); |
3781 | + virtual void table_release(size_t tbl_id); |
3782 | + virtual void cmd_open_index(dbcallback_i& cb, size_t pst_id, const char *dbn, |
3783 | + const char *tbl, const char *idx, const char *retflds, |
3784 | + const char *filflds); |
3785 | + virtual void cmd_exec_on_index(dbcallback_i& cb, const cmd_exec_args& args); |
3786 | + virtual void set_statistics(size_t num_conns, size_t num_active); |
3787 | + private: |
3788 | + int set_thread_message(const char *fmt, ...) |
3789 | + __attribute__((format (printf, 2, 3))); |
3790 | + bool parse_fields(TABLE *const table, const char *str, |
3791 | + prep_stmt::fields_type& flds); |
3792 | + void cmd_insert_internal(dbcallback_i& cb, const prep_stmt& pst, |
3793 | + const string_ref *fvals, size_t fvalslen); |
3794 | + void cmd_sql_internal(dbcallback_i& cb, const prep_stmt& pst, |
3795 | + const string_ref *fvals, size_t fvalslen); |
3796 | + void cmd_find_internal(dbcallback_i& cb, const prep_stmt& pst, |
3797 | + ha_rkey_function find_flag, const cmd_exec_args& args); |
3798 | + size_t calc_filter_buf_size(TABLE *table, const prep_stmt& pst, |
3799 | + const record_filter *filters); |
3800 | + bool fill_filter_buf(TABLE *table, const prep_stmt& pst, |
3801 | + const record_filter *filters, uchar *filter_buf, size_t len); |
3802 | + int check_filter(dbcallback_i& cb, TABLE *table, const prep_stmt& pst, |
3803 | + const record_filter *filters, const uchar *filter_buf); |
3804 | + void resp_record(dbcallback_i& cb, TABLE *const table, const prep_stmt& pst); |
3805 | + void dump_record(dbcallback_i& cb, TABLE *const table, const prep_stmt& pst); |
3806 | + int modify_record(dbcallback_i& cb, TABLE *const table, |
3807 | + const prep_stmt& pst, const cmd_exec_args& args, char mod_op, |
3808 | + size_t& modified_count); |
3809 | + private: |
3810 | + typedef std::vector<tablevec_entry> table_vec_type; |
3811 | + typedef std::pair<std::string, std::string> table_name_type; |
3812 | + typedef std::map<table_name_type, size_t> table_map_type; |
3813 | + private: |
3814 | + volatile database *const dbref; |
3815 | + bool for_write_flag; |
3816 | + THD *thd; |
3817 | + MYSQL_LOCK *lock; |
3818 | + bool lock_failed; |
3819 | + std::auto_ptr<expr_user_lock> user_lock; |
3820 | + int user_level_lock_timeout; |
3821 | + bool user_level_lock_locked; |
3822 | + bool commit_error; |
3823 | + std::vector<char> info_message_buf; |
3824 | + table_vec_type table_vec; |
3825 | + table_map_type table_map; |
3826 | + #if MYSQL_VERSION_ID >= 50505 |
3827 | + MDL_request *mdl_request; |
3828 | + #else |
3829 | + void *mdl_request; |
3830 | + #endif |
3831 | +}; |
3832 | + |
3833 | +database::database(const config& c) |
3834 | + : child_running(1), conf(c) |
3835 | +{ |
3836 | +} |
3837 | + |
3838 | +database::~database() |
3839 | +{ |
3840 | +} |
3841 | + |
3842 | +dbcontext_ptr |
3843 | +database::create_context(bool for_write) volatile |
3844 | +{ |
3845 | + return dbcontext_ptr(new dbcontext(this, for_write)); |
3846 | +} |
3847 | + |
3848 | +void |
3849 | +database::stop() volatile |
3850 | +{ |
3851 | + child_running = false; |
3852 | +} |
3853 | + |
3854 | +const config& |
3855 | +database::get_conf() const volatile |
3856 | +{ |
3857 | + return const_cast<const config&>(conf); |
3858 | +} |
3859 | + |
3860 | +database_ptr |
3861 | +database_i::create(const config& conf) |
3862 | +{ |
3863 | + return database_ptr(new database(conf)); |
3864 | +} |
3865 | + |
3866 | +dbcontext::dbcontext(volatile database *d, bool for_write) |
3867 | + : dbref(d), for_write_flag(for_write), thd(0), lock(0), lock_failed(false), |
3868 | + user_level_lock_timeout(0), user_level_lock_locked(false), |
3869 | + commit_error(false), mdl_request(0) |
3870 | +{ |
3871 | + info_message_buf.resize(8192); |
3872 | + user_level_lock_timeout = d->get_conf().get_int("wrlock_timeout", 12); |
3873 | +} |
3874 | + |
3875 | +dbcontext::~dbcontext() |
3876 | +{ |
3877 | +} |
3878 | + |
3879 | +namespace { |
3880 | + |
3881 | +int |
3882 | +wait_server_to_start(THD *thd, volatile int& shutdown_flag) |
3883 | +{ |
3884 | + int r = 0; |
3885 | + DBG_SHUT(fprintf(stderr, "HNDSOCK wsts\n")); |
3886 | + pthread_mutex_lock(&LOCK_server_started); |
3887 | + while (!mysqld_server_started) { |
3888 | + timespec abstime = { }; |
3889 | + set_timespec(abstime, 1); |
3890 | + pthread_cond_timedwait(&COND_server_started, &LOCK_server_started, |
3891 | + &abstime); |
3892 | + pthread_mutex_unlock(&LOCK_server_started); |
3893 | + pthread_mutex_lock(&thd->mysys_var->mutex); |
3894 | + THD::killed_state st = thd->killed; |
3895 | + pthread_mutex_unlock(&thd->mysys_var->mutex); |
3896 | + DBG_SHUT(fprintf(stderr, "HNDSOCK wsts kst %d\n", (int)st)); |
3897 | + pthread_mutex_lock(&LOCK_server_started); |
3898 | + if (st != THD::NOT_KILLED) { |
3899 | + DBG_SHUT(fprintf(stderr, "HNDSOCK wsts kst %d break\n", (int)st)); |
3900 | + r = -1; |
3901 | + break; |
3902 | + } |
3903 | + if (shutdown_flag) { |
3904 | + DBG_SHUT(fprintf(stderr, "HNDSOCK wsts kst shut break\n")); |
3905 | + r = -1; |
3906 | + break; |
3907 | + } |
3908 | + } |
3909 | + pthread_mutex_unlock(&LOCK_server_started); |
3910 | + DBG_SHUT(fprintf(stderr, "HNDSOCK wsts done\n")); |
3911 | + return r; |
3912 | +} |
3913 | + |
3914 | +}; // namespace |
3915 | + |
3916 | +void |
3917 | +dbcontext::init_thread(const void *stack_bottom, volatile int& shutdown_flag) |
3918 | +{ |
3919 | + DBG_THR(fprintf(stderr, "HNDSOCK init thread\n")); |
3920 | + { |
3921 | + my_thread_init(); |
3922 | + thd = new THD; |
3923 | + thd->thread_stack = (char *)stack_bottom; |
3924 | + DBG_THR(const size_t of = (char *)(&thd->thread_stack) - (char *)thd); |
3925 | + DBG_THR(fprintf(stderr, "thread_stack = %p sz=%zu of=%zu\n", |
3926 | + thd->thread_stack, sizeof(THD), of)); |
3927 | + thd->store_globals(); |
3928 | + thd->system_thread = static_cast<enum_thread_type>(1<<30UL); |
3929 | + const NET v = { 0 }; |
3930 | + thd->net = v; |
3931 | + if (for_write_flag) { |
3932 | + #if MYSQL_VERSION_ID >= 50505 |
3933 | + thd->variables.option_bits |= OPTION_BIN_LOG; |
3934 | + #else |
3935 | + thd->options |= OPTION_BIN_LOG; |
3936 | + #endif |
3937 | + safeFree(thd->db); |
3938 | + thd->db = 0; |
3939 | + thd->db = my_strdup("handlersocket", MYF(0)); |
3940 | + } |
3941 | + my_pthread_setspecific_ptr(THR_THD, thd); |
3942 | + DBG_THR(fprintf(stderr, "HNDSOCK x0 %p\n", thd)); |
3943 | + } |
3944 | + { |
3945 | + pthread_mutex_lock(&LOCK_thread_count); |
3946 | + thd->thread_id = thread_id++; |
3947 | + threads.append(thd); |
3948 | + ++thread_count; |
3949 | + pthread_mutex_unlock(&LOCK_thread_count); |
3950 | + } |
3951 | + |
3952 | + DBG_THR(fprintf(stderr, "HNDSOCK init thread wsts\n")); |
3953 | + wait_server_to_start(thd, shutdown_flag); |
3954 | + DBG_THR(fprintf(stderr, "HNDSOCK init thread done\n")); |
3955 | + |
3956 | + thd_proc_info(thd, &info_message_buf[0]); |
3957 | + set_thread_message("hs:listening"); |
3958 | + DBG_THR(fprintf(stderr, "HNDSOCK x1 %p\n", thd)); |
3959 | + |
3960 | + #if MYSQL_VERSION_ID >= 50508 |
3961 | + mdl_request = new(thd->mem_root) MDL_request; |
3962 | + mdl_request->init(MDL_key::TABLE, "", "", |
3963 | + for_write_flag ? MDL_SHARED_WRITE : MDL_SHARED_READ, MDL_STATEMENT); |
3964 | + #elif MYSQL_VERSION_ID >= 50505 |
3965 | + mdl_request = MDL_request::create(MDL_key::TABLE, "", "", |
3966 | + for_write_flag ? MDL_SHARED_WRITE : MDL_SHARED_READ, thd->mem_root); |
3967 | + #endif |
3968 | + |
3969 | + lex_start(thd); |
3970 | + |
3971 | + user_lock.reset(new expr_user_lock(thd, user_level_lock_timeout)); |
3972 | +} |
3973 | + |
3974 | +int |
3975 | +dbcontext::set_thread_message(const char *fmt, ...) |
3976 | +{ |
3977 | + va_list ap; |
3978 | + va_start(ap, fmt); |
3979 | + const int n = vsnprintf(&info_message_buf[0], info_message_buf.size(), |
3980 | + fmt, ap); |
3981 | + va_end(ap); |
3982 | + return n; |
3983 | +} |
3984 | + |
3985 | +void |
3986 | +dbcontext::term_thread() |
3987 | +{ |
3988 | + DBG_THR(fprintf(stderr, "HNDSOCK thread end %p\n", thd)); |
3989 | + unlock_tables_if(); |
3990 | + my_pthread_setspecific_ptr(THR_THD, 0); |
3991 | + { |
3992 | + pthread_mutex_lock(&LOCK_thread_count); |
3993 | + delete thd; |
3994 | + thd = 0; |
3995 | + --thread_count; |
3996 | + pthread_mutex_unlock(&LOCK_thread_count); |
3997 | + my_thread_end(); |
3998 | + } |
3999 | +} |
4000 | + |
4001 | +bool |
4002 | +dbcontext::check_alive() |
4003 | +{ |
4004 | + pthread_mutex_lock(&thd->mysys_var->mutex); |
4005 | + THD::killed_state st = thd->killed; |
4006 | + pthread_mutex_unlock(&thd->mysys_var->mutex); |
4007 | + DBG_SHUT(fprintf(stderr, "chk HNDSOCK kst %p %p %d %zu\n", thd, &thd->killed, |
4008 | + (int)st, sizeof(*thd))); |
4009 | + if (st != THD::NOT_KILLED) { |
4010 | + DBG_SHUT(fprintf(stderr, "chk HNDSOCK kst %d break\n", (int)st)); |
4011 | + return false; |
4012 | + } |
4013 | + return true; |
4014 | +} |
4015 | + |
4016 | +void |
4017 | +dbcontext::lock_tables_if() |
4018 | +{ |
4019 | + if (lock_failed) { |
4020 | + return; |
4021 | + } |
4022 | + if (for_write_flag && !user_level_lock_locked) { |
4023 | + if (user_lock->get_lock()) { |
4024 | + user_level_lock_locked = true; |
4025 | + } else { |
4026 | + lock_failed = true; |
4027 | + return; |
4028 | + } |
4029 | + } |
4030 | + if (lock == 0) { |
4031 | + const size_t num_max = table_vec.size(); |
4032 | + TABLE *tables[num_max ? num_max : 1]; /* GNU */ |
4033 | + size_t num_open = 0; |
4034 | + for (size_t i = 0; i < num_max; ++i) { |
4035 | + if (table_vec[i].refcount > 0) { |
4036 | + tables[num_open++] = table_vec[i].table; |
4037 | + } |
4038 | + table_vec[i].modified = false; |
4039 | + } |
4040 | + #if MYSQL_VERSION_ID >= 50505 |
4041 | + lock = thd->lock = mysql_lock_tables(thd, &tables[0], num_open, 0); |
4042 | + #else |
4043 | + bool need_reopen= false; |
4044 | + lock = thd->lock = mysql_lock_tables(thd, &tables[0], num_open, |
4045 | + MYSQL_LOCK_NOTIFY_IF_NEED_REOPEN, &need_reopen); |
4046 | + #endif |
4047 | + statistic_increment(lock_tables_count, &LOCK_status); |
4048 | + thd_proc_info(thd, &info_message_buf[0]); |
4049 | + DENA_VERBOSE(100, fprintf(stderr, "HNDSOCK lock tables %p %p %zu %zu\n", |
4050 | + thd, lock, num_max, num_open)); |
4051 | + if (lock == 0) { |
4052 | + lock_failed = true; |
4053 | + DENA_VERBOSE(10, fprintf(stderr, "HNDSOCK failed to lock tables %p\n", |
4054 | + thd)); |
4055 | + } |
4056 | + if (for_write_flag) { |
4057 | + #if MYSQL_VERSION_ID >= 50505 |
4058 | + thd->set_current_stmt_binlog_format_row(); |
4059 | + #else |
4060 | + thd->current_stmt_binlog_row_based = 1; |
4061 | + #endif |
4062 | + } |
4063 | + } |
4064 | + DBG_LOCK(fprintf(stderr, "HNDSOCK tblnum=%d\n", (int)tblnum)); |
4065 | +} |
4066 | + |
4067 | +void |
4068 | +dbcontext::unlock_tables_if() |
4069 | +{ |
4070 | + if (lock != 0) { |
4071 | + DENA_VERBOSE(100, fprintf(stderr, "HNDSOCK unlock tables\n")); |
4072 | + if (for_write_flag) { |
4073 | + for (size_t i = 0; i < table_vec.size(); ++i) { |
4074 | + if (table_vec[i].modified) { |
4075 | + query_cache_invalidate3(thd, table_vec[i].table, 0); |
4076 | + /* invalidate immediately */ |
4077 | + } |
4078 | + } |
4079 | + bool suc = true; |
4080 | + #if MYSQL_VERSION_ID >= 50505 |
4081 | + suc = (trans_commit_stmt(thd) == 0); |
4082 | + #else |
4083 | + suc = (ha_autocommit_or_rollback(thd, 0) == 0); |
4084 | + #endif |
4085 | + if (!suc) { |
4086 | + commit_error = true; |
4087 | + DENA_VERBOSE(10, fprintf(stderr, |
4088 | + "HNDSOCK unlock tables: commit failed\n")); |
4089 | + } |
4090 | + } |
4091 | + mysql_unlock_tables(thd, lock); |
4092 | + lock = thd->lock = 0; |
4093 | + statistic_increment(unlock_tables_count, &LOCK_status); |
4094 | + } |
4095 | + if (user_level_lock_locked) { |
4096 | + if (user_lock->release_lock()) { |
4097 | + user_level_lock_locked = false; |
4098 | + } |
4099 | + } |
4100 | +} |
4101 | + |
4102 | +bool |
4103 | +dbcontext::get_commit_error() |
4104 | +{ |
4105 | + return commit_error; |
4106 | +} |
4107 | + |
4108 | +void |
4109 | +dbcontext::clear_error() |
4110 | +{ |
4111 | + lock_failed = false; |
4112 | + commit_error = false; |
4113 | +} |
4114 | + |
4115 | +void |
4116 | +dbcontext::close_tables_if() |
4117 | +{ |
4118 | + unlock_tables_if(); |
4119 | + if (!table_vec.empty()) { |
4120 | + DENA_VERBOSE(100, fprintf(stderr, "HNDSOCK close tables\n")); |
4121 | + close_thread_tables(thd); |
4122 | + statistic_increment(close_tables_count, &LOCK_status); |
4123 | + table_vec.clear(); |
4124 | + table_map.clear(); |
4125 | + } |
4126 | +} |
4127 | + |
4128 | +void |
4129 | +dbcontext::table_addref(size_t tbl_id) |
4130 | +{ |
4131 | + table_vec[tbl_id].refcount += 1; |
4132 | + DBG_REFCNT(fprintf(stderr, "%p %zu %zu addref\n", this, tbl_id, |
4133 | + table_vec[tbl_id].refcount)); |
4134 | +} |
4135 | + |
4136 | +void |
4137 | +dbcontext::table_release(size_t tbl_id) |
4138 | +{ |
4139 | + table_vec[tbl_id].refcount -= 1; |
4140 | + DBG_REFCNT(fprintf(stderr, "%p %zu %zu release\n", this, tbl_id, |
4141 | + table_vec[tbl_id].refcount)); |
4142 | +} |
4143 | + |
4144 | +void |
4145 | +dbcontext::resp_record(dbcallback_i& cb, TABLE *const table, |
4146 | + const prep_stmt& pst) |
4147 | +{ |
4148 | + char rwpstr_buf[64]; |
4149 | + String rwpstr(rwpstr_buf, sizeof(rwpstr_buf), &my_charset_bin); |
4150 | + const prep_stmt::fields_type& rf = pst.get_ret_fields(); |
4151 | + const size_t n = rf.size(); |
4152 | + for (size_t i = 0; i < n; ++i) { |
4153 | + uint32_t fn = rf[i]; |
4154 | + Field *const fld = table->field[fn]; |
4155 | + DBG_FLD(fprintf(stderr, "fld=%p %zu\n", fld, fn)); |
4156 | + if (fld->is_null()) { |
4157 | + /* null */ |
4158 | + cb.dbcb_resp_entry(0, 0); |
4159 | + } else { |
4160 | + fld->val_str(&rwpstr, &rwpstr); |
4161 | + const size_t len = rwpstr.length(); |
4162 | + if (len != 0) { |
4163 | + /* non-empty */ |
4164 | + cb.dbcb_resp_entry(rwpstr.ptr(), rwpstr.length()); |
4165 | + } else { |
4166 | + /* empty */ |
4167 | + static const char empty_str[] = ""; |
4168 | + cb.dbcb_resp_entry(empty_str, 0); |
4169 | + } |
4170 | + } |
4171 | + } |
4172 | +} |
4173 | + |
4174 | +void |
4175 | +dbcontext::dump_record(dbcallback_i& cb, TABLE *const table, |
4176 | + const prep_stmt& pst) |
4177 | +{ |
4178 | + char rwpstr_buf[64]; |
4179 | + String rwpstr(rwpstr_buf, sizeof(rwpstr_buf), &my_charset_bin); |
4180 | + const prep_stmt::fields_type& rf = pst.get_ret_fields(); |
4181 | + const size_t n = rf.size(); |
4182 | + for (size_t i = 0; i < n; ++i) { |
4183 | + uint32_t fn = rf[i]; |
4184 | + Field *const fld = table->field[fn]; |
4185 | + if (fld->is_null()) { |
4186 | + /* null */ |
4187 | + cb.dbcb_resp_entry(0, 0); |
4188 | + fprintf(stderr, "NULL"); |
4189 | + } else { |
4190 | + fld->val_str(&rwpstr, &rwpstr); |
4191 | + const std::string s(rwpstr.ptr(), rwpstr.length()); |
4192 | + fprintf(stderr, "[%s]", s.c_str()); |
4193 | + } |
4194 | + } |
4195 | + fprintf(stderr, "\n"); |
4196 | +} |
4197 | + |
4198 | +int |
4199 | +dbcontext::modify_record(dbcallback_i& cb, TABLE *const table, |
4200 | + const prep_stmt& pst, const cmd_exec_args& args, char mod_op, |
4201 | + size_t& modified_count) |
4202 | +{ |
4203 | + if (mod_op == 'U') { |
4204 | + /* update */ |
4205 | + handler *const hnd = table->file; |
4206 | + uchar *const buf = table->record[0]; |
4207 | + store_record(table, record[1]); |
4208 | + const prep_stmt::fields_type& rf = pst.get_ret_fields(); |
4209 | + const size_t n = rf.size(); |
4210 | + for (size_t i = 0; i < n; ++i) { |
4211 | + const string_ref& nv = args.uvals[i]; |
4212 | + uint32_t fn = rf[i]; |
4213 | + Field *const fld = table->field[fn]; |
4214 | + if (nv.begin() == 0) { |
4215 | + fld->set_null(); |
4216 | + } else { |
4217 | + fld->set_notnull(); |
4218 | + fld->store(nv.begin(), nv.size(), &my_charset_bin); |
4219 | + } |
4220 | + } |
4221 | + table_vec[pst.get_table_id()].modified = true; |
4222 | + const int r = hnd->ha_update_row(table->record[1], buf); |
4223 | + if (r != 0 && r != HA_ERR_RECORD_IS_THE_SAME) { |
4224 | + return r; |
4225 | + } |
4226 | + ++modified_count; /* TODO: HA_ERR_RECORD_IS_THE_SAME? */ |
4227 | + } else if (mod_op == 'D') { |
4228 | + /* delete */ |
4229 | + handler *const hnd = table->file; |
4230 | + table_vec[pst.get_table_id()].modified = true; |
4231 | + const int r = hnd->ha_delete_row(table->record[0]); |
4232 | + if (r != 0) { |
4233 | + return r; |
4234 | + } |
4235 | + ++modified_count; |
4236 | + } else if (mod_op == '+' || mod_op == '-') { |
4237 | + /* increment/decrement */ |
4238 | + handler *const hnd = table->file; |
4239 | + uchar *const buf = table->record[0]; |
4240 | + store_record(table, record[1]); |
4241 | + const prep_stmt::fields_type& rf = pst.get_ret_fields(); |
4242 | + const size_t n = rf.size(); |
4243 | + size_t i = 0; |
4244 | + for (i = 0; i < n; ++i) { |
4245 | + const string_ref& nv = args.uvals[i]; |
4246 | + uint32_t fn = rf[i]; |
4247 | + Field *const fld = table->field[fn]; |
4248 | + if (fld->is_null() || nv.begin() == 0) { |
4249 | + continue; |
4250 | + } |
4251 | + const long long pval = fld->val_int(); |
4252 | + const long long llv = atoll_nocheck(nv.begin(), nv.end()); |
4253 | + /* TODO: llv == 0? */ |
4254 | + long long nval = 0; |
4255 | + if (mod_op == '+') { |
4256 | + /* increment */ |
4257 | + nval = pval + llv; |
4258 | + } else { |
4259 | + /* decrement */ |
4260 | + nval = pval - llv; |
4261 | + if ((pval < 0 && nval > 0) || (pval > 0 && nval < 0)) { |
4262 | + break; /* don't modify */ |
4263 | + } |
4264 | + if ((pval < 0) != (nval < 0)) { |
4265 | + nval = 0; /* crip */ |
4266 | + } |
4267 | + } |
4268 | + fld->store(nval, false); |
4269 | + } |
4270 | + if (i == n) { |
4271 | + /* modify */ |
4272 | + table_vec[pst.get_table_id()].modified = true; |
4273 | + const int r = hnd->ha_update_row(table->record[1], buf); |
4274 | + if (r != 0 && r != HA_ERR_RECORD_IS_THE_SAME) { |
4275 | + return r; |
4276 | + } |
4277 | + ++modified_count; |
4278 | + } |
4279 | + } |
4280 | + return 0; |
4281 | +} |
4282 | + |
4283 | +void |
4284 | +dbcontext::cmd_insert_internal(dbcallback_i& cb, const prep_stmt& pst, |
4285 | + const string_ref *fvals, size_t fvalslen) |
4286 | +{ |
4287 | + if (!for_write_flag) { |
4288 | + return cb.dbcb_resp_short(2, "readonly"); |
4289 | + } |
4290 | + lock_tables_if(); |
4291 | + if (lock == 0) { |
4292 | + return cb.dbcb_resp_short(2, "lock_tables"); |
4293 | + } |
4294 | + if (pst.get_table_id() >= table_vec.size()) { |
4295 | + return cb.dbcb_resp_short(2, "tblnum"); |
4296 | + } |
4297 | + TABLE *const table = table_vec[pst.get_table_id()].table; |
4298 | + handler *const hnd = table->file; |
4299 | + uchar *const buf = table->record[0]; |
4300 | + empty_record(table); |
4301 | + memset(buf, 0, table->s->null_bytes); /* clear null flags */ |
4302 | + Field **fld = table->field; |
4303 | + size_t i = 0; |
4304 | + for (; *fld && i < fvalslen; ++fld, ++i) { |
4305 | + if (fvals[i].begin() == 0) { |
4306 | + (*fld)->set_null(); |
4307 | + } else { |
4308 | + (*fld)->store(fvals[i].begin(), fvals[i].size(), &my_charset_bin); |
4309 | + } |
4310 | + } |
4311 | + table->next_number_field = table->found_next_number_field; |
4312 | + const int r = hnd->ha_write_row(buf); |
4313 | + table->next_number_field = 0; |
4314 | + table_vec[pst.get_table_id()].modified = true; |
4315 | + return cb.dbcb_resp_short(r != 0 ? 1 : 0, ""); |
4316 | +} |
4317 | + |
4318 | +void |
4319 | +dbcontext::cmd_sql_internal(dbcallback_i& cb, const prep_stmt& pst, |
4320 | + const string_ref *fvals, size_t fvalslen) |
4321 | +{ |
4322 | + if (fvalslen < 1) { |
4323 | + return cb.dbcb_resp_short(2, "syntax"); |
4324 | + } |
4325 | + return cb.dbcb_resp_short(2, "notimpl"); |
4326 | +} |
4327 | + |
4328 | +void |
4329 | +dbcontext::cmd_find_internal(dbcallback_i& cb, const prep_stmt& pst, |
4330 | + ha_rkey_function find_flag, const cmd_exec_args& args) |
4331 | +{ |
4332 | + const bool debug_out = (verbose_level >= 100); |
4333 | + bool need_resp_record = true; |
4334 | + char mod_op = 0; |
4335 | + const string_ref& mod_op_str = args.mod_op; |
4336 | + if (mod_op_str.size() != 0) { |
4337 | + if (!for_write_flag) { |
4338 | + return cb.dbcb_resp_short(2, "readonly"); |
4339 | + } |
4340 | + mod_op = mod_op_str.begin()[0]; |
4341 | + need_resp_record = mod_op_str.size() > 1 && mod_op_str.begin()[1] == '?'; |
4342 | + switch (mod_op) { |
4343 | + case 'U': /* update */ |
4344 | + case 'D': /* delete */ |
4345 | + case '+': /* increment */ |
4346 | + case '-': /* decrement */ |
4347 | + break; |
4348 | + default: |
4349 | + if (debug_out) { |
4350 | + fprintf(stderr, "unknown modop: %c\n", mod_op); |
4351 | + } |
4352 | + return cb.dbcb_resp_short(2, "modop"); |
4353 | + } |
4354 | + } |
4355 | + lock_tables_if(); |
4356 | + if (lock == 0) { |
4357 | + return cb.dbcb_resp_short(2, "lock_tables"); |
4358 | + } |
4359 | + if (pst.get_table_id() >= table_vec.size()) { |
4360 | + return cb.dbcb_resp_short(2, "tblnum"); |
4361 | + } |
4362 | + TABLE *const table = table_vec[pst.get_table_id()].table; |
4363 | + /* keys */ |
4364 | + if (pst.get_idxnum() >= table->s->keys) { |
4365 | + return cb.dbcb_resp_short(2, "idxnum"); |
4366 | + } |
4367 | + KEY& kinfo = table->key_info[pst.get_idxnum()]; |
4368 | + if (args.kvalslen > kinfo.key_parts) { |
4369 | + return cb.dbcb_resp_short(2, "kpnum"); |
4370 | + } |
4371 | + uchar key_buf[kinfo.key_length]; /* GNU */ |
4372 | + size_t kplen_sum = 0; |
4373 | + { |
4374 | + DBG_KEY(fprintf(stderr, "SLOW\n")); |
4375 | + for (size_t i = 0; i < args.kvalslen; ++i) { |
4376 | + const KEY_PART_INFO & kpt = kinfo.key_part[i]; |
4377 | + const string_ref& kval = args.kvals[i]; |
4378 | + if (kval.begin() == 0) { |
4379 | + kpt.field->set_null(); |
4380 | + } else { |
4381 | + kpt.field->set_notnull(); |
4382 | + } |
4383 | + kpt.field->store(kval.begin(), kval.size(), &my_charset_bin); |
4384 | + kplen_sum += kpt.store_length; |
4385 | + } |
4386 | + key_copy(key_buf, table->record[0], &kinfo, kplen_sum); |
4387 | + } |
4388 | + /* filters */ |
4389 | + uchar *filter_buf = 0; |
4390 | + if (args.filters != 0) { |
4391 | + const size_t filter_buf_len = calc_filter_buf_size(table, pst, |
4392 | + args.filters); |
4393 | + filter_buf = reinterpret_cast<uchar *>(alloca(filter_buf_len)); |
4394 | + /* FIXME: TEST */ |
4395 | + if (!fill_filter_buf(table, pst, args.filters, filter_buf, |
4396 | + filter_buf_len)) { |
4397 | + return cb.dbcb_resp_short(2, "filterblob"); |
4398 | + } |
4399 | + } |
4400 | + /* handler */ |
4401 | + table->read_set = &table->s->all_set; |
4402 | + handler *const hnd = table->file; |
4403 | + if (!for_write_flag) { |
4404 | + hnd->init_table_handle_for_HANDLER(); |
4405 | + } |
4406 | + hnd->ha_index_or_rnd_end(); |
4407 | + hnd->ha_index_init(pst.get_idxnum(), 1); |
4408 | + #if 0 |
4409 | + statistic_increment(index_exec_count, &LOCK_status); |
4410 | + #endif |
4411 | + if (need_resp_record) { |
4412 | + cb.dbcb_resp_begin(pst.get_ret_fields().size()); |
4413 | + } |
4414 | + const uint32_t limit = args.limit ? args.limit : 1; |
4415 | + uint32_t skip = args.skip; |
4416 | + size_t modified_count = 0; |
4417 | + int r = 0; |
4418 | + for (uint32_t i = 0; i < limit + skip; ++i) { |
4419 | + if (i == 0) { |
4420 | + const key_part_map kpm = (1U << args.kvalslen) - 1; |
4421 | + r = hnd->index_read_map(table->record[0], key_buf, kpm, find_flag); |
4422 | + } else { |
4423 | + switch (find_flag) { |
4424 | + case HA_READ_BEFORE_KEY: |
4425 | + case HA_READ_KEY_OR_PREV: |
4426 | + r = hnd->index_prev(table->record[0]); |
4427 | + break; |
4428 | + case HA_READ_AFTER_KEY: |
4429 | + case HA_READ_KEY_OR_NEXT: |
4430 | + r = hnd->index_next(table->record[0]); |
4431 | + break; |
4432 | + case HA_READ_KEY_EXACT: |
4433 | + r = hnd->index_next_same(table->record[0], key_buf, kplen_sum); |
4434 | + break; |
4435 | + default: |
4436 | + r = HA_ERR_END_OF_FILE; /* to finish the loop */ |
4437 | + break; |
4438 | + } |
4439 | + } |
4440 | + if (debug_out) { |
4441 | + fprintf(stderr, "r=%d\n", r); |
4442 | + if (r == 0 || r == HA_ERR_RECORD_DELETED) { |
4443 | + dump_record(cb, table, pst); |
4444 | + } |
4445 | + } |
4446 | + int filter_res = 0; |
4447 | + if (r != 0) { |
4448 | + /* no-count */ |
4449 | + } else if (args.filters != 0 && (filter_res = check_filter(cb, table, |
4450 | + pst, args.filters, filter_buf)) != 0) { |
4451 | + if (filter_res < 0) { |
4452 | + break; |
4453 | + } |
4454 | + } else if (skip > 0) { |
4455 | + --skip; |
4456 | + } else { |
4457 | + if (need_resp_record) { |
4458 | + resp_record(cb, table, pst); |
4459 | + } |
4460 | + if (mod_op != 0) { |
4461 | + r = modify_record(cb, table, pst, args, mod_op, modified_count); |
4462 | + } |
4463 | + } |
4464 | + if (r != 0 && r != HA_ERR_RECORD_DELETED) { |
4465 | + break; |
4466 | + } |
4467 | + } |
4468 | + hnd->ha_index_or_rnd_end(); |
4469 | + if (r != 0 && r != HA_ERR_RECORD_DELETED && r != HA_ERR_KEY_NOT_FOUND && |
4470 | + r != HA_ERR_END_OF_FILE) { |
4471 | + /* failed */ |
4472 | + if (need_resp_record) { |
4473 | + /* revert dbcb_resp_begin() and dbcb_resp_entry() */ |
4474 | + cb.dbcb_resp_cancel(); |
4475 | + } |
4476 | + cb.dbcb_resp_short_num(2, r); |
4477 | + } else { |
4478 | + /* succeeded */ |
4479 | + if (need_resp_record) { |
4480 | + cb.dbcb_resp_end(); |
4481 | + } else { |
4482 | + cb.dbcb_resp_short_num(0, modified_count); |
4483 | + } |
4484 | + } |
4485 | +} |
4486 | + |
4487 | +size_t |
4488 | +dbcontext::calc_filter_buf_size(TABLE *table, const prep_stmt& pst, |
4489 | + const record_filter *filters) |
4490 | +{ |
4491 | + size_t filter_buf_len = 0; |
4492 | + for (const record_filter *f = filters; f->op.begin() != 0; ++f) { |
4493 | + if (f->val.begin() == 0) { |
4494 | + continue; |
4495 | + } |
4496 | + const uint32_t fn = pst.get_filter_fields()[f->ff_offset]; |
4497 | + filter_buf_len += table->field[fn]->pack_length(); |
4498 | + } |
4499 | + return filter_buf_len; |
4500 | +} |
4501 | + |
4502 | +bool |
4503 | +dbcontext::fill_filter_buf(TABLE *table, const prep_stmt& pst, |
4504 | + const record_filter *filters, uchar *filter_buf, size_t len) |
4505 | +{ |
4506 | + memset(filter_buf, 0, len); |
4507 | + size_t pos = 0; |
4508 | + for (const record_filter *f = filters; f->op.begin() != 0; ++f) { |
4509 | + if (f->val.begin() == 0) { |
4510 | + continue; |
4511 | + } |
4512 | + const uint32_t fn = pst.get_filter_fields()[f->ff_offset]; |
4513 | + Field *const fld = table->field[fn]; |
4514 | + if ((fld->flags & BLOB_FLAG) != 0) { |
4515 | + return false; |
4516 | + } |
4517 | + fld->store(f->val.begin(), f->val.size(), &my_charset_bin); |
4518 | + const size_t packlen = fld->pack_length(); |
4519 | + memcpy(filter_buf + pos, fld->ptr, packlen); |
4520 | + pos += packlen; |
4521 | + } |
4522 | + return true; |
4523 | +} |
4524 | + |
4525 | +int |
4526 | +dbcontext::check_filter(dbcallback_i& cb, TABLE *table, const prep_stmt& pst, |
4527 | + const record_filter *filters, const uchar *filter_buf) |
4528 | +{ |
4529 | + DBG_FILTER(fprintf(stderr, "check_filter\n")); |
4530 | + size_t pos = 0; |
4531 | + for (const record_filter *f = filters; f->op.begin() != 0; ++f) { |
4532 | + const string_ref& op = f->op; |
4533 | + const string_ref& val = f->val; |
4534 | + const uint32_t fn = pst.get_filter_fields()[f->ff_offset]; |
4535 | + Field *const fld = table->field[fn]; |
4536 | + const size_t packlen = fld->pack_length(); |
4537 | + const uchar *const bval = filter_buf + pos; |
4538 | + int cv = 0; |
4539 | + if (fld->is_null()) { |
4540 | + cv = (val.begin() == 0) ? 0 : -1; |
4541 | + } else { |
4542 | + cv = (val.begin() == 0) ? 1 : fld->cmp(bval); |
4543 | + } |
4544 | + DBG_FILTER(fprintf(stderr, "check_filter cv=%d\n", cv)); |
4545 | + bool cond = true; |
4546 | + if (op.size() == 1) { |
4547 | + switch (op.begin()[0]) { |
4548 | + case '>': |
4549 | + DBG_FILTER(fprintf(stderr, "check_filter op: >\n")); |
4550 | + cond = (cv > 0); |
4551 | + break; |
4552 | + case '<': |
4553 | + DBG_FILTER(fprintf(stderr, "check_filter op: <\n")); |
4554 | + cond = (cv < 0); |
4555 | + break; |
4556 | + case '=': |
4557 | + DBG_FILTER(fprintf(stderr, "check_filter op: =\n")); |
4558 | + cond = (cv == 0); |
4559 | + break; |
4560 | + default: |
4561 | + DBG_FILTER(fprintf(stderr, "check_filter op: unknown\n")); |
4562 | + cond = false; /* FIXME: error */ |
4563 | + break; |
4564 | + } |
4565 | + } else if (op.size() == 2 && op.begin()[1] == '=') { |
4566 | + switch (op.begin()[0]) { |
4567 | + case '>': |
4568 | + DBG_FILTER(fprintf(stderr, "check_filter op: >=\n")); |
4569 | + cond = (cv >= 0); |
4570 | + break; |
4571 | + case '<': |
4572 | + DBG_FILTER(fprintf(stderr, "check_filter op: <=\n")); |
4573 | + cond = (cv <= 0); |
4574 | + break; |
4575 | + case '!': |
4576 | + DBG_FILTER(fprintf(stderr, "check_filter op: !=\n")); |
4577 | + cond = (cv != 0); |
4578 | + break; |
4579 | + default: |
4580 | + DBG_FILTER(fprintf(stderr, "check_filter op: unknown\n")); |
4581 | + cond = false; /* FIXME: error */ |
4582 | + break; |
4583 | + } |
4584 | + } |
4585 | + DBG_FILTER(fprintf(stderr, "check_filter cond: %d\n", (int)cond)); |
4586 | + if (!cond) { |
4587 | + return (f->filter_type == record_filter_type_skip) ? 1 : -1; |
4588 | + } |
4589 | + if (val.begin() != 0) { |
4590 | + pos += packlen; |
4591 | + } |
4592 | + } |
4593 | + return 0; |
4594 | +} |
4595 | + |
4596 | +void |
4597 | +dbcontext::cmd_open_index(dbcallback_i& cb, size_t pst_id, const char *dbn, |
4598 | + const char *tbl, const char *idx, const char *retflds, const char *filflds) |
4599 | +{ |
4600 | + unlock_tables_if(); |
4601 | + const table_name_type k = std::make_pair(std::string(dbn), std::string(tbl)); |
4602 | + const table_map_type::const_iterator iter = table_map.find(k); |
4603 | + uint32_t tblnum = 0; |
4604 | + if (iter != table_map.end()) { |
4605 | + tblnum = iter->second; |
4606 | + DBG_CMP(fprintf(stderr, "HNDSOCK k=%s tblnum=%d\n", k.c_str(), |
4607 | + (int)tblnum)); |
4608 | + } else { |
4609 | + TABLE_LIST tables; |
4610 | + TABLE *table = 0; |
4611 | + bool refresh = true; |
4612 | + const thr_lock_type lock_type = for_write_flag ? TL_WRITE : TL_READ; |
4613 | + #if MYSQL_VERSION_ID >= 50505 |
4614 | + tables.init_one_table(dbn, strlen(dbn), tbl, strlen(tbl), tbl, |
4615 | + lock_type); |
4616 | + tables.mdl_request = mdl_request; |
4617 | + Open_table_context ot_act(thd, MYSQL_OPEN_REOPEN); |
4618 | + if (!open_table(thd, &tables, thd->mem_root, &ot_act)) { |
4619 | + table = tables.table; |
4620 | + } |
4621 | + #else |
4622 | + tables.init_one_table(dbn, tbl, lock_type); |
4623 | + table = open_table(thd, &tables, thd->mem_root, &refresh, |
4624 | + OPEN_VIEW_NO_PARSE); |
4625 | + #endif |
4626 | + if (table == 0) { |
4627 | + DENA_VERBOSE(10, fprintf(stderr, |
4628 | + "HNDSOCK failed to open %p [%s] [%s] [%d]\n", |
4629 | + thd, dbn, tbl, static_cast<int>(refresh))); |
4630 | + return cb.dbcb_resp_short(2, "open_table"); |
4631 | + } |
4632 | + statistic_increment(open_tables_count, &LOCK_status); |
4633 | + table->reginfo.lock_type = lock_type; |
4634 | + table->use_all_columns(); |
4635 | + tblnum = table_vec.size(); |
4636 | + tablevec_entry e; |
4637 | + e.table = table; |
4638 | + table_vec.push_back(e); |
4639 | + table_map[k] = tblnum; |
4640 | + } |
4641 | + size_t idxnum = static_cast<size_t>(-1); |
4642 | + if (idx[0] >= '0' && idx[0] <= '9') { |
4643 | + /* numeric */ |
4644 | + TABLE *const table = table_vec[tblnum].table; |
4645 | + idxnum = atoi(idx); |
4646 | + if (idxnum >= table->s->keys) { |
4647 | + return cb.dbcb_resp_short(2, "idxnum"); |
4648 | + } |
4649 | + } else { |
4650 | + const char *const idx_name_to_open = idx[0] == '\0' ? "PRIMARY" : idx; |
4651 | + TABLE *const table = table_vec[tblnum].table; |
4652 | + for (uint i = 0; i < table->s->keys; ++i) { |
4653 | + KEY& kinfo = table->key_info[i]; |
4654 | + if (strcmp(kinfo.name, idx_name_to_open) == 0) { |
4655 | + idxnum = i; |
4656 | + break; |
4657 | + } |
4658 | + } |
4659 | + } |
4660 | + if (idxnum == size_t(-1)) { |
4661 | + return cb.dbcb_resp_short(2, "idxnum"); |
4662 | + } |
4663 | + prep_stmt::fields_type rf; |
4664 | + prep_stmt::fields_type ff; |
4665 | + if (!parse_fields(table_vec[tblnum].table, retflds, rf)) { |
4666 | + return cb.dbcb_resp_short(2, "fld"); |
4667 | + } |
4668 | + if (!parse_fields(table_vec[tblnum].table, filflds, ff)) { |
4669 | + return cb.dbcb_resp_short(2, "fld"); |
4670 | + } |
4671 | + prep_stmt p(this, tblnum, idxnum, rf, ff); |
4672 | + cb.dbcb_set_prep_stmt(pst_id, p); |
4673 | + return cb.dbcb_resp_short(0, ""); |
4674 | +} |
4675 | + |
4676 | +bool |
4677 | +dbcontext::parse_fields(TABLE *const table, const char *str, |
4678 | + prep_stmt::fields_type& flds) |
4679 | +{ |
4680 | + string_ref flds_sr(str, strlen(str)); |
4681 | + std::vector<string_ref> fldnms; |
4682 | + if (flds_sr.size() != 0) { |
4683 | + split(',', flds_sr, fldnms); |
4684 | + } |
4685 | + for (size_t i = 0; i < fldnms.size(); ++i) { |
4686 | + Field **fld = 0; |
4687 | + size_t j = 0; |
4688 | + for (fld = table->field; *fld; ++fld, ++j) { |
4689 | + DBG_FLD(fprintf(stderr, "f %s\n", (*fld)->field_name)); |
4690 | + string_ref fn((*fld)->field_name, strlen((*fld)->field_name)); |
4691 | + if (fn == fldnms[i]) { |
4692 | + break; |
4693 | + } |
4694 | + } |
4695 | + if (*fld == 0) { |
4696 | + DBG_FLD(fprintf(stderr, "UNKNOWN FLD %s [%s]\n", retflds, |
4697 | + std::string(fldnms[i].begin(), fldnms[i].size()).c_str())); |
4698 | + return false; |
4699 | + } |
4700 | + DBG_FLD(fprintf(stderr, "FLD %s %zu\n", (*fld)->field_name, j)); |
4701 | + flds.push_back(j); |
4702 | + } |
4703 | + return true; |
4704 | +} |
4705 | + |
4706 | +enum db_write_op { |
4707 | + db_write_op_none = 0, |
4708 | + db_write_op_insert = 1, |
4709 | + db_write_op_sql = 2, |
4710 | +}; |
4711 | + |
4712 | +void |
4713 | +dbcontext::cmd_exec_on_index(dbcallback_i& cb, const cmd_exec_args& args) |
4714 | +{ |
4715 | + const prep_stmt& p = *args.pst; |
4716 | + if (p.get_table_id() == static_cast<size_t>(-1)) { |
4717 | + return cb.dbcb_resp_short(2, "stmtnum"); |
4718 | + } |
4719 | + ha_rkey_function find_flag = HA_READ_KEY_EXACT; |
4720 | + db_write_op wrop = db_write_op_none; |
4721 | + if (args.op.size() == 1) { |
4722 | + switch (args.op.begin()[0]) { |
4723 | + case '=': |
4724 | + find_flag = HA_READ_KEY_EXACT; |
4725 | + break; |
4726 | + case '>': |
4727 | + find_flag = HA_READ_AFTER_KEY; |
4728 | + break; |
4729 | + case '<': |
4730 | + find_flag = HA_READ_BEFORE_KEY; |
4731 | + break; |
4732 | + case '+': |
4733 | + wrop = db_write_op_insert; |
4734 | + break; |
4735 | + case 'S': |
4736 | + wrop = db_write_op_sql; |
4737 | + break; |
4738 | + default: |
4739 | + return cb.dbcb_resp_short(1, "op"); |
4740 | + } |
4741 | + } else if (args.op.size() == 2 && args.op.begin()[1] == '=') { |
4742 | + switch (args.op.begin()[0]) { |
4743 | + case '>': |
4744 | + find_flag = HA_READ_KEY_OR_NEXT; |
4745 | + break; |
4746 | + case '<': |
4747 | + find_flag = HA_READ_KEY_OR_PREV; |
4748 | + break; |
4749 | + default: |
4750 | + return cb.dbcb_resp_short(1, "op"); |
4751 | + } |
4752 | + } else { |
4753 | + return cb.dbcb_resp_short(1, "op"); |
4754 | + } |
4755 | + if (args.kvalslen <= 0) { |
4756 | + return cb.dbcb_resp_short(2, "klen"); |
4757 | + } |
4758 | + switch (wrop) { |
4759 | + case db_write_op_none: |
4760 | + return cmd_find_internal(cb, p, find_flag, args); |
4761 | + case db_write_op_insert: |
4762 | + return cmd_insert_internal(cb, p, args.kvals, args.kvalslen); |
4763 | + case db_write_op_sql: |
4764 | + return cmd_sql_internal(cb, p, args.kvals, args.kvalslen); |
4765 | + } |
4766 | +} |
4767 | + |
4768 | +void |
4769 | +dbcontext::set_statistics(size_t num_conns, size_t num_active) |
4770 | +{ |
4771 | + thd_proc_info(thd, &info_message_buf[0]); |
4772 | + if (for_write_flag) { |
4773 | + set_thread_message("handlersocket: mode=wr, %zu conns, %zu active", |
4774 | + num_conns, num_active); |
4775 | + } else { |
4776 | + set_thread_message("handlersocket: mode=rd, %zu conns, %zu active", |
4777 | + num_conns, num_active); |
4778 | + } |
4779 | +} |
4780 | + |
4781 | +}; |
4782 | + |
4783 | |
4784 | === added file 'HandlerSocket-Plugin-for-MySQL/handlersocket/database.hpp' |
4785 | --- HandlerSocket-Plugin-for-MySQL/handlersocket/database.hpp 1970-01-01 00:00:00 +0000 |
4786 | +++ HandlerSocket-Plugin-for-MySQL/handlersocket/database.hpp 2011-04-12 04:16:24 +0000 |
4787 | @@ -0,0 +1,130 @@ |
4788 | + |
4789 | +// vim:sw=2:ai |
4790 | + |
4791 | +/* |
4792 | + * Copyright (C) 2010 DeNA Co.,Ltd.. All rights reserved. |
4793 | + * See COPYRIGHT.txt for details. |
4794 | + */ |
4795 | + |
4796 | +#ifndef DENA_DATABASE_HPP |
4797 | +#define DENA_DATABASE_HPP |
4798 | + |
4799 | +#include <string> |
4800 | +#include <memory> |
4801 | +#include <vector> |
4802 | +#include <stdint.h> |
4803 | + |
4804 | +#include "string_buffer.hpp" |
4805 | +#include "string_ref.hpp" |
4806 | +#include "config.hpp" |
4807 | + |
4808 | +namespace dena { |
4809 | + |
4810 | +struct database_i; |
4811 | +typedef std::auto_ptr<volatile database_i> database_ptr; |
4812 | + |
4813 | +struct dbcontext_i; |
4814 | +typedef std::auto_ptr<dbcontext_i> dbcontext_ptr; |
4815 | + |
4816 | +struct database_i { |
4817 | + virtual ~database_i() { } |
4818 | + virtual dbcontext_ptr create_context(bool for_write) volatile = 0; |
4819 | + virtual void stop() volatile = 0; |
4820 | + virtual const config& get_conf() const volatile = 0; |
4821 | + static database_ptr create(const config& conf); |
4822 | +}; |
4823 | + |
4824 | +struct prep_stmt { |
4825 | + typedef std::vector<uint32_t> fields_type; |
4826 | + private: |
4827 | + dbcontext_i *dbctx; /* must be valid while *this is alive */ |
4828 | + size_t table_id; /* a prep_stmt object holds a refcount of the table */ |
4829 | + size_t idxnum; |
4830 | + fields_type ret_fields; |
4831 | + fields_type filter_fields; |
4832 | + public: |
4833 | + prep_stmt(); |
4834 | + prep_stmt(dbcontext_i *c, size_t tbl, size_t idx, const fields_type& rf, |
4835 | + const fields_type& ff); |
4836 | + ~prep_stmt(); |
4837 | + prep_stmt(const prep_stmt& x); |
4838 | + prep_stmt& operator =(const prep_stmt& x); |
4839 | + public: |
4840 | + size_t get_table_id() const { return table_id; } |
4841 | + size_t get_idxnum() const { return idxnum; } |
4842 | + const fields_type& get_ret_fields() const { return ret_fields; } |
4843 | + const fields_type& get_filter_fields() const { return filter_fields; } |
4844 | +}; |
4845 | + |
4846 | +struct dbcallback_i { |
4847 | + virtual ~dbcallback_i () { } |
4848 | + virtual void dbcb_set_prep_stmt(size_t pst_id, const prep_stmt& v) = 0; |
4849 | + virtual const prep_stmt *dbcb_get_prep_stmt(size_t pst_id) const = 0; |
4850 | + virtual void dbcb_resp_short(uint32_t code, const char *msg) = 0; |
4851 | + virtual void dbcb_resp_short_num(uint32_t code, uint32_t value) = 0; |
4852 | + virtual void dbcb_resp_begin(size_t num_flds) = 0; |
4853 | + virtual void dbcb_resp_entry(const char *fld, size_t fldlen) = 0; |
4854 | + virtual void dbcb_resp_end() = 0; |
4855 | + virtual void dbcb_resp_cancel() = 0; |
4856 | +}; |
4857 | + |
4858 | +enum record_filter_type { |
4859 | + record_filter_type_skip = 0, |
4860 | + record_filter_type_break = 1, |
4861 | +}; |
4862 | + |
4863 | +struct record_filter { |
4864 | + record_filter_type filter_type; |
4865 | + string_ref op; |
4866 | + uint32_t ff_offset; /* offset in filter_fields */ |
4867 | + string_ref val; |
4868 | + record_filter() : filter_type(record_filter_type_skip), ff_offset(0) { } |
4869 | +}; |
4870 | + |
4871 | +struct cmd_exec_args { |
4872 | + const prep_stmt *pst; |
4873 | + string_ref op; |
4874 | + const string_ref *kvals; |
4875 | + size_t kvalslen; |
4876 | + uint32_t limit; |
4877 | + uint32_t skip; |
4878 | + string_ref mod_op; |
4879 | + const string_ref *uvals; /* size must be pst->retfieelds.size() */ |
4880 | + const record_filter *filters; |
4881 | + cmd_exec_args() : pst(0), kvals(0), kvalslen(0), limit(0), skip(0), |
4882 | + uvals(0), filters(0) { } |
4883 | +}; |
4884 | + |
4885 | +struct dbcontext_i { |
4886 | + virtual ~dbcontext_i() { } |
4887 | + virtual void init_thread(const void *stack_bottom, |
4888 | + volatile int& shutdown_flag) = 0; |
4889 | + virtual void term_thread() = 0; |
4890 | + virtual bool check_alive() = 0; |
4891 | + virtual void lock_tables_if() = 0; |
4892 | + virtual void unlock_tables_if() = 0; |
4893 | + virtual bool get_commit_error() = 0; |
4894 | + virtual void clear_error() = 0; |
4895 | + virtual void close_tables_if() = 0; |
4896 | + virtual void table_addref(size_t tbl_id) = 0; /* TODO: hide */ |
4897 | + virtual void table_release(size_t tbl_id) = 0; /* TODO: hide */ |
4898 | + virtual void cmd_open_index(dbcallback_i& cb, size_t pst_id, const char *dbn, |
4899 | + const char *tbl, const char *idx, const char *retflds, |
4900 | + const char *filflds) = 0; |
4901 | + virtual void cmd_exec_on_index(dbcallback_i& cb, const cmd_exec_args& args) |
4902 | + = 0; |
4903 | + virtual void set_statistics(size_t num_conns, size_t num_active) = 0; |
4904 | +}; |
4905 | + |
4906 | +}; |
4907 | + |
4908 | +extern unsigned long long int open_tables_count; |
4909 | +extern unsigned long long int close_tables_count; |
4910 | +extern unsigned long long int lock_tables_count; |
4911 | +extern unsigned long long int unlock_tables_count; |
4912 | +#if 0 |
4913 | +extern unsigned long long int index_exec_count; |
4914 | +#endif |
4915 | + |
4916 | +#endif |
4917 | + |
4918 | |
4919 | === added file 'HandlerSocket-Plugin-for-MySQL/handlersocket/handlersocket.cpp' |
4920 | --- HandlerSocket-Plugin-for-MySQL/handlersocket/handlersocket.cpp 1970-01-01 00:00:00 +0000 |
4921 | +++ HandlerSocket-Plugin-for-MySQL/handlersocket/handlersocket.cpp 2011-04-12 04:16:24 +0000 |
4922 | @@ -0,0 +1,216 @@ |
4923 | + |
4924 | +// vim:sw=2:ai |
4925 | + |
4926 | +/* |
4927 | + * Copyright (C) 2010 DeNA Co.,Ltd.. All rights reserved. |
4928 | + * See COPYRIGHT.txt for details. |
4929 | + */ |
4930 | + |
4931 | +#include <memory> |
4932 | +#include <string> |
4933 | +#include <stdio.h> |
4934 | + |
4935 | +#include "config.hpp" |
4936 | +#include "hstcpsvr.hpp" |
4937 | +#include "string_util.hpp" |
4938 | +#include "mysql_incl.hpp" |
4939 | + |
4940 | +#define DBG_LOG \ |
4941 | + if (dena::verbose_level >= 100) { \ |
4942 | + fprintf(stderr, "%s %p\n", __PRETTY_FUNCTION__, this); \ |
4943 | + } |
4944 | +#define DBG_DO(x) if (dena::verbose_level >= 100) { x; } |
4945 | + |
4946 | +#define DBG_DIR(x) |
4947 | + |
4948 | +using namespace dena; |
4949 | + |
4950 | +static char *handlersocket_address = 0; |
4951 | +static char *handlersocket_port = 0; |
4952 | +static char *handlersocket_port_wr = 0; |
4953 | +static unsigned int handlersocket_epoll = 1; |
4954 | +static unsigned int handlersocket_threads = 32; |
4955 | +static unsigned int handlersocket_threads_wr = 1; |
4956 | +static unsigned int handlersocket_timeout = 30; |
4957 | +static unsigned int handlersocket_backlog = 32768; |
4958 | +static unsigned int handlersocket_sndbuf = 0; |
4959 | +static unsigned int handlersocket_rcvbuf = 0; |
4960 | +static unsigned int handlersocket_readsize = 0; |
4961 | +static unsigned int handlersocket_accept_balance = 0; |
4962 | +static unsigned int handlersocket_wrlock_timeout = 0; |
4963 | +static char *handlersocket_plain_secret = 0; |
4964 | +static char *handlersocket_plain_secret_wr = 0; |
4965 | + |
4966 | +struct daemon_handlersocket_data { |
4967 | + hstcpsvr_ptr hssvr_rd; |
4968 | + hstcpsvr_ptr hssvr_wr; |
4969 | +}; |
4970 | + |
4971 | +static int |
4972 | +daemon_handlersocket_init(void *p) |
4973 | +{ |
4974 | + DENA_VERBOSE(10, fprintf(stderr, "handlersocket: initialized\n")); |
4975 | + config conf; |
4976 | + conf["use_epoll"] = handlersocket_epoll ? "1" : "0"; |
4977 | + if (handlersocket_address) { |
4978 | + conf["host"] = handlersocket_address; |
4979 | + } |
4980 | + if (handlersocket_port) { |
4981 | + conf["port"] = handlersocket_port; |
4982 | + } |
4983 | + /* |
4984 | + * unix domain socket |
4985 | + * conf["host"] = "/"; |
4986 | + * conf["port"] = "/tmp/handlersocket"; |
4987 | + */ |
4988 | + if (handlersocket_threads > 0) { |
4989 | + conf["num_threads"] = to_stdstring(handlersocket_threads); |
4990 | + } else { |
4991 | + conf["num_threads"] = "1"; |
4992 | + } |
4993 | + conf["timeout"] = to_stdstring(handlersocket_timeout); |
4994 | + conf["listen_backlog"] = to_stdstring(handlersocket_backlog); |
4995 | + conf["sndbuf"] = to_stdstring(handlersocket_sndbuf); |
4996 | + conf["rcvbuf"] = to_stdstring(handlersocket_rcvbuf); |
4997 | + conf["readsize"] = to_stdstring(handlersocket_readsize); |
4998 | + conf["accept_balance"] = to_stdstring(handlersocket_accept_balance); |
4999 | + conf["wrlock_timeout"] = to_stdstring(handlersocket_wrlock_timeout); |
5000 | + std::auto_ptr<daemon_handlersocket_data> ap(new daemon_handlersocket_data); |
The diff has been truncated for viewing.