Merge lp:~percona-dev/percona-xtradb-cluster/5.5.28 into lp:~percona-core/percona-xtradb-cluster/5.5.24

Proposed by Ignacio Nin
Status: Work in progress
Proposed branch: lp:~percona-dev/percona-xtradb-cluster/5.5.28
Merge into: lp:~percona-core/percona-xtradb-cluster/5.5.24
Diff against target: 127920 lines (has conflicts)
Conflict adding file doc-pxc/source/release-notes/Percona-XtraDB-Cluster-5.5.28.rst.  Moved existing file to doc-pxc/source/release-notes/Percona-XtraDB-Cluster-5.5.28.rst.moved.
To merge this branch: bzr merge lp:~percona-dev/percona-xtradb-cluster/5.5.28
Reviewer Review Type Date Requested Status
Vadim Tkachenko Needs Fixing
Review via email: mp+137396@code.launchpad.net

Description of the change

Changes for release 5.5.28

To post a comment you must log in.
Revision history for this message
Vadim Tkachenko (vadim-tk) wrote :

merge says
"Diff against target: 114271 lines (has conflicts)
Conflict adding file doc-pxc/source/release-notes/Percona-XtraDB-Cluster-5.5.28.rst. Moved existing file to doc-pxc/source/release-notes/Percona-XtraDB-Cluster-5.5.28.rst.moved"

review: Needs Fixing
374. By Vadim Tkachenko

fixed release date in release notes

375. By Vadim Tkachenko

merged lp:percona-server rev 384

376. By Vadim Tkachenko

merged lp:~codership/codership-mysql/5.5-23 rev 3838

Unmerged revisions

376. By Vadim Tkachenko

merged lp:~codership/codership-mysql/5.5-23 rev 3838

375. By Vadim Tkachenko

merged lp:percona-server rev 384

374. By Vadim Tkachenko

fixed release date in release notes

373. By Ignacio Nin

In build-dpkg.sh, updated the dch(1) change so it sets the correct
distribution to use in the repository. Not having it explicitely
forced resulted in UNRELEASED being chosen in quantal, due to a
change in the default in dch(1) (see the --release-heuristic
explanation in the man page of dch(1)).

372. By Ignacio Nin

Merge fix from 5.5

371. By Ignacio Nin

Use the wsrep revision in the server wsrep version for the binary builder

370. By Hrvoje Matijakovic

* merged lp:~hrvojem/percona-xtradb-cluster/rn-5.5.28-update

369. By Ignacio Nin

Use the wsrep revision in the server wsrep version.

Instead of using our branch's revno for the wsrep revision, use upstream's.
To this end add a WSREP-REVISION file to be updated when wsrep is merged.

368. By Vadim Tkachenko

merged lp:codership-mysql rev3821

367. By Vadim Tkachenko

merged lp:codership-mysql rev3820

Preview Diff

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

Subscribers

People subscribed via source and target branches