Merge lp:~stewart/percona-server/5.5-update-handlersocket into lp:percona-server/5.5

Proposed by Stewart Smith
Status: Work in progress
Proposed branch: lp:~stewart/percona-server/5.5-update-handlersocket
Merge into: lp:percona-server/5.5
Diff against target: 81747 lines
To merge this branch: bzr merge lp:~stewart/percona-server/5.5-update-handlersocket
Reviewer Review Type Date Requested Status
Laurynas Biveinis (community) Needs Fixing
Review via email: mp+111767@code.launchpad.net

Description of the change

Update HandlerSocket to 1.1.0 from a git branch (imported with bzr-git). This should make it easier to keep up to date in the future.

http://jenkins.percona.com/job/percona-server-5.5-param/442/

To post a comment you must log in.
Revision history for this message
Laurynas Biveinis (laurynas-biveinis) wrote :

Same comment as for the 5.1 MP.

Also, for 5.5, is it a merge from 5.1? I'm asking because the commit message does not say "merge from 5.1" or similar.

review: Needs Information
Revision history for this message
Laurynas Biveinis (laurynas-biveinis) wrote :

Setting to WiP as will need to be redone the same way 5.1 was after the bzr bug breaking trunk.

review: Needs Fixing

Unmerged revisions

266. By Stewart Smith

update HandlerSocket to 1.1.0 (by removing old HandlerSocket tree and replacing with a 'bzr join'ed one)

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

Subscribers

People subscribed via source and target branches