<?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>join-fu!</title>
	<atom:link href="http://www.joinfu.com/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.joinfu.com</link>
	<description>the art of sql</description>
	<lastBuildDate>Thu, 22 Jul 2010 19:08:11 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9.2</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Developing Nova on Linux &#8211; Getting Started</title>
		<link>http://www.joinfu.com/2010/07/developing-nova-on-linux-getting-started/</link>
		<comments>http://www.joinfu.com/2010/07/developing-nova-on-linux-getting-started/#comments</comments>
		<pubDate>Thu, 22 Jul 2010 19:01:36 +0000</pubDate>
		<dc:creator>jaypipes</dc:creator>
				<category><![CDATA[Bazaar]]></category>
		<category><![CDATA[Launchpad]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[openstack]]></category>

		<guid isPermaLink="false">http://www.joinfu.com/?p=373</guid>
		<description><![CDATA[In the past few weeks, I&#8217;ve gotten involved in the newly-debuted OpenStack project.  Right now, my focus is on the Compute sub-project of the stack, called Nova.  The initial pieces I am focusing on are the unit tests and end-to-end systems testing of the compute stack.
I struggled over the last couple days to [...]]]></description>
			<content:encoded><![CDATA[<p>In the past few weeks, I&#8217;ve gotten involved in the newly-debuted <a href="http://openstack.org">OpenStack</a> project.  Right now, my focus is on the Compute sub-project of the stack, called <a href="http://launchpad.net/nova/">Nova</a>.  The initial pieces I am focusing on are the unit tests and end-to-end systems testing of the compute stack.</p>
<p>I struggled over the last couple days to solve a bug that turned out to be not a bug at all, but an issue with the Python development environment I use.  I figured I&#8217;d write a blog article for those Python developers who are looking to contribute to the Nova project and may also be struggling to get up and going.  </p>
<p>If you&#8217;re contributing to an open source project like Nova, you&#8217;ll want to be able to work on multiple branches of the source code at the same time &mdash; for instance, if you&#8217;re working on fixing a few bugs simultaneously.  </p>
<p>There are quite a few dependencies for Nova, and, because of the way Python searches for packages, it&#8217;s imperative that you use a tool such as <tt>virtualenv</tt> to isolate your multiple branches into their own development environments.  Otherwise, as I learned today, the location of your site-packages and what has previously been installed on your development machine can wreak havoc on you. <img src='http://www.joinfu.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<div style="border: solid 1px #ccc; background-color: #f7f7f7; padding: 15px 40px;">
<strong style="color: red;">NOTE</strong>: For this article, I assume the reader is on Debian/Ubuntu Linux, since that is what I use as my development machine.  If you&#8217;re on a different flavour of Linux, feel free to adapt the instructions here to suit your particular package manager.
</div>
<h2>Installing the Tools for Installing the Tools</h2>
<p>Before we get into our virtual development environments, you&#8217;ll first want to ensure you&#8217;ve got a few packages installed, including <tt>bzr</tt>, <tt>libssl-dev</tt>, <tt>swig</tt> and <tt>virtualenv</tt>.  The following should do the trick:</p>
<pre>
sudo apt-get install -y swig libssl-dev bzr python-virtualenv
</pre>
<h2>A Setup for Source Control and Virtual Environments</h2>
<p>In order to get properly setup to contribute to the Nova project, you&#8217;ll want to setup a local repository to keep branches of source code that you work on.  Although <tt>bzr</tt> is not required as your revision control system, I use <tt>bzr</tt> myself and will use it in this article.  Adapt as needed if you use <tt>git-bzr</tt> or similar.</p>
<p>I like to have the following directory structure for working on Python projects:</p>
<pre>
~/repos/$projectname/ <-- shared repository for branches of your project
~/repos/$projectname/trunk <-- local trunk branch
~/repos/$projectname/$branch <-- a branch you work in
~/virtenvs/$projectname/ <-- Development environments for your project
~/virtenvs/$projectname/$branch <-- development environment for a branch you work in
</pre>
<p>Assuming you want to contribute to the Nova project and you want to work on fixing a bug #XXXXX, then following would get you started:</p>
<pre>
bzr init-repo ~/repos/nova
cd ~/repos/nova
bzr branch lp:nova trunk
bzr branch trunk bugXXXXX
mkdir -p ~/virtenvs/nova
</pre>
<p>At this point, we'll go ahead and create a virtual development environment for bugXXXXX:</p>
<pre>
cd ~/virtenvs/nova
virtualenv --no-site-packages bugXXXXX
cd bugXXXXX
source bin/activate
</pre>
<p>At this point, you'll notice your prompt change, indicating that you are now in a virtual development environment.  The <tt>--no-site-packages</tt> ensures that your locally-installed Python packages aren't included in your Python PATH when inside your virtual environment.</p>
<p>Next step is to install into this virtual development environment all the packages and dependencies we'll need.  This should do the trick:</p>
<pre>
easy_install twisted tornado boto M2Crypto IPy carrot mox redis
easy_install http://python-gflags.googlecode.com/files/python_gflags-1.3-py2.5.egg
</pre>
<p>Alright, next we simply link to our bzr branch location from inside the virtual environment and run the Nova test suite:</p>
<pre>
ln -s ~/repos/nova/bugXXXXX bugXXXXX
cd bugXXXXX
python run_tests.py
</pre>
<p>If all went smoothly, you'll see all passing test cases, like below <img src='http://www.joinfu.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<p><img src="http://joinfu.com/img/nova-test-screenshot.png" style="float: center; margin: 10px;" /></p>
<p>Having issues getting up and running?  Find us on Freenode IRC #openstack.</p>
<p>See ya,</p>
<p>Jay</p>
]]></content:encoded>
			<wfw:commentRss>http://www.joinfu.com/2010/07/developing-nova-on-linux-getting-started/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>MySQL Stored Procedures Ain&#8217;t All That</title>
		<link>http://www.joinfu.com/2010/05/mysql-stored-procedures-aint-all-that/</link>
		<comments>http://www.joinfu.com/2010/05/mysql-stored-procedures-aint-all-that/#comments</comments>
		<pubDate>Thu, 13 May 2010 17:40:57 +0000</pubDate>
		<dc:creator>jaypipes</dc:creator>
				<category><![CDATA[MySQL]]></category>

		<guid isPermaLink="false">http://www.joinfu.com/?p=369</guid>
		<description><![CDATA[I give quite a lot of presentations.  A whole lot less than I used to, but still quite a few per year.  Most of the time, the presentations are on performance tuning MySQL.
Almost every time I give a presentation on MySQL performance tuning &#8212; and this happens 100% of the time if I [...]]]></description>
			<content:encoded><![CDATA[<p>I give quite a lot of presentations.  A whole lot less than I used to, but still quite a few per year.  Most of the time, the presentations are on performance tuning MySQL.</p>
<p>Almost every time I give a presentation on MySQL performance tuning &mdash; and this happens 100% of the time if I am presenting to a Windows SQL Server crowd &mdash; I get the following question:</p>
<blockquote><p>
Why don&#8217;t you cover using stored procedures in order to increase performance?  Wouldn&#8217;t that be the easiest way to get better performance since the stored procedures will only be parsed once and then the compiled bytecode would be efficiently executed from then on?
</p></blockquote>
<p>Every person that asks this question assumes something about MySQL&#8217;s stored procedure implementation; they incorrectly believe that <strong>stored procedures are compiled and stored in a global stored procedure cache</strong>, similar to the stored procedure cache in Microsoft SQL Server<sup>[1]</sup> or Oracle<sup>[2]</sup>.</p>
<p>This is wrong.  Flat-out incorrect.</p>
<p>Here is the truth: <strong>Every single connection</strong> to the MySQL server maintains it&#8217;s own stored procedure cache.</p>
<p>This means two very important things that users of stored procedures should understand:</p>
<ul>
<li>If you operate in a shared-nothing environment &mdash; for example, the majority of PHP and Python applications that do <em>not</em> use connection pooling or persistent connections &mdash; if your application uses stored procedures, the connection is compiling the stored procedure, storing it in a cache, and destroying that cache every single time you connect to the database server and issue a CALL statement</li>
<li>If you use stored procedures, the <strong>memory usage</strong> of every single connection that uses those stored procedures is going to increase, and will increase substantially if you use many stored procedures</li>
</ul>
<h2>Ooops, I Invalidated Everything Again</h2>
<p>So, what happens when you <tt>CREATE</tt>, <tt>ALTER</tt>, or <tt>DROP</tt> <em>any stored procedures</em>?  Since MySQL stores all stored procedure execution code on the connection threads, each of those connection threads must invalidate the procedure in its caches that has changed, right?</p>
<p>No, it&#8217;s worse.  Every time <strong>ANY</strong> stored procedure is added, dropped, or updated, <strong>ALL stored procedures on ALL connection threads will be invalidated and must be re-compiled</strong>.  Here is how the &#8220;caches&#8221; are invalidated:</p>
<p><strong>from <tt>/sql/sp_cache.cc</tt>, lines 193-197, in MySQL 5.5</strong></p>

<div class="wp_syntax"><div class="code"><pre class="cpp" style="font-family:monospace;"><span style="color: #ff0000; font-style: italic;">/*
  Invalidate all routines in all caches.
&nbsp;
  SYNOPSIS
    sp_cache_invalidate()
&nbsp;
  NOTE
    This is called when a VIEW definition is created or modified (and in some
    other contexts). We can't destroy sp_head objects here as one may modify
    VIEW definitions from prelocking-free SPs.
*/</span>
<span style="color: #0000ff;">void</span> sp_cache_invalidate<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span>
<span style="color: #008000;">&#123;</span>
  DBUG_PRINT<span style="color: #008000;">&#40;</span><span style="color: #FF0000;">&quot;info&quot;</span>,<span style="color: #008000;">&#40;</span><span style="color: #FF0000;">&quot;sp_cache: invalidating&quot;</span><span style="color: #008000;">&#41;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
  thread_safe_increment<span style="color: #008000;">&#40;</span>Cversion, <span style="color: #000040;">&amp;</span>Cversion_lock<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
<span style="color: #008000;">&#125;</span></pre></div></div>

<p>It&#8217;s a bit misleading, since it actually doesn&#8217;t invalidate anything at all.  What the above code does is increment the global &#8220;Cversion&#8221; variable.  When a connection thread attempts to execute, drop or insert a new procedure, it will notice that it&#8217;s local cache&#8217;s version number is less than this Cversion number and will destroy the entire cache and rebuild it gradually as procedures are affected or executed.</p>
<h2>So, Should You Use Stored Procedures in MySQL?</h2>
<p>The above warning doesn&#8217;t <em>necessarily</em> mean that you should <em>never</em> use stored procedures?  No.  What it means (besides being a bit of a rant on the implementation of MySQL&#8217;s stored procedures) is that you should be aware of these issues and use stored procedures where they make the most sense:</p>
<ul>
<li>When you <em>know</em> that you will be executing the stored procedure over and over again on the same connection &mdash; for instance, in a bulk loading script or similar</li>
<li>When you <em>know</em> that you will not be disconnecting from the MySQL server at the end of script execution &mdash; for instance, if you use JDBC connection pooling</li>
<li>When you <em>know</em> that you have a limited number of stored procedures and the memory usage of connections won&#8217;t be an issue</li>
</ul>
<p>Finally, if you see benchmarks that purport to show a huge performance increase from using stored procedures in MySQL, be careful to understand what the benchmark is doing and whether that benchmark represents <strong>your real-world environment</strong>.  For instance, if you see a huge performance increase in sysbench when using stored procedures, but you have a PHP shared-nothing environment, understand that those benchmark results mean very little to you, since sysbench connections don&#8217;t get destroyed until the end of the run&#8230;</p>
<p><sup>[1]</sup> From my copy of Inside SQL Server 2000, Delaney (2001), pages 852-865.  For a short, but decent, online explanation of SQL Server&#8217;s stored procedure cache, see <a href="http://www.databasejournal.com/features/mssql/article.php/3067071/SQL-Server-Stored-Procedures-Administration.htm">here</a></p>
<p><sup>[2]</sup> Oracle&#8217;s stored procedures are stored in the shared pool of the Oracle system global area (SGA)</p>
]]></content:encoded>
			<wfw:commentRss>http://www.joinfu.com/2010/05/mysql-stored-procedures-aint-all-that/feed/</wfw:commentRss>
		<slash:comments>18</slash:comments>
		</item>
		<item>
		<title>Now Recording Drizzle Contributor Tutorial</title>
		<link>http://www.joinfu.com/2010/05/now-recording-drizzle-contributor-tutorial/</link>
		<comments>http://www.joinfu.com/2010/05/now-recording-drizzle-contributor-tutorial/#comments</comments>
		<pubDate>Thu, 13 May 2010 15:25:26 +0000</pubDate>
		<dc:creator>jaypipes</dc:creator>
				<category><![CDATA[Drizzle]]></category>
		<category><![CDATA[MySQL]]></category>

		<guid isPermaLink="false">http://www.joinfu.com/?p=368</guid>
		<description><![CDATA[Hi all!
I was swamped with registrations for the online contributor tutorial for Drizzle, and so I&#8217;ve bumped up my account to a DimDim Pro account.  This means two things:

I can take >20 registrations
I can record the session

So, Diego, rest assured, the session will be recorded (hopefully with no glitches).  I&#8217;m going to call [...]]]></description>
			<content:encoded><![CDATA[<p>Hi all!</p>
<p>I was swamped with registrations for the online contributor tutorial for Drizzle, and so I&#8217;ve bumped up my account to a DimDim Pro account.  This means two things:</p>
<ol>
<li>I can take >20 registrations</li>
<li>I can record the session</li>
</ol>
<p>So, Diego, rest assured, the session will be recorded (hopefully with no glitches).  I&#8217;m going to call DimDim to see if I can do a practice recording beforehand to verify Linux64 is a platform they support for recording (if not, I&#8217;ll go to my neighbour&#8217;s Windows computer to record)</p>
<p>Again, if you&#8217;re interested in the webinar, please do register using the widget below:</p>
<p><script language='javascript' type='text/javascript' src='https://my.dimdim.com/static/js/common_support.js'></script><object type='application/x-shockwave-flash' id='flash_dimdim_widget' data='https://my.dimdim.com/static/dimdimWebinar2.swf?widgetParams=mid/4c1b7c5c-3c08-4b11-acd9-67af7b6cdaa6/furl/aHR0cHM6Ly9teS5kaW1kaW0uY29tLw==/op/saas:dimdim:all:jaypipes:default:dimdim:default:en_US/rec/1/tim/0/tra/0/reg/0/' width='250' height='310'><param name='movie' value='https://my.dimdim.com/static/dimdimWebinar2.swf?widgetParams=mid/4c1b7c5c-3c08-4b11-acd9-67af7b6cdaa6/furl/aHR0cHM6Ly9teS5kaW1kaW0uY29tLw==/op/saas:dimdim:all:jaypipes:default:dimdim:default:en_US/rec/1/tim/0/tra/0/reg/0/' /><param name='wmode' value='transparent' /><param name='allowNetworking' value='all' /><param name='allowFullScreen' value='false' /><param name='allowscriptaccess' value='always'></param></object><br />
Cheers,</p>
<p>jay</p>
]]></content:encoded>
			<wfw:commentRss>http://www.joinfu.com/2010/05/now-recording-drizzle-contributor-tutorial/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Signup for Drizzle Contributor Tutorial Webinar &#8211; May 15th</title>
		<link>http://www.joinfu.com/2010/05/signup-for-drizzle-contributor-tutorial-webinar-may-15th/</link>
		<comments>http://www.joinfu.com/2010/05/signup-for-drizzle-contributor-tutorial-webinar-may-15th/#comments</comments>
		<pubDate>Tue, 11 May 2010 15:48:57 +0000</pubDate>
		<dc:creator>jaypipes</dc:creator>
				<category><![CDATA[C/C++]]></category>
		<category><![CDATA[Drizzle]]></category>
		<category><![CDATA[MySQL]]></category>

		<guid isPermaLink="false">http://www.joinfu.com/?p=367</guid>
		<description><![CDATA[Hi all!
I&#8217;ll be giving an online webinar for Drizzle contributors on Saturday, May 15th @ 1am GMT (In the U.S. this is Friday, May14th @ 9pm EDT, 6pm PDT).
Note that the DimDim widget below shows the time as May 14th @ 8pm.  The widget is wrong, since DimDim does not account for daylight savings.
Space [...]]]></description>
			<content:encoded><![CDATA[<p>Hi all!</p>
<p>I&#8217;ll be giving an online webinar for <a href="http://drizzle.org">Drizzle</a> contributors on Saturday, May 15th @ 1am GMT (In the U.S. this is Friday, May14th @ 9pm EDT, 6pm PDT).</p>
<p><strong>Note that the DimDim widget below shows the time as May 14th @ 8pm.  The widget is wrong, since DimDim does not account for daylight savings.</strong></p>
<p>Space is strictly limited to 20 people and this will be done via DimDim.com.  Please register for the webinar by entering your email address in the widget below and clicking &#8220;Sign Up&#8221;.</p>
<p><script language='javascript' type='text/javascript' src='https://my.dimdim.com/static/js/common_support.js'></script><object type='application/x-shockwave-flash' id='flash_dimdim_widget' data='https://my.dimdim.com/static/dimdimWebinar2.swf?widgetParams=mid/4c1b7c5c-3c08-4b11-acd9-67af7b6cdaa6/furl/aHR0cHM6Ly9teS5kaW1kaW0uY29tLw==/op/saas:dimdim:all:jaypipes:default:dimdim:default:en_US/rec/0/tim/0/tra/0/reg/0/' width='250' height='310'><param name='movie' value='https://my.dimdim.com/static/dimdimWebinar2.swf?widgetParams=mid/4c1b7c5c-3c08-4b11-acd9-67af7b6cdaa6/furl/aHR0cHM6Ly9teS5kaW1kaW0uY29tLw==/op/saas:dimdim:all:jaypipes:default:dimdim:default:en_US/rec/0/tim/0/tra/0/reg/0/' /><param name='wmode' value='transparent' /><param name='allowNetworking' value='all' /><param name='allowFullScreen' value='false' /><param name='allowscriptaccess' value='always'></param></object></p>
<p>The agenda for this 2-3 hour tutorial will be:</p>
<ol>
<li>First Steps
<ul>
<li>Getting registered as a contributor for Drizzle on Launchpad</li>
<li>Registering your SSH keys with Launchpad</li>
<li>Picking up and creating blueprints</li>
<li>Basics of Bazaar</li>
<li>Setting up a local code repository for Drizzle</li>
<li>Committing your work to a Bazaar branch</li>
<li>Pushing your code to Launchpad</LI>
<li>Requesting a code review and merge into trunk</li>
<li><strong>One slide</strong> explaining the license your contributions may be submitted under</li>
</ul>
</li>
<li>The Drizzle Source Code
<ul>
<li>Our coding standards</li>
<li>Our build system</li>
<li>Walkthrough of major directories in Drizzle</li>
<li>Understanding the plugin system</li>
<li>Understanding what the kernel is responsible for</li>
<li>Where the Dragons live &mdash; and how to avoid them</li>
</ul>
</li>
<li>
Walkthrough of a SELECT statement</p>
<ul>
<li>Client communication with server</li>
<li>The role of the session scheduler plugin</li>
<li>How, when and where authentication and authorization plugins are called</li>
<li>How the <tt>drizzled::statement::Statement</tt> subclasses work</li>
<li>Dive into <tt>drizzled::statement::Select::execute()</tt></li>
<li>Walkthrough how a Table&#8217;s definition (metadata) is read from a protobuffer file or an engine</li>
<li>Dive into mysql_lock_tables()</li>
<li>How does <tt>drizzled::plugin::StorageEngine::startStatement()</tt> work?</li>
<li>How does <tt>drizzled::plugin::TransactionalStorageEngine::startTransaction()</tt> work?</li>
<li>Inside the join optimizer and <tt>Join::optimize()</tt>
<li>How does the nested loops algorithm get executed and how does <tt>READ_RECORD</tt> work?</tt>
<li>How does <tt>drizzled::Cursor</tt> perform table and index scans and seeks?</tt>
<li>How are result sets packaged up and sent to clients?</tt>
</ul>
</li>
<li>
Plugin Development Tutorial</p>
<ul>
<li>What plugin classes are even available?</li>
<li>Creating your basic plugin</li>
<li>The plugin.ini file</li>
<li>The module initialization and configuration file</li>
<li>Registering your plugin with the kernel with <tt>plugin::Context::add()</tt></li>
<li>Publishing your plugin's information using table functions</li>
<li>Providing users control over your plugin with user-defined functions</li>
</ul>
</li>
]]></content:encoded>
			<wfw:commentRss>http://www.joinfu.com/2010/05/signup-for-drizzle-contributor-tutorial-webinar-may-15th/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>Slides from Developing Drizzle Replication Plugins Tutorial</title>
		<link>http://www.joinfu.com/2010/04/slides-from-developing-drizzle-replication-plugins-tutorial/</link>
		<comments>http://www.joinfu.com/2010/04/slides-from-developing-drizzle-replication-plugins-tutorial/#comments</comments>
		<pubDate>Tue, 13 Apr 2010 23:09:12 +0000</pubDate>
		<dc:creator>jaypipes</dc:creator>
				<category><![CDATA[All]]></category>

		<guid isPermaLink="false">http://www.joinfu.com/?p=365</guid>
		<description><![CDATA[Hi all!
So, Padraig, Toru, and myself teamed up yesterday at the MySQL Conference for about thirty or so attendees to discuss developing Drizzle plugins in C++.  It was a set of slides that covered basic stuff all the way up through pretty advanced topics.  We hope attendees got something out of it  [...]]]></description>
			<content:encoded><![CDATA[<p>Hi all!</p>
<p>So, <a href="http://posulliv.com">Padraig</a>, <a href="http://torum.net">Toru</a>, and myself teamed up yesterday at the <a href="http://mysqlconf.com">MySQL Conference</a> for about thirty or so attendees to discuss developing Drizzle plugins in C++.  It was a set of slides that covered basic stuff all the way up through pretty advanced topics.  We hope attendees got something out of it <img src='http://www.joinfu.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<p>Below are the slides from Padraig&#8217;s and my part of the tutorial which focused on plugin development basics and the replication plugin API in Drizzle.  I&#8217;ve also tacked them onto my page of presentations.</p>
<p>Enjoy, and feel free to email me with comments and suggestions to <tt>SELECT REVERSE('moc.liamg@sepipyaj');</tt></p>
<h2>Developing Drizzle Replication Plugins</h2>
<p><img src="http://joinfu.com/presentations/drizzle-replication-plugins/drizzle-replication-plugins.png" style="float: left; margin: 0px 40px 10px 0px;"/><br />
<img src="http://joinfu.com/img/impress.png" /><a href="http://joinfu.com/presentations/drizzle-replication-plugins/drizzle-replication-plugins.odp"  title="Developing Drizzle Replication Plugins">Open Office Impress slides</a><br />
<img src="http://joinfu.com/img/pdf.png" /><a href="http://joinfu.com/presentations/drizzle-replication-plugins/drizzle-replication-plugins.pdf"  title="Developing Drizzle Replication Plugins">PDF  slides</a><br />
<br clear="left" /><br />
Topics included in the slides:</p>
<ul>
<li>About the Drizzle Community and Expectations of Contributors</li>
<li>Getting started on Launchpad</li>
<li>Various features of Launchpad</li>
<li>Understanding the Source Code Directory Structure</li>
<li>Code walkthrough of Drizzle plugin basics</li>
<li>Drizzle&#8217;s System Architecture</li>
<li>Overview of Drizzle&#8217;s Replication System</li>
<li>Understanding Google Protobuffers</li>
<li>The Transaction message in Detail</li>
<li>In-depth code walkthrough of the Filtered Replicator module</li>
<li>In-depth code walkthrough of the Transaction Log module</li>
<li>Future of Drizzle replication &#8211; Publisher and Subscriber plugins</li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://www.joinfu.com/2010/04/slides-from-developing-drizzle-replication-plugins-tutorial/feed/</wfw:commentRss>
		<slash:comments>9</slash:comments>
		</item>
		<item>
		<title>Holy Google Summer of Code, Batman</title>
		<link>http://www.joinfu.com/2010/03/holy-google-summer-of-code-batman/</link>
		<comments>http://www.joinfu.com/2010/03/holy-google-summer-of-code-batman/#comments</comments>
		<pubDate>Fri, 26 Mar 2010 16:06:02 +0000</pubDate>
		<dc:creator>jaypipes</dc:creator>
				<category><![CDATA[C/C++]]></category>
		<category><![CDATA[Drizzle]]></category>
		<category><![CDATA[MySQL]]></category>

		<guid isPermaLink="false">http://www.joinfu.com/?p=356</guid>
		<description><![CDATA[So, last year, Drizzle participated in the Google Summer of Code under the MySQL project organization.  We had four excellent student submissions and myself, Monty Taylor, Eric Day and Stewart Smith all mentored students for the summer.  It was my second year mentoring, and I really enjoyed it, so I was looking forward [...]]]></description>
			<content:encoded><![CDATA[<p>So, last year, <a href="http://launchpad.net/drizzle">Drizzle</a> <a href="http://socghop.appspot.com/gsoc/program/list_projects/google/gsoc2009">participated</a> in the Google Summer of Code under the MySQL project organization.  We had four excellent student submissions and myself, <a href="http://inaugust.com">Monty Taylor</a>, <a href="http://oddments.org">Eric Day</a> and <a href="http://flamingspork.com">Stewart Smith</a> all mentored students for the summer.  It was my second year mentoring, and I really enjoyed it, so I was looking forward to this year&#8217;s summer of code.</p>
<p>This year, <a href="http://posulliv.com">Padraig O&#8217;Sullivan</a>, a GSoC student last year, is now working at <a href="http://www.akiban.com/">Akiban Technologies</a>, partly on Drizzle, and is the GSoC Adminsitrator and also a mentor for Drizzle this year, and <em>Drizzle is its own <a href="http://socghop.appspot.com/gsoc/program/accepted_orgs/google/gsoc2010">sponsored project organization</a> this year</em>.  Thank you, Padraig!</p>
<p>I have been absolutely floored by the flood of potential students who have shown up on the <a href="https://lists.launchpad.net/drizzle-discuss/">mailing list</a> and the #drizzle IRC channel.  I have been even more impressed with those students&#8217; ambition, sense of community, and willingness to ask questions and help other students as they show up.  A couple students have even gotten code contributed to the source trees even before submitting their official applications to GSoC.  See, I told you they were ambitious! <img src='http://www.joinfu.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<p>This year, Drizzle has a <a href="http://drizzle.org/wiki/Soc">listing of 16 potential projects</a> for students to work on.  The projects are for students interested in developing in C++, Python, or Perl.</p>
<p>If you are interested in participating, please do check out Drizzle!  For those new to Launchpad, Bazaar, and C++ development with Drizzle, feel free to check out these blog articles which cover those topics:</p>
<ul>
<li><a href="http://www.joinfu.com/2008/08/a-contributors-guide-to-launchpadnet-part-1-getting-started/">A Contributor&#8217;s Guide to Launchpad and Bazaar &#8211; Part 1 &#8211; Getting Started</a></li>
<li><a href="http://www.joinfu.com/2008/08/a-contributors-guide-to-launchpadnet-part-2-code-management/">A Contributor&#8217;s Guide to Launchpad and Bazaar &#8211; Part 2 &#8211; Code Management</a></li>
<li><a href="http://www.joinfu.com/2008/08/getting-a-working-c-c-plusplus-development-environment-for-developing-drizzle/">Getting a C++ Development Enviroment Established</a></li>
</ul>
<p>And, in other news, <a href="http://www.ncaa.com/brackets/basketball/men/">Go Buckeyes</a>!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.joinfu.com/2010/03/holy-google-summer-of-code-batman/feed/</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
		<item>
		<title>Understanding Drizzle&#8217;s Transaction Log</title>
		<link>http://www.joinfu.com/2010/03/understanding-drizzles-transaction-log/</link>
		<comments>http://www.joinfu.com/2010/03/understanding-drizzles-transaction-log/#comments</comments>
		<pubDate>Wed, 17 Mar 2010 21:03:00 +0000</pubDate>
		<dc:creator>jaypipes</dc:creator>
				<category><![CDATA[C/C++]]></category>
		<category><![CDATA[Drizzle]]></category>
		<category><![CDATA[MySQL]]></category>

		<guid isPermaLink="false">http://www.joinfu.com/?p=355</guid>
		<description><![CDATA[Today I pushed up the initial patch which adds XA support to Drizzle&#8217;s transaction log.  So, to give myself a bit of a rest from coding, I&#8217;m going to blog a bit about the transaction log and show off some of its features.

WARNING: Please keep in mind that the transaction log module in Drizzle [...]]]></description>
			<content:encoded><![CDATA[<p>Today I pushed up the <a href="http://bazaar.launchpad.net/~jaypipes/drizzle/xa-transaction-log/revision/1312">initial patch</a> which adds XA support to Drizzle&#8217;s transaction log.  So, to give myself a bit of a rest from coding, I&#8217;m going to blog a bit about the transaction log and show off some of its features.</p>
<div style="padding: 15px 50px; background-color: #f7f7f7; border: solid 1px #666; color: red;">
<strong>WARNING</strong>: Please keep in mind that the transaction log module in Drizzle is under heavy development and should not be used in production environments.  That said, I&#8217;d love to get as much feedback as possible on it, and if you feel like throwing some heavy data at it, that would be awesome <img src='http://www.joinfu.com/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' />
</div>
<h2>What is the Transaction Log?</h2>
<p>Simply put, the transaction log is a record of every modification to the state of the server&#8217;s data.  It is similar to MySQL&#8217;s binlog, with some substantial differences:</p>
<ul>
<li>The transaction log is composed of <a href="http://code.google.com/apis/protocolbuffers/docs/overview.html">Google Protobuffer</a> messages.  Because of this, it is possible to read the log using a variety of programming languages, as <a href="http://developian.blogspot.com/">Marcus Eriksson</a>&#8217;s <a href="https://launchpad.net/rabbitreplication">RabbitReplication</a> project demonstrates.</li>
<li>The transaction log is a plugin<sup>[1]</sup>.  It lives entirely outside of the Drizzle kernel.  The advantage of this is that development of the transaction log does not need to be linked with development in the kernel and versioning of the transaction log can happen independently of the kernel.</li>
<li>Currently, there is only a single log file.  MySQL&#8217;s binlog can be split into multiple files.  This may or may not change in the future. <img src='http://www.joinfu.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </li>
<li>Drizzle&#8217;s transaction log is indexed.  Among other things, this means that you can query the transaction log directly from within a Drizzle client via DATA_DICTIONARY views.  I will demonstrate this feature below.</li>
</ul>
<p>It is important to also point out that Drizzle&#8217;s transaction log is not required for Drizzle replication.  This probably sounds very weird to folks who are accustomed to MySQL replication, which depends on the MySQL binlog.  In Drizzle, the replication API is different.  Although the transaction log <em><strong>can be used</strong></em> in Drizzle&#8217;s replication system, it&#8217;s not required.  I&#8217;ll write more on this in later blog posts which demonstrate how the replication system is not dependent on the transaction log, but in this article I just want to highlight the transaction log module. </p>
<h2>How Do I Enable the Transaction Log</h2>
<p>First things first, let&#8217;s see how we can enable the Transaction Log.  If you&#8217;ve built Drizzle from source or have installed Drizzle locally, you will be familiar with the process of starting up a Drizzle server.  To review, here is how you do so:</p>
<pre>
cd $basedir
./drizzled [options] &#038;
</pre>
<p>Where <tt>$basedir</tt> is the directory you built Drizzle or installed Drizzle.  For the <tt>[options]</tt>, typically you will need at the very least a <tt>--datadir=$DATADIR</tt> and a <tt>--mysql-protocol-port=$PORT</tt> value.  For an explanation of the <tt>--mysql-protocol-port</tt> option, see <a href="http://oddments.org">Eric Day</a>&#8217;s <a href="http://oddments.org/?p=307">recent article</a>.</p>
<p>To demonstrate, I&#8217;ve built a Drizzle server in a local directory of mine, and I&#8217;ll use the <tt>/tests/var/</tt> directory as my <tt>$datadir</tt>:</p>
<pre>
cd /home/jpipes/repos/drizzle/xa-transaction-log/drizzled/
./drizzled --datadir=/home/jpipes/repos/drizzle/xa-transaction-log/tests/var/ --mysql-protocol-port=9306 &#038;
</pre>
<p>You should see output similar to this:</p>
<pre>
jpipes@serialcoder:~/repos/drizzle/xa-transaction-log/drizzled$ ./drizzled --datadir=/home/jpipes/repos/drizzle/xa-transaction-log/tests/var/ --mysql-protocol-port=9306 &#038;
[1] 31499
jpipes@serialcoder:~/repos/drizzle/xa-transaction-log/drizzled$ InnoDB: The InnoDB memory heap is disabled
InnoDB: Mutexes and rw_locks use GCC atomic builtins.
InnoDB: The first specified data file ./ibdata1 did not exist:
InnoDB: a new database to be created!
100317 15:41:51  InnoDB: Setting file ./ibdata1 size to 10 MB
InnoDB: Database physically writes the file full: wait...
100317 15:41:52  InnoDB: Log file ./ib_logfile0 did not exist: new to be created
InnoDB: Setting log file ./ib_logfile0 size to 5 MB
InnoDB: Database physically writes the file full: wait...
100317 15:41:52  InnoDB: Log file ./ib_logfile1 did not exist: new to be created
InnoDB: Setting log file ./ib_logfile1 size to 5 MB
InnoDB: Database physically writes the file full: wait...
InnoDB: Doublewrite buffer not found: creating new
InnoDB: Doublewrite buffer created
InnoDB: Creating foreign key constraint system tables
InnoDB: Foreign key constraint system tables created
100317 15:41:53 InnoDB Plugin 1.0.4 started; log sequence number 0
Listening on 0.0.0.0:9306
Listening on :::9306
Listening on 0.0.0.0:4427
Listening on :::4427
./drizzled: Forcing close of thread 0 user: ''
./drizzled: ready for connections.
Version: '2010.03.1314' Source distribution (xa-transaction-log)
</pre>
<p>To connect to the above server, I then do:</p>
<pre>
../client/drizzle --port=9306
</pre>
<p>If all went well, you should be at a drizzle client prompt:</p>
<pre>
jpipes@serialcoder:~/repos/drizzle/xa-transaction-log/drizzled$ ../client/drizzle --port=9306
Welcome to the Drizzle client..  Commands end with ; or \g.
Your Drizzle connection id is 2
Server version: 7 Source distribution (xa-transaction-log)

Type 'help;' or '\h' for help. Type '\c' to clear the buffer.

drizzle>
</pre>
<p>You can check to see whether the transaction log is enabled by querying the <tt>DATA_DICTIONARY.VARIABLES</tt> table.  The transaction log is not on by default:</p>
<pre>
drizzle> use data_dictionary
Reading table information for completion of table and column names
    You can turn off this feature to get a quicker startup with -A

Database changed
drizzle> SELECT * FROM GLOBAL_VARIABLES WHERE VARIABLE_NAME LIKE 'transaction_log%';
+---------------------------------+-----------------+
| VARIABLE_NAME                   | VARIABLE_VALUE  |
+---------------------------------+-----------------+
| transaction_log_enable          | OFF             |
| transaction_log_enable_checksum | OFF             |
| transaction_log_enable_xa       | OFF             |
| transaction_log_log_file        | transaction.log |
| transaction_log_sync_method     | 0               |
| transaction_log_truncate_debug  | OFF             |
| transaction_log_xa_num_slots    | 8               |
+---------------------------------+-----------------+
7 rows in set (0 sec)
</pre>
<p>OK, let&#8217;s start up the server, this time with the transaction log enabled.  To shutdown Drizzle, there is no need to use a tool like mysqladmin.  You can shutdown the server via the client:</p>
<pre>
drizzle> exit
Bye
jpipes@serialcoder:~/repos/drizzle/xa-transaction-log/drizzled$ ../client/drizzle --port=9306 --shutdown
jpipes@serialcoder:~/repos/drizzle/xa-transaction-log/drizzled$ ./drizzled: Normal shutdown
100317 15:53:48  InnoDB: Starting shutdown...
100317 15:53:49  InnoDB: Shutdown completed; log sequence number 44244
...
</pre>
<p>Now let&#8217;s start up the server, this time passing the <tt>--transaction-log-enable</tt> and the <tt>--default-replicator-enable</tt> options.  The <tt>--default-replicator-enable</tt> option is needed when the transaction log is not in XA mode (more on that later):</p>
<pre>
jpipes@serialcoder:~/repos/drizzle/xa-transaction-log/drizzled$ ./drizzled --datadir=/home/jpipes/repos/drizzle/xa-transaction-log/tests/var/ --mysql-protocol-port=9306 --transaction-log-enable --default-replicator-enable &#038;
[2] 31582
[1]   Done                    ./drizzled --datadir=/home/jpipes/repos/drizzle/xa-transaction-log/tests/var/ --mysql-protocol-port=9306
jpipes@serialcoder:~/repos/drizzle/xa-transaction-log/drizzled$ InnoDB: The InnoDB memory heap is disabled
...
./drizzled: ready for connections.
</pre>
<p>And again, connect to the server and check our transaction log variables again:</p>
<pre>
jpipes@serialcoder:~/repos/drizzle/xa-transaction-log/drizzled$ ../client/drizzle --port=9306
Welcome to the Drizzle client..  Commands end with ; or \g.
Your Drizzle connection id is 2
Server version: 7 Source distribution (xa-transaction-log)

Type 'help;' or '\h' for help. Type '\c' to clear the buffer.

drizzle> use data_dictionary
Reading table information for completion of table and column names
    You can turn off this feature to get a quicker startup with -A

Database changed
drizzle> SELECT * FROM GLOBAL_VARIABLES WHERE VARIABLE_NAME LIKE 'transaction_log%';
+---------------------------------+-----------------+
| VARIABLE_NAME                   | VARIABLE_VALUE  |
+---------------------------------+-----------------+
| transaction_log_enable          | ON              |
| transaction_log_enable_checksum | OFF             |
| transaction_log_enable_xa       | OFF             |
| transaction_log_log_file        | transaction.log |
| transaction_log_sync_method     | 0               |
| transaction_log_truncate_debug  | OFF             |
| transaction_log_xa_num_slots    | 8               |
+---------------------------------+-----------------+
7 rows in set (0 sec)

drizzle>
</pre>
<p>OK.  So, if you check the <tt>$datadir</tt>, you should see a file called <tt>transaction.log</tt>, with a size of 0:</p>
<pre>
jpipes@serialcoder:~/repos/drizzle/xa-transaction-log/drizzled$ ls -lha ../tests/var/
total 21M
drwxr-xr-x  6 jpipes jpipes 4.0K 2010-03-17 15:54 .
drwxr-xr-x 11 jpipes jpipes 4.0K 2010-03-17 14:57 ..
-rw-rw----  1 jpipes jpipes  10M 2010-03-17 15:54 ibdata1
-rw-rw----  1 jpipes jpipes 5.0M 2010-03-17 15:54 ib_logfile0
-rw-rw----  1 jpipes jpipes 5.0M 2010-03-17 15:41 ib_logfile1
-rwxr-----  1 jpipes jpipes    6 2010-03-17 15:54 serialcoder.pid
-rwx------  1 jpipes jpipes    0 2010-03-17 15:54 transaction.log
</pre>
<p>Back in the drizzle client, let&#8217;s go ahead and create a new schema, a new table, and add a single row to that table.  This will add some entries to the transaction log that we&#8217;ll be able to view:</p>
<pre>
drizzle> CREATE SCHEMA lebowski;
Query OK, 1 rows affected (0.06 sec)
drizzle> USE lebowski
Database changed
drizzle> CREATE TABLE characters (name VARCHAR(20) NOT NULL PRIMARY KEY,
    -> hobby VARCHAR(10) NOT NULL) ENGINE=InnoDB;
Query OK, 0 rows affected (0.06 sec)

drizzle> INSERT INTO characters VALUES ('the dude','bowling');
Query OK, 1 row affected (0.05 sec)
</pre>
<p>Checking in on our transaction log file, we see it now has some size to it:</p>
<pre>
jpipes@serialcoder:~/repos/drizzle/xa-transaction-log/drizzled$ ls -lha ../tests/var/
total 21M
drwxr-xr-x  7 jpipes jpipes 4.0K 2010-03-17 16:11 .
drwxr-xr-x 11 jpipes jpipes 4.0K 2010-03-17 14:57 ..
-rw-rw----  1 jpipes jpipes  10M 2010-03-17 16:11 ibdata1
-rw-rw----  1 jpipes jpipes 5.0M 2010-03-17 16:11 ib_logfile0
-rw-rw----  1 jpipes jpipes 5.0M 2010-03-17 16:11 ib_logfile1
drwxrwx--x  2 jpipes jpipes 4.0K 2010-03-17 16:11 lebowski
-rwxr-----  1 jpipes jpipes    6 2010-03-17 16:11 serialcoder.pid
-rwx------  1 jpipes jpipes  444 2010-03-17 16:11 transaction.log
</pre>
<h2>Finding Out What&#8217;s In the Transaction Log</h2>
<p>OK, so now for the really cool part of this little demonstration. <img src='http://www.joinfu.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' />   Let&#8217;s take a look at what is now contained in the transaction log, all via the Drizzle client and the <tt>DATA_DICTIONARY</tt> views.</p>
<p>There are currently three <tt>DATA_DICTIONARY</tt> views which show information about the transaction log and its contents:</p>
<ul>
<li><tt>DATA_DICTIONARY.TRANSACTION_LOG</tt></li>
<li><tt>DATA_DICTIONARY.TRANSACTION_LOG_ENTRIES</tt></li>
<li><tt>DATA_DICTIONARY.TRANSACTION_LOG_TRANSACTIONS</tt></li>
</ul>
<p>To see what each view contains, simply do a <tt>DESC</tt> on them:</p>
<pre>
drizzle> use data_dictionary
Reading table information for completion of table and column names
    You can turn off this feature to get a quicker startup with -A

Database changed
drizzle> DESC TRANSACTION_LOG;
+---------------------+---------+-------+---------+-----------------+-----------+
| Field               | Type    | Null  | Default | Default_is_NULL | On_Update |
+---------------------+---------+-------+---------+-----------------+-----------+
| FILE_NAME           | VARCHAR | FALSE |         | FALSE           |           |
| FILE_LENGTH         | BIGINT  | FALSE |         | FALSE           |           |
| NUM_LOG_ENTRIES     | BIGINT  | FALSE |         | FALSE           |           |
| NUM_TRANSACTIONS    | BIGINT  | FALSE |         | FALSE           |           |
| MIN_TRANSACTION_ID  | BIGINT  | FALSE |         | FALSE           |           |
| MAX_TRANSACTION_ID  | BIGINT  | FALSE |         | FALSE           |           |
| MIN_END_TIMESTAMP   | BIGINT  | FALSE |         | FALSE           |           |
| MAX_END_TIMESTAMP   | BIGINT  | FALSE |         | FALSE           |           |
| INDEX_SIZE_IN_BYTES | BIGINT  | FALSE |         | FALSE           |           |
+---------------------+---------+-------+---------+-----------------+-----------+
9 rows in set (0 sec)

drizzle> DESC TRANSACTION_LOG_ENTRIES;
+--------------+---------+-------+---------+-----------------+-----------+
| Field        | Type    | Null  | Default | Default_is_NULL | On_Update |
+--------------+---------+-------+---------+-----------------+-----------+
| ENTRY_OFFSET | BIGINT  | FALSE |         | FALSE           |           |
| ENTRY_TYPE   | VARCHAR | FALSE |         | FALSE           |           |
| ENTRY_LENGTH | BIGINT  | FALSE |         | FALSE           |           |
+--------------+---------+-------+---------+-----------------+-----------+
3 rows in set (0 sec)

drizzle> DESC TRANSACTION_LOG_TRANSACTIONS;
+-----------------+--------+-------+---------+-----------------+-----------+
| Field           | Type   | Null  | Default | Default_is_NULL | On_Update |
+-----------------+--------+-------+---------+-----------------+-----------+
| ENTRY_OFFSET    | BIGINT | FALSE |         | FALSE           |           |
| TRANSACTION_ID  | BIGINT | FALSE |         | FALSE           |           |
| SERVER_ID       | BIGINT | FALSE |         | FALSE           |           |
| START_TIMESTAMP | BIGINT | FALSE |         | FALSE           |           |
| END_TIMESTAMP   | BIGINT | FALSE |         | FALSE           |           |
| NUM_STATEMENTS  | BIGINT | FALSE |         | FALSE           |           |
| CHECKSUM        | BIGINT | FALSE |         | FALSE           |           |
+-----------------+--------+-------+---------+-----------------+-----------+
7 rows in set (0 sec)
</pre>
<p>Let&#8217;s see what each of the views tells us about what is in the transaction log.  Remember, we&#8217;ve executed a <tt>CREATE SCHEMA</tt>, a <tt>CREATE TABLE</tt>, and a single <tt>INSERT</tt>.  Here is what the <tt>TRANSACTION_LOG</tt> view shows:</p>
<pre>
drizzle> SELECT * FROM TRANSACTION_LOG\G
*************************** 1. row ***************************
          FILE_NAME: transaction.log
        FILE_LENGTH: 444
    NUM_LOG_ENTRIES: 3
   NUM_TRANSACTIONS: 3
 MIN_TRANSACTION_ID: 1
 MAX_TRANSACTION_ID: 3
  MIN_END_TIMESTAMP: 1268856698672620
  MAX_END_TIMESTAMP: 1268856707093000
INDEX_SIZE_IN_BYTES: 73736
</pre>
<p>The column names should be self explanatory.  The <tt>FILE_LENGTH</tt> shows the size in bytes of the log (which matches the output we had from our <tt>ls -lha</tt> above.)  The <tt>INDEX_SIZE_IN_BYTES</tt> is total amount of memory allocated for the transaction log index. </p>
<p>The <tt>TRANSACTION_LOG_ENTRIES</tt> view isn&#8217;t that interesting at first glance:</p>
<pre>
drizzle> SELECT * FROM TRANSACTION_LOG_ENTRIES;
+--------------+-------------+--------------+
| ENTRY_OFFSET | ENTRY_TYPE  | ENTRY_LENGTH |
+--------------+-------------+--------------+
|            0 | TRANSACTION |           89 |
|           89 | TRANSACTION |          223 |
|          312 | TRANSACTION |          132 |
+--------------+-------------+--------------+
</pre>
<p>You might be tempted to ask what the heck the purpose of the <tt>TRANSACTION_LOG_ENTRIES</tt> view is for.  It is a bit of a bridge table that allows one to see the type of entries at each offset.  Currently, the only types of entries in the transaction log are of type <tt>TRANSACTION</tt> &mdash; basically a serialized GPB Protobuffer message &mdash; and a <tt>BLOB</tt> entry, which is for storage of large blob data.</p>
<p>The <tt>TRANSACTION_LOG_TRANSACTIONS</tt> view shows all the transaction log entries which are of type <tt>TRANSACTION</tt>:</p>
<pre>
drizzle> SELECT * FROM TRANSACTION_LOG_TRANSACTIONS;
+--------------+----------------+-----------+------------------+------------------+----------------+----------+
| ENTRY_OFFSET | TRANSACTION_ID | SERVER_ID | START_TIMESTAMP  | END_TIMESTAMP    | NUM_STATEMENTS | CHECKSUM |
+--------------+----------------+-----------+------------------+------------------+----------------+----------+
|            0 |              1 |         1 | 1268856698672606 | 1268856698672620 |              1 |        0 |
|           89 |              2 |         1 | 1268856702792284 | 1268856702792331 |              1 |        0 |
|          312 |              3 |         1 | 1268856707025455 | 1268856707093000 |              1 |        0 |
+--------------+----------------+-----------+------------------+------------------+----------------+----------+
3 rows in set (0 sec)
</pre>
<p>As you can see, there is some basic information about each transaction entry in the log, including the offset in the transaction log, the start and end timestamp of the transaction, it&#8217;s transaction identifier, the number of statements involved in the transaction, and an optional checksum for the message (more on checksums below).</p>
<h2>Viewing the Transaction Content</h2>
<p>While the above view output may be nice, what we&#8217;d really like to be able to do is see what <em>precisely</em> were the changes a Transaction effected.  To see this, we can use the <tt>PRINT_TRANSACTION_MESSAGE(<em>log_file</em>, <em>offset</em>)</tt> UDF.  Below, I&#8217;ve added two more rows to the <tt>lebowski.characters</tt> table within an explicit transaction.  I then query the <tt>DATA_DICTIONARY</tt> views using the <tt>PRINT_TRANSACTION_MESSAGE()</tt> function to show the changes logged to the transaction log:</p>
<pre>
drizzle> use lebowski
Reading table information for completion of table and column names
    You can turn off this feature to get a quicker startup with -A

Database changed
drizzle> START TRANSACTION;
Query OK, 0 rows affected (0 sec)

drizzle> INSERT INTO characters VALUES ('walter','bowling');
Query OK, 1 row affected (0 sec)

drizzle> INSERT INTO characters VALUES ('donny','bowling');
Query OK, 1 row affected (0 sec)

drizzle> COMMIT;
Query OK, 0 rows affected (0.09 sec)
</pre>
<p>We now see an additional Transaction Log entry and can see that this transaction contains the two individual <tt>INSERT</tt> statements just executed:</p>
<pre>
drizzle> SELECT * FROM TRANSACTION_LOG_TRANSACTIONS;
+--------------+----------------+-----------+------------------+------------------+----------------+----------+
| ENTRY_OFFSET | TRANSACTION_ID | SERVER_ID | START_TIMESTAMP  | END_TIMESTAMP    | NUM_STATEMENTS | CHECKSUM |
+--------------+----------------+-----------+------------------+------------------+----------------+----------+
|            0 |              1 |         1 | 1268856698672606 | 1268856698672620 |              1 |        0 |
|           89 |              2 |         1 | 1268856702792284 | 1268856702792331 |              1 |        0 |
|          312 |              3 |         1 | 1268856707025455 | 1268856707093000 |              1 |        0 |
|          444 |              4 |         1 | 1268857926482600 | 1268857938514312 |              1 |        0 |
+--------------+----------------+-----------+------------------+------------------+----------------+----------+
...
drizzle> SELECT PRINT_TRANSACTION_MESSAGE('transaction.log', ENTRY_OFFSET) as info
    -> FROM TRANSACTION_LOG_TRANSACTIONS WHERE ENTRY_OFFSET = 444\G
*************************** 1. row ***************************
info: transaction_context {
  server_id: 1
  transaction_id: 4
  start_timestamp: 1268857926482600
  end_timestamp: 1268857938514312
}
statement {
  type: INSERT
  start_timestamp: 1268857926482605
  end_timestamp: 1268857938514310
  insert_header {
    table_metadata {
      schema_name: "lebowski"
      table_name: "characters"
    }
    field_metadata {
      type: VARCHAR
      name: "name"
    }
    field_metadata {
      type: VARCHAR
      name: "hobby"
    }
  }
  insert_data {
    segment_id: 1
    end_segment: true
    record {
      insert_value: "walter"
      insert_value: "bowling"
    }
    record {
      insert_value: "donny"
      insert_value: "bowling"
    }
  }
}

1 row in set (0.01 sec)
</pre>
<p>You may notice that <tt>NUM_STATEMENTS</tt> is equal to 1 even though there were 2 <tt>INSERT</tt> statements issued.  This is because the kernel packages both the <tt>INSERT</tt>s into a single <tt>message::Statement::InsertData</tt> package for more efficient storage.  If there had been an <tt>INSERT</tt> and an <tt>UPDATE</tt>, <tt>NUM_STATEMENTS</tt> would be 2.</p>
<h2>Enable Automatic Checksumming</h2>
<p>One final feature I&#8217;ll highlight in this blog post is an option to automatically store a checksum of each transaction message when writing entries to the transaction log.  To enable this feature, simply use the <tt>--transaction-log-enable-checksum</tt> command line option.  You can view the checksums of entries in the <tt>TRANSACTION_LOG_TRANSACTIONS</tt> view, as demonstrated below:</p>
<pre>
jpipes@serialcoder:~/repos/drizzle/xa-transaction-log/drizzled$ ./drizzled --datadir=/home/jpipes/repos/drizzle/xa-transaction-log/tests/var/ --mysql-protocol-port=9306 --transaction-log-enable --default-replicator-enable --transaction-log-enable-checksum &#038;
[5] 32042
[4]   Done                    ./drizzled --datadir=/home/jpipes/repos/drizzle/xa-transaction-log/tests/var/ --mysql-protocol-port=9306 --transaction-log-enable --default-replicator-enable
jpipes@serialcoder:~/repos/drizzle/xa-transaction-log/drizzled$ InnoDB: The InnoDB memory heap is disabled
InnoDB: Mutexes and rw_locks use GCC atomic builtins.
InnoDB: The first specified data file ./ibdata1 did not exist:
InnoDB: a new database to be created!
100317 16:47:07  InnoDB: Setting file ./ibdata1 size to 10 MB
InnoDB: Database physically writes the file full: wait...
100317 16:47:07  InnoDB: Log file ./ib_logfile0 did not exist: new to be created
InnoDB: Setting log file ./ib_logfile0 size to 5 MB
InnoDB: Database physically writes the file full: wait...
100317 16:47:08  InnoDB: Log file ./ib_logfile1 did not exist: new to be created
InnoDB: Setting log file ./ib_logfile1 size to 5 MB
InnoDB: Database physically writes the file full: wait...
InnoDB: Doublewrite buffer not found: creating new
InnoDB: Doublewrite buffer created
InnoDB: Creating foreign key constraint system tables
InnoDB: Foreign key constraint system tables created
100317 16:47:08 InnoDB Plugin 1.0.4 started; log sequence number 0
Listening on 0.0.0.0:9306
Listening on :::9306
Listening on 0.0.0.0:4427
Listening on :::4427
./drizzled: Forcing close of thread 0 user: ''
./drizzled: ready for connections.
Version: '2010.03.1314' Source distribution (xa-transaction-log)
...
jpipes@serialcoder:~/repos/drizzle/xa-transaction-log/drizzled$ ../client/drizzle --port=9306
Welcome to the Drizzle client..  Commands end with ; or \g.
Your Drizzle connection id is 2
Server version: 7 Source distribution (xa-transaction-log)

Type 'help;' or '\h' for help. Type '\c' to clear the buffer.

drizzle> CREATE SCHEMA lebowski;
Query OK, 1 row affected (0.05 sec)

drizzle> CREATE TABLE characters (name VARCHAR(20) NOT NULL PRIMARY KEY, hobby VARCHAR(10) NOT NULL) ENGINE=InnoDB;
ERROR 1046 (3D000): No database selected
drizzle> use lebowski
Database changed
drizzle> CREATE TABLE characters (name VARCHAR(20) NOT NULL PRIMARY KEY, hobby VARCHAR(10) NOT NULL) ENGINE=InnoDB;
Query OK, 0 rows affected (0.11 sec)

drizzle> INSERT INTO characters VALUES ('the dude','bowling');
Query OK, 1 row affected (0.1 sec)

drizzle> use data_dictionary
Reading table information for completion of table and column names
    You can turn off this feature to get a quicker startup with -A

Database changed
drizzle> SELECT ENTRY_OFFSET, TRANSACTION_ID, CHECKSUM FROM TRANSACTION_LOG_TRANSACTIONS;
+--------------+----------------+------------+
| ENTRY_OFFSET | TRANSACTION_ID | CHECKSUM   |
+--------------+----------------+------------+
|            0 |              2 |  143866125 |
|           89 |              8 | 1466831622 |
|          312 |              9 |  460824986 |
+--------------+----------------+------------+
3 rows in set (0 sec)
</pre>
<h2>DDL is not Statement-based Replication</h2>
<p>As a final note, I&#8217;d like to point out that even DDL in Drizzle is replicated as row-based transaction messages, and not as raw SQL statements like in MySQL.  You can see, for instance, the <tt>message::Statement::CreateTableStatement</tt> inside the transaction message which contains all the metadata about the table you just created. <img src='http://www.joinfu.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<pre>
drizzle> SELECT PRINT_TRANSACTION_MESSAGE('transaction.log', ENTRY_OFFSET)
    -> FROM TRANSACTION_LOG_TRANSACTIONS WHERE ENTRY_OFFSET = 89\G
*************************** 1. row ***************************
PRINT_TRANSACTION_MESSAGE('transaction.log', ENTRY_OFFSET): transaction_context {
  server_id: 1
  transaction_id: 2
  start_timestamp: 1268858897017396
  end_timestamp: 1268858897017447
}
statement {
  type: CREATE_TABLE
  start_timestamp: 1268858897017402
  end_timestamp: 1268858897017445
  create_table_statement {
    table {
      name: "characters"
      engine {
        name: "InnoDB"
      }
      field {
        name: "name"
        type: VARCHAR
        format: DefaultFormat
        constraints {
          is_nullable: false
        }
        string_options {
          length: 20
          collation_id: 45
          collation: "utf8_general_ci"
        }
      }
      field {
        name: "hobby"
        type: VARCHAR
        format: DefaultFormat
        constraints {
          is_nullable: false
        }
        string_options {
          length: 10
          collation_id: 45
          collation: "utf8_general_ci"
        }
      }
      indexes {
        name: "PRIMARY"
        is_primary: true
        is_unique: true
        type: UNKNOWN_INDEX
        key_length: 80
        index_part {
          fieldnr: 0
          compare_length: 80
          key_type: 0
        }
        options {
          binary_pack_key: true
          var_length_key: true
        }
      }
      type: STANDARD
      options {
        collation: "utf8_general_ci"
        collation_id: 45
      }
    }
  }
}

1 row in set (0 sec)
</pre>
<p>If you like or don&#8217;t like what you see, please do get in touch with me or fire off a wishlist to the <a href="https://launchpad.net/~drizzle-discuss">Drizzle Discuss mailing list</a>.  We&#8217;d love to hear from ya!</p>
<p><sup>[1]</sup> Actually, the transaction log module is a set of plugins.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.joinfu.com/2010/03/understanding-drizzles-transaction-log/feed/</wfw:commentRss>
		<slash:comments>11</slash:comments>
		</item>
		<item>
		<title>Is Anyone Else Looking Forward To&#8230;</title>
		<link>http://www.joinfu.com/2010/03/is-anyone-else-looking-forward-to/</link>
		<comments>http://www.joinfu.com/2010/03/is-anyone-else-looking-forward-to/#comments</comments>
		<pubDate>Sun, 14 Mar 2010 21:05:25 +0000</pubDate>
		<dc:creator>jaypipes</dc:creator>
				<category><![CDATA[All]]></category>

		<guid isPermaLink="false">http://www.joinfu.com/?p=349</guid>
		<description><![CDATA[&#8230;the new Clash of the Titans movie, coming out soon?  I loved the original back in 1981.  Can&#8217;t wait to see this one.  
I would have linked to the new trailer site, but it was all Flash and took over two minutes to load even with broadband.  I figured I&#8217;d save [...]]]></description>
			<content:encoded><![CDATA[<p>&#8230;the new Clash of the Titans movie, coming out soon?  I loved the <a href="http://www.imdb.com/title/tt0082186/">original back in 1981</a>.  Can&#8217;t wait to see this one. <img src='http://www.joinfu.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<p>I would have linked to the new trailer site, but it was all Flash and took over two minutes to load even with broadband.  I figured I&#8217;d save users the hassle&#8230;</p>
]]></content:encoded>
			<wfw:commentRss>http://www.joinfu.com/2010/03/is-anyone-else-looking-forward-to/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>O&#8217;Gara Cloud Computing Article Off Base</title>
		<link>http://www.joinfu.com/2010/03/cloud-computing-article-off-bas/</link>
		<comments>http://www.joinfu.com/2010/03/cloud-computing-article-off-bas/#comments</comments>
		<pubDate>Sun, 14 Mar 2010 19:30:26 +0000</pubDate>
		<dc:creator>jaypipes</dc:creator>
				<category><![CDATA[All]]></category>
		<category><![CDATA[Drizzle]]></category>
		<category><![CDATA[MySQL]]></category>
		<category><![CDATA[Open Source]]></category>

		<guid isPermaLink="false">http://www.joinfu.com/?p=347</guid>
		<description><![CDATA[Maureen O&#8217;Gara, self-described as &#8220;the most read technology reporter for the past 20 years&#8221;, has written an article about Drizzle at Rackspace for one of Sys-con&#8217;s online zines called Cloud Computing Journal, of which she is an editor.
I tried commenting on Maureen&#8217;s article on their website, but the login system is apparently borked, at least [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://maureenogara.ulitzer.com/">Maureen O&#8217;Gara</a>, self-described as &#8220;the most read technology reporter for the past 20 years&#8221;, has written an <a href="http://cloudcomputing.sys-con.com/node/1318133">article about Drizzle at Rackspace</a> for one of Sys-con&#8217;s online zines called <a href="http://cloudcomputing.sys-con.com/">Cloud Computing Journal</a>, of which she is an editor.</p>
<p>I tried commenting on Maureen&#8217;s article on their website, but the login system is apparently borked, at least for registered users who use <a href="http://myopenid.com">OpenID</a>, which it wants to still have a separate user ID and login.  Note to sys-con.com: OpenID is designed so that users <em>don&#8217;t have to remember yet another login for your website</em>.</p>
<p>Besides having little patience for content-sparse websites that simply provide an online haven for dozens of Flash advertisements per web page, the article had some serious problems with it, not the least of which was using large chunks of my <a href="http://www.joinfu.com/2010/03/happiness-is-a-warm-cloud/">Happiness is a Warm Cloud</a> article without citation.  Very professional.</p>
<p>OK, to start with, let&#8217;s take this quote from the article:</p>
<blockquote><p>
Drizzle runs the risk of not being as stable as MySQL, because the Drizzle team is taking things out and putting other stuff in. Of course it may be successful in trying to create a product that&#8217;s more stable than MySQL. But creating a stable DBMS engine is something that has always taken years and years.
</p></blockquote>
<p>This is just about the most naïve explanation for whether a product will or will not be stable that I&#8217;ve ever read.  If Maureen had bothered to email or call any one of the core Drizzle developers, they&#8217;d have been happy to tell her what is and is not stable about Drizzle, and why.  Drizzle has not changed the underlying storage engines, so the InnoDB storage engine in Drizzle is the same plugin as available in MySQL (version 1.0.6).  </p>
<p>The pieces of MySQL which were removed from Drizzle happen to be the parts of MySQL which have had the most stability issues &mdash; namely the additional features added to MySQL 5.0: stored procedures, views, triggers, stored functions, the INFORMATION_SCHEMA implementation, and server-side cursors and prepared statements.  In addition to these removed features of MySQL, Drizzle also has no built-in Query Cache, does not support anything other than UTF-8 character sets, and has removed the MySQL replication system and binary logging &#8212; moving a rewrite of these pieces out into the plugin ecosystem. </p>
<p>The pieces that were added to Drizzle have mostly been done by adding plugins that provide functionality.  Maureen, the reason this was done was precisely to allow for greater stability of the kernel by segregating new features and functionality into the plugin ecosystem, where they can be properly versioned and quarantined, therefore increasing kernel stability.  It&#8217;s pretty much the biggest principle of Drizzle&#8217;s design&#8230;</p>
<p>The core developers of Drizzle (and much of the Drizzle community) would also have been happy to tell Maureen how the Drizzle team defines &#8220;stability&#8221;: when the community says Drizzle is stable &mdash; simple as that.</p>
<p>OK, so the next thing I took objection to is the following line:</p>
<blockquote><p>
Half of Rackspace&#8217;s customers are on MySQL so there&#8217;ll be some donkey-style nosing to get them to migrate.
</p></blockquote>
<p>I think my Rackspace colleagues might have quite a bit to say about the above.  I haven&#8217;t seen any Rackers talking about mass migration from MySQL to Drizzle.  As far as I have seen, the plan is to provide Drizzle as an additional service to Rackspace customers.</p>
<blockquote><p>
Rackspace evidently wants its new boys, who were not the core pillars of the MySQL engineering team, to hitch MySQL, er, Drizzle to Cassandra
</p></blockquote>
<p>MySQL != Drizzle.  Implying that the two are equal do a disservice to both, as they have very different target markets and developer audiences.</p>
<blockquote><p>
The smart money is betting that even if a good number of high-volume web sites go down this route, an even higher number such as Facebook and Google will continue with relational databases, primarily MySQL.
</p></blockquote>
<p>Again, probably best to do your homework on this one, too.  Facebook runs an amalgamation of a custom MySQL version and storage engines, distributed key-value stores, and Memcached servers.  I would think that Facebook moving to Drizzle would be one tough migration.  Thousands (tens of thousands?) of MySQL servers all running custom software and integrated into their caching layers is a huge barrier to entry, and not one I would expect a large site like Facebook to casually undertake.  But, the same could be said about a move to SQL Server or Oracle, for that matter, and has little to do with Drizzle.</p>
<p>Google is moving away from using MySQL entirely.  <a href="http://mysqlha.blogspot.com/">Mark Callaghan</a>, previously at Google, has moved over to Facebook (possibly because of this trend at Google to get rid of MySQL), and <a href="http://antbits.blogspot.com/">Anthony Curtis</a>, formerly of MySQL, then Google, <a href="https://www.blogger.com/comment.g?blogID=27751205&#038;postID=6473049572958956231&#038;pli=1">left Google partially because of this reason</a>.</p>
<p>OK, so the next quote got me really fired up because it demonstrates a complete lack of understanding (maybe not Maureen&#8217;s, but the unnamed source it&#8217;s from at least):</p>
<blockquote><p>
Somebody &#8211; sorry we forget who exactly &#8211; claimed that as GPL 2 code Drizzle &#8220;severely limits revenue opportunities. For Rackspace, the opportunity to have some key Drizzle developers on its payrolls basically comes down to a promotional benefit, trying to position Rackspace as particularly Drizzle-savvy in the eyes of the community and currying favor for its seemingly generous contributions. What&#8217;s unclear is whether they may develop some Drizzle-related functionality that they will then not release as open source and just rent out to Rackspace hosting customers&#8230;that would be a way for them to differentiate themselves from competitors and GPLv2 would in principle allow this.&#8221;
</p></blockquote>
<p>A few points to make about the above quote.</p>
<p>First, name your source.  I find it difficult to believe that the most-read technology writer would not write down a source.  Is it the same person you deliberately left out of a quote from my Happiness article? (why did you do that, btw?).</p>
<p>Second, the MySQL server source code is licensed under the GPL 2, and so is Drizzle&#8217;s <strong>kernel</strong>, because it is a derivative work of the MySQL server.  </p>
<p>Let me be clear: <strong>Developers who contribute code to Drizzle do so under the GPLv2 if that contribution is in the Drizzle kernel.  If the code contribution is a plugin, the contributor is free to pick whatever license they choose</strong>.  </p>
<p>Third, licensing has little if anything to do with revenue at all.  The license is besides the point.  There are two things which dictate the company&#8217;s revenue derivation from software:</p>
<ol>
<li>Copyright ownership</li>
<li>Principles of the Company</li>
</ol>
<p>Drizzle, Rackspace, or any company a Drizzle contributor works for, does not have the copyright ownership of the MySQL source code, from which Drizzle&#8217;s <em>kernel</em> is derived.  Oracle does.  Therefore, companies do not have any right to re-sell Drizzle (under <em>any</em> license) without explicit permission from Oracle.  Period.  Has nothing to do with the GPLv2.</p>
<p>That said, contributors <em>do</em> have the right to make money on plugins built for the Drizzle server, and Rackspace, while not having expressed any interest to yours truly in doing so, has the right like any other Drizzle contributor, to make money on plugins its contributors create for Drizzle.</p>
<p>It is my knowledge (after actually having talked to Rackspace managers and decision makers), that Rackspace is not interested in getting into the business of selling commercial Drizzle plugins.  Their core direction is to create value for their customers, and I fail to see how getting into the commercial software sales business meets that goal. </p>
<p>Next time, please feel free to contact myself or any other Drizzle contributor to get the low-down on Drizzle-related stuff.  We&#8217;ll be nice.  I promise.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.joinfu.com/2010/03/cloud-computing-article-off-bas/feed/</wfw:commentRss>
		<slash:comments>9</slash:comments>
		</item>
		<item>
		<title>Recent Work on Improving Drizzle&#8217;s Storage Engine API</title>
		<link>http://www.joinfu.com/2010/03/recent-work-on-improving-drizzles-storage-engine-api/</link>
		<comments>http://www.joinfu.com/2010/03/recent-work-on-improving-drizzles-storage-engine-api/#comments</comments>
		<pubDate>Sat, 13 Mar 2010 07:07:59 +0000</pubDate>
		<dc:creator>jaypipes</dc:creator>
				<category><![CDATA[C/C++]]></category>
		<category><![CDATA[Drizzle]]></category>
		<category><![CDATA[MySQL]]></category>
		<category><![CDATA[storage engine API]]></category>

		<guid isPermaLink="false">http://www.joinfu.com/?p=343</guid>
		<description><![CDATA[Over the past six weeks or so, I have been working on cleaning up the pluggable storage engine API in Drizzle.  I&#8217;d like to describe some of this work and talk a bit about the next steps I&#8217;m taking in the coming months as we roll towards implementing Log Shipping in Drizzle.
First, how did it [...]]]></description>
			<content:encoded><![CDATA[<p>Over the past six weeks or so, I have been working on cleaning up the pluggable storage engine API in Drizzle.  I&#8217;d like to describe some of this work and talk a bit about the next steps I&#8217;m taking in the coming months as we roll towards implementing <a href="https://blueprints.launchpad.net/drizzle/+spec/replication-log-shipping">Log Shipping in Drizzle</a>.</p>
<p>First, how did it come about that I started working on the storage engine API?</p>
<h3>From Commands to Transactions</h3>
<p>Well, it really goes back to my work on Drizzle&#8217;s replication system.  I had implemented a simple, fast, and extensible log which stored records of the data changes made to a server.  Originally, the log was called the Command Log, because the Google Protobuffer messages it contained were called <tt><a href="http://www.joinfu.com/2009/08/drizzle-replication-the-command-message/">message::Command</a></tt>s.  The API  for implementing replication plugins was very simple and within a month or so of debuting the API, quite a few replication plugins had been built, including one replicating to Memcached, a prototype one replicating to Gearman, and a filtering replicator plugin.</p>
<p>In addition, <a href="http://developian.blogspot.com">Marcus Eriksson</a> had created the <a href="http://www.rabbitreplication.org/">RabbitReplication</a> project which could replicate from Drizzle to other data stores, including Cassandra and Project Voldemort.  However, Marcus did not actually implement any C/C++ plugins using the Drizzle replication API.  Instead, RabbitReplication simply read the new Command Log, which due to it simply being a file full of Google Protobuffer messages, was quick and easy to read into memory using a variety of different programming languages.  RabbitReplication is written in Java, and it was great to see other programming languages be able to read Drizzle&#8217;s replication log so easily.  Marcus <a href="http://developian.blogspot.com/2010/01/replicating-transactions-directly-to.html" alt="Replicate Drizzle to RabbitMQ">later coded up</a> a C++ TransactionApplier plugin which replaces the Drizzle replication log and instead replicates the GPB messages directly to RabbitMQ.</p>
<p>And there, you&#8217;ll note that one of the plugins involved in Drizzle&#8217;s replication system is called <em>Transaction</em>Applier.  It used to be called CommandApplier. That was because the GPB Command messages were individual row change events for the most part.  However, I made a series of changes to the replication API and now the GPB messages sent through the APIs are of class <tt><a href="http://www.joinfu.com/2009/10/drizzle-replication-changes-in-api-to-support-group-commit/">message::Transaction</a></tt>.  <tt>message::Transaction</tt> objects contain a transaction context, with information about the transaction&#8217;s start and end time, it&#8217;s transaction identifer, along with a series of <tt>message::Statement objects</tt>, each of which representing a part of the data changes that the SQL transaction made.</p>
<p>Thus, the Command Log now turned into the Transaction Log, and everywhere the term Command was used now was replaced with the terms Transaction and Statement (depending on whether you were talking about the entire Transaction or a piece of it).  Log entries were now written at COMMIT to the Transaction Log and were not written if no COMMIT occurred<sup>1</sup>.</p>
<p>After finishing this work to make the transaction log write Transaction messages at commit time, I was keen to begin coding up the publisher and subscriber plugins which represent a node in the replication environment.  However, Brian had asked me to delay working on other replication features and ensure that the replication API could support fully distributed transactions via the X/Open XA distributed transaction protocol.  XA support had been removed from Drizzle when the MySQL binlog and original replication system was ripped out and needed some TLC.  Fair enough, I said.  So, off I went to work on XA.</p>
<h3>If Only It Were Simple&#8230;</h3>
<p>As anyone who has worked on the MySQL source code or developed storage engines for MySQL knows, working with the MySQL pluggable storage engine API is sometimes not the easiest or most straightforward thing.  I think the biggest problem with the MySQL storage engine API is that, due to understandable historical reasons, it&#8217;s an API that was designed with the MyISAM and HEAP storage engines in mind.  Much of the transactional pieces of the API seem to be a bolted-on afterthought and can be very confusing to work with.</p>
<p>As an example, <a href="http://pbxt.blogspot.com/">Paul McCullagh</a>, developer of the transactional storage engine <a href="http://www.primebase.org/">PBXT</a>, recently <a href="http://lists.mysql.com/internals/37662">emailed</a> the mysql internals mailing list asking how the storage engine could tell when a SQL statement started and ended.  You would think that such a seemingly basic functionality would have a simple answer.  You&#8217;d be wrong.  <a href="http://monty-says.blogspot.com">Monty Widenius</a> <a href="http://lists.mysql.com/internals/37675">answered</a> like this:</p>
<blockquote><p>
Why not simply have a counter in your transaction object for how start_stmt &#8211; reset();  When this is 0 then you know stmnt ended.</p>
<p>In Maria we count number of calls to external_lock() and when the sum goes to 0 we know the transaction has ended.
</p></blockquote>
<p>To this, <a href="http://mysqlha.blogspot.com/">Mark Callaghan</a> responded:</p>
<blockquote><p>
Why does the solution need to be so obscure?
</p></blockquote>
<p>Monty <a href="http://lists.mysql.com/internals/37689">answered</a> (emphasis mine):</p>
<blockquote><p>
Historic reasons.</p>
<p>MySQL never kept a count of which handlers are used by a transaction, only which tables.</p>
<p>So the original logic was that external_lock(lock/unlock) is called for each usage of the table, which is normally more than enough information for a handler to know when a statement starts/ends.</p>
<p>The one case this didn&#8217;t work was in the case someone does lock tables as then external_lock is not called per statement. It was to satisfy this case that we added a call to start_stmt() for each table.</p>
<p><strong>It&#8217;s of course possible to change things so that start_stmt() / end_stmt() would be called once per used handler, but this would be yet another overhead for the upper level to do which the current handlers that tracks call to external_lock() doesn&#8217;t need.</strong>
</p></blockquote>
<p>Well, in Drizzle-land, we aren&#8217;t beholden to &#8220;historic reasons&#8221; <img src='http://www.joinfu.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' />   So, after looking through the in-need-of-attention transaction processing code in the kernel, I decided that I would clean up the API so that storage engines did not have to jump through hoops to notify the kernel they participate in a transaction or just to figure out when a statement and a transaction started and ended.</p>
<p>The resulting changes to the API are quite dramatic I think, but I&#8217;ll leave it to the storage engine developers to tell me if the changes are good or not.  The following is a summary of the changes to the storage engine API that I committed in the last few weeks.</p>
<h3><tt>plugin::StorageEngine</tt> Split Into Subclasses</h3>
<p>The very first thing I did was to split the enormous base plugin class for a storage engine, <tt>plugin::StorageEngine</tt>, into two other subclasses containing transactional elements.  <tt>plugin::TransactionalStorageEngine</tt> is now the base class for all storage engines which implement SQL transactions:</p>

<div class="wp_syntax"><div class="code"><pre class="cpp" style="font-family:monospace;"><span style="color: #ff0000; font-style: italic;">/**
 * A type of storage engine which supports SQL transactions.
 *
 * This class adds the SQL transactional API to the regular
 * storage engine.  In other words, it adds support for the
 * following SQL statements:
 *
 * START TRANSACTION;
 * COMMIT;
 * ROLLBACK;
 * ROLLBACK TO SAVEPOINT;
 * SET SAVEPOINT;
 * RELEASE SAVEPOINT;
 */</span>
<span style="color: #0000ff;">class</span> TransactionalStorageEngine <span style="color: #008080;">:</span><span style="color: #0000ff;">public</span> StorageEngine
<span style="color: #008000;">&#123;</span>
<span style="color: #0000ff;">public</span><span style="color: #008080;">:</span>
  TransactionalStorageEngine<span style="color: #008000;">&#40;</span><span style="color: #0000ff;">const</span> std<span style="color: #008080;">::</span><span style="color: #007788;">string</span> name_arg,
                             <span style="color: #0000ff;">const</span> std<span style="color: #008080;">::</span><span style="color: #007788;">bitset</span><span style="color: #000080;">&lt;</span>HTON_BIT_SIZE<span style="color: #000080;">&gt;</span> <span style="color: #000040;">&amp;</span>flags_arg<span style="color: #000080;">=</span> HTON_NO_FLAGS<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
&nbsp;
  <span style="color: #0000ff;">virtual</span> ~TransactionalStorageEngine<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
...
<span style="color: #0000ff;">private</span><span style="color: #008080;">:</span>
  <span style="color: #0000ff;">void</span> setTransactionReadWrite<span style="color: #008000;">&#40;</span>Session<span style="color: #000040;">&amp;</span> session<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
&nbsp;
  <span style="color: #ff0000; font-style: italic;">/*
   * Indicates to a storage engine the start of a
   * new SQL transaction.  This is called ONLY in the following
   * scenarios:
   *
   * 1) An explicit BEGIN WORK/START TRANSACTION is called
   * 2) After an explicit COMMIT AND CHAIN is called
   * 3) After an explicit ROLLBACK AND RELEASE is called
   * 4) When in AUTOCOMMIT mode and directly before a new
   *    SQL statement is started.
   */</span>
  <span style="color: #0000ff;">virtual</span> <span style="color: #0000ff;">int</span> doStartTransaction<span style="color: #008000;">&#40;</span>Session <span style="color: #000040;">*</span>session, start_transaction_option_t options<span style="color: #008000;">&#41;</span>
  <span style="color: #008000;">&#123;</span>
    <span style="color: #008000;">&#40;</span><span style="color: #0000ff;">void</span><span style="color: #008000;">&#41;</span> session<span style="color: #008080;">;</span>
    <span style="color: #008000;">&#40;</span><span style="color: #0000ff;">void</span><span style="color: #008000;">&#41;</span> options<span style="color: #008080;">;</span>
    <span style="color: #0000ff;">return</span> <span style="color: #0000dd;">0</span><span style="color: #008080;">;</span>
  <span style="color: #008000;">&#125;</span>
&nbsp;
  <span style="color: #ff0000; font-style: italic;">/**
   * Implementing classes should override these to provide savepoint
   * functionality.
   */</span>
  <span style="color: #0000ff;">virtual</span> <span style="color: #0000ff;">int</span> doSetSavepoint<span style="color: #008000;">&#40;</span>Session <span style="color: #000040;">*</span>session, NamedSavepoint <span style="color: #000040;">&amp;</span>savepoint<span style="color: #008000;">&#41;</span><span style="color: #000080;">=</span> <span style="color: #0000dd;">0</span><span style="color: #008080;">;</span>
  <span style="color: #0000ff;">virtual</span> <span style="color: #0000ff;">int</span> doRollbackToSavepoint<span style="color: #008000;">&#40;</span>Session <span style="color: #000040;">*</span>session, NamedSavepoint <span style="color: #000040;">&amp;</span>savepoint<span style="color: #008000;">&#41;</span><span style="color: #000080;">=</span> <span style="color: #0000dd;">0</span><span style="color: #008080;">;</span>
  <span style="color: #0000ff;">virtual</span> <span style="color: #0000ff;">int</span> doReleaseSavepoint<span style="color: #008000;">&#40;</span>Session <span style="color: #000040;">*</span>session, NamedSavepoint <span style="color: #000040;">&amp;</span>savepoint<span style="color: #008000;">&#41;</span><span style="color: #000080;">=</span> <span style="color: #0000dd;">0</span><span style="color: #008080;">;</span>
&nbsp;
  <span style="color: #ff0000; font-style: italic;">/**
   * Commits either the &quot;statement transaction&quot; or the &quot;normal transaction&quot;.
   *
   * @param[in] The Session
   * @param[in] true if it's a real commit, that makes persistent changes
   *            false if it's not in fact a commit but an end of the
   *            statement that is part of the transaction.
   * @note
   *
   * 'normal_transaction' is also false in auto-commit mode where 'end of statement'
   * and 'real commit' mean the same event.
   */</span>
  <span style="color: #0000ff;">virtual</span> <span style="color: #0000ff;">int</span> doCommit<span style="color: #008000;">&#40;</span>Session <span style="color: #000040;">*</span>session, <span style="color: #0000ff;">bool</span> normal_transaction<span style="color: #008000;">&#41;</span><span style="color: #000080;">=</span> <span style="color: #0000dd;">0</span><span style="color: #008080;">;</span>
&nbsp;
  <span style="color: #ff0000; font-style: italic;">/**
   * Rolls back either the &quot;statement transaction&quot; or the &quot;normal transaction&quot;.
   *
   * @param[in] The Session
   * @param[in] true if it's a real commit, that makes persistent changes
   *            false if it's not in fact a commit but an end of the
   *            statement that is part of the transaction.
   * @note
   *
   * 'normal_transaction' is also false in auto-commit mode where 'end of statement'
   * and 'real commit' mean the same event.
   */</span>
  <span style="color: #0000ff;">virtual</span> <span style="color: #0000ff;">int</span> doRollback<span style="color: #008000;">&#40;</span>Session <span style="color: #000040;">*</span>session, <span style="color: #0000ff;">bool</span> normal_transaction<span style="color: #008000;">&#41;</span><span style="color: #000080;">=</span> <span style="color: #0000dd;">0</span><span style="color: #008080;">;</span>
  <span style="color: #0000ff;">virtual</span> <span style="color: #0000ff;">int</span> doReleaseTemporaryLatches<span style="color: #008000;">&#40;</span>Session <span style="color: #000040;">*</span>session<span style="color: #008000;">&#41;</span>
  <span style="color: #008000;">&#123;</span>
    <span style="color: #008000;">&#40;</span><span style="color: #0000ff;">void</span><span style="color: #008000;">&#41;</span> session<span style="color: #008080;">;</span>
    <span style="color: #0000ff;">return</span> <span style="color: #0000dd;">0</span><span style="color: #008080;">;</span>
  <span style="color: #008000;">&#125;</span>
  <span style="color: #0000ff;">virtual</span> <span style="color: #0000ff;">int</span> doStartConsistentSnapshot<span style="color: #008000;">&#40;</span>Session <span style="color: #000040;">*</span>session<span style="color: #008000;">&#41;</span>
  <span style="color: #008000;">&#123;</span>
    <span style="color: #008000;">&#40;</span><span style="color: #0000ff;">void</span><span style="color: #008000;">&#41;</span> session<span style="color: #008080;">;</span>
    <span style="color: #0000ff;">return</span> <span style="color: #0000dd;">0</span><span style="color: #008080;">;</span>
  <span style="color: #008000;">&#125;</span>
<span style="color: #008000;">&#125;</span><span style="color: #008080;">;</span></pre></div></div>

<p>As you can see, <tt>plugin::TransactionalStorageEngine</tt> inherits from <tt>plugin::StorageEngine</tt> and extends it with a series of private pure virtual methods that implement the SQL transaction parts of a query &mdash; doCommit(), doRollback(), etc.  Implementing classes simply inherit from <tt>plugin::TransactionalStorageEngine</tt> and implement their internal transaction processing in these private methods.</p>
<p>In addition to the SQL transaction, however, is the concept of an XA transaction, which is for distributed transaction coordination.  The <a href="http://en.wikipedia.org/wiki/X/Open_XA">XA protocol</a> is a <a href="http://en.wikipedia.org/wiki/Two-phase_commit">two-phase commit protocol</a> because it implements a PREPARE step before a COMMIT occurs.  This XA API is exposed via two other classes, <tt>plugin::XaResourceManager</tt> and <tt>plugin::XaStorageEngine</tt>.  <tt>plugin::XaResourceManager</tt> derived classes implement the resource manager API of the XA protocol.  <tt>plugin::XaStorageEngine</tt> is a storage engine subclass which, while also implementing SQL transactions, also implements XA transactions.</p>
<p>Here is the <tt>plugin::XaResourceManager</tt> class:</p>

<div class="wp_syntax"><div class="code"><pre class="cpp" style="font-family:monospace;"><span style="color: #ff0000; font-style: italic;">/**
 * An abstract interface class which exposes the participation
 * of implementing classes in distributed transactions in the XA protocol.
 */</span>
<span style="color: #0000ff;">class</span> XaResourceManager
<span style="color: #008000;">&#123;</span>
<span style="color: #0000ff;">public</span><span style="color: #008080;">:</span>
  XaResourceManager<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span> <span style="color: #008000;">&#123;</span><span style="color: #008000;">&#125;</span>
  <span style="color: #0000ff;">virtual</span> ~XaResourceManager<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span> <span style="color: #008000;">&#123;</span><span style="color: #008000;">&#125;</span>
...
<span style="color: #0000ff;">private</span><span style="color: #008080;">:</span>
  <span style="color: #ff0000; font-style: italic;">/**
   * Does the COMMIT stage of the two-phase commit.
   */</span>
  <span style="color: #0000ff;">virtual</span> <span style="color: #0000ff;">int</span> doXaCommit<span style="color: #008000;">&#40;</span>Session <span style="color: #000040;">*</span>session, <span style="color: #0000ff;">bool</span> normal_transaction<span style="color: #008000;">&#41;</span><span style="color: #000080;">=</span> <span style="color: #0000dd;">0</span><span style="color: #008080;">;</span>
  <span style="color: #ff0000; font-style: italic;">/**
   * Does the ROLLBACK stage of the two-phase commit.
   */</span>
  <span style="color: #0000ff;">virtual</span> <span style="color: #0000ff;">int</span> doXaRollback<span style="color: #008000;">&#40;</span>Session <span style="color: #000040;">*</span>session, <span style="color: #0000ff;">bool</span> normal_transaction<span style="color: #008000;">&#41;</span><span style="color: #000080;">=</span> <span style="color: #0000dd;">0</span><span style="color: #008080;">;</span>
  <span style="color: #ff0000; font-style: italic;">/**
   * Does the PREPARE stage of the two-phase commit.
   */</span>
  <span style="color: #0000ff;">virtual</span> <span style="color: #0000ff;">int</span> doXaPrepare<span style="color: #008000;">&#40;</span>Session <span style="color: #000040;">*</span>session, <span style="color: #0000ff;">bool</span> normal_transaction<span style="color: #008000;">&#41;</span><span style="color: #000080;">=</span> <span style="color: #0000dd;">0</span><span style="color: #008080;">;</span>
  <span style="color: #ff0000; font-style: italic;">/**
   * Rolls back a transaction identified by a XID.
   */</span>
  <span style="color: #0000ff;">virtual</span> <span style="color: #0000ff;">int</span> doXaRollbackXid<span style="color: #008000;">&#40;</span>XID <span style="color: #000040;">*</span>xid<span style="color: #008000;">&#41;</span><span style="color: #000080;">=</span> <span style="color: #0000dd;">0</span><span style="color: #008080;">;</span>
  <span style="color: #ff0000; font-style: italic;">/**
   * Commits a transaction identified by a XID.
   */</span>
  <span style="color: #0000ff;">virtual</span> <span style="color: #0000ff;">int</span> doXaCommitXid<span style="color: #008000;">&#40;</span>XID <span style="color: #000040;">*</span>xid<span style="color: #008000;">&#41;</span><span style="color: #000080;">=</span> <span style="color: #0000dd;">0</span><span style="color: #008080;">;</span>
  <span style="color: #ff0000; font-style: italic;">/**
   * Notifies the transaction manager of any transactions
   * which had been marked prepared but not committed at
   * crash time or that have been heurtistically completed
   * by the storage engine.
   *
   * @param[out] Reference to a vector of XIDs to add to
   *
   * @retval
   *  Returns the number of transactions left to recover
   *  for this engine.
   */</span>
  <span style="color: #0000ff;">virtual</span> <span style="color: #0000ff;">int</span> doXaRecover<span style="color: #008000;">&#40;</span>XID <span style="color: #000040;">*</span> append_to, <span style="color: #0000ff;">size_t</span> len<span style="color: #008000;">&#41;</span><span style="color: #000080;">=</span> <span style="color: #0000dd;">0</span><span style="color: #008080;">;</span>
<span style="color: #008000;">&#125;</span><span style="color: #008080;">;</span></pre></div></div>

<p>and here is the <tt>plugin::XaStorageEngine</tt> class:</p>

<div class="wp_syntax"><div class="code"><pre class="cpp" style="font-family:monospace;"><span style="color: #ff0000; font-style: italic;">/**
 * A type of storage engine which supports distributed
 * transactions in the XA protocol.
 */</span>
<span style="color: #0000ff;">class</span> XaStorageEngine <span style="color: #008080;">:</span><span style="color: #0000ff;">public</span> TransactionalStorageEngine,
                       <span style="color: #0000ff;">public</span> XaResourceManager
<span style="color: #008000;">&#123;</span>
<span style="color: #0000ff;">public</span><span style="color: #008080;">:</span>
  XaStorageEngine<span style="color: #008000;">&#40;</span><span style="color: #0000ff;">const</span> std<span style="color: #008080;">::</span><span style="color: #007788;">string</span> name_arg,
                  <span style="color: #0000ff;">const</span> std<span style="color: #008080;">::</span><span style="color: #007788;">bitset</span><span style="color: #000080;">&lt;</span>HTON_BIT_SIZE<span style="color: #000080;">&gt;</span> <span style="color: #000040;">&amp;</span>flags_arg<span style="color: #000080;">=</span> HTON_NO_FLAGS<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
&nbsp;
  <span style="color: #0000ff;">virtual</span> ~XaStorageEngine<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
  ...
<span style="color: #008000;">&#125;</span><span style="color: #008080;">;</span></pre></div></div>

<p>Pretty clear.  A <tt>plugin::XaStorageEngine</tt> inherits from both <tt>plugin::TransactionStorageEngine</tt> and <tt>plugin::XaResourceManager</tt> because it implements both SQL transactions and XA transactions.  The <tt>InnobaseEngine</tt> is a plugin which inherits from <tt>plugin::XaStorageEngine</tt> because InnoDB supports SQL transactions as well as XA.</p>
<h3>Explicit Statement and Transaction Boundaries</h3>
<p>The second major change I made addressed the problem that Mark Callaghan noted in asking why finding out when a statement starts and ends was so obscure.  I added two new methods to <tt>plugin::StorageEngine</tt> called <tt>doStartStatement()</tt> and <tt>doEndStatement()</tt>.  The kernel now explicitly tells storage engines when a SQL statement starts and ends.  This happens before any calls to <tt>Cursor::external_lock()</tt> happen, and there are no exception cases.  In addition, the kernel now always tells transactional storage engines when a new SQL transaction is starting.  It does this via an explicit call to <tt>plugin::TransactionalStorageEngine::doStartTransaction()</tt>.  No exceptions, and yes, even for DDL operations.</p>
<p>What this means is that for a transactional storage engine, it no longer needs to &#8220;count the calls to Cursor::external_lock()&#8221; in order to know when a statement or transaction starts and ends.  For a SQL transaction, this means that there is a clear code call path and there is no need for the storage engine to track whether the session is in AUTOCOMMIT mode or not.  The kernel does all that work for the storage engine.  Imagine a Session executes a single INSERT statement against an InnoDB table while in AUTOCOMMIT mode.  This is what the call path looks like:</p>
<pre>
 drizzled::Statement::Insert::execute()
 |
 -> drizzled::mysql_lock_tables()
    |
    -> drizzled::TransactionServices::registerResourceForTransaction()
       |
       -> drizzled::plugin::TransactionalStorageEngine::startTransaction()
          |
          -> InnobaseEngine::doStartTransaction()
       |
       -> drizzled::plugin::StorageEngine::startStatement()
          |
          -> InnobaseEngine::doStartStatement()
       |
       -> drizzled::plugin::StorageEngine::getCursor()
          |
          -> drizzled::Cursor::write_row()
             |
             -> InnobaseCursor::write_row()
       |
       -> drizzled::TransactionServices::autocommitOrRollback()
          |
          -> drizzled::plugin::TransactionStorageEngine::commit()
             |
             -> InnobaseEngine::doCommit()
</pre>
<p>I think this will come as a welcome change to storage engine developers working with Drizzle.</p>
<h3>No More Need for Engine to Call <tt>trans_register_ha()</tt></h3>
<p>There was an interesting comment in the <a href="http://bazaar.launchpad.net/~mysql/mysql-server/mysql-next-mr/annotate/head%3A/sql/handler.cc">original documentation</a> for the transaction processing code.  It read:</p>
<blockquote><p>
  Roles and responsibilities<br />
  &#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8211;</p>
<p>  The server has no way to know that an engine participates in<br />
  the statement and a transaction has been started<br />
  in it unless the engine says so. Thus, in order to be<br />
  a part of a transaction, the engine must &#8220;register&#8221; itself.<br />
  This is done by invoking trans_register_ha() server call.<br />
  Normally the engine registers itself whenever handler::external_lock()<br />
  is called. trans_register_ha() can be invoked many times: if<br />
  an engine is already registered, the call does nothing.<br />
  In case autocommit is not set, the engine must register itself<br />
  twice &#8212; both in the statement list and in the normal transaction<br />
  list.
</p></blockquote>
<p>That comment, and I&#8217;ve read it dozens of times, always seemed strange to me.  I mean, does the server <em>really not know</em> that an engine participates in a statement or transaction unless the engine tells it?  Of course not.</p>
<p>So, I removed the need for a storage engine to &#8220;register itself&#8221; with the kernel.  Now, the transaction manager inside the Drizzle kernel (implemented in the TransactionServices component) automatically monitors which engines are participating in an SQL transaction and the engine doesn&#8217;t need to do anything to register itself.</p>
<p>In addition, due to the break-up of the <tt>plugin::StorageEngine</tt> class and the XA API into <tt>plugin::XaResourceManager</tt>, Drizzle&#8217;s transaction manager can now coordinate XA transactions from <em>plugins other than storage engines</em>.  Yep, that&#8217;s right.  Any plugin which implements <tt>plugin::XaResourceManager</tt> can participate in an XA transaction and Drizzle will act as the transaction manager.  What&#8217;s the first plugin that will do this?  Drizzle&#8217;s transaction log.  The transaction log isn&#8217;t a storage engine, but it <em>is</em> able to participate in an XA transaction, so it will implement <tt>plugin::XaResourceManager</tt> but not <tt>plugin::StorageEngine</tt>.</p>
<h3>Performance Impact of Code Changes</h3>
<p>So, that &#8220;yet another overhead&#8221; Monty talked about in the quote above?  There wasn&#8217;t any noticeable impact in performance or scalability at all.  So much for optimize-first coding.</p>
<h3>What&#8217;s Next?</h3>
<p>The next thing I&#8217;m working on is removing the notion of the &#8220;statement transaction&#8221;, which is also a historical by-product, this time because of BerkeleyDB.  Gee, I&#8217;ve got a lot of work ahead of me&#8230;</p>
<p><sup>[1]</sup> Actually, there is a way that a transaction that was rolled back can get written to the transaction log.  For bulk operations, the server can cut a Transaction message into multiple segments, and if the SQL transaction is rolled back, a special RollbackStatement message is written to the transaction log.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.joinfu.com/2010/03/recent-work-on-improving-drizzles-storage-engine-api/feed/</wfw:commentRss>
		<slash:comments>15</slash:comments>
		</item>
	</channel>
</rss>

<!-- Dynamic page generated in 0.821 seconds. -->
<!-- Cached page generated by WP-Super-Cache on 2010-09-06 12:32:33 -->
