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