<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>PlanetMysql.ru - информация о СУБД MySQL &#187; testing</title>
	<atom:link href="http://planetmysql.ru/category/testing/feed/" rel="self" type="application/rss+xml" />
	<link>http://planetmysql.ru</link>
	<description>Блог о самой популярной СУБД MySQL</description>
	<lastBuildDate>Fri, 10 Feb 2012 22:53:14 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3</generator>
		<item>
		<title>dbqp being renamed</title>
		<link>http://www.wc220.com/?p=323&#038;utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=dbqp-being-renamed</link>
		<comments>http://www.wc220.com/?p=323#comments</comments>
		<pubDate>Tue, 20 Dec 2011 23:06:39 +0000</pubDate>
		<dc:creator>patrick crews</dc:creator>
				<category><![CDATA[dbqp]]></category>
		<category><![CDATA[Drizzle]]></category>
		<category><![CDATA[mysql]]></category>
		<category><![CDATA[testing]]></category>

		<guid isPermaLink="false">http://www.wc220.com/?p=323</guid>
		<description><![CDATA[One of the best things that can happen to a piece of software is for people to actually use it.
I&#8217;ve been fortunate enough to have received feedback on the tool from several members of both the Percona and Drizzle teams.  The most common and strongly emphasized comments were in regards to what a terrible, terrible name dbqp really is in terms of saying, seeing, and typing it ; )
As that isn&#8217;t something that can be disputed (it&#8217;s really annoying to use in conversations *and* to type several dozen times a day), the project has been renamed to kewpie.  For those that follow such things, I did present on another tool with that name at the last MySQL Conference, but *that* tool is a nice-to-have, while the test-runner sees daily use.  Better to save the good names for software that actually stands a chance of being used, I say : )
While there are probably 1*10^6 other things I need to do (Stewart is a merciless slave driver as a boss, btw&#8230;heheh), the fact that we are merging the tool into the various Percona branches meant it should be done sooner rather than later.  The tool is currently in our 5.1 branch and I have merge requests up for both Drizzle and Xtrabackup (dbqp was living there too).
I have several other interesting things going on with the tests and tool, which I&#8217;ll be blogging about over at MySQL Performance Blog.  Later this week, I&#8217;ll be talking about what we&#8217;ve been doing to work on this bug ; )
&#160;
Also, the Percona Live MySQL Conference in DC is just around the corner.  There are going to be some great speakers and attendees]]></description>
			<content:encoded><![CDATA[<p>One of the best things that can happen to a piece of software is for people to actually use it.</p>
<p>I&#8217;ve been fortunate enough to have received feedback on the tool from several members of both the <a href="http://www.percona.com/">Percona</a> and <a href="http://drizzle.org/">Drizzle</a> teams.  The most common and strongly emphasized comments were in regards to what a terrible, terrible name <a href="http://docs.drizzle.org/testing/dbqp.html">dbqp</a> really is in terms of saying, seeing, and typing it ; )</p>
<p>As that isn&#8217;t something that can be disputed (it&#8217;s really annoying to use in conversations *and* to type several dozen times a day), the project has been renamed to <a href="https://launchpad.net/kewpie">kewpie</a>.  For those that follow such things, I did present on <a href="http://www.google.com/url?sa=t&amp;rct=j&amp;q=&amp;esrc=s&amp;source=web&amp;cd=1&amp;ved=0CDcQFjAA&amp;url=http://en.oreilly.com/mysql2011/public/schedule/detail/17216&amp;ei=dBHxTsf6KIiWtwfzpu3PBg&amp;usg=AFQjCNHkSdJoBU3pAgVEkgxuGdpQ2whJmg">another tool with that name</a> at the last <a href="http://www.percona.com/live/mysql-conference-2012/">MySQL Conference</a>, but *that* tool is a nice-to-have, while the test-runner sees daily use.  Better to save the good names for software that actually stands a chance of being used, I say : )</p>
<p>While there are probably 1*10^6 other things I need to do (<a href="http://www.flamingspork.com/blog/">Stewart</a> is a merciless slave driver as a boss, btw&#8230;heheh), the fact that we are merging the tool into the <a href="https://launchpad.net/percona-xtrabackup">various</a> <a href="https://launchpad.net/percona-server">Percona branches</a> meant it should be done sooner rather than later.  The tool is currently in our 5.1 branch and I have merge requests up for both <a href="https://launchpad.net/drizzle">Drizzle</a> and <a href="https://launchpad.net/percona-xtrabackup">Xtrabackup</a> (dbqp was living there too).</p>
<p>I have several other interesting things going on with the tests and tool, which I&#8217;ll be blogging about over at <a href="http://www.wc220.com/www.mysqlperformanceblog.com/">MySQL Performance Blog</a>.  Later this week, I&#8217;ll be talking about what we&#8217;ve been doing to work on <a href="http://bugs.mysql.com/bug.php?id=60343">this bug</a> ; )</p>
<p>&nbsp;</p>
<p>Also, the <a href="http://www.percona.com/live/dc-2012/">Percona Live MySQL Conference in DC</a> is just around the corner.  There are going to be some great speakers and <a href="http://dshrewsbury.blogspot.com/">attendees</a></p><br/>PlanetMySQL Voting:
	 <a href="http://planet.mysql.com/entry/vote/?entry_id=31381&vote=1&apivote=1">Vote UP</a> /
	 <a href="http://planet.mysql.com/entry/vote/?entry_id=31381&vote=-1&apivote=1">Vote DOWN</a>]]></content:encoded>
			<wfw:commentRss>http://planetmysql.ru/2011/12/21/dbqp-being-renamed/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>dbqp and Xtrabackup testing</title>
		<link>http://www.wc220.com/?p=309&#038;utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=dbqp-and-xtrabackup-testing</link>
		<comments>http://www.wc220.com/?p=309#comments</comments>
		<pubDate>Mon, 07 Nov 2011 22:55:23 +0000</pubDate>
		<dc:creator>patrick crews</dc:creator>
				<category><![CDATA[dbqp]]></category>
		<category><![CDATA[Drizzle]]></category>
		<category><![CDATA[mysql]]></category>
		<category><![CDATA[testing]]></category>
		<category><![CDATA[XtraBackup]]></category>

		<guid isPermaLink="false">http://www.wc220.com/?p=309</guid>
		<description><![CDATA[So I&#8217;m back from the Percona dev team&#8217;s recent meeting.  While there, we spent a fair bit of time discussing Xtrabackup development.  One of our challenges is that as we add richer features to the tool, we need equivalent testing capabilities.  However, it seems a constant in the MySQL world that available QA tools often leave something to be desired.  The randgen is a literal wonder-tool for database testing, but it is also occasionally frustrating / doesn&#8217;t scratch every testing itch.  It is based on technology SQL Server was using in 1998 (MySQL began using it in ~2007, IIRC).  So this is no knock, it is merely meant to be an example of a poor QA engineer&#8217;s frustrations ; )  While the current Xtrabackup test suite is commendable, it also has its limitations. Enter the flexible, adaptable, and expressive answer: dbqp.
One of my demos at the dev meeting was showing how we can set up tests for Xtrabackup using the unittest paradigm.  While this sounds fancy, basically, we take advantage of Python&#8217;s unittest and write classes that use their code.  The biggest bit dbqp does is search the specified server code (to make sure we have everything we should), allocate and manage servers as requested by the test cases, and do some reporting and management of the test cases.  As the tool matures, I will be striving to let more of the work be done by unittest code rather than things I have written : )
To return to my main point, we now have two basic tests of xtrabackup:
Basic test of backup + restore:

Populate server
 Take a validation snapshot (mysqldump)
 Take the backup (via innobackupex)
 Clean datadir
Restore from backup
 Take restored state snapshot and compare to original state

Slave setup

 Similar to our basic test except we create a slave from the backup, replicating from the backed up server.
After the initial setup, we ensure replication is set up ok, then we do additional work on the master and compare master and slave states

One of the great things about this is that we have the magic of assertions.  We can insert them at any point of the test we feel like validating and the test will fail with useful output at that stage.  The backup didn&#8217;t take correctly?  No point going through any other steps &#8212; FAIL! : )  The assertion methods just make it easy to express what behavior we are looking for.  We want the innobackupex prepare call to run without error?
Boom goes the dynamite!:

# prepare our backup
cmd = ("%s --apply-log --no-timestamp --use-memory=500M "
"--ibbackup=%s %s" %( innobackupex
, xtrabackup
, backup_path))
retcode, output = execute_cmd(cmd, output_path, exec_path, True)
self.assertEqual(retcode, 0, msg = output)

From these basic tests, it will be easy to craft more complex test cases.  Creating the slave test was simply matter of adapting the initial basic test case slightly.  Our plans include: *heavy* crash testing of both xtrabackup and the server, enhancing / expanding replication tests by creating heavy randgen loads against the master during backup and slave setup, and other assorted crimes against database software.  We will also be porting the existing test suite to use dbqp entirely&#8230;who knows, we may even start working on Windows one day ; )
These tests are by no means the be-all-end-all, but I think they do represent an interesting step forward.  We can now write actual, honest-to-goodness Python code to test the server.  On top of that, we can make use of the included unittest module to give us all sorts of assertive goodness to express what we are looking for.  We will need to and plan to refine things as time moves forward, but at the moment, we are able to do some cool testing tricks that weren&#8217;t easily do-able before.
If you&#8217;d like to try these tests out, you will need the following:
* dbqp (bzr branch lp:dbqp)
* DBD:mysql installed (test tests use the randgen and this is required&#8230;hey, it is a WONDER-tool!) : )
* Innobackupex, a MySQL / Percona server and the appropriate xtrabackup binary.
To run them:
$./dbqp.py &#8211;suite=xtrabackup_basic &#8211;basedir=/path/to/mysql &#8211;xtrabackup-path=/mah/path &#8211;innobackupex-path=/mah/other/path &#8211;default-server-type=mysql &#8211;no-shm
Some next steps for dbqp include:
1)  Improved docs
2)  Merging into the Percona Server trees
3)  Setting up test jobs in Jenkins (crashme / sqlbench / randgen)
4)  Other assorted awesomeness
Naturally, this testing goodness will also find its way into Drizzle (which currently has a 7.1 beta out).  We definitely need to see some Xtrabackup test cases for Drizzle&#8217;s version of the tool (mwa ha ha!) &#62;: )]]></description>
			<content:encoded><![CDATA[<p>So I&#8217;m back from the <a href="http://www.percona.com/">Percona</a> dev team&#8217;s recent meeting.  While there, we spent a fair bit of time discussing <a href="http://www.percona.com/software/percona-xtrabackup/">Xtrabackup</a> development.  One of our challenges is that as we add richer features to the tool, we need equivalent testing capabilities.  However, it seems a constant in the MySQL world that available QA tools often leave something to be desired.  The <a href="https://launchpad.net/randgen">randgen</a> is a literal wonder-tool for database testing, but it is also occasionally frustrating / doesn&#8217;t scratch every testing itch.  It is based on technology SQL Server was using in 1998 (MySQL began using it in ~2007, IIRC).  So this is no knock, it is merely meant to be an example of a poor QA engineer&#8217;s frustrations ; )  While the current <a href="http://www.percona.com/software/percona-xtrabackup/">Xtrabackup</a> test suite is commendable, it also has its limitations. Enter the flexible, adaptable, and expressive answer: <a href="http://www.wc220.com/?category_name=dbqp">dbqp</a>.</p>
<p>One of my demos at the dev meeting was showing how we can set up tests for Xtrabackup using the unittest paradigm.  While this sounds fancy, basically, we take advantage of <a href="http://docs.python.org/library/unittest.html">Python&#8217;s unittest</a> and write classes that use their code.  The biggest bit <a href="http://docs.drizzle.org/testing/dbqp.html">dbqp</a> does is search the specified server code (to make sure we have everything we should), allocate and manage servers as requested by the test cases, and do some reporting and management of the test cases.  As the tool matures, I will be striving to let more of the work be done by unittest code rather than things I have written : )</p>
<p>To return to my main point, we now have two basic tests of xtrabackup:</p>
<h4>Basic test of backup + restore:</h4>
<ol>
<li>Populate server</li>
<li> Take a validation snapshot (mysqldump)</li>
<li> Take the backup (via innobackupex)</li>
<li> Clean datadir</li>
<li>Restore from backup</li>
<li> Take restored state snapshot and compare to original state</li>
</ol>
<h4>Slave setup</h4>
<ol>
<li> Similar to our basic test except we create a slave from the backup, replicating from the backed up server.</li>
<li>After the initial setup, we ensure replication is set up ok, then we do additional work on the master and compare master and slave states</li>
</ol>
<p>One of the great things about this is that we have the <a href="http://docs.python.org/library/unittest.html#assert-methods">magic of assertions</a>.  We can insert them at any point of the test we feel like validating and the test will fail with useful output at that stage.  The backup didn&#8217;t take correctly?  No point going through any other steps &#8212; FAIL! : )  The assertion methods just make it easy to express what behavior we are looking for.  We want the innobackupex prepare call to run without error?<br />
<a href="http://www.youtube.com/watch?v=W45DRy7M1no">Boom goes the dynamite!</a>:<br />
<code><br />
# prepare our backup<br />
cmd = ("%s --apply-log --no-timestamp --use-memory=500M "<br />
"--ibbackup=%s %s" %( innobackupex<br />
, xtrabackup<br />
, backup_path))<br />
retcode, output = execute_cmd(cmd, output_path, exec_path, True)<br />
self.assertEqual(retcode, 0, msg = output)<br />
</code></p>
<p>From these basic tests, it will be easy to craft more complex test cases.  Creating the slave test was simply matter of adapting the initial basic test case slightly.  Our plans include: *heavy* crash testing of both xtrabackup and the server, enhancing / expanding replication tests by creating heavy randgen loads against the master during backup and slave setup, and other assorted crimes against database software.  We will also be porting the existing test suite to use dbqp entirely&#8230;who knows, we may even start working on Windows one day ; )</p>
<p>These tests are by no means the be-all-end-all, but I think they do represent an interesting step forward.  We can now write actual, <a href="http://xkcd.com/353/">honest-to-goodness Python code</a> to test the server.  On top of that, we can make use of the included unittest module to give us all sorts of assertive goodness to express what we are looking for.  We will need to and plan to refine things as time moves forward, but at the moment, we are able to do some cool testing tricks that weren&#8217;t easily do-able before.</p>
<p>If you&#8217;d like to try these tests out, you will need the following:<br />
* <a href="https://launchpad.net/dbqp">dbqp</a> (bzr branch lp:dbqp)<br />
* <a href="http://search.cpan.org/~capttofu/DBD-mysql-4.018/lib/DBD/mysql.pm">DBD:mysql</a> installed (test tests use the randgen and this is required&#8230;hey, it is a WONDER-tool!) : )<br />
* <a href="http://www.percona.com/doc/percona-xtrabackup/innobackupex/innobackupex_script.html">Innobackupex</a>, a MySQL / Percona server and the appropriate xtrabackup binary.</p>
<p>To run them:<br />
$./dbqp.py &#8211;suite=xtrabackup_basic &#8211;basedir=/path/to/mysql &#8211;xtrabackup-path=/mah/path &#8211;innobackupex-path=/mah/other/path &#8211;default-server-type=mysql &#8211;no-shm</p>
<p>Some next steps for dbqp include:<br />
1)  Improved docs<br />
2)  Merging into the Percona Server trees<br />
3)  Setting up test jobs in Jenkins (crashme / sqlbench / randgen)<br />
4)  Other assorted awesomeness</p>
<p>Naturally, this testing goodness will also find its way into <a href="http://www.drizzle.org/">Drizzle</a> (which currently has a <a href="http://blog.drizzle.org/2011/10/25/fremont-beta-2011-10-28-has-been-released/">7.1 beta out</a>).  We definitely need to see some Xtrabackup test cases for <a href="http://www.flamingspork.com/blog/2011/04/01/online-non-blocking-backup-for-drizzle-with-xtrabackup/">Drizzle&#8217;s version of the tool</a> (mwa ha ha!) &gt;: )</p><br/>PlanetMySQL Voting:
	 <a href="http://planet.mysql.com/entry/vote/?entry_id=30614&vote=1&apivote=1">Vote UP</a> /
	 <a href="http://planet.mysql.com/entry/vote/?entry_id=30614&vote=-1&apivote=1">Vote DOWN</a>]]></content:encoded>
			<wfw:commentRss>http://planetmysql.ru/2011/11/08/dbqp-and-xtrabackup-testing/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Drizzle / dbqp updates</title>
		<link>http://www.wc220.com/?p=298&#038;utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=drizzle-dbqp-updates</link>
		<comments>http://www.wc220.com/?p=298#comments</comments>
		<pubDate>Fri, 14 Oct 2011 20:31:39 +0000</pubDate>
		<dc:creator>patrick crews</dc:creator>
				<category><![CDATA[dbqp]]></category>
		<category><![CDATA[Drizzle]]></category>
		<category><![CDATA[testing]]></category>

		<guid isPermaLink="false">http://www.wc220.com/?p=298</guid>
		<description><![CDATA[Just wanted to blog about some of the latest updates to dbqp.  We just merged some interesting changes into Drizzle (just in time for the impending Fremont beta).  In additional to general code cleanup / reorganization, we have the following goodies:
Randgen in the Drizzle tree
One of the biggest things is that the random query generator (aka randgen) is now part of the Drizzle tree.  While I did some of the work here, the major drivers of this happening were Brian and Stewart:

Brian makes a fair argument that the easier / more convenient it is to run a test, the greater the likelihood of it being run.  Additional tools to install, etc = not so much.  Having something right there and ready to go = win!
Stewart is also a fan of convenience, lotsa testing, and working smarter, not harder.  As a result, he did the initial legwork on merging the randgen.  I do suspect there is still much for me to learn about properly bzr joining trees and whatnot, but we&#8217;ll get it right soon enough ; )

This doesn&#8217;t mean we won&#8217;t be contributing any changes we make back to the main randgen project / branch, it is strictly to facilitate more testing for Drizzle.  As we already have our randgen tests packaged into dbqp-runnable suites, running these tests is even easier : )
&#8211;libeatmydata
Another request fulfilled in this update is the ability to use Stewart&#8217;s libeatmydata to speed up testing.  By default, dbqp uses shared memory as a workdir, similar to mysql-test-run&#8217;s &#8211;mem option (this can be bypassed in dbqp with &#8211;no-shm, fyi).  However, this isn&#8217;t always perfect or desirable to do.
An alternative is to use libeatmydata, which disables fsync() calls.  As the name implies, you don&#8217;t want to use it if care about your data, but for general testing purposes, it can greatly speed up test execution.
If you have the library installed / on your machine, you can use it like so:  ./dbqp &#8211;libeatmydata [--libeatmydata-path ] &#8230;
By default, libeatmydata-path is /usr/local/lib/libeatmydata.so (as if you used make install)
Multiple server types
IMHO, this is one of the coolest new tricks.  dbqp can now handle more than just Drizzle servers / source!  The ultimate idea is to allow tests that utilize more than one type / version of a server to have more interesting tests : )  This will be useful for scenarios like testing Drizzledump migration as we can feed in one (or more) MySQL servers and a Drizzle tree and make sure we can migrate data from all of them.
We also intend to utilize dbqp for testing a variety of Percona products, and it is kind of handy to be able to run the code you are testing ; )  I already have the tool running Percona / MySQL servers and have some randgen tests working:

$ ./dbqp.py  --default_server_type=mysql --basedir=/percona-server/Percona-Server --mode=randgen
Setting --no-secure-file-priv=True for randgen usage...
20111013-163443 INFO Linking workdir /dbqp/workdir to /dev/shm/dbqp_workdir_pcrews_9dbc7e8a-2872-45a9-8a07-f347f6184246
20111013-163443 INFO Using mysql source tree:
20111013-163443 INFO basedir: /percona-server/Percona-Server
20111013-163443 INFO clientbindir: /percona-server/Percona-Server/client
20111013-163443 INFO testdir: /dbqp
20111013-163443 INFO server_version: 5.5.16-rel21.0
20111013-163443 INFO server_compile_os: Linux
20111013-163443 INFO server_platform: x86_64
20111013-163443 INFO server_comment: (Percona Server with XtraDB (GPL), Release rel21.0, Revision 188)
20111013-163443 INFO Using default-storage-engine: innodb
20111013-163443 INFO Using testing mode: randgen
20111013-163443 INFO Processing test suites...
20111013-163443 INFO Found 5 test(s) for execution
20111013-163443 INFO Creating 1 bot(s)
20111013-163449 INFO Taking clean db snapshot...
20111013-163452 INFO bot0 server:
20111013-163452 INFO NAME: s0
20111013-163452 INFO MASTER_PORT: 9307
20111013-163452 INFO SOCKET_FILE: /dbqp/workdir/bot0/s0/var/s0.sock
20111013-163452 INFO VARDIR: /dbqp/workdir/bot0/s0/var
20111013-163452 INFO STATUS: 1
20111013-163506  ===============================================================
20111013-163506  TEST NAME                                  [ RESULT ] TIME (ms)
20111013-163506  ===============================================================
20111013-163506  main.blob                                  [ pass ]     8624
20111013-163516  main.create_drop                           [ pass ]     2862
20111013-163524  main.many_indexes                          [ pass ]     1429
20111013-163547  main.optimizer_subquery                    [ pass ]    17153
20111013-163558  main.outer_join                            [ pass ]     4243
20111013-163558  ===============================================================
20111013-163558 INFO Test execution complete in 69 seconds
20111013-163558 INFO Summary report:
20111013-163558 INFO Executed 5/5 test cases, 100.00 percent
20111013-163558 INFO STATUS: PASS, 5/5 test cases, 100.00 percent executed
20111013-163558 INFO Spent 34 / 69 seconds on: TEST(s)
20111013-163558 INFO Test execution complete
20111013-163558 INFO Stopping all running servers...

Expect to see this up and running tests against Percona Server in the next week or so.  I&#8217;ll be writing more about this soon.
Native / unittest mode
This hasn&#8217;t made it into the Drizzle tree yet.  To ease merging the code with Percona Server / Xtrabackup, I&#8217;ve created a separate launchpad project.  One of the things we needed was the ability to write complex tests directly.  It is currently easy to plug new tools into dbqp, but we essentially needed a new tool for certain testing needs.
Our solution for this was to allow dbqp to run python unittest modules.  We still have a bit of work to do before we have some demo tests ready, but we will be creating some expanded Xtrabackup tests using this system very soon.  So far, it is turning out to be pretty neat:

./dbqp.py  --default_server_type=mysql --basedir=/percona-server/Percona-Server --mode=native
20111013-190744 INFO Killing pid 1747 from /dbqp/workdir/bot0/s0/var/run/s0.pid
20111013-190744 INFO Linking workdir /dbqp/workdir to /dev/shm/dbqp_workdir_pcrews_9dbc7e8a-2872-45a9-8a07-f347f6184246
20111013-190744 INFO Using mysql source tree:
20111013-190744 INFO basedir: /percona-server/Percona-Server
20111013-190744 INFO clientbindir: /percona-server/Percona-Server/client
20111013-190744 INFO testdir: /dbqp
20111013-190744 INFO server_version: 5.5.16-rel21.0
20111013-190744 INFO server_compile_os: Linux
20111013-190744 INFO server_platform: x86_64
20111013-190744 INFO server_comment: (Percona Server with XtraDB (GPL), Release rel21.0, Revision 188)
20111013-190744 INFO Using default-storage-engine: innodb
20111013-190744 INFO Using testing mode: native
20111013-190744 INFO Processing test suites...
20111013-190744 INFO Found 1 test(s) for execution
20111013-190744 INFO Creating 1 bot(s)
20111013-190749 INFO Taking clean db snapshot...
20111013-190750 INFO bot0 server:
20111013-190750 INFO NAME: s0
20111013-190750 INFO MASTER_PORT: 9306
20111013-190750 INFO SOCKET_FILE: /dbqp/workdir/bot0/s0/var/s0.sock
20111013-190750 INFO VARDIR: /dbqp/workdir/bot0/s0/var
20111013-190750 INFO STATUS: 1
20111013-190756  ===============================================================
20111013-190756  TEST NAME                                  [ RESULT ] TIME (ms)
20111013-190756  ===============================================================
20111013-190756  main.example_test                          [ pass ]        1
20111013-190756  test_choice (example_test.TestSequenceFunctions) ... ok
20111013-190756  test_sample (example_test.TestSequenceFunctions) ... ok
20111013-190756  test_shuffle (example_test.TestSequenceFunctions) ... ok
20111013-190756
20111013-190756  ----------------------------------------------------------------------
20111013-190756  Ran 3 tests in 0.000s
20111013-190756
20111013-190756  OK
20111013-190756
20111013-190756  ===============================================================
20111013-190756 INFO Test execution complete in 6 seconds
20111013-190756 INFO Summary report:
20111013-190756 INFO Executed 1/1 test cases, 100.00 percent
20111013-190756 INFO STATUS: PASS, 1/1 test cases, 100.00 percent executed
20111013-190756 INFO Spent 0 / 6 seconds on: TEST(s)
20111013-190756 INFO Test execution complete
20111013-190756 INFO Stopping all running servers...

This really only scratches the surface of what can happen, but I&#8217;ll be writing more in-depth articles on what kind of tricks we can pull off as the code gets more polished.
Three non-testing bits:
1)  Percona Live London is just around the corner and members of the Drizzle team will be there.
2)  We are *this* close to Fremont beta being ready.  The contributions and feedback have been most welcome.  Any additional testing / etc are most appreciated.
3)  Drizzle is now part of the SPI!
&#160;]]></description>
			<content:encoded><![CDATA[<p>Just wanted to blog about some of the latest updates to <a href="http://docs.drizzle.org/testing/dbqp.html">dbqp</a>.  We just merged some interesting changes into <a href="http://www.wc220.com/drizzle.org">Drizzle</a> (just in time for the impending Fremont beta).  In additional to general code cleanup / reorganization, we have the following goodies:</p>
<h2>Randgen in the Drizzle tree</h2>
<p>One of the biggest things is that the <a href="https://launchpad.net/randgen">random query generator</a> (aka <a href="http://docs.drizzle.org/testing/randgen.html">randgen</a>) is now part of the Drizzle tree.  While I did some of the work here, the major drivers of this happening were <a href="https://twitter.com/#!/brianaker">Brian</a> and <a href="http://www.flamingspork.com/blog/">Stewart</a>:</p>
<ol>
<li>Brian makes a fair argument that the easier / more convenient it is to run a test, the greater the likelihood of it being run.  Additional tools to install, etc = not so much.  Having something right there and ready to go = win!</li>
<li>Stewart is also a fan of convenience, lotsa testing, and working smarter, not harder.  As a result, he did the initial legwork on merging the randgen.  I do suspect there is still much for me to learn about properly <a href="http://www.flamingspork.com/blog/2011/05/21/howto-fix-bzr-join-error-of-trees-have-the-same-root/">bzr joining</a> trees and whatnot, but we&#8217;ll get it right soon enough ; )</li>
</ol>
<p>This doesn&#8217;t mean we won&#8217;t be contributing any changes we make back to the main randgen project / branch, it is strictly to facilitate more testing for Drizzle.  As we already have our <a href="http://www.wc220.com/?p=152">randgen tests</a> packaged into dbqp-runnable suites, running these tests is even easier : )</p>
<h2>&#8211;libeatmydata</h2>
<p>Another request fulfilled in this update is the ability to use Stewart&#8217;s <a href="http://www.wc220.com/www.flamingspork.com/blog/2007/11/27/libeatmydata/">libeatmydata</a> to speed up testing.  By default, dbqp uses shared memory as a workdir, similar to mysql-test-run&#8217;s &#8211;mem option (this can be bypassed in dbqp with &#8211;no-shm, fyi).  However, this isn&#8217;t always perfect or desirable to do.</p>
<p>An alternative is to use <a href="https://launchpad.net/libeatmydata">libeatmydata</a>, which disables fsync() calls.  As the name implies, you don&#8217;t want to use it if care about your data, but for general testing purposes, it can greatly speed up test execution.</p>
<p>If you have the library installed / on your machine, you can use it like so:  ./dbqp &#8211;libeatmydata [--libeatmydata-path ] &#8230;</p>
<p>By default, libeatmydata-path is /usr/local/lib/libeatmydata.so (as if you used make install)</p>
<h2>Multiple server types</h2>
<p>IMHO, this is one of the coolest new tricks.  dbqp can now handle more than just Drizzle servers / source!  The ultimate idea is to allow tests that utilize more than one type / version of a server to have more interesting tests : )  This will be useful for scenarios like testing <a href="http://www.linuxjedi.co.uk/?p=35">Drizzledump migration</a> as we can feed in one (or more) MySQL servers and a Drizzle tree and make sure we can migrate data from all of them.</p>
<p>We also intend to utilize dbqp for testing a variety of <a href="http://www.percona.com/software/">Percona products</a>, and it is kind of handy to be able to run the code you are testing ; )  I already have the tool running Percona / MySQL servers and have some randgen tests working:</p>
<p><code><br />
$ ./dbqp.py  --default_server_type=mysql --basedir=/percona-server/Percona-Server --mode=randgen<br />
Setting --no-secure-file-priv=True for randgen usage...<br />
20111013-163443 INFO Linking workdir /dbqp/workdir to /dev/shm/dbqp_workdir_pcrews_9dbc7e8a-2872-45a9-8a07-f347f6184246<br />
20111013-163443 INFO Using mysql source tree:<br />
20111013-163443 INFO basedir: /percona-server/Percona-Server<br />
20111013-163443 INFO clientbindir: /percona-server/Percona-Server/client<br />
20111013-163443 INFO testdir: /dbqp<br />
20111013-163443 INFO server_version: 5.5.16-rel21.0<br />
20111013-163443 INFO server_compile_os: Linux<br />
20111013-163443 INFO server_platform: x86_64<br />
20111013-163443 INFO server_comment: (Percona Server with XtraDB (GPL), Release rel21.0, Revision 188)<br />
20111013-163443 INFO Using default-storage-engine: innodb<br />
20111013-163443 INFO Using testing mode: randgen<br />
20111013-163443 INFO Processing test suites...<br />
20111013-163443 INFO Found 5 test(s) for execution<br />
20111013-163443 INFO Creating 1 bot(s)<br />
20111013-163449 INFO Taking clean db snapshot...<br />
20111013-163452 INFO bot0 server:<br />
20111013-163452 INFO NAME: s0<br />
20111013-163452 INFO MASTER_PORT: 9307<br />
20111013-163452 INFO SOCKET_FILE: /dbqp/workdir/bot0/s0/var/s0.sock<br />
20111013-163452 INFO VARDIR: /dbqp/workdir/bot0/s0/var<br />
20111013-163452 INFO STATUS: 1<br />
20111013-163506  ===============================================================<br />
20111013-163506  TEST NAME                                  [ RESULT ] TIME (ms)<br />
20111013-163506  ===============================================================<br />
20111013-163506  main.blob                                  [ pass ]     8624<br />
20111013-163516  main.create_drop                           [ pass ]     2862<br />
20111013-163524  main.many_indexes                          [ pass ]     1429<br />
20111013-163547  main.optimizer_subquery                    [ pass ]    17153<br />
20111013-163558  main.outer_join                            [ pass ]     4243<br />
20111013-163558  ===============================================================<br />
20111013-163558 INFO Test execution complete in 69 seconds<br />
20111013-163558 INFO Summary report:<br />
20111013-163558 INFO Executed 5/5 test cases, 100.00 percent<br />
20111013-163558 INFO STATUS: PASS, 5/5 test cases, 100.00 percent executed<br />
20111013-163558 INFO Spent 34 / 69 seconds on: TEST(s)<br />
20111013-163558 INFO Test execution complete<br />
20111013-163558 INFO Stopping all running servers...<br />
</code></p>
<p>Expect to see this up and running tests against Percona Server in the next week or so.  I&#8217;ll be writing more about this soon.</p>
<h2>Native / unittest mode</h2>
<p>This hasn&#8217;t made it into the Drizzle tree yet.  To ease merging the code with <a href="http://www.percona.com/software/percona-server/">Percona Server</a> / <a href="http://www.percona.com/software/percona-xtrabackup/">Xtrabackup</a>, I&#8217;ve created a separate <a href="https://launchpad.net/dbqp">launchpad project</a>.  One of the things we needed was the ability to write complex tests directly.  It is currently easy to plug new tools into dbqp, but we essentially needed a new tool for certain testing needs.</p>
<p>Our solution for this was to allow dbqp to run python unittest modules.  We still have a bit of work to do before we have some demo tests ready, but we will be creating some expanded <a href="http://www.percona.com/software/percona-xtrabackup/">Xtrabackup</a> tests using this system very soon.  So far, it is turning out to be pretty neat:</p>
<p><code><br />
./dbqp.py  --default_server_type=mysql --basedir=/percona-server/Percona-Server --mode=native<br />
20111013-190744 INFO Killing pid 1747 from /dbqp/workdir/bot0/s0/var/run/s0.pid<br />
20111013-190744 INFO Linking workdir /dbqp/workdir to /dev/shm/dbqp_workdir_pcrews_9dbc7e8a-2872-45a9-8a07-f347f6184246<br />
20111013-190744 INFO Using mysql source tree:<br />
20111013-190744 INFO basedir: /percona-server/Percona-Server<br />
20111013-190744 INFO clientbindir: /percona-server/Percona-Server/client<br />
20111013-190744 INFO testdir: /dbqp<br />
20111013-190744 INFO server_version: 5.5.16-rel21.0<br />
20111013-190744 INFO server_compile_os: Linux<br />
20111013-190744 INFO server_platform: x86_64<br />
20111013-190744 INFO server_comment: (Percona Server with XtraDB (GPL), Release rel21.0, Revision 188)<br />
20111013-190744 INFO Using default-storage-engine: innodb<br />
20111013-190744 INFO Using testing mode: native<br />
20111013-190744 INFO Processing test suites...<br />
20111013-190744 INFO Found 1 test(s) for execution<br />
20111013-190744 INFO Creating 1 bot(s)<br />
20111013-190749 INFO Taking clean db snapshot...<br />
20111013-190750 INFO bot0 server:<br />
20111013-190750 INFO NAME: s0<br />
20111013-190750 INFO MASTER_PORT: 9306<br />
20111013-190750 INFO SOCKET_FILE: /dbqp/workdir/bot0/s0/var/s0.sock<br />
20111013-190750 INFO VARDIR: /dbqp/workdir/bot0/s0/var<br />
20111013-190750 INFO STATUS: 1<br />
20111013-190756  ===============================================================<br />
20111013-190756  TEST NAME                                  [ RESULT ] TIME (ms)<br />
20111013-190756  ===============================================================<br />
20111013-190756  main.example_test                          [ pass ]        1<br />
20111013-190756  test_choice (example_test.TestSequenceFunctions) ... ok<br />
20111013-190756  test_sample (example_test.TestSequenceFunctions) ... ok<br />
20111013-190756  test_shuffle (example_test.TestSequenceFunctions) ... ok<br />
20111013-190756<br />
20111013-190756  ----------------------------------------------------------------------<br />
20111013-190756  Ran 3 tests in 0.000s<br />
20111013-190756<br />
20111013-190756  OK<br />
20111013-190756<br />
20111013-190756  ===============================================================<br />
20111013-190756 INFO Test execution complete in 6 seconds<br />
20111013-190756 INFO Summary report:<br />
20111013-190756 INFO Executed 1/1 test cases, 100.00 percent<br />
20111013-190756 INFO STATUS: PASS, 1/1 test cases, 100.00 percent executed<br />
20111013-190756 INFO Spent 0 / 6 seconds on: TEST(s)<br />
20111013-190756 INFO Test execution complete<br />
20111013-190756 INFO Stopping all running servers...</p>
<p></code></p>
<p>This really only scratches the surface of what can happen, but I&#8217;ll be writing more in-depth articles on what kind of tricks we can pull off as the code gets more polished.</p>
<p>Three non-testing bits:</p>
<p>1)  <a href="http://www.percona.com/live/london-2011/">Percona Live London</a> is just around the corner and members of the <a href="http://blog.drizzle.org/2011/09/27/drizzle-at-percona-live/">Drizzle team will be there</a>.</p>
<p>2)  We are *this* close to Fremont beta being ready.  The <a href="http://hackdrizzle.com/drizzle-query-log-parser/">contributions</a> and feedback have been most welcome.  Any additional testing / etc are most appreciated.</p>
<p>3)  <a href="http://blog.drizzle.org/2011/10/06/drizzle-is-now-member-of-software-in-the-public-interest-can-take-donations/">Drizzle is now part of the SPI</a>!</p>
<p>&nbsp;</p><br/>PlanetMySQL Voting:
	 <a href="http://planet.mysql.com/entry/vote/?entry_id=30382&vote=1&apivote=1">Vote UP</a> /
	 <a href="http://planet.mysql.com/entry/vote/?entry_id=30382&vote=-1&apivote=1">Vote DOWN</a>]]></content:encoded>
			<wfw:commentRss>http://planetmysql.ru/2011/10/15/drizzle-dbqp-updates/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Testing Xeround’s database as a service</title>
		<link>http://www.wc220.com/?p=221&#038;utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=testing-xeround%25e2%2580%2599s-database-as-a-service</link>
		<comments>http://www.wc220.com/?p=221#comments</comments>
		<pubDate>Thu, 28 Apr 2011 04:56:21 +0000</pubDate>
		<dc:creator>patrick crews</dc:creator>
				<category><![CDATA[Drizzle]]></category>
		<category><![CDATA[mysql]]></category>
		<category><![CDATA[randgen]]></category>
		<category><![CDATA[testing]]></category>

		<guid isPermaLink="false">http://www.wc220.com/?p=221</guid>
		<description><![CDATA[So while I was at the MySQL UC, The Xeround database came to my attention.  It bills itself as database as a service for MySQL systems and a seamless replacement for standard MySQL.
Of course, since I am a QA Engineer, I could not resist the urge to try to break it &#62;:)  As my friend and former MySQL colleage, Kostja says, &#8220;QA Engineers are a unique breed&#8230;they like to push all the buttons&#8221; : )  I would say that the QA mindset goes a bit further than that, but it is something I will delve into in another post.  I will only say that there is a reason that Microsoft recognizes QA software engineering as a distinct and specialized discipline.
So, let&#8217;s get back to Xeround.  It was the first database as a service that caught my eye and I just had to test it!  They are currently offering a free beta.  It is remarkably easy and fast to get set up with a test database and the web-based dashboard they provide is pretty interesting and offers some good information (though some of it is confusing&#8230;more on that in a bit)
It was my intent to run a small handful of tests with the mighty, mighty randgen!
My tests were as follows:
1)  outer_join grammar &#8211; creates seriously nasty JOIN queries that can use up to 20 tables
2)  transactional grammar &#8211; we have a grammar that creates a variety of transactions.  Some good, some bad, with lots of ROLLBACKs and SAVEPOINTs sprinkled in for spice.
3)  subqueries &#8211; the nastiest grammar I have created and as I have mentioned elsewhere, it is also part of why we are just now seeing optimizer features like index condition pushdown (ICP) being reintroduced to MySQL &#62;: )
My thoughts were that these could be quickly executed and point out any serious problems in basic functionality.  MySQL and Drizzle both use these grammars as part of their testing.  Drizzle must survive these tests on every push to trunk, so these seem like reasonable stressors for a new engine &#62;: )
It should be noted that I had to modify the test grammars to accomodate some Xeround limitations, the modified randgen branch I used is here.  It can be branched via bzr branch lp:~patrick-crews/randgen/randgen_drizzle_exp
Each grammar would be run with the randgen&#8217;s &#8211;debug option.  This is because the user is presented with a nice report at the end of the run which indicates:  query_count:row_count (ie how many queries returned how many rows):
# 2011-04-27T20:40:18 Rows returned:
$VAR1 = {
&#8216;    0&#8242; =&#62; 59,
&#8216;    1&#8242; =&#62; 2,
&#8216;    4&#8242; =&#62; 1,
&#8216;    9&#8242; =&#62; 1,
&#8216;   -1&#8242; =&#62; 35,
&#8216;&#62;100&#8242; =&#62; 1
};
I would use this as a comparison point against MySQL 5.1.  Granted, I could use the &#8211;Validator=ResultsetComparatorSimplify option, but then I would have an actual bug report that I would feel compelled to file and this would feel less like fun and more like work ; )  However, I have been in contact with engineers from Xeround and have shared my findings with them.
For the transactional grammar, I would run the grammar on each system and then do a diff of mysqldump files from each database.  As Xeround is a MySQL engine, this could cause some differences, but the data in the tables should be consistent.
Before I get into the testing results, I&#8217;ll provide some overall impressions:
As I said, the web interface is pretty nice and provides you with a lot of useful information.  It allows you to easily create a new named database instance and provides you with data such as status, scale, uptime, cpu utilization, memory utilization, number of connections, ops/sec, and message count.  Scale refers to the autoscale capabilities that Xeround advertises.  For the beta, you are allowed to scale from 3 to 4 servers.  3 servers is considered 100%, adding the extra server (when certain user-specified CPU or Memory limits are hit) equates to 133% .  Interestingly enough, I observed that there were always 6 active connections when the database was idle (probably some of the Xeround &#8216;secret sauce&#8216; working&#8230;).
The control panel also allows the user to set the CPU, memory, and connections limits that will trigger scale up (and possibly scale down).  In my experiments, I never seemed to tax memory or connections, but CPU limits were hit and auto-scale did trigger, though I will admit that I didn&#8217;t observe any noticeable change in the test execution.
There are also tabs for backup (not available in the free beta, though mysqldump does work against a Xeround instance), general monitoring which provides real-time information about cpu, memory and connections, and an events (messages tab).  The one thing I noted about the events tab was that I received a number of warning messages about the health of my database during times I wasn&#8217;t using it.  However, it is a beta service for general evaluation and certain oddities are to be expected.
Here is what I found with my tests:
1)  Xeround is a MySQL engine.  They do advertise this, but the main reason I noticed that all of my created test tables were now &#8216;Engine=Xeround&#8217; was that I was unable to create a varchar_1024 indexed column.  Xeround is limited to 255 characters max:

# 2011-04-27T19:50:27 key (`col_char_1024_key` ))  failed: 1074 Column length too big for column 'col_char_1024' (max = 255); use BLOB or TEXT instead

This limitation required modification of the randgen grammars and gendata files to limit char columns to 255.  As noted above, you can find the modified version of the randgen here.
2)  Tables with an ENGINE=$engine_name argument are processed without an issue (ie you should be able to use a dumpfile without problems) and are converted to Xeround tables.  One thing to note is that dumpfiles *from* Xeround have ENGINE=Xeround for the CREATE TABLE statements

create table t1 (a int not null auto_increment, primary key(a)) engine=innodb;
Query OK, 0 rows affected, 2 warnings (0.702761 sec)
drizzle&#62; show create table t1;
+-------+---------------------------------------------------------------------------------------------------------------------------------------+
&#124; Table &#124; Create Table                                                                                                                          &#124;
+-------+---------------------------------------------------------------------------------------------------------------------------------------+
&#124; t1    &#124; CREATE TABLE `t1` (
`a` int(11) NOT NULL AUTO_INCREMENT,
PRIMARY KEY (`a`)
) ENGINE=Xeround DEFAULT CHARSET=utf8 COLLATE=utf8_bin &#124;
+-------+---------------------------------------------------------------------------------------------------------------------------------------+

2)  outer_join grammar:
I used the following command line:

./gentest.pl --gendata=conf/drizzle/outer_join_drizzle.zz --grammar=conf/drizzle/outer_join_drizzle.yy --queries=100 --threads=1 --dsn=dbi:mysql:host=00.00.00.00:port=9999:user=USER:password=PASSWORD:database=test --sqltrace --debug

The test ran without much incident.  The Xeround server monitor indicated that the CPU was hovering near 80% for most of the time, but again&#8230;beta test setup, so I&#8217;ll give them some leeway.
The big trouble is what follows.  Remember those randgen summary reports I mentioned earlier?  Below is a comparison of Xeround vs. MySQL for the same command line.  The values are row_count&#8217; =&#62; number_of_queries_returning_said_row_count.  What this means is that for the same set of queries, Xeround and MySQL do not always return the same result sets.  I did not note any differences in query failures, so this simply indicates that results processing is differing somewhere : (  To elaborate, Xeround had 56 queries that returned 0 rows, for the same workload, MySQL only had 39.  A row count of -1 indicates that there was an error with the query, such as referencing a table or column that doesn&#8217;t exist.  Somehow, Xeround hit fewer errors than MySQL, though that is also worrisome &#8211; why do they register errors differently?
Xeround:

# 2011-04-27T20:11:05 Rows returned:
$VAR1 = {
'    0' =&#62; 56,
'    1' =&#62; 16,
'    2' =&#62; 6,
'    3' =&#62; 2,
'    5' =&#62; 1,
'    6' =&#62; 1,
'    7' =&#62; 1,
'    8' =&#62; 1,
'   -1' =&#62; 13,
'   10' =&#62; 2,
'&#62;10' =&#62; 1
};

MySQL 5.1

$VAR1 = {
'    0' =&#62; 39,
'    1' =&#62; 15,
'    2' =&#62; 2,
'    3' =&#62; 2,
'    4' =&#62; 1,
'    7' =&#62; 2,
'    8' =&#62; 1,
'   -1' =&#62; 32,
'   10' =&#62; 1,
'&#62;10' =&#62; 5
};

3)  transactional grammar:
I used the following command line:

./gentest.pl --gendata=conf/drizzle/translog_drizzle.zz --grammar=conf/drizzle/translog_concurrent1.yy --queries=100 --threads=1 --dsn=dbi:mysql:host=00.00.00.00:port=9999:user=USER:password=PASSWORD:database=test --sqltrace --debug

Unfortunately, I noticed a large number of differences.  We&#8217;ll start with the easiest one:

&#60; DROP TABLE IF EXISTS `A`;
&#60; CREATE TABLE `A` (
---
&#62; DROP TABLE IF EXISTS `a`;
&#62; CREATE TABLE `a` (
50c50
&#60; ) ENGINE='InnoDB' AUTO_INCREMENT=105 COLLATE='utf8_general_ci';
---
&#62; ) ENGINE='Xeround' COLLATE='utf8_bin';

It isn&#8217;t huge, but Xeround apparently auto-converts tables names to lower-case.  The randgen attempts to create table `A`, but it is stored as table `a`.  This could be an issue for some people, but Xeround does say that the beta is for people to evaluate the system&#8217;s suitability for their purposes.
The big issue is that Xeround appears to not have registered a lot of the transactions issued by the randgen.  The Xeround dumpfile only contained the original 10 rows from table `a`, while the MySQL 5.1 version I ran locally had 94 rows by the end of the randgen run : (
Further research of the randgen logs indicate the following issue:

# 2011-04-27T20:06:56 Query:  INSERT INTO `d` ( `col_char_10` , `col_char_10_key` , `col_char_10_not_null` , `col_char_10_not_null_key` , `col_char_255` , `col_char_255_key` , `col_char_255_not_null` , `col_char_255_not_null_key` , `col_int` , `col_int_key` , `col_int_not_null` , `col_int_not_null_key` , `col_bigint` , `col_bigint_key` , `col_bigint_not_null` , `col_bigint_not_null_key` , `col_enum` , `col_enum_key` , `col_enum_not_null` , `col_enum_not_null_key` , `col_text` , `col_text_key` , `col_text_not_null` , `col_text_not_null_key` ) SELECT `col_char_10` , `col_char_10_key` , `col_char_10_not_null` , `col_char_10_not_null_key` , `col_char_255` , `col_char_255_key` , `col_char_255_not_null` , `col_char_255_not_null_key` , `col_int` , `col_int_key` , `col_int_not_null` , `col_int_not_null_key` , `col_bigint` , `col_bigint_key` , `col_bigint_not_null` , `col_bigint_not_null_key` , `col_enum` , `col_enum_key` , `col_enum_not_null` , `col_enum_not_null_key` , `col_text` , `col_text_key` , `col_text_not_null` , `col_text_not_null_key` FROM `bb`  ORDER BY `col_bigint`,`col_bigint_key`,`col_bigint_not_null`,`col_bigint_not_null_key`,`col_char_10`,`col_char_10_key`,`col_char_10_not_null`,`col_char_10_not_null_key`,`col_char_255`,`col_char_255_key`,`col_char_255_not_null`,`col_char_255_not_null_key`,`col_enum`,`col_enum_key`,`col_enum_not_null`,`col_enum_not_null_key`,`col_int`,`col_int_key`,`col_int_not_null`,`col_int_not_null_key`,`col_text`,`col_text_key`,`col_text_not_null`,`col_text_not_null_key`,`pk` LIMIT 50 /*Generated by THREAD_ID 1*/  failed: 1038 Out of sort memory; increase server sort buffer size

So, it would appear that transactions are failing for some reason or another.  However, I repeat the disclaimer about this being a beta and not a production deployment.  It could have something to do with the resources allocated for each beta user.
3)  Subquery grammar
This was the initial test I ran, but I have saved it for last.  First of all, the command line:

./gentest.pl --gendata=conf/drizzle/drizzle.zz --grammar=conf/drizzle/optimizer_subquery_drizzle.yy --queries=100 --threads=1 --dsn=dbi:mysql:host=00.00.00.00:port=9999:user=USER:password=PASSWORD:database=test --sqltrace --debug

The first thing I noticed on the single-threaded run was that Xeround seemed to not like this query very much at all:

SELECT    table2 . `col_int` AS field1 FROM ( CC AS table1 STRAIGHT_JOIN ( ( CC AS table2 STRAIGHT_JOIN CC AS table3 ON (table3 . `col_bigint_key` = table2 . `col_int_not_null_key`  ) ) ) ON (table3 . `col_text_not_null_key` = table2 . `col_char_10_key`  ) ) WHERE (  table1 . `col_int` NOT IN ( SELECT   SUBQUERY1_t1 . `col_int_not_null_key` AS SUBQUERY1_field1 FROM ( BB AS SUBQUERY1_t1 INNER JOIN ( CC AS SUBQUERY1_t2 INNER JOIN BB AS SUBQUERY1_t3 ON (SUBQUERY1_t3 . `col_char_10_key` = SUBQUERY1_t2 . `col_char_10_key`  ) ) ON (SUBQUERY1_t3 . `col_char_10_not_null_key` = SUBQUERY1_t2 . `col_char_10`  ) ) WHERE SUBQUERY1_t2 . `col_bigint` != table1 . `pk` OR SUBQUERY1_t2 . `pk` &#62;= table2 . `pk` ) ) OR ( table1 . `col_int_key`  BETWEEN 48 AND ( 48 + 183 ) OR table1 . `pk`  BETWEEN 48 AND ( 48 + 104 ) )  GROUP BY field1  ;

Now it is quite nasty, but standard MySQL executes it with a minimum of fuss (though it does take a moment to handle this monster as well).
The other thing is that Xeround took an exceedingly long time to execute this workload.  While the other grammars executed in moderate amounts of time (my testing was from a hotel room in Santa Clara while the instance is in Chicago), the subquery test was noticeably slow.  I was able to walk down to the lobby, buy something, and return to my room while it was dealing with the nasty query above : (  For some context, running the same command line on my laptop took 8 seconds, Xeround took 14 minutes, but again&#8230;beta test setup and hardware, so YMMV.
Finally, we have the dreaded row count report:
Xeround:

# 2011-04-27T20:45:19 Rows returned:
$VAR1 = {
'    0' =&#62; 59,
'    1' =&#62; 2,
'    4' =&#62; 1,
'   -1' =&#62; 35,
'&#62;10' =&#62; 1,
'&#62;100' =&#62; 1
};

MySQL 5.1:

# 2011-04-27T20:40:18 Rows returned:
$VAR1 = {
'    0' =&#62; 59,
'    1' =&#62; 2,
'    4' =&#62; 1,
'    9' =&#62; 1,
'   -1' =&#62; 35,
'&#62;100' =&#62; 1
};

As we can see, there is 1 query out of the 100 issued where result sets differed (returning 9 rows in MySQL vs. &#62;10 rows in Xeround).
I also tried using &#8211;threads=10 to really stress the Xeround system (I didn&#8217;t bother with MySQL, it handles 10 threads of nasty subqueries like a champ&#8230;incidentally, so does Drizzle) ; )  Xeround was able to handle the workload and did so in 27 minutes.  Since single-threaded took 14 minutes, perhaps Xeround doesn&#8217;t really begin to shine until we start hitting large numbers of concurrent connections?
So what can I say from the results of these informal tests?  Personally, I would hesitate to say that Xeround is a drop-in replacement.  The limitations on column sizes, changes in table naming, and differing result sets are a bit worrisome.  However, I will say that the Xeround engineers I met at the UC were very engaged and interested in my findings and have made significant strides in subquery processing since my initial tests.  I believe that with time these issues will be fixed and that not every customer will run into them (I know I&#8217;m beating this into the ground, but I was using a beta test system).  Behavior may be different on a production machine and not every MySQL user will generate such workloads and every customer should perform their own careful testing and evaluation before making any changes to their systems.
My personal interest ends here.  The UC introduced me to a number of interesting new storage engines and I was mainly curious about ways of evaluating them.  This was a quick and dirty bit of testing just to see if I could produce any interesting pyrotechnics ; )  Go go randgen!
I really want this picture to be shown when anyone searches for &#039;randgen&#039; ; )
In all seriousness, I highly recommend adoption of the random query generator.  It offers a modular and customizable system for creating evaluation tools (like result set comparison, execution time comparison, replication validation, etc, etc) and has been used in production-level testing for MySQL, MariaDB and Drizzle for some time.  It also plays with Postgresql and Java DB (kind of scary that 40% of that list is owned by Oracle&#8230;), so please give it a spin and see what kinds of pretty explosions you can make&#8230;who knows, testing might actually become fun for non-QA folks &#62;; )
Additionally, these tests only took me about half an hour to setup and execute.  Granted, I have been using the tool for some time, but 30 minutes to identify a number of potential problem areas seems pretty awesome to me, but then again, I am a QA Engineer and we live for such things.]]></description>
			<content:encoded><![CDATA[<p>So while I was at the MySQL UC, The <a href="http://xeround.com/">Xeround</a> database came to my attention.  It bills itself as database as a service for MySQL systems and a seamless replacement for standard MySQL.</p>
<p>Of course, since I am a QA Engineer, I could not resist the urge to try to break it &gt;:)  As my friend and former MySQL colleage, <a href="http://kostja-osipov.livejournal.com/">Kostja</a> says, &#8220;QA Engineers are a unique breed&#8230;they like to push all the buttons&#8221; : )  I would say that the QA mindset goes a bit further than that, but it is something I will delve into in another post.  I will only say that there is a reason that Microsoft recognizes QA software engineering as a distinct and specialized discipline.</p>
<p>So, let&#8217;s get back to Xeround.  It was the first database as a service that caught my eye and I just had to test it!  They are currently offering a <a href="http://xeround.com/mysql-cloud-db-free-registration/">free beta</a>.  It is remarkably easy and fast to get set up with a test database and the web-based dashboard they provide is pretty interesting and offers some good information (though some of it is confusing&#8230;more on that in a bit)</p>
<p>It was my intent to run a small handful of tests with the mighty, mighty <a href="https://launchpad.net/randgen">randgen</a>!</p>
<p>My tests were as follows:<br />
1)  outer_join grammar &#8211; creates seriously nasty JOIN queries that can use up to 20 tables<br />
2)  transactional grammar &#8211; we have a grammar that creates a variety of transactions.  Some good, some bad, with lots of ROLLBACKs and SAVEPOINTs sprinkled in for spice.<br />
3)  subqueries &#8211; the nastiest grammar I have created and as I have mentioned elsewhere, it is also part of why we are just now seeing optimizer features like index condition pushdown (ICP) being reintroduced to MySQL &gt;: )</p>
<p>My thoughts were that these could be quickly executed and point out any serious problems in basic functionality.  MySQL and Drizzle both use these grammars as part of their testing.  Drizzle must survive these tests on every push to trunk, so these seem like reasonable stressors for a new engine &gt;: )</p>
<p>It should be noted that I had to modify the test grammars to accomodate some Xeround limitations, the modified randgen branch I used is <a href="https://code.launchpad.net/~patrick-crews/randgen/randgen_drizzle_exp">here</a>.  It can be branched via bzr branch lp:~patrick-crews/randgen/randgen_drizzle_exp</p>
<p>Each grammar would be run with the randgen&#8217;s &#8211;debug option.  This is because the user is presented with a nice report at the end of the run which indicates:  query_count:row_count (ie how many queries returned how many rows):</p>
<p># 2011-04-27T20:40:18 Rows returned:<br />
$VAR1 = {<br />
&#8216;    0&#8242; =&gt; 59,<br />
&#8216;    1&#8242; =&gt; 2,<br />
&#8216;    4&#8242; =&gt; 1,<br />
&#8216;    9&#8242; =&gt; 1,<br />
&#8216;   -1&#8242; =&gt; 35,<br />
&#8216;&gt;100&#8242; =&gt; 1<br />
};</p>
<p>I would use this as a comparison point against MySQL 5.1.  Granted, I could use the &#8211;Validator=ResultsetComparatorSimplify option, but then I would have an actual bug report that I would feel compelled to file and this would feel less like fun and more like work ; )  However, I have been in contact with engineers from Xeround and have shared my findings with them.</p>
<p>For the transactional grammar, I would run the grammar on each system and then do a diff of mysqldump files from each database.  As Xeround is a MySQL engine, this could cause some differences, but the data in the tables should be consistent.</p>
<p>Before I get into the testing results, I&#8217;ll provide some overall impressions:<br />
As I said, the web interface is pretty nice and provides you with a lot of useful information.  It allows you to easily create a new named database instance and provides you with data such as status, scale, uptime, cpu utilization, memory utilization, number of connections, ops/sec, and message count.  Scale refers to the autoscale capabilities that Xeround advertises.  For the beta, you are allowed to scale from 3 to 4 servers.  3 servers is considered 100%, adding the extra server (when certain user-specified CPU or Memory limits are hit) e<a href="http://xeround.com/developers/faq">quates to 133%</a> .  Interestingly enough, I observed that there were always 6 active connections when the database was idle (probably some of the Xeround &#8216;<a href="http://xeround.com/developers/faq/#faq-general">secret sauce</a>&#8216; working&#8230;).</p>
<p>The control panel also allows the user to set the CPU, memory, and connections limits that will trigger scale up (and possibly scale down).  In my experiments, I never seemed to tax memory or connections, but CPU limits were hit and auto-scale did trigger, though I will admit that I didn&#8217;t observe any noticeable change in the test execution.</p>
<p>There are also tabs for backup (not available in the free beta, though mysqldump does work against a Xeround instance), general monitoring which provides real-time information about cpu, memory and connections, and an events (messages tab).  The one thing I noted about the events tab was that I received a number of warning messages about the health of my database during times I wasn&#8217;t using it.  However, it is a beta service for general evaluation and certain oddities are to be expected.</p>
<p>Here is what I found with my tests:<br />
1)  Xeround is a MySQL engine.  They do advertise this, but the main reason I noticed that all of my created test tables were now &#8216;Engine=Xeround&#8217; was that I was unable to create a varchar_1024 indexed column.  Xeround is limited to 255 characters max:<br />
<code><br />
# 2011-04-27T19:50:27 key (`col_char_1024_key` ))  failed: 1074 Column length too big for column 'col_char_1024' (max = 255); use BLOB or TEXT instead<br />
</code></p>
<p>This limitation required modification of the randgen grammars and gendata files to limit char columns to 255.  As noted above, you can find the modified version of the randgen <a href="https://code.launchpad.net/~patrick-crews/randgen/randgen_drizzle_exp">here</a>.</p>
<p>2)  Tables with an ENGINE=$engine_name argument are processed without an issue (ie you should be able to use a dumpfile without problems) and are converted to Xeround tables.  One thing to note is that dumpfiles *from* Xeround have ENGINE=Xeround for the CREATE TABLE statements</p>
<p><code><br />
create table t1 (a int not null auto_increment, primary key(a)) engine=innodb;<br />
Query OK, 0 rows affected, 2 warnings (0.702761 sec)<br />
drizzle&gt; show create table t1;<br />
+-------+---------------------------------------------------------------------------------------------------------------------------------------+<br />
| Table | Create Table                                                                                                                          |<br />
+-------+---------------------------------------------------------------------------------------------------------------------------------------+<br />
| t1    | CREATE TABLE `t1` (<br />
`a` int(11) NOT NULL AUTO_INCREMENT,<br />
PRIMARY KEY (`a`)<br />
) ENGINE=Xeround DEFAULT CHARSET=utf8 COLLATE=utf8_bin |<br />
+-------+---------------------------------------------------------------------------------------------------------------------------------------+<br />
</code></p>
<p>2)  outer_join grammar:<br />
I used the following command line:<br />
<code><br />
./gentest.pl --gendata=conf/drizzle/outer_join_drizzle.zz --grammar=conf/drizzle/outer_join_drizzle.yy --queries=100 --threads=1 --dsn=dbi:mysql:host=00.00.00.00:port=9999:user=USER:password=PASSWORD:database=test --sqltrace --debug<br />
</code></p>
<p>The test ran without much incident.  The Xeround server monitor indicated that the CPU was hovering near 80% for most of the time, but again&#8230;beta test setup, so I&#8217;ll give them some leeway.</p>
<p>The big trouble is what follows.  Remember those randgen summary reports I mentioned earlier?  Below is a comparison of Xeround vs. MySQL for the same command line.  The values are row_count&#8217; =&gt; number_of_queries_returning_said_row_count.  What this means is that for the same set of queries, Xeround and MySQL do not always return the same result sets.  I did not note any differences in query failures, so this simply indicates that results processing is differing somewhere : (  To elaborate, Xeround had 56 queries that returned 0 rows, for the same workload, MySQL only had 39.  A row count of -1 indicates that there was an error with the query, such as referencing a table or column that doesn&#8217;t exist.  Somehow, Xeround hit fewer errors than MySQL, though that is also worrisome &#8211; why do they register errors differently?<br />
Xeround:<br />
<code><br />
# 2011-04-27T20:11:05 Rows returned:<br />
$VAR1 = {<br />
'    0' =&gt; 56,<br />
'    1' =&gt; 16,<br />
'    2' =&gt; 6,<br />
'    3' =&gt; 2,<br />
'    5' =&gt; 1,<br />
'    6' =&gt; 1,<br />
'    7' =&gt; 1,<br />
'    8' =&gt; 1,<br />
'   -1' =&gt; 13,<br />
'   10' =&gt; 2,<br />
'&gt;10' =&gt; 1<br />
};<br />
</code></p>
<p>MySQL 5.1<br />
<code><br />
$VAR1 = {<br />
'    0' =&gt; 39,<br />
'    1' =&gt; 15,<br />
'    2' =&gt; 2,<br />
'    3' =&gt; 2,<br />
'    4' =&gt; 1,<br />
'    7' =&gt; 2,<br />
'    8' =&gt; 1,<br />
'   -1' =&gt; 32,<br />
'   10' =&gt; 1,<br />
'&gt;10' =&gt; 5<br />
};<br />
</code></p>
<p>3)  transactional grammar:<br />
I used the following command line:<br />
<code><br />
./gentest.pl --gendata=conf/drizzle/translog_drizzle.zz --grammar=conf/drizzle/translog_concurrent1.yy --queries=100 --threads=1 --dsn=dbi:mysql:host=00.00.00.00:port=9999:user=USER:password=PASSWORD:database=test --sqltrace --debug<br />
</code></p>
<p>Unfortunately, I noticed a large number of differences.  We&#8217;ll start with the easiest one:<br />
<code><br />
&lt; DROP TABLE IF EXISTS `A`;<br />
&lt; CREATE TABLE `A` (<br />
---<br />
&gt; DROP TABLE IF EXISTS `a`;<br />
&gt; CREATE TABLE `a` (<br />
50c50<br />
&lt; ) ENGINE='InnoDB' AUTO_INCREMENT=105 COLLATE='utf8_general_ci';<br />
---<br />
&gt; ) ENGINE='Xeround' COLLATE='utf8_bin';<br />
</code></p>
<p>It isn&#8217;t huge, but Xeround apparently auto-converts tables names to lower-case.  The randgen attempts to create table `A`, but it is stored as table `a`.  This could be an issue for some people, but Xeround does say that the beta is for people to evaluate the system&#8217;s suitability for their purposes.</p>
<p>The big issue is that Xeround appears to not have registered a lot of the transactions issued by the randgen.  The Xeround dumpfile only contained the original 10 rows from table `a`, while the MySQL 5.1 version I ran locally had 94 rows by the end of the randgen run : (</p>
<p>Further research of the randgen logs indicate the following issue:<br />
<code><br />
# 2011-04-27T20:06:56 Query:  INSERT INTO `d` ( `col_char_10` , `col_char_10_key` , `col_char_10_not_null` , `col_char_10_not_null_key` , `col_char_255` , `col_char_255_key` , `col_char_255_not_null` , `col_char_255_not_null_key` , `col_int` , `col_int_key` , `col_int_not_null` , `col_int_not_null_key` , `col_bigint` , `col_bigint_key` , `col_bigint_not_null` , `col_bigint_not_null_key` , `col_enum` , `col_enum_key` , `col_enum_not_null` , `col_enum_not_null_key` , `col_text` , `col_text_key` , `col_text_not_null` , `col_text_not_null_key` ) SELECT `col_char_10` , `col_char_10_key` , `col_char_10_not_null` , `col_char_10_not_null_key` , `col_char_255` , `col_char_255_key` , `col_char_255_not_null` , `col_char_255_not_null_key` , `col_int` , `col_int_key` , `col_int_not_null` , `col_int_not_null_key` , `col_bigint` , `col_bigint_key` , `col_bigint_not_null` , `col_bigint_not_null_key` , `col_enum` , `col_enum_key` , `col_enum_not_null` , `col_enum_not_null_key` , `col_text` , `col_text_key` , `col_text_not_null` , `col_text_not_null_key` FROM `bb`  ORDER BY `col_bigint`,`col_bigint_key`,`col_bigint_not_null`,`col_bigint_not_null_key`,`col_char_10`,`col_char_10_key`,`col_char_10_not_null`,`col_char_10_not_null_key`,`col_char_255`,`col_char_255_key`,`col_char_255_not_null`,`col_char_255_not_null_key`,`col_enum`,`col_enum_key`,`col_enum_not_null`,`col_enum_not_null_key`,`col_int`,`col_int_key`,`col_int_not_null`,`col_int_not_null_key`,`col_text`,`col_text_key`,`col_text_not_null`,`col_text_not_null_key`,`pk` LIMIT 50 /*Generated by THREAD_ID 1*/  failed: 1038 Out of sort memory; increase server sort buffer size<br />
</code></p>
<p>So, it would appear that transactions are failing for some reason or another.  However, I repeat the disclaimer about this being a beta and not a production deployment.  It could have something to do with the resources allocated for each beta user.</p>
<p>3)  Subquery grammar<br />
This was the initial test I ran, but I have saved it for last.  First of all, the command line:<br />
<code><br />
./gentest.pl --gendata=conf/drizzle/drizzle.zz --grammar=conf/drizzle/optimizer_subquery_drizzle.yy --queries=100 --threads=1 --dsn=dbi:mysql:host=00.00.00.00:port=9999:user=USER:password=PASSWORD:database=test --sqltrace --debug<br />
</code></p>
<p>The first thing I noticed on the single-threaded run was that Xeround seemed to not like this query very much at all:<br />
<code><br />
SELECT    table2 . `col_int` AS field1 FROM ( CC AS table1 STRAIGHT_JOIN ( ( CC AS table2 STRAIGHT_JOIN CC AS table3 ON (table3 . `col_bigint_key` = table2 . `col_int_not_null_key`  ) ) ) ON (table3 . `col_text_not_null_key` = table2 . `col_char_10_key`  ) ) WHERE (  table1 . `col_int` NOT IN ( SELECT   SUBQUERY1_t1 . `col_int_not_null_key` AS SUBQUERY1_field1 FROM ( BB AS SUBQUERY1_t1 INNER JOIN ( CC AS SUBQUERY1_t2 INNER JOIN BB AS SUBQUERY1_t3 ON (SUBQUERY1_t3 . `col_char_10_key` = SUBQUERY1_t2 . `col_char_10_key`  ) ) ON (SUBQUERY1_t3 . `col_char_10_not_null_key` = SUBQUERY1_t2 . `col_char_10`  ) ) WHERE SUBQUERY1_t2 . `col_bigint` != table1 . `pk` OR SUBQUERY1_t2 . `pk` &gt;= table2 . `pk` ) ) OR ( table1 . `col_int_key`  BETWEEN 48 AND ( 48 + 183 ) OR table1 . `pk`  BETWEEN 48 AND ( 48 + 104 ) )  GROUP BY field1  ;<br />
</code></p>
<p>Now it is quite nasty, but standard MySQL executes it with a minimum of fuss (though it does take a moment to handle this monster as well).</p>
<p>The other thing is that Xeround took an exceedingly long time to execute this workload.  While the other grammars executed in moderate amounts of time (my testing was from a hotel room in Santa Clara while the instance is in Chicago), the subquery test was noticeably slow.  I was able to walk down to the lobby, buy something, and return to my room while it was dealing with the nasty query above : (  For some context, running the same command line on my laptop took 8 seconds, Xeround took 14 minutes, but again&#8230;beta test setup and hardware, so YMMV.</p>
<p>Finally, we have the dreaded row count report:<br />
Xeround:<br />
<code><br />
# 2011-04-27T20:45:19 Rows returned:<br />
$VAR1 = {<br />
'    0' =&gt; 59,<br />
'    1' =&gt; 2,<br />
'    4' =&gt; 1,<br />
'   -1' =&gt; 35,<br />
'&gt;10' =&gt; 1,<br />
'&gt;100' =&gt; 1<br />
};<br />
</code></p>
<p>MySQL 5.1:<br />
<code><br />
# 2011-04-27T20:40:18 Rows returned:<br />
$VAR1 = {<br />
'    0' =&gt; 59,<br />
'    1' =&gt; 2,<br />
'    4' =&gt; 1,<br />
'    9' =&gt; 1,<br />
'   -1' =&gt; 35,<br />
'&gt;100' =&gt; 1<br />
};<br />
</code></p>
<p>As we can see, there is 1 query out of the 100 issued where result sets differed (returning 9 rows in MySQL vs. &gt;10 rows in Xeround).</p>
<p>I also tried using &#8211;threads=10 to really stress the Xeround system (I didn&#8217;t bother with MySQL, it handles 10 threads of nasty subqueries like a champ&#8230;incidentally, so does Drizzle) ; )  Xeround was able to handle the workload and did so in 27 minutes.  Since single-threaded took 14 minutes, perhaps Xeround doesn&#8217;t really begin to shine until we start hitting large numbers of concurrent connections?</p>
<p>So what can I say from the results of these informal tests?  Personally, I would hesitate to say that Xeround is a drop-in replacement.  The limitations on column sizes, changes in table naming, and differing result sets are a bit worrisome.  However, I will say that the Xeround engineers I met at the UC were <span><strong>very</strong></span> engaged and interested in my findings and have made significant strides in subquery processing since my initial tests.  I believe that with time these issues will be fixed and that not every customer will run into them (I know I&#8217;m beating this into the ground, but I was using a beta test system).  Behavior may be different on a production machine and not every MySQL user will generate such workloads and every customer should perform their own careful testing and evaluation before making any changes to their systems.</p>
<p>My personal interest ends here.  The UC introduced me to a number of interesting new storage engines and I was mainly curious about ways of evaluating them.  This was a quick and dirty bit of testing just to see if I could produce any interesting pyrotechnics ; )  Go go randgen!</p>
<div><a href="http://www.wc220.com/wp-content/uploads/2011/04/randgen1.png"><img class="size-medium wp-image-219" title="randgen" src="http://www.wc220.com/wp-content/uploads/2011/04/randgen1-300x238.png" alt="" width="300" height="238" /></a><p>I really want this picture to be shown when anyone searches for &#39;randgen&#39; ; )</p></div>
<p>In all seriousness, I highly recommend adoption of the random query generator.  It offers a modular and customizable system for creating evaluation tools (like result set comparison, execution time comparison, replication validation, etc, etc) and has been used in production-level testing for <a href="http://mysql.com/">MySQL</a>, <a href="http://mariadb.org/">MariaDB</a> and <a href="http://drizzle.org/">Drizzle</a> for some time.  It also plays with <a href="http://www.postgresql.org/">Postgresql</a> and <a href="http://www.oracle.com/technetwork/java/javadb/overview/index.html">Java DB</a> (kind of scary that 40% of that list is owned by Oracle&#8230;), so please give it a spin and see what kinds of pretty explosions you can make&#8230;who knows, testing might actually become fun for non-QA folks &gt;; )</p>
<p>Additionally, these tests only took me about half an hour to setup and execute.  Granted, I have been using the tool for some time, but 30 minutes to identify a number of potential problem areas seems pretty awesome to me, but then again, I am a QA Engineer and we live for such things.</p><br/>PlanetMySQL Voting:
	 <a href="http://planet.mysql.com/entry/vote/?entry_id=28242&vote=1&apivote=1">Vote UP</a> /
	 <a href="http://planet.mysql.com/entry/vote/?entry_id=28242&vote=-1&apivote=1">Vote DOWN</a>]]></content:encoded>
			<wfw:commentRss>http://planetmysql.ru/2011/04/28/testing-xeround%e2%80%99s-database-as-a-service/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Quick benchmarking trick</title>
		<link>http://datacharmer.blogspot.com/2011/03/quick-benchmarking-trick.html?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=quick-benchmarking-trick</link>
		<comments>http://datacharmer.blogspot.com/2011/03/quick-benchmarking-trick.html#comments</comments>
		<pubDate>Tue, 15 Mar 2011 00:27:24 +0000</pubDate>
		<dc:creator>Giuseppe Maxia</dc:creator>
				<category><![CDATA[benchmark]]></category>
		<category><![CDATA[command line]]></category>
		<category><![CDATA[mysql]]></category>
		<category><![CDATA[Q/A]]></category>
		<category><![CDATA[testing]]></category>
		<category><![CDATA[tricks]]></category>

		<guid isPermaLink="false"></guid>
		<description><![CDATA[I have been doing quite a lot of benchmarking recently.I needed to find a safe way of measuring the time spend by the database doing a long task, like catching up on a huge backlog of accumulated replication updates. The problem with measuring this event is that I can record when it starts, but I can't easily detect when it finishes. My initial approach was to monitor the database and count the tables rows to see when the task was done, but I ended up affecting the task performance with my additional queries. So I thought of another method.Since I had control on what was sent from the master to the slave, I used the following:The initial time is calculated as the minimum creation time of the databases that I know are created during the exercise. Let's say that I had 5 databases named from db1 to db5: set @START = (select min(create_time) from information_schema.tables where table_schema like "db%")Then, to make sure that I catch the exact moment that the task is finished, I added to the master a command for each database: create table last_table db1.(i int);create table last_table db2.(i int);create table last_table db3.(i int);create table last_table db4.(i int);create table last_table db5.(i int);To know if the task is done, I query the database as follows:select count(*) from information_schema.tables where table_schema like "db%" and table_name="last_table";If the count is less than 5 (the number of databases that were in my binary logs), I wait more.Finally, when the count matches the expected one, I get the end time:set @END = (select max(create_time) from information_schema.tables where table_schema like "db%" and table_name="last_table"');Now I have two values, @START, and @ENDselect timediff(@END,@START) as elapsed;+----------+&#124; elapsed  &#124;+----------+&#124; 00:09:44 &#124;+----------+It does not matter if I query the database immediately, or hour after coming back from my errands. Using the table creation times makes sure that I get a clean start and finish time.I put all the above in a script, and I can check the elapsed time without fear of mistakes.]]></description>
			<content:encoded><![CDATA[I have been doing quite a lot of benchmarking recently.<br />I needed to find a safe way of measuring the time spend by the database doing a long task, like catching up on a huge backlog of accumulated replication updates. The problem with measuring this event is that I can record when it starts, but I can't easily detect when it finishes. My initial approach was to monitor the database and count the tables rows to see when the task was done, but I ended up affecting the task performance with my additional queries. So I thought of another method.<br />Since I had control on what was sent from the master to the slave, I used the following:<br />The initial time is calculated as the minimum creation time of the databases that I know are created during the exercise. Let's say that I had 5 databases named from db1 to db5: <br /><pre>set @START = (select min(create_time) from information_schema.tables where table_schema like "db%")<br /></pre>Then, to make sure that I catch the exact moment that the task is finished, I added to the master a command for each database: <br /><pre>create table last_table db1.(i int);<br />create table last_table db2.(i int);<br />create table last_table db3.(i int);<br />create table last_table db4.(i int);<br />create table last_table db5.(i int);<br /></pre>To know if the task is done, I query the database as follows:<br /><pre>select count(*) from information_schema.tables where table_schema like "db%" and table_name="last_table";<br /></pre>If the count is less than 5 (the number of databases that were in my binary logs), I wait more.<br />Finally, when the count matches the expected one, I get the end time:<br /><br /><pre>set @END = (select max(create_time) from information_schema.tables where table_schema like "db%" and table_name="last_table"');<br /></pre>Now I have two values, @START, and @END<br /><pre>select timediff(@END,@START) as elapsed;<br />+----------+<br />| elapsed  |<br />+----------+<br />| 00:09:44 |<br />+----------+<br /></pre>It does not matter if I query the database immediately, or hour after coming back from my errands. Using the table creation times makes sure that I get a clean start and finish time.<br />I put all the above in a script, and I can check the elapsed time without fear of mistakes.<div><img width="1" height="1" src="https://blogger.googleusercontent.com/tracker/16959946-7877561910049733417?l=datacharmer.blogspot.com" alt="" /></div><br/>PlanetMySQL Voting:
	 <a href="http://planet.mysql.com/entry/vote/?entry_id=27598&vote=1&apivote=1">Vote UP</a> /
	 <a href="http://planet.mysql.com/entry/vote/?entry_id=27598&vote=-1&apivote=1">Vote DOWN</a>]]></content:encoded>
			<wfw:commentRss>http://planetmysql.ru/2011/03/15/quick-benchmarking-trick/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Quick benchmarking trick</title>
		<link>http://datacharmer.blogspot.com/2011/03/quick-benchmarking-trick.html?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=quick-benchmarking-trick</link>
		<comments>http://datacharmer.blogspot.com/2011/03/quick-benchmarking-trick.html#comments</comments>
		<pubDate>Tue, 15 Mar 2011 00:27:24 +0000</pubDate>
		<dc:creator>Giuseppe Maxia</dc:creator>
				<category><![CDATA[benchmark]]></category>
		<category><![CDATA[command line]]></category>
		<category><![CDATA[mysql]]></category>
		<category><![CDATA[Q/A]]></category>
		<category><![CDATA[testing]]></category>
		<category><![CDATA[tricks]]></category>

		<guid isPermaLink="false"></guid>
		<description><![CDATA[I have been doing quite a lot of benchmarking recently.I needed to find a safe way of measuring the time spend by the database doing a long task, like catching up on a huge backlog of accumulated replication updates. The problem with measuring this event is that I can record when it starts, but I can't easily detect when it finishes. My initial approach was to monitor the database and count the tables rows to see when the task was done, but I ended up affecting the task performance with my additional queries. So I thought of another method.Since I had control on what was sent from the master to the slave, I used the following:The initial time is calculated as the minimum creation time of the databases that I know are created during the exercise. Let's say that I had 5 databases named from db1 to db5: set @START = (select min(create_time) from information_schema.tables where table_schema like "db%")Then, to make sure that I catch the exact moment that the task is finished, I added to the master a command for each database: create table last_table db1.(i int);create table last_table db2.(i int);create table last_table db3.(i int);create table last_table db4.(i int);create table last_table db5.(i int);To know if the task is done, I query the database as follows:select count(*) from information_schema.tables where table_schema like "db%" and table_name="last_table";If the count is less than 5 (the number of databases that were in my binary logs), I wait more.Finally, when the count matches the expected one, I get the end time:set @END = (select max(create_time) from information_schema.tables where table_schema like "db%" and table_name="last_table"');Now I have two values, @START, and @ENDselect timediff(@END,@START) as elapsed;+----------+&#124; elapsed  &#124;+----------+&#124; 00:09:44 &#124;+----------+It does not matter if I query the database immediately, or hour after coming back from my errands. Using the table creation times makes sure that I get a clean start and finish time.I put all the above in a script, and I can check the elapsed time without fear of mistakes.]]></description>
			<content:encoded><![CDATA[I have been doing quite a lot of benchmarking recently.<br />I needed to find a safe way of measuring the time spend by the database doing a long task, like catching up on a huge backlog of accumulated replication updates. The problem with measuring this event is that I can record when it starts, but I can't easily detect when it finishes. My initial approach was to monitor the database and count the tables rows to see when the task was done, but I ended up affecting the task performance with my additional queries. So I thought of another method.<br />Since I had control on what was sent from the master to the slave, I used the following:<br />The initial time is calculated as the minimum creation time of the databases that I know are created during the exercise. Let's say that I had 5 databases named from db1 to db5: <br /><pre>set @START = (select min(create_time) from information_schema.tables where table_schema like "db%")<br /></pre>Then, to make sure that I catch the exact moment that the task is finished, I added to the master a command for each database: <br /><pre>create table last_table db1.(i int);<br />create table last_table db2.(i int);<br />create table last_table db3.(i int);<br />create table last_table db4.(i int);<br />create table last_table db5.(i int);<br /></pre>To know if the task is done, I query the database as follows:<br /><pre>select count(*) from information_schema.tables where table_schema like "db%" and table_name="last_table";<br /></pre>If the count is less than 5 (the number of databases that were in my binary logs), I wait more.<br />Finally, when the count matches the expected one, I get the end time:<br /><br /><pre>set @END = (select max(create_time) from information_schema.tables where table_schema like "db%" and table_name="last_table"');<br /></pre>Now I have two values, @START, and @END<br /><pre>select timediff(@END,@START) as elapsed;<br />+----------+<br />| elapsed  |<br />+----------+<br />| 00:09:44 |<br />+----------+<br /></pre>It does not matter if I query the database immediately, or hour after coming back from my errands. Using the table creation times makes sure that I get a clean start and finish time.<br />I put all the above in a script, and I can check the elapsed time without fear of mistakes.<div><img width="1" height="1" src="https://blogger.googleusercontent.com/tracker/16959946-7877561910049733417?l=datacharmer.blogspot.com" alt="" /></div><br/>PlanetMySQL Voting:
	 <a href="http://planet.mysql.com/entry/vote/?entry_id=27598&vote=1&apivote=1">Vote UP</a> /
	 <a href="http://planet.mysql.com/entry/vote/?entry_id=27598&vote=-1&apivote=1">Vote DOWN</a>]]></content:encoded>
			<wfw:commentRss>http://planetmysql.ru/2011/03/15/quick-benchmarking-trick/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>How MySQL Workbench breaks itself</title>
		<link>http://datacharmer.blogspot.com/2010/11/how-mysql-workbench-breaks-itself.html?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=how-mysql-workbench-breaks-itself</link>
		<comments>http://datacharmer.blogspot.com/2010/11/how-mysql-workbench-breaks-itself.html#comments</comments>
		<pubDate>Sun, 21 Nov 2010 16:32:00 +0000</pubDate>
		<dc:creator>Giuseppe Maxia</dc:creator>
				<category><![CDATA[bugs]]></category>
		<category><![CDATA[mysql]]></category>
		<category><![CDATA[testing]]></category>
		<category><![CDATA[workbench]]></category>

		<guid isPermaLink="false"></guid>
		<description><![CDATA[Once upon a time, there was a policy in MySQL not to add new features after the beta stage.To my surprise, MySQL Workbench 5.2.30 introduces a new feature, the query formatter. I gave it a try. The results are not extremely encouraging. Granted, it's a plugin and not a feature in the core application, but nonetheless one would expect something more stable in a GA release, especially since the plugin features are displayed in the main menu, and unless you have read the announcement, you couldn't easily tell the core from the plugins.This is what I have got in just a few minutes: Bug #58356: beautify function fails on CREATE TABLE  Bug #58357: beutify function erases statement on CREATE INDEX   Bug #58358: query formatter fails on selected query   Bug #58359: query formatter indentation fails on partially selected query  Bug #58360 query formatter converts non-keywords to uppercase Bug #58361 Query formatter mangles query when CASE operator is usedMySQL Workbench is a great product. I would like it to be more solid. New features, even as a plugin, should be more carefully released that this one.]]></description>
			<content:encoded><![CDATA[Once upon a time, there was a policy in MySQL not to add new features after the beta stage.<br />To my surprise, <a href="http://wb.mysql.com/?p=833">MySQL Workbench 5.2.30</a> introduces a new feature, the query formatter. I gave it a try. The results are not extremely encouraging. Granted, it's a plugin and not a feature in the core application, but nonetheless one would expect something more stable in a GA release, especially since the plugin features are displayed in the main menu, and unless you have read the <a href="http://wb.mysql.com/?p=833">announcement</a>, you couldn't easily tell the core from the plugins.<br />This is what I have got in just a few minutes:<br /><br /><a href="http://bugs.mysql.com/58356"> Bug #58356: beautify function fails on CREATE TABLE </a><br /><a href="http://bugs.mysql.com/58357"> Bug #58357: beutify function erases statement on CREATE INDEX </a> <br /><a href="http://bugs.mysql.com/58358"> Bug #58358: query formatter fails on selected query  </a><br /><a href="http://bugs.mysql.com/58359"> Bug #58359: query formatter indentation fails on partially selected query </a><br /><a href="http://bugs.mysql.com/58360"> Bug #58360 query formatter converts non-keywords to uppercase </a><br /><a href="http://bugs.mysql.com/58360">Bug #58361 Query formatter mangles query when CASE operator is used</a><br /><br />MySQL Workbench is a great product. I would like it to be more solid. New features, even as a plugin, should be more carefully released that this one.<div><img width="1" height="1" src="https://blogger.googleusercontent.com/tracker/16959946-977563335068143061?l=datacharmer.blogspot.com" alt="" /></div><br/>PlanetMySQL Voting:
	 <a href="http://planet.mysql.com/entry/vote/?entry_id=26520&vote=1&apivote=1">Vote UP</a> /
	 <a href="http://planet.mysql.com/entry/vote/?entry_id=26520&vote=-1&apivote=1">Vote DOWN</a>]]></content:encoded>
			<wfw:commentRss>http://planetmysql.ru/2010/11/21/how-mysql-workbench-breaks-itself/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Testing MySQL 5.5 semi-synchronous replication</title>
		<link>http://datacharmer.blogspot.com/2010/11/testing-mysql-55-semi-synchronous.html?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=testing-mysql-5-5-semi-synchronous-replication</link>
		<comments>http://datacharmer.blogspot.com/2010/11/testing-mysql-55-semi-synchronous.html#comments</comments>
		<pubDate>Thu, 04 Nov 2010 00:19:00 +0000</pubDate>
		<dc:creator>Giuseppe Maxia</dc:creator>
				<category><![CDATA[mysql]]></category>
		<category><![CDATA[Replication]]></category>
		<category><![CDATA[sandbox]]></category>
		<category><![CDATA[semisynch]]></category>
		<category><![CDATA[testing]]></category>

		<guid isPermaLink="false"></guid>
		<description><![CDATA[A few days ago I saw an article about Semi-Synchronous Replication in MySQL 5.5. It asks questions, and doesn't give answers beyond gut feeling. So I thought that I would do some practical testing of this new feature.Before we go that way, though, let's revisit the theory.How semi-synchronous replication worksFigure 1. A transaction with regular replicationWith regular replication, you send a transaction to the master (1). When the COMMIT is received, the master executes it (2), and if successful it logs the transaction to the binary log (3). The the master answers the client request (4) with a successful result. In the meantime, the slaves replicate the record (5).What happens if the master crashes after point #4 and before a slave has had a chance of getting the data in point #5?The client will have a result for that transaction, but that data is lost, because it has never reached one slave. Figure 2. A transaction with semi-synchronous replicationLet's see the same scenario with semi-synchronous replication. All is the same until point #3. Then, things change. The master does not return to the client. Instead, it alerts the slave that a transaction is available (4). The slave gets it and stores it to the relay log (5). Without further action, the slave tells the master that the transaction was received (6) and only then the master returns the result to the client (7).What is the benefit? If the master crashes, the transaction is lost. but the client does not get the false information that the transaction was stored. Instead, if the master crashes before it returns the result to the client, the client gets an error, and knows that that transaction needs to be reworked when a new master is back.Semi-synchronous replication in practiceNow, the practicalities.How do you tell if semi-synchronous replication is working? If you leave the default timeout of 10 seconds, you have an immediate clue that something is wrong when a query takes too long to return. Investigation is possible by looking at the GLOBAL STATUS variables.Rpl_semi_sync_master_status tells you if the master is ready for semi-synchronous replication.Rpl_semi_sync_master_yes_tx is the number of positive transactions that were delivered using semi-synchronous replication.Rpl_semi_sync_master_no_tx is the number of failed attempts at delivering a transaction via semi-synchronous replication. When that happens, Rpl_semi_sync_master_status becomes "OFF", and you need investigating.The important thing to understand about this feature is that semi-synchronous replication does not guarantee that your transaction is executed in the slave. It will only tell you that the data has been transferred to the slave relay log. It can still happen that the transaction fails to execute on the slave (which could be either a bug in your application or a bug in MySQL replication). But this is not a cluster. Don't expect a two-phase commit.Testing semi-synchronous replicationIf you want to test this feature without suffering too much, you can use a tarball binary and MySQL Sandbox. Once you have installed MySQL Sandbox and have downloaded the server tarball, you can install a test replication system withmake_replication_sandbox --how_many_slaves=4 /path/to/mysql-5.5.6-yourOS.tar.gzThis will create a system with 1 master and 4 slaves.The Sandbox has a shortcut to install the plugin quickly and painlessly:sbtool -o plugin --plugin=semisynch -s $HOME/sandboxes/rsandbox_5_5_6Now you will have the semi-synchronous plugin installed in the master and all the slaves. For our tests, we will make a shell script, an easy task thanks to the sandbox utilities.#!/bin/shecho "disabling semi-synch replication in all slaves except 1"./s1 -e 'set global rpl_semi_sync_slave_enabled=1'./s1 -e 'slave stop io_thread; slave start'for E in 2 3 4do    ./s$E -e 'set global rpl_semi_sync_slave_enabled=0'    ./s$E -e 'slave stop io_thread; slave start'done## this query will show the main variables that tell# if semi-synch replication is working#Q1='select variable_name, variable_value'Q2='from information_schema.global_status'Q3='where variable_name in'Q4='("RPL_SEMI_SYNC_MASTER_YES_TX", "RPL_SEMI_SYNC_MASTER_NO_TX")'I_S_Q="$Q1 $Q2 $Q3 $Q4"echo ""echo "creating a table. it should replicate through the semi-synch"./m -vvv -e 'create table test.t1( i int)'./m -e "$I_S_Q"echo ""echo "inserting a record. The number of 'YES' should increase"./m -e 'insert into test.t1 values (1)'./m -e "$I_S_Q"echo ""echo "disabling semi-synch replication in slave 1"./s1 -e 'set global rpl_semi_sync_slave_enabled=0'./s1 -e 'slave stop io_thread; slave start'echo ""echo "enabling semi-synch replication in slave 3"./s3 -e 'set global rpl_semi_sync_slave_enabled=1'./s3 -e 'slave stop io_thread; slave start'echo ""echo "inserting a record. The number of 'YES' should increase"./m -e 'insert into test.t1 values (2)'./m -e "$I_S_Q"echo ""echo "disabling semi-synch replication in slave 3"./s3 -e 'set global rpl_semi_sync_slave_enabled=0'./s3 -e 'slave stop io_thread; slave start'echo ""echo "inserting a record. The number of 'NO' should increase"./m -vvv -e 'insert into test.t1 values (3)'./m -e "$I_S_Q"echo ""echo "enabling semi-synch replication in slave 2"./s2 -e 'set global rpl_semi_sync_slave_enabled=1'./s2 -e 'slave stop io_thread; slave start'echo ""echo "inserting a record. The number of 'YES' should increase"./m -e 'insert into test.t1 values (4)'./m -e "$I_S_Q"This script will first disable semi-synchronous replication in all the slaves except one. Then it will create a table, and check for the telling status variables.This should work quickly and without problems. Then it will disable the plugin on the only slave that was active, and enable another slave instead. Inserting a record on the master will work again quickly, as the newly enabled slave will get the record immediately.Then the slave gets disabled, and we can witness what happens. The query takes a bit longer than 10 seconds, and the status variable tells us that semi-synchronous replication has failed.We finally enable yet another slave, and when we try a further insertion, we can see that the semi-synchronous replication has resumed.Very important:To enable or disable semi-synchronous replication on a slave it is not enough to set the appropriate variable. You need also to restart the slave by issuing a STOP SLAVE IO_THREAD followed by a START SLAVE commands.Here is a sample run:disabling semi-synch replication in all slaves except 1creating a table. it should replicate through the semi-synch--------------create table test.t1( i int)--------------Query OK, 0 rows affected (0.87 sec)Bye+-----------------------------+----------------+&#124; variable_name               &#124; variable_value &#124;+-----------------------------+----------------+&#124; RPL_SEMI_SYNC_MASTER_NO_TX  &#124; 0              &#124;&#124; RPL_SEMI_SYNC_MASTER_YES_TX &#124; 1              &#124;+-----------------------------+----------------+inserting a record. The number of 'YES' should increase+-----------------------------+----------------+&#124; variable_name               &#124; variable_value &#124;+-----------------------------+----------------+&#124; RPL_SEMI_SYNC_MASTER_NO_TX  &#124; 0              &#124;&#124; RPL_SEMI_SYNC_MASTER_YES_TX &#124; 2              &#124;+-----------------------------+----------------+disabling semi-synch replication in slave 1enabling semi-synch replication in slave 3inserting a record. The number of 'YES' should increase+-----------------------------+----------------+&#124; variable_name               &#124; variable_value &#124;+-----------------------------+----------------+&#124; RPL_SEMI_SYNC_MASTER_NO_TX  &#124; 0              &#124;&#124; RPL_SEMI_SYNC_MASTER_YES_TX &#124; 3              &#124;+-----------------------------+----------------+disabling semi-synch replication in slave 3inserting a record. The number of 'NO' should increase--------------insert into test.t1 values (3)--------------Query OK, 1 row affected (10.12 sec)Bye+-----------------------------+----------------+&#124; variable_name               &#124; variable_value &#124;+-----------------------------+----------------+&#124; RPL_SEMI_SYNC_MASTER_NO_TX  &#124; 1              &#124;&#124; RPL_SEMI_SYNC_MASTER_YES_TX &#124; 3              &#124;+-----------------------------+----------------+enabling semi-synch replication in slave 2inserting a record. The number of 'YES' should increase+-----------------------------+----------------+&#124; variable_name               &#124; variable_value &#124;+-----------------------------+----------------+&#124; RPL_SEMI_SYNC_MASTER_NO_TX  &#124; 1              &#124;&#124; RPL_SEMI_SYNC_MASTER_YES_TX &#124; 4              &#124;+-----------------------------+----------------+Using the above steps, you should be able to use semi-synchronous replication and do some basic monitoring to make sure that it works as expected.]]></description>
			<content:encoded><![CDATA[A few days ago I saw an article about <a href="http://www.bluegecko.net/mysql/semi-synchronous-replication-in-mysql-5-5/">Semi-Synchronous Replication in MySQL 5.5</a>. It asks questions, and doesn't give answers beyond gut feeling. So I thought that I would do some practical testing of this new feature.<br />Before we go that way, though, let's revisit the theory.<br /><h3>How semi-synchronous replication works</h3><img border="0" src="http://lh6.ggpht.com/_gVfZHGgf5LA/TNHwuuWOkgI/AAAAAAAAA-k/kdhEL_WL1do/s640/scaling_with_replication.065.jpg" /><br /><i>Figure 1. A transaction with regular replication</i><br />With regular replication, you send a transaction to the master (1). When the <code>COMMIT</code> is received, the master executes it (2), and if successful it logs the transaction to the binary log (3). The the master answers the client request (4) with a successful result. In the meantime, the slaves replicate the record (5).<br />What happens if the master crashes after point #4 and before a slave has had a chance of getting the data in point #5?<br />The client will have a result for that transaction, but that data is lost, because it has never reached one slave. <br /><br /><img border="0" src="http://lh6.ggpht.com/_gVfZHGgf5LA/TNHwuuDum0I/AAAAAAAAA-o/kSWM5ux2f6c/s640/scaling_with_replication.066.jpg" /><br /><i>Figure 2. A transaction with semi-synchronous replication</i><br /><br />Let's see the same scenario with semi-synchronous replication. All is the same until point #3. Then, things change. The master does not return to the client. Instead, it alerts the slave that a transaction is available (4). The slave gets it and stores it to the relay log (5). Without further action, the slave tells the master that the transaction was received (6) and only then the master returns the result to the client (7).<br />What is the benefit? If the master crashes, the transaction is lost. but the client does not get the false information that the transaction was stored. Instead, if the master crashes before it returns the result to the client, the client gets an error, and knows that that transaction needs to be reworked when a new master is back.<br /><h3>Semi-synchronous replication in practice</h3>Now, the practicalities.<br />How do you tell if semi-synchronous replication is working? If you leave the default timeout of 10 seconds, you have an immediate clue that something is wrong when a query takes too long to return. Investigation is possible by looking at the GLOBAL STATUS variables.<br /><code>Rpl_semi_sync_master_status</code> tells you if the master is ready for semi-synchronous replication.<br /><code>Rpl_semi_sync_master_yes_tx</code> is the number of positive transactions that were delivered using semi-synchronous replication.<br /><code>Rpl_semi_sync_master_no_tx</code> is the number of failed attempts at delivering a transaction via semi-synchronous replication. When that happens, <code>Rpl_semi_sync_master_status</code> becomes "OFF", and you need investigating.<br /><br />The important thing to understand about this feature is that semi-synchronous replication does not guarantee that your transaction is executed in the slave. It will only tell you that the data has been transferred to the slave relay log. It can still happen that the transaction fails to execute on the slave (which could be either a bug in your application or a bug in MySQL replication). But this is not a cluster. Don't expect a two-phase commit.<br /><h3>Testing semi-synchronous replication</h3>If you want to test this feature without suffering too much, you can use a tarball binary and <a href="http://mysqlsandbox.net/">MySQL Sandbox</a>. Once you have installed MySQL Sandbox and have downloaded the server tarball, you can install a test replication system with<br /><pre><code>make_replication_sandbox --how_many_slaves=4 /path/to/mysql-5.5.6-yourOS.tar.gz</code></pre>This will create a system with 1 master and 4 slaves.<br />The Sandbox has a shortcut to install the plugin quickly and painlessly:<br /><pre><code>sbtool -o plugin --plugin=semisynch -s $HOME/sandboxes/rsandbox_5_5_6</code></pre>Now you will have the semi-synchronous plugin installed in the master and all the slaves. For our tests, we will make a shell script, an easy task thanks to the sandbox utilities.<br /><pre><code><br />#!/bin/sh<br /><br />echo "disabling semi-synch replication in all slaves except 1"<br />./s1 -e 'set global rpl_semi_sync_slave_enabled=1'<br />./s1 -e 'slave stop io_thread; slave start'<br /><br />for E in 2 3 4<br />do<br />    ./s$E -e 'set global rpl_semi_sync_slave_enabled=0'<br />    ./s$E -e 'slave stop io_thread; slave start'<br />done<br /><br />#<br /># this query will show the main variables that tell<br /># if semi-synch replication is working<br />#<br />Q1='select variable_name, variable_value'<br />Q2='from information_schema.global_status'<br />Q3='where variable_name in'<br />Q4='("RPL_SEMI_SYNC_MASTER_YES_TX", "RPL_SEMI_SYNC_MASTER_NO_TX")'<br />I_S_Q="$Q1 $Q2 $Q3 $Q4"<br /><br />echo ""<br />echo "creating a table. it should replicate through the semi-synch"<br />./m -vvv -e 'create table test.t1( i int)'<br />./m -e "$I_S_Q"<br /><br />echo ""<br />echo "inserting a record. The number of 'YES' should increase"<br />./m -e 'insert into test.t1 values (1)'<br />./m -e "$I_S_Q"<br /><br />echo ""<br />echo "disabling semi-synch replication in slave 1"<br />./s1 -e 'set global rpl_semi_sync_slave_enabled=0'<br />./s1 -e 'slave stop io_thread; slave start'<br /><br />echo ""<br />echo "enabling semi-synch replication in slave 3"<br />./s3 -e 'set global rpl_semi_sync_slave_enabled=1'<br />./s3 -e 'slave stop io_thread; slave start'<br /><br />echo ""<br />echo "inserting a record. The number of 'YES' should increase"<br />./m -e 'insert into test.t1 values (2)'<br />./m -e "$I_S_Q"<br /><br />echo ""<br />echo "disabling semi-synch replication in slave 3"<br />./s3 -e 'set global rpl_semi_sync_slave_enabled=0'<br />./s3 -e 'slave stop io_thread; slave start'<br /><br />echo ""<br />echo "inserting a record. The number of 'NO' should increase"<br />./m -vvv -e 'insert into test.t1 values (3)'<br />./m -e "$I_S_Q"<br /><br />echo ""<br />echo "enabling semi-synch replication in slave 2"<br />./s2 -e 'set global rpl_semi_sync_slave_enabled=1'<br />./s2 -e 'slave stop io_thread; slave start'<br /><br />echo ""<br />echo "inserting a record. The number of 'YES' should increase"<br />./m -e 'insert into test.t1 values (4)'<br />./m -e "$I_S_Q"<br /><code></code></code></pre>This script will first disable semi-synchronous replication in all the slaves except one. Then it will create a table, and check for the telling status variables.<br />This should work quickly and without problems. Then it will disable the plugin on the only slave that was active, and enable another slave instead. <br />Inserting a record on the master will work again quickly, as the newly enabled slave will get the record immediately.<br />Then the slave gets disabled, and we can witness what happens. The query takes a bit longer than 10 seconds, and the status variable tells us that semi-synchronous replication has failed.<br />We finally enable yet another slave, and when we try a further insertion, we can see that the semi-synchronous replication has resumed.<br /><br /><b>Very important:</b><br />To enable or disable semi-synchronous replication on a slave it is not enough to set the appropriate variable. You need also to restart the slave by issuing a <code>STOP SLAVE IO_THREAD</code> followed by a <code>START SLAVE</code> commands.<br /><br />Here is a sample run:<br /><pre>disabling semi-synch replication in all slaves except 1<br /><br />creating a table. it should replicate through the semi-synch<br />--------------<br />create table test.t1( i int)<br />--------------<br /><br />Query OK, 0 rows affected (0.87 sec)<br /><br />Bye<br />+-----------------------------+----------------+<br />| variable_name               | variable_value |<br />+-----------------------------+----------------+<br />| RPL_SEMI_SYNC_MASTER_NO_TX  | 0              |<br />| RPL_SEMI_SYNC_MASTER_YES_TX | 1              |<br />+-----------------------------+----------------+<br /><br />inserting a record. The number of 'YES' should increase<br />+-----------------------------+----------------+<br />| variable_name               | variable_value |<br />+-----------------------------+----------------+<br />| RPL_SEMI_SYNC_MASTER_NO_TX  | 0              |<br />| RPL_SEMI_SYNC_MASTER_YES_TX | 2              |<br />+-----------------------------+----------------+<br /><br />disabling semi-synch replication in slave 1<br /><br />enabling semi-synch replication in slave 3<br /><br />inserting a record. The number of 'YES' should increase<br />+-----------------------------+----------------+<br />| variable_name               | variable_value |<br />+-----------------------------+----------------+<br />| RPL_SEMI_SYNC_MASTER_NO_TX  | 0              |<br />| RPL_SEMI_SYNC_MASTER_YES_TX | 3              |<br />+-----------------------------+----------------+<br /><br />disabling semi-synch replication in slave 3<br /><br />inserting a record. The number of 'NO' should increase<br />--------------<br />insert into test.t1 values (3)<br />--------------<br /><br />Query OK, 1 row affected (10.12 sec)<br /><br />Bye<br />+-----------------------------+----------------+<br />| variable_name               | variable_value |<br />+-----------------------------+----------------+<br />| RPL_SEMI_SYNC_MASTER_NO_TX  | 1              |<br />| RPL_SEMI_SYNC_MASTER_YES_TX | 3              |<br />+-----------------------------+----------------+<br /><br />enabling semi-synch replication in slave 2<br /><br />inserting a record. The number of 'YES' should increase<br />+-----------------------------+----------------+<br />| variable_name               | variable_value |<br />+-----------------------------+----------------+<br />| RPL_SEMI_SYNC_MASTER_NO_TX  | 1              |<br />| RPL_SEMI_SYNC_MASTER_YES_TX | 4              |<br />+-----------------------------+----------------+<br /></pre>Using the above steps, you should be able to use semi-synchronous replication and do some basic monitoring to make sure that it works as expected.<div><img width="1" height="1" src="https://blogger.googleusercontent.com/tracker/16959946-7211354341709462617?l=datacharmer.blogspot.com" alt="" /></div><br/>PlanetMySQL Voting:
	 <a href="http://planet.mysql.com/entry/vote/?entry_id=26369&vote=1&apivote=1">Vote UP</a> /
	 <a href="http://planet.mysql.com/entry/vote/?entry_id=26369&vote=-1&apivote=1">Vote DOWN</a>]]></content:encoded>
			<wfw:commentRss>http://planetmysql.ru/2010/11/04/testing-mysql-5-5-semi-synchronous-replication/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Performance gain of MySQL 5.1 InnoDB plugin</title>
		<link>http://datacharmer.blogspot.com/2010/06/performance-gain-of-mysql-51-innodb.html?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=performance-gain-of-mysql-5-1-innodb-plugin</link>
		<comments>http://datacharmer.blogspot.com/2010/06/performance-gain-of-mysql-51-innodb.html#comments</comments>
		<pubDate>Sun, 06 Jun 2010 19:30:00 +0000</pubDate>
		<dc:creator>Giuseppe Maxia</dc:creator>
				<category><![CDATA[InnoDB]]></category>
		<category><![CDATA[mysql]]></category>
		<category><![CDATA[performance]]></category>
		<category><![CDATA[plugin]]></category>
		<category><![CDATA[testing]]></category>

		<guid isPermaLink="false"></guid>
		<description><![CDATA[You know already that InnoDB in MySQL 5.5 has great improvements in performance and scalability. You will have to wait a few months for that, though, because MySQL 5.5 is not GA yet. But if you need some extra performance in MySQL 5.1, you may want to use the Innodb Plugin instead of the built-in one. As of version 5.1.47, the Innodb plugin is of GA  quality, and it comes with a good out-of-the-box improvement compared to the built-in engine.To test my assumptions, I used one of my test Linux servers to perform a sysbench on 5.0.91, 5.1.47 built-in and plugin, and 5.5.4. The MySQL servers were all configured with innodb_buffer_pool_size=5GMySQL 4.1.47 was tested both as out-of-the-box, and with the plugin enabled.ignore_builtin_innodb# note: the following statements must go all in one lineplugin-load=innodb=ha_innodb_plugin.so;innodb_trx=ha_innodb_plugin.so;innodb_locks=ha_innodb_plugin.so;innodb_lock_waits=ha_innodb_plugin.so;innodb_cmp=ha_innodb_plugin.so;innodb_cmp_reset=ha_innodb_plugin.so;innodb_cmpmem=ha_innodb_plugin.so;innodb_cmpmem_reset=ha_innodb_plugin.sodefault-storage-engine=InnoDBinnodb_file_per_table=1innodb_file_format=barracudainnodb_strict_mode=1The test was the same for all the servers. A simple sysbench both read-only and read/write on a 1M records table.sysbench \    --test=oltp \    --oltp-table-size=1000000 \    --mysql-db=test \    --mysql-user=$PASSWD \    --mysql-password=$USER \    --mysql-host=$HOST \    --mysql-port=$PORT \    --max-time=60 \    --oltp-read-only=$ON_OFF \    --max-requests=0 \    --num-threads=8 runWhat came out is that, by using the innodb plugin instead of the built-in engine, you get roughly 15% more in read-only, and close to 8% in read/write.Note that 5.5. enhancements are more impressive in scalability tests with more than 8 cores. In this server, I have just tested a simple scenario.I did some more testing using "ROW_FORMAT=COMPRESSED KEY_BLOCK_SIZE=X" in the InnoDB table, where X changed from 4 to 16. But sysbench didn't seem to play well with compression. For low values of KEY_BLOCK_SIZE, you actually get a much worse result than the built-in engine. I have yet to figure out how I would use this compressed InnoDB in practice.]]></description>
			<content:encoded><![CDATA[<table border="0"><tr><td><a href="http://dev.mysql.com/doc/innodb-plugin/1.0/en/innodb-plugin-introduction.html"><img src="http://lh6.ggpht.com/_gVfZHGgf5LA/TAs2RD0WZcI/AAAAAAAAA7E/bhg77-B3EzY/mysql_plugin.png" alt="plugin performance" title="innodb plugin performance" width="300" border="0" /></a></td><td>You know already that InnoDB in MySQL 5.5 has great improvements in performance and scalability. You will have to wait a few months for that, though, because MySQL 5.5 is not GA yet. <br />But if you need some extra performance in MySQL 5.1, you may want to use the Innodb Plugin instead of the built-in one. As of version 5.1.47, the <a href="http://dev.mysql.com/doc/refman/5.1/en/news-5-1-47.html">Innodb plugin is of GA  quality</a>, and it comes with a good out-of-the-box improvement compared to the built-in engine.</td></tr></table><br />To test my assumptions, I used one of my test Linux servers to perform a sysbench on 5.0.91, 5.1.47 built-in and plugin, and 5.5.4. The MySQL servers were all configured with <pre><code>innodb_buffer_pool_size=5G</code></pre><br />MySQL 4.1.47 was tested both as out-of-the-box, and with the plugin enabled.<br /><code><br />ignore_builtin_innodb<br /># note: the following statements must go all in one line<br />plugin-load=innodb=ha_innodb_plugin.so;innodb_trx=ha_innodb_plugin.so;innodb_locks=ha_innodb_plugin.so;innodb_lock_waits=ha_innodb_plugin.so;innodb_cmp=ha_innodb_plugin.so;innodb_cmp_reset=ha_innodb_plugin.so;innodb_cmpmem=ha_innodb_plugin.so;innodb_cmpmem_reset=ha_innodb_plugin.so<br /><br />default-storage-engine=InnoDBinnodb_file_per_table=1<br />innodb_file_format=barracudainnodb_strict_mode=1<br /></code><br />The test was the same for all the servers. A simple sysbench both read-only and read/write on a 1M records table.<br /><pre><br />sysbench \<br />    --test=oltp \<br />    --oltp-table-size=1000000 \<br />    --mysql-db=test \<br />    --mysql-user=$PASSWD \<br />    --mysql-password=$USER \<br />    --mysql-host=$HOST \<br />    --mysql-port=$PORT \<br />    --max-time=60 \<br />    --oltp-read-only=$ON_OFF \<br />    --max-requests=0 \<br />    --num-threads=8 run<br /></pre><br />What came out is that, by using the innodb plugin instead of the built-in engine, you get roughly 15% more in read-only, and close to 8% in read/write.<br /><img src="http://lh6.ggpht.com/_gVfZHGgf5LA/TAqkedfCE1I/AAAAAAAAA60/-TDLtWmJZs4/plugin_performance_simple.jpg" /><br /><img src="http://lh3.ggpht.com/_gVfZHGgf5LA/TAqke3lNpJI/AAAAAAAAA68/mRdXstSIr8c/s512/plugin_performance_charts.jpg" /><br />Note that 5.5. enhancements are more impressive in scalability tests with more than 8 cores. In this server, I have just tested a simple scenario.<br /><br />I did some more testing using "ROW_FORMAT=COMPRESSED KEY_BLOCK_SIZE=X" in the InnoDB table, where X changed from 4 to 16. But sysbench didn't seem to play well with compression. For low values of KEY_BLOCK_SIZE, you actually get a much worse result than the built-in engine. I have yet to figure out how I would use this compressed InnoDB in practice.<br /><br /><img src="http://lh6.ggpht.com/_gVfZHGgf5LA/TAqkepABXkI/AAAAAAAAA64/fdKc6kkGAGo/s640/plugin_performance_compression.jpg" /><div><img width="1" height="1" src="https://blogger.googleusercontent.com/tracker/16959946-2434285055672137838?l=datacharmer.blogspot.com" alt="" /></div><br/>PlanetMySQL Voting:
	 <a href="http://planet.mysql.com/entry/vote/?entry_id=24959&vote=1&apivote=1">Vote UP</a> /
	 <a href="http://planet.mysql.com/entry/vote/?entry_id=24959&vote=-1&apivote=1">Vote DOWN</a>]]></content:encoded>
			<wfw:commentRss>http://planetmysql.ru/2010/06/06/performance-gain-of-mysql-5-1-innodb-plugin/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>MySQL Sandbox now with plugins, more tests, instrumentation</title>
		<link>http://datacharmer.blogspot.com/2010/05/mysql-sandbox-now-with-plugins-more.html?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=mysql-sandbox-now-with-plugins-more-tests-instrumentation</link>
		<comments>http://datacharmer.blogspot.com/2010/05/mysql-sandbox-now-with-plugins-more.html#comments</comments>
		<pubDate>Sun, 30 May 2010 19:01:00 +0000</pubDate>
		<dc:creator>Giuseppe Maxia</dc:creator>
				<category><![CDATA[InnoDB]]></category>
		<category><![CDATA[instrumentation]]></category>
		<category><![CDATA[mysql]]></category>
		<category><![CDATA[plugin]]></category>
		<category><![CDATA[Replication]]></category>
		<category><![CDATA[sandbox]]></category>
		<category><![CDATA[semisynch]]></category>
		<category><![CDATA[testing]]></category>

		<guid isPermaLink="false"></guid>
		<description><![CDATA[The latest release of MySQL Sandbox, 3.0.12, has integrated plugin installation features, as mentioned in my previous post.Not only that. This version has also more tests, fixes a couple of bugs, and introduces basic instrumentation. Now each script released with MySQL Sandbox, and every one that the Sandbox itself installs, can leave a trail in a file.Let's start with the plugin. The documentation has been updated to cover this new feature. And 27 new tests give me some confidence that it should work as advertised.While I was waiting for the test suite to finish its 238 tests, I was wondering how much was going on under the hood. So I spent one hour implementing some basic instrumentation, not only in the make_* scripts, but also in every script that the sandbox installs. The code is quite modular, and adding this feature was easy.Now, if you want to use this instrumentation, you need to create a file, and set the operating system variable $SBINSTR to the full path of that file prior to using the Sandbox. Then, every script will leave an entry in that file, saying its name, the current time, and which parameters was using.This is what I got after running the test suite. 66 instances of MySQL installed to perform over 200 tests, in about 18 minutes.MySQL Sandbox scriptscallsmake_sandbox   66low_level_make_sandbox   66make_replication_sandbox   8make_multiple_sandbox   7make_multiple_custom_sandbox   2Installed scriptscallsuse   440stop   192start   128clear   56sandbox_action   56sbtool   34stop_all   30use_all   20clear_all   13start_all   12send_kill   11restart   9initialize_slaves   8restart_all   4change_paths   2change_ports   1total  1165The new release is available from Launchpad or directly from the CPAN]]></description>
			<content:encoded><![CDATA[<table border="0"><tbody><tr><td><a href="http://mysqlsandbox.net/"><img src="http://lh4.ggpht.com/_gVfZHGgf5LA/TAK1xS5wedI/AAAAAAAAA6o/Y56lSG4fbFY/sandbox_instrument_small_detail.png" alt="MySQL Sandbox" title="MySQL Sandbox instrumentation" border="0" width="300" /></a></td><td>The latest release of <a href="http://mysqlsandbox.net/">MySQL Sandbox</a>, 3.0.12, has integrated plugin installation features, as mentioned in my previous <a href="http://datacharmer.blogspot.com/2010/05/mysql-sandbox-meets-plugins.html">post</a>.<br />Not only that. This version has also more tests, fixes a couple of bugs, and introduces basic instrumentation. Now each script released with MySQL Sandbox, and every one that the Sandbox itself installs, can leave a trail in a file.<br /></td></tr></tbody></table><br />Let's start with the plugin. The <a href="http://search.cpan.org/~gmax/MySQL-Sandbox-3.0.12/lib/MySQL/Sandbox.pm#sbtool_-o_plugin">documentation</a> has been updated to cover this new feature. And 27 new tests give me some confidence that it should work as advertised.<br />While I was waiting for the test suite to finish its 238 tests, I was wondering how much was going on under the hood. So I spent one hour implementing some basic instrumentation, not only in the <code>make_*</code> scripts, but also in every script that the sandbox installs. The code is quite modular, and adding this feature was easy.<br />Now, if you want to use this instrumentation, you need to create a file, and set the operating system variable <code>$SBINSTR</code> to the full path of that file prior to using the Sandbox. Then, every script will leave an entry in that file, saying its name, the current time, and which parameters was using.<br />This is what I got after running the test suite. 66 instances of MySQL installed to perform over 200 tests, in about 18 minutes.<br /><table border="1"><br /><tbody><tr><th align="left">MySQL Sandbox scripts</th><th>calls</th></tr><tr><td>make_sandbox </td> <td align="right"> 66</td></tr><tr><td>low_level_make_sandbox </td> <td align="right"> 66</td></tr><tr><td>make_replication_sandbox </td> <td align="right"> 8</td></tr><tr><td>make_multiple_sandbox </td> <td align="right"> 7</td></tr><tr><td>make_multiple_custom_sandbox </td> <td align="right"> 2</td></tr><br /><tr><th align="left">Installed scripts</th><th>calls</th></tr><tr><td>use </td> <td align="right"> 440</td></tr><tr><td>stop </td> <td align="right"> 192</td></tr><tr><td>start </td> <td align="right"> 128</td></tr><tr><td>clear </td> <td align="right"> 56</td></tr><tr><td>sandbox_action </td> <td align="right"> 56</td></tr><tr><td>sbtool </td> <td align="right"> 34</td></tr><tr><td>stop_all </td> <td align="right"> 30</td></tr><tr><td>use_all </td> <td align="right"> 20</td></tr><tr><td>clear_all </td> <td align="right"> 13</td></tr><tr><td>start_all </td> <td align="right"> 12</td></tr><tr><td>send_kill </td> <td align="right"> 11</td></tr><tr><td>restart </td> <td align="right"> 9</td></tr><tr><td>initialize_slaves </td> <td align="right"> 8</td></tr><tr><td>restart_all </td> <td align="right"> 4</td></tr><tr><td>change_paths </td> <td align="right"> 2</td></tr><tr><td>change_ports </td> <td align="right"> 1</td></tr><tr><th align="left">total</th> <th align="right"> 1165</th></tr></tbody></table><br />The new release is available from <a href="http://launchpad.net/mysql-sandbox">Launchpad</a> or directly from the <a href="http://search.cpan.org/~gmax/MySQL-Sandbox-3.0.12/">CPAN</a><div><img width="1" height="1" src="https://blogger.googleusercontent.com/tracker/16959946-7929248491486139547?l=datacharmer.blogspot.com" alt="" /></div><br/>PlanetMySQL Voting:
	 <a href="http://planet.mysql.com/entry/vote/?entry_id=24899&vote=1&apivote=1">Vote UP</a> /
	 <a href="http://planet.mysql.com/entry/vote/?entry_id=24899&vote=-1&apivote=1">Vote DOWN</a>]]></content:encoded>
			<wfw:commentRss>http://planetmysql.ru/2010/05/30/mysql-sandbox-now-with-plugins-more-tests-instrumentation/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

