<?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/"
	xmlns:georss="http://www.georss.org/georss" xmlns:geo="http://www.w3.org/2003/01/geo/wgs84_pos#" xmlns:media="http://search.yahoo.com/mrss/"
	>

<channel>
	<title>Jeremy Cole</title>
	<atom:link href="http://blog.jcole.us/feed/" rel="self" type="application/rss+xml" />
	<link>http://blog.jcole.us</link>
	<description>Geek, electronics nerd, database nerd, father of three.</description>
	<lastBuildDate>Wed, 22 May 2013 06:09:37 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.com/</generator>
<cloud domain='blog.jcole.us' port='80' path='/?rsscloud=notify' registerProcedure='' protocol='http-post' />
<image>
		<url>http://1.gravatar.com/blavatar/7459ccc490ba93bfffc5f91293d1b51f?s=96&#038;d=http%3A%2F%2Fs2.wp.com%2Fi%2Fbuttonw-com.png</url>
		<title>Jeremy Cole</title>
		<link>http://blog.jcole.us</link>
	</image>
	<atom:link rel="search" type="application/opensearchdescription+xml" href="http://blog.jcole.us/osd.xml" title="Jeremy Cole" />
	<atom:link rel='hub' href='http://blog.jcole.us/?pushpress=hub'/>
		<item>
		<title>InnoDB Tidbit: The doublewrite buffer wastes 32 pages (512 KiB)</title>
		<link>http://blog.jcole.us/2013/05/05/innodb-tidbit-the-doublewrite-buffer-wastes-32-pages-512-kib/</link>
		<comments>http://blog.jcole.us/2013/05/05/innodb-tidbit-the-doublewrite-buffer-wastes-32-pages-512-kib/#comments</comments>
		<pubDate>Sun, 05 May 2013 19:19:05 +0000</pubDate>
		<dc:creator>Jeremy Cole</dc:creator>
				<category><![CDATA[InnoDB]]></category>
		<category><![CDATA[MySQL]]></category>

		<guid isPermaLink="false">http://blog.jcole.us/?p=1088</guid>
		<description><![CDATA[In my ongoing quest to completely understand InnoDB&#8217;s data storage, I came across a quite small and inconsequential waste, which is nevertheless fun to write about. I noticed the following block of pages which were allocated very early in the ibdata1 system tablespace but apparently unused (unnecessary lines removed from output): $ innodb_space -f ibdata1 [&#8230;]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=blog.jcole.us&#038;blog=30683698&#038;post=1088&#038;subd=jcoledotus&#038;ref=&#038;feed=1" width="1" height="1" />]]></description>
				<content:encoded><![CDATA[<p>In my ongoing <a href="http://blog.jcole.us/innodb/">quest to completely understand InnoDB&#8217;s data storage</a>, I came across a quite small and inconsequential waste, which is nevertheless fun to write about. I noticed the following block of pages which were allocated very early in the <tt>ibdata1</tt> system tablespace but apparently unused (unnecessary lines removed from output):</p>
<blockquote><pre>
$ innodb_space -f ibdata1 space-page-type-regions

start       end         count       type                
<strong>13          44          32          ALLOCATED           </strong>
</pre>
</blockquote>
<h2>Background on the doublewrite buffer</h2>
<p>Most people using InnoDB have heard of the &#8220;doublewrite buffer&#8221;&mdash;part of InnoDB&#8217;s page flushing strategy. The doublewrite buffer is used as a &#8220;scratch area&#8221; to write (by default) 128 pages contiguously before flushing them out to their final destinations (which may be up to 128 different writes). The MySQL manual says, in <a href="http://dev.mysql.com/doc/refman/5.5/en/innodb-disk-io.html">&#8220;InnoDB Disk I/O&#8221;</a>:</p>
<blockquote><p>
InnoDB uses a novel file flush technique involving a structure called the doublewrite buffer. It adds safety to recovery following an operating system crash or a power outage, and improves performance on most varieties of Unix by reducing the need for fsync() operations.</p>
<p>Before writing pages to a data file, InnoDB first writes them to a contiguous tablespace area called the doublewrite buffer. Only after the write and the flush to the doublewrite buffer has completed does InnoDB write the pages to their proper positions in the data file. If the operating system crashes in the middle of a page write, InnoDB can later find a good copy of the page from the doublewrite buffer during recovery.
</p></blockquote>
<h2>The doublewrite buffer needs to be accounted for, too</h2>
<p>Normally the doublewrite buffer consists of two extents, each of which is 64 contiguous pages (1 MiB), for a total of 128 pages, or 2 MiB. However, InnoDB can&#8217;t just blindly borrow those two extents; it must account for them in the space file. To do this, it creates a file segment (aka Fseg) and uses an Inode to point to it. In <a href="http://blog.jcole.us/2013/01/04/page-management-in-innodb-space-files/">Page management in InnoDB space files</a> I described how file segments contain:</p>
<ul>
<li>An array of up to 32 individually-allocated &#8220;fragment&#8221; pages</li>
<li>A list of &#8220;full&#8221; extents (no pages free)</li>
<li>A list of &#8220;not full&#8221; extents (partially allocated)</li>
<li>A list of &#8220;free&#8221; extents (no pages allocated)</li>
</ul>
<h2>Causing full extents to be allocated</h2>
<p>Allocations to a file segment will <em>always</em> fill up the fragment array before allocating complete extents. The doublewrite buffer is strangely not special in this case. The code which allocates it uses the following loop in <a href="https://github.com/jeremycole/mysql/blob/mysql-5.5.30/storage/innobase/trx/trx0sys.c#L335"><tt>trx/trx0sys.c</tt> at line 335</a>:</p>
<blockquote><pre>
for (i = 0; i &lt; 2 * TRX_SYS_DOUBLEWRITE_BLOCK_SIZE
       + FSP_EXTENT_SIZE / 2; i++) {
</pre>
</blockquote>
<p>This is unfortunately written without any comments of note, but it is allocating a total of 160 pages:</p>
<ul>
<li><tt>FSP_EXTENT_SIZE / 2</tt> &rarr; <tt>64 / 2</tt> &rarr; 32 pages</li>
<li><tt>2 * TRX_SYS_DOUBLEWRITE_BLOCK_SIZE</tt> &rarr; <tt>2 * 64</tt> &rarr; 128 pages</li>
</ul>
<p>The initial 32 pages allocated are there purely just to cause the fragment array to be filled up thus forcing the <tt>fseg_alloc_free_page</tt> calls that follow to start allocating complete extents for the remaining 128 pages (that the doublewrite buffer actually needs). The code then checks <em>which</em> extents were allocated and adds the initial page numbers for those extents to the <tt>TRX_SYS</tt> header as the doublewrite buffer allocation. In a typical system, InnoDB would allocate the following pages:</p>
<ul>
<li>Fragment pages 13-44 &mdash; Perpetually unused fragment pages, but left allocated to the file segment for the doublewrite buffer.</li>
<li>Extent starting at page 64, ending at page 127 &mdash; Block 1 of the doublewrite buffer in practice.</li>
<li>Extent starting at page 128, ending at page 191 &mdash; Block 2 of the doublewrite buffer in practice.</li>
</ul>
<h2>Using <tt>innodb_ruby</tt> to dump file segments (by inode)</h2>
<p>I recently added a new <tt>space-inodes-detail</tt> and <tt>space-inodes-summary</tt> modes to <a href="https://github.com/jeremycole/innodb_ruby">the <tt>innodb_space</tt> program in <tt>innodb_ruby</tt></a> which can handily show exactly which pages and extents are allocated to a given file segment (trimmed for clarity and reformatted for line wrap; normally printed on a single long line):</p>
<blockquote><pre>
$ innodb_space -f ibdata1 space-inodes-detail

INODE fseg_id=15, pages=160,
  frag=32 pages (13, 14, ..., 43, 44),
  full=2 extents (64-127, 128-191),
  not_full=0 extents () (0/0 pages used),
  free=0 extents ()
</pre>
</blockquote>
<p>Here you can clearly see the two complete extents in the file segment&#8217;s &#8220;full&#8221; list, along with the 32 fragment pages.</p>
<h2>Conclusions</h2>
<p>There are a few ways this could have been avoided, such as freeing the individual pages after the two extents were allocated, or adding a special &#8220;no fragments&#8221; allocation method. However, as I said at the start it is pretty inconsequential, as it amounts to only 512 KiB per installation. The code could definitely use a rewrite for clarity though, given the nuanced behavior. It could also stand to use one of the existing defines such as <tt>FSEG_FRAG_ARR_N_SLOTS</tt> or <tt>FSEG_FRAG_LIMIT</tt> rather than repeating the basically unexplained calculation <tt>FSP_EXTENT_SIZE / 2</tt>. Additionally rewriting it to use a more meaningful loop structure would be helpful; there&#8217;s no reason it needs to allocate all three sets of pages in the same <tt>for</tt> loop (especially without comments).</p>
<br />  <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=blog.jcole.us&#038;blog=30683698&#038;post=1088&#038;subd=jcoledotus&#038;ref=&#038;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://blog.jcole.us/2013/05/05/innodb-tidbit-the-doublewrite-buffer-wastes-32-pages-512-kib/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/37cd63a9fd0344804fd6a991a55c283a?s=96&#38;d=http%3A%2F%2F0.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D96&#38;r=R" medium="image">
			<media:title type="html">jeremycole</media:title>
		</media:content>
	</item>
		<item>
		<title>How does InnoDB behave without a Primary Key?</title>
		<link>http://blog.jcole.us/2013/05/02/how-does-innodb-behave-without-a-primary-key/</link>
		<comments>http://blog.jcole.us/2013/05/02/how-does-innodb-behave-without-a-primary-key/#comments</comments>
		<pubDate>Fri, 03 May 2013 05:18:27 +0000</pubDate>
		<dc:creator>Jeremy Cole</dc:creator>
				<category><![CDATA[InnoDB]]></category>
		<category><![CDATA[MySQL]]></category>

		<guid isPermaLink="false">http://blog.jcole.us/?p=1060</guid>
		<description><![CDATA[This afternoon, Arjen Lentz and I were discussing InnoDB&#8217;s behavior without a declared PRIMARY KEY, and the topic felt interesting enough and undocumented enough to warrant its own short post. Background on InnoDB clustered keys In The physical structure of InnoDB index pages I described how &#8220;Everything is an index in InnoDB&#8221;. This means that [&#8230;]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=blog.jcole.us&#038;blog=30683698&#038;post=1060&#038;subd=jcoledotus&#038;ref=&#038;feed=1" width="1" height="1" />]]></description>
				<content:encoded><![CDATA[<p>This afternoon, <a href="https://twitter.com/arjenlentz">Arjen Lentz</a> and I were discussing InnoDB&#8217;s behavior without a declared <tt>PRIMARY KEY</tt>, and the topic felt interesting enough and undocumented enough to warrant its own short post. </p>
<h2>Background on InnoDB clustered keys</h2>
<p>In <a href="http://blog.jcole.us/2013/01/07/the-physical-structure-of-innodb-index-pages/">The physical structure of InnoDB index pages</a> I described how &#8220;Everything is an index in InnoDB&#8221;. This means that InnoDB must always have a &#8220;cluster key&#8221; for each table, which is normally the <tt>PRIMARY KEY</tt>. The manual has this to say in <a href="http://dev.mysql.com/doc/refman/5.5/en/innodb-index-types.html">Clustered and Secondary Indexes</a>:</p>
<blockquote><p>
If the table has no <tt>PRIMARY KEY</tt> or suitable <tt>UNIQUE</tt> index, InnoDB internally generates a hidden clustered index on a synthetic column containing row ID values. The rows are ordered by the ID that InnoDB assigns to the rows in such a table. The row ID is a 6-byte field that increases monotonically as new rows are inserted. Thus, the rows ordered by the row ID are physically in insertion order.
</p></blockquote>
<p>I had previously assumed this meant that an invisible column would be used along with the same sequence generation code <a href="http://dev.mysql.com/doc/refman/5.5/en/innodb-auto-increment-handling.html">that is used to implement <tt>auto_increment</tt></a> (which itself has some scalability issues). However the reality is that they are completely different implementations.</p>
<h2>Implementation of implicit Row IDs</h2>
<p>How this is <em>actually</em> implemented is, as the manual says, if a table is declared with no <tt>PRIMARY KEY</tt> and no non-nullable <tt>UNIQUE KEY</tt>, InnoDB will automatically add a 6-byte (48-bit) integer column called <tt>ROW_ID</tt> to the table, and cluster the data based on that column. The column won&#8217;t be accessible to any queries nor usable for anything internally such as row-based replication.</p>
<p>What the manual doesn&#8217;t mention is that all tables using such <tt>ROW_ID</tt> columns share the same <strong>global</strong> sequence counter (the manual says &#8220;increases monotonically&#8221; and doesn&#8217;t clarify), which is part of the data dictionary. The maximum used value for all row IDs (well, technically the next ID to be used) is <a href="http://blog.jcole.us/2013/01/03/the-basics-of-innodb-space-file-layout/">stored in the system tablespace</a> (e.g. <tt>ibdata1</tt>) in page 7 (type <tt>SYS</tt>), within the data dictionary header (field <tt>DICT_HDR_ROW_ID</tt>).</p>
<p>This global sequence counter is protected by <tt>dict_sys-&gt;mutex</tt>, even for incrementing (as opposed to using atomic increment). The implementation is in <tt>include/dict0boot.ic</tt> (many blank lines deleted):</p>
<blockquote><pre>
    38  UNIV_INLINE
    39  row_id_t
    40  dict_sys_get_new_row_id(void)
    41  /*=========================*/
    42  {
    43          row_id_t        id;
    44  
    45          mutex_enter(&amp;(dict_sys-&gt;mutex));
    47          id = dict_sys-&gt;row_id;
    49          if (0 == (id % DICT_HDR_ROW_ID_WRITE_MARGIN)) {
    51                  dict_hdr_flush_row_id();
    52          }
    54          dict_sys-&gt;row_id++;
    56          mutex_exit(&amp;(dict_sys-&gt;mutex));
    57  
    58          return(id);
    59  }
</pre>
</blockquote>
<p>(You may also notice that this code lacks any protection for overflowing the 48 bits allotted to row IDs. That is unnecessarily sloppy coding, but even at a continuous 1 million inserts per second [which is probably a bit optimistic ;)] it would take about 9 years to exhaust the ID space. I guess that&#8217;s okay.)</p>
<h2>Ensuring non-conflicting IDs are generated</h2>
<p>The counter is flushed to disk every 256th ID generated (the define <tt> DICT_HDR_ROW_ID_WRITE_MARGIN</tt> above), by modifying the value in the <tt>SYS</tt> data dictionary page, which is logged to the transaction log. On startup, InnoDB will increase the <tt>DICT_HDR_ROW_ID</tt> stored on disk by at least 256, and at most 511. This ensures that any IDs generated will have been less than the new starting value, and thus there will not be any conflicts.</p>
<h2>Performance and contention implications</h2>
<p>Given how much other code within InnoDB is protected by <tt>dict_sys-&gt;mutex</tt> I think it&#8217;s fair to say any tables with an implicit clustered key (<tt>ROW_ID</tt>) could expect to experience random insert stalls during operations like dropping (unrelated) tables. Parallel insertion into multiple tables with implicit keys could be performance-constrained, as it will be serialized on both the shared mutex and cache contention for the shared counter variable. Additionally, every 256th value generated will cause a log write (and flush) for the <tt>SYS</tt> page modification, regardless of whether the transaction has committed yet (or ever will).</p>
<br />  <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=blog.jcole.us&#038;blog=30683698&#038;post=1060&#038;subd=jcoledotus&#038;ref=&#038;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://blog.jcole.us/2013/05/02/how-does-innodb-behave-without-a-primary-key/feed/</wfw:commentRss>
		<slash:comments>8</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/37cd63a9fd0344804fd6a991a55c283a?s=96&#38;d=http%3A%2F%2F0.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D96&#38;r=R" medium="image">
			<media:title type="html">jeremycole</media:title>
		</media:content>
	</item>
		<item>
		<title>MySQL Community Contributor of the Year 2013</title>
		<link>http://blog.jcole.us/2013/04/25/mysql-community-contributor-of-the-year-2013/</link>
		<comments>http://blog.jcole.us/2013/04/25/mysql-community-contributor-of-the-year-2013/#comments</comments>
		<pubDate>Thu, 25 Apr 2013 21:07:24 +0000</pubDate>
		<dc:creator>Jeremy Cole</dc:creator>
				<category><![CDATA[MySQL]]></category>
		<category><![CDATA[MySQL Conference]]></category>

		<guid isPermaLink="false">http://blog.jcole.us/?p=1049</guid>
		<description><![CDATA[First of all, thank you to everyone who nominated me, voted for me, and to those of you who shared kind words with me and congratulated me. It&#8217;s humbling to have been awarded one of the &#8220;MySQL Community Contributor of the Year&#8221; awards for 2013. Many people have asked or wondered without asking why I [&#8230;]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=blog.jcole.us&#038;blog=30683698&#038;post=1049&#038;subd=jcoledotus&#038;ref=&#038;feed=1" width="1" height="1" />]]></description>
				<content:encoded><![CDATA[<p>First of all, thank you to everyone who nominated me, voted for me, and to those of you who shared kind words with me and congratulated me. It&#8217;s humbling to have been awarded one of the &#8220;MySQL Community Contributor of the Year&#8221; awards for 2013. Many people have asked or wondered without asking <em>why</em> I do what I do, and how I got here. Given the occasion, I thought I would share some thoughts on that.</p>
<h2>Early days as a user in web development</h2>
<p>I started working with MySQL (and before that, mSQL) back in 1998 while working with a web development company. MySQL worked quite well (and I pretty quickly forgot about mSQL), and I started to learn more and more about it. As many new users at the time, I hit a few bugs or quirks, and poked at the code from time to time to understand what was going on. I continued just being a user of MySQL into 1999, and started to build more and more complex applications. </p>
<h2>A first bug report</h2>
<p>In October 1999, I encountered a crashing bug (a floating point exception which wasn&#8217;t caught) with <tt>SELECT FLOOR(POW(2,63))</tt> on MySQL 3.22 and FreeBSD 3.3, and <a href="http://lists.mysql.com/mysql/18592">I made my first MySQL bug report</a> by emailing the mailing list. After a short discussion with Sinisa Milivojevic and Monty Widenius, <a href="http://lists.mysql.com/mysql/18592">Monty agreed to fix the bug</a>. Of course I watched with bright eyes, I read the code for the fix, and I worked to understand it.</p>
<h2>The mailing list and IRC drew me in</h2>
<p>I was hooked. I found an actual problem, as a 17 year old hacker sitting in Kansas, and I worked with these nice folks who I&#8217;ve never met, halfway around the world in Cyprus and Finland, and they agreed to do work <em>for me</em> to fix it, and they didn&#8217;t even complain. They were genuinely happy to help me. </p>
<p>I joined the mailing list to report that bug, but I stayed subscribed to it and read every mail. I browsed the archives and learned how the (tiny) community worked at the time. I joined the <tt>#mysql</tt> IRC channel on EFnet and started listening there as well.</p>
<h2>Helping out on the mailing list and on IRC</h2>
<p>While lurking on the mailing list and on IRC, I quickly realized that there were a lot of people with problems and questions that I could help out with. I knew some of the answers! I answered things where I knew the answer, and I worked to answer questions that I didn&#8217;t know. Through experimentation and reading the MySQL documentation and source code to solve other people&#8217;s problems, I learned an amazing amount.</p>
<h2>Improving the documentation</h2>
<p>In the process of doing web development work, and of helping out answering other people&#8217;s questions, I found that the MySQL manual was moderately technically complete, but very messy, sometimes buggy, and strangely worded. I poked around until I could figure out how the manual itself worked. I learned about this weird Texinfo format it was written in. Once I got things to build, I undertook an initial editing of the MySQL manual by reading through the entire Texinfo file, fixing typos and rewording things. I checked examples in the manual against an actual server and cleaned up broken examples and incomplete documentation.</p>
<h2>Hey, this is more fun than my real job</h2>
<p>I was then working at a web development company in Nashville, and realized that I wasn&#8217;t very happy doing that work. At the same time, the company started to melt down, and I began interviewing elsewhere. I spent more and more time doing work on MySQL (sometimes instead of work I should&#8217;ve been doing). Contributing to MySQL and working with the MySQL community made me much happier than any other work I had done so far.</p>
<h2>Monty??? Hire me!</h2>
<p>I don&#8217;t actually remember how I initially contacted Monty about this (although he probably still has the email archives), but he and I exchanged emails. He offered that I should come to an upcoming developer meeting in Monterey, California in July of 2000, coinciding with OSCON 2000. I jumped at the chance. I mentioned the invitation to Indrek Siitan on IRC, and he invited me to join a planned road trip to Monterey with some of the earliest MySQL employees: himself, Matt Wagner, and Tim Smith.</p>
<h2>No interstates, no hotels, nothing but love</h2>
<p>Although I wasn&#8217;t an employee yet, and had never met any of them in person, Matt Wagner drove from Minnesota and Tim Smith drove from North Carolina to my house in Tennessee. We piled in Matt&#8217;s pickup truck and drove from there down to Louisiana to pick up Indrek. The four of us drove in two cars from New Orleans to Monterey for about 10 days, with a plan to use no interstates&mdash;only highways&mdash;and camp each night.</p>
<p>I was an almost completely broke and unemployed kid, and they paid for almost everything and took me along&mdash;as a friend&mdash;across the entire country. I got to know my first few MySQL employees through those many hours in the car talking about life, technology, MySQL, and anything that came up. We had a lot of fun and they showed literally nothing but love. We all became fast friends and they accepted me without hesitation. This became my canonical example of the MySQL community, and still is, even to this day.</p>
<h2>Meeting the team</h2>
<p>We arrived in Monterey and I (a random non-employee) got to sit in all of the internal company meetings and technical discussions. I got to have a say in how MySQL was being made, and I got to argue with the very creators of MySQL. They not only listened, but respected me and valued my opinion. I mostly just listened through these meetings and got to know everyone, but this was an amazing experience.</p>
<p>At some point later in the meeting, Monty and I met, and he offered me a job at MySQL. I accepted it without hesitation and jumped into my official MySQL career head-first. My first paycheck was wired directly from Monty&#8217;s personal bank account in Finland, because there was some trouble setting up payroll for me, and Monty was concerned about making sure I got paid quickly.</p>
<h2>Documenting MySQL, and a foray into Swedish and Swenglish</h2>
<p>My first tasks were all about making the MySQL documentation better. I made several complete passes through the manual, reading and correcting it. I did some fairly major restructuring of the order of the sections, and normalized the structure as much as possible. (I also got quite good at reading Texinfo documents unformatted and visualizing the formatting.)</p>
<p>I started studying Swedish in order to understand all of the source code comments, variable and function names, and the Swedish error messages. I translated many of these remnants of Swedish and Swenglish as some of my first contributions to the actual codebase, and I did a lot of other easy formatting and fixing work while learning how the code worked. I figured out where all the functions and syntax were defined in order to make sure all elements of the syntax were documented.</p>
<h2>A new life as a MySQLer</h2>
<p>While at MySQL, I initially worked on documentation and helped out with support, and when customers needed help in person, I flew around and consulted with them. Kaj Arnö&#8217;s company Polycon&#8217;s training group was acquired by MySQL, and I started helping out with that training. They needed someone to teach training classes, so I started doing that too, eventually managing the whole group.</p>
<h2>Ever present in the MySQL world</h2>
<p>Since then I have had the opportunity to be a part of a lot of amazing things, and have made sure that every new opportunity and every new job undertaken gives me ample opportunity and motivation to continue being part of the MySQL community. Why? It&#8217;s just a part of who I am. I have some gifts for communication, making dense material understandable, understanding the needs of database users, and building scalable and manageable database systems. I want to share with others and give back to the community to give them the same or better opportunities as I was given.</p>
<h2>Thanks to you all</h2>
<p>Where I am in the MySQL community, and where I am in my life and career would not be possible without amazing examples given to me by a bunch of amazing people. There&#8217;s not any one mentor who was my sole example, but rather a community of dozens of individuals, each of whom I admire and have aspired to learn various things from. I&#8217;d like to offer special thanks and acknowledgement to the following folks though:</p>
<ul>
<li><strong>Monty Widenius</strong> &mdash; Of course, Monty was the father of it all, but he has also acted as a father to me personally, taken care of me, and invited me into his home and his family. He has a huge heart and is both a personal and technical mentor to me.</li>
<li><strong>Matt Wagner, Indrek Siitan, and Tim Smith</strong> &mdash; Matt, Indrek, and Tim offered a great example of how a team can be a family, and welcomed me into the community, into their lives, and into the company in an amazing fashion. In addition, they were also great technical mentors and taught me a lot about MySQL.</li>
<li><strong>Sinisa Milivojevic, Sasha Pachev, Jani Tolonen, Miguel Solórzano, Tõnu Samuel, Sergei Golubchik, Paul DuBois, Kaj Arnö, Arjen Lentz, Mårten Mickos, Carsten Pedersen, Zak Greant, David Axmark, Brian Aker</strong> &mdash; These folks are a mix of developers, executives, peers and community, of all backgrounds and experiences. One thing they all have in common is that they helped me to learn what it takes to build software, to run a company, and to be a community. While we haven&#8217;t always gotten along or agreed on everything, I have always respected every one of them and keep track of as many of them as I can.</li>
<li>Countless others in the community &mdash; Others on the mailing lists and IRC, customers, partners, and peers. Thanks for all being here and being awesome!</li>
</ul>
<h2>On the award</h2>
<p>In <a href="http://openlife.cc/blogs/2013/april/mysql-community-awards-2013-and-winners-are">Henrik Ingo&#8217;s words</a>:</p>
<blockquote><p>
Several people nominated Jeremy and indeed he has a long history with MySQL, pretty much back to the first release.</p>
<p>For example, people mentioned Jeremy&#8217;s insights shared on his blog, on issues such as Linux NUMA memory management. His recent work on innodb_ruby has been widely appreciated both for it&#8217;s educational value and perhaps even some potential usefullness.</p>
<p>Most of us will have used the SHOW PROFILE(S) commands created by Jeremy &#8211; and for a long time this was the only community contribution that actually made it into MySQL Server!</p>
<p>His consulting company Proven Scaling used to mirror the MySQL Enterprise binaries that were GPL but not otherwise publicly available. This grew into a historical archive of (almost) all MySQL binaries ever released. Related to his issues with the MySQL Enterprise process, and poor handling of community contributions, Proven Scaling was actually the first company to create a community fork of MySQL known as Dorsal Source.</p>
<p>You might also remember in 2008 Jeremy took a public stand against MySQL&#8217;s plans to offer new backup functionality only as closed source. This resulted in public outcry on Slashdot and elsewhere, and Sun eventually commanded MySQL executives to give up on those plans.</p>
<p>So any way we look at it, over the years he has really contributed a lot and always had the interests of the MySQL Community close to his heart.
</p></blockquote>
<h2>Onwards!</h2>
<p>I look forward to continuing to contribute my efforts and my skills to MySQL, and always making my work available to the community. There&#8217;s a lot of work left to do, and I hope my efforts in that will be useful to many.</p>
<br />  <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=blog.jcole.us&#038;blog=30683698&#038;post=1049&#038;subd=jcoledotus&#038;ref=&#038;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://blog.jcole.us/2013/04/25/mysql-community-contributor-of-the-year-2013/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/37cd63a9fd0344804fd6a991a55c283a?s=96&#38;d=http%3A%2F%2F0.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D96&#38;r=R" medium="image">
			<media:title type="html">jeremycole</media:title>
		</media:content>
	</item>
		<item>
		<title>InnoDB: A journey to the core: At the MySQL Conference</title>
		<link>http://blog.jcole.us/2013/04/17/innodb-a-journey-to-the-core-at-the-mysql-conference/</link>
		<comments>http://blog.jcole.us/2013/04/17/innodb-a-journey-to-the-core-at-the-mysql-conference/#comments</comments>
		<pubDate>Wed, 17 Apr 2013 23:32:13 +0000</pubDate>
		<dc:creator>Jeremy Cole</dc:creator>
				<category><![CDATA[InnoDB]]></category>
		<category><![CDATA[MySQL]]></category>

		<guid isPermaLink="false">http://blog.jcole.us/?p=1041</guid>
		<description><![CDATA[Next week is the Percona Live MySQL Conference and Expo 2013. Davi Arnaut and I are co-presenting InnoDB: A journey to the core, based on my InnoDB blog series by the same name. We will (fairly quickly) cover InnoDB&#8217;s storage formats as described in those posts, but in an interactive format. There will be some [&#8230;]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=blog.jcole.us&#038;blog=30683698&#038;post=1041&#038;subd=jcoledotus&#038;ref=&#038;feed=1" width="1" height="1" />]]></description>
				<content:encoded><![CDATA[<p>Next week is the <a href="http://www.percona.com/live/mysql-conference-2013/">Percona Live MySQL Conference and Expo 2013</a>.</p>
<p><a href="https://twitter.com/darnaut">Davi Arnaut</a> and I are co-presenting <a href="http://www.percona.com/live/mysql-conference-2013/sessions/innodb-journey-core">InnoDB: A journey to the core</a>, based on <a href="http://blog.jcole.us/innodb/">my InnoDB blog series by the same name</a>. We will (fairly quickly) cover InnoDB&#8217;s storage formats as described in those posts, but in an interactive format. There will be some new material that hasn&#8217;t been blogged yet (mostly stuff that is more difficult to explain or has been incompletely described in <a href="https://github.com/jeremycole/innodb_diagrams">innodb_diagrams</a>). Most importantly, Davi and I will be available for questions, and hopefully some of the InnoDB developers will stop by as well!</p>
<p>You might have seen my previous post about <a href="http://blog.jcole.us/2013/04/15/julian-cash-white-background-community-photos-at-percona-live-mysql-conference/">Julian Cash “white background” community photos at Percona Live MySQL Conference</a> &mdash; Take a moment to help out by <a href="http://www.indiegogo.com/projects/385229/emal/3002348">funding Julian&#8217;s photography</a> at the conference, if you can! I&#8217;d really love to see a bunch of new MySQL community photos!</p>
<p>See you there!</p>
<br />  <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=blog.jcole.us&#038;blog=30683698&#038;post=1041&#038;subd=jcoledotus&#038;ref=&#038;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://blog.jcole.us/2013/04/17/innodb-a-journey-to-the-core-at-the-mysql-conference/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/37cd63a9fd0344804fd6a991a55c283a?s=96&#38;d=http%3A%2F%2F0.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D96&#38;r=R" medium="image">
			<media:title type="html">jeremycole</media:title>
		</media:content>
	</item>
		<item>
		<title>Julian Cash &#8220;white background&#8221; community photos at Percona Live MySQL Conference</title>
		<link>http://blog.jcole.us/2013/04/15/julian-cash-white-background-community-photos-at-percona-live-mysql-conference/</link>
		<comments>http://blog.jcole.us/2013/04/15/julian-cash-white-background-community-photos-at-percona-live-mysql-conference/#comments</comments>
		<pubDate>Tue, 16 Apr 2013 00:09:20 +0000</pubDate>
		<dc:creator>Jeremy Cole</dc:creator>
				<category><![CDATA[MySQL]]></category>
		<category><![CDATA[MySQL Conference]]></category>

		<guid isPermaLink="false">http://blog.jcole.us/?p=1028</guid>
		<description><![CDATA[You might have noticed from my profile picture on this blog, as well as on Facebook, Twitter, etc., that I am a fan of Julian Cash&#8216;s photography. If you&#8217;re in the MySQL community, you almost certainly know his photography, both the &#8220;white background&#8221; style and &#8220;light painting&#8221; style. Julian took a bunch of photos of [&#8230;]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=blog.jcole.us&#038;blog=30683698&#038;post=1028&#038;subd=jcoledotus&#038;ref=&#038;feed=1" width="1" height="1" />]]></description>
				<content:encoded><![CDATA[<p>You might have noticed from my profile picture on this blog, as well as on Facebook, Twitter, etc., that I am a fan of <a href="http://jceventphoto.com/">Julian Cash</a>&#8216;s photography.</p>
<p>If you&#8217;re in the MySQL community, you almost certainly know his photography, both the <a href="http://jceventphoto.com/v/mysql/">&#8220;white background&#8221; style</a> and <a href="http://jceventphoto.com/index.html#lightpainting">&#8220;light painting&#8221; style</a>. Julian took a bunch of photos of the MySQL community at conferences a few years ago, but the community has changed tremendously since then, and it&#8217;s time for a whole lot of new ones! I&#8217;ve asked Julian to come to the conference and take a bunch more photos of the MySQL community in his iconic &#8220;white background&#8221; style at the <a href="http://www.percona.com/live/mysql-conference-2013/home">Percona Live MySQL Conference and Expo</a> next week.</p>
<p>In order to be as inclusive as possible, we wanted this to be free for everyone getting their picture taken (come one, come all!) &mdash; however, to make this a success&#8230;</p>
<h2><a href="http://www.indiegogo.com/projects/385229/emal/3002348">We need your help to fund the project on Indiegogo!</a></h2>
<p>If you have the means to fund it<sup>1</sup>, it will certainly help; any amount helps! If you don&#8217;t, that&#8217;s fine as well, and you can absolutely come get your photo taken regardless. If you&#8217;re coming to the conference and want to get your photo taken with Julian, <a href="https://www.facebook.com/events/184523725031188/">join the MySQL Studio Photos @ Percona Live MySQL event</a> on Facebook so you can get updates about the location, schedule, and any changes.</p>
<p>See you there!</p>
<p>&mdash;</p>
<p><sup>1</sup> If you&#8217;re a company and want to do something more exotic than what Indiegogo has listed, feel free to <a href="mailto:jeremy@jcole.us">send me an email</a> and I&#8217;ll put you in touch with Julian to do that!</p>
<br />  <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=blog.jcole.us&#038;blog=30683698&#038;post=1028&#038;subd=jcoledotus&#038;ref=&#038;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://blog.jcole.us/2013/04/15/julian-cash-white-background-community-photos-at-percona-live-mysql-conference/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/37cd63a9fd0344804fd6a991a55c283a?s=96&#38;d=http%3A%2F%2F0.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D96&#38;r=R" medium="image">
			<media:title type="html">jeremycole</media:title>
		</media:content>
	</item>
		<item>
		<title>Power consumption of Dyson Air Multiplier (AM01)</title>
		<link>http://blog.jcole.us/2013/04/12/power-consumption-of-dyson-air-multiplier-am01/</link>
		<comments>http://blog.jcole.us/2013/04/12/power-consumption-of-dyson-air-multiplier-am01/#comments</comments>
		<pubDate>Sat, 13 Apr 2013 01:16:35 +0000</pubDate>
		<dc:creator>Jeremy Cole</dc:creator>
				<category><![CDATA[Electronics]]></category>
		<category><![CDATA[General]]></category>

		<guid isPermaLink="false">http://blog.jcole.us/?p=1022</guid>
		<description><![CDATA[A few weeks ago I got a Dyson Air Multiplier (AM01) for my desk at work. My brother Rob asked me about the power consumption, and I got a chance to measure it. However, since I couldn&#8217;t find any real data about it online I figured I&#8217;d fix that and write it here rather than [&#8230;]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=blog.jcole.us&#038;blog=30683698&#038;post=1022&#038;subd=jcoledotus&#038;ref=&#038;feed=1" width="1" height="1" />]]></description>
				<content:encoded><![CDATA[<p>A few weeks ago I got a <a href="http://www.amazon.com/Dyson-AM01-10-table-fan-Blue/dp/B0076ZGFYW">Dyson Air Multiplier (AM01)</a> for my desk at work. My brother Rob asked me about the power consumption, and I got a chance to measure it. However, since I couldn&#8217;t find any real data about it online I figured I&#8217;d fix that and write it here rather than in email&#8230;</p>
<p>Measured using a <a href="http://www.p3international.com/products/special/p4400/p4400-ce.html">Kill-a-watt</a> at 120.5V:</p>
<ul>
<li><b>Lowest setting</b>: 2-3W</li>
<li><b>Medium setting</b><sup>1</sup>: 13-14W</li>
<li><b>Highest setting</b>: 31W</li>
<li><b>Oscillation enabled</b>: +2W</li>
</ul>
<p>Not bad actually!</p>
<p>&mdash;</p>
<p><sup>1</sup> Since the Dyson is infinitely adjustable, I had to guess at a &#8220;medium&#8221; position by feel. It&#8217;s adjustable in about 1W increments all the way from the lowest to the highest setting.</p>
<br />  <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=blog.jcole.us&#038;blog=30683698&#038;post=1022&#038;subd=jcoledotus&#038;ref=&#038;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://blog.jcole.us/2013/04/12/power-consumption-of-dyson-air-multiplier-am01/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/37cd63a9fd0344804fd6a991a55c283a?s=96&#38;d=http%3A%2F%2F0.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D96&#38;r=R" medium="image">
			<media:title type="html">jeremycole</media:title>
		</media:content>
	</item>
		<item>
		<title>InnoDB bugs found during research on InnoDB data storage</title>
		<link>http://blog.jcole.us/2013/04/09/innodb-bugs-found-during-research-on-innodb-data-storage/</link>
		<comments>http://blog.jcole.us/2013/04/09/innodb-bugs-found-during-research-on-innodb-data-storage/#comments</comments>
		<pubDate>Tue, 09 Apr 2013 07:12:22 +0000</pubDate>
		<dc:creator>Jeremy Cole</dc:creator>
				<category><![CDATA[InnoDB]]></category>
		<category><![CDATA[MySQL]]></category>
		<category><![CDATA[MySQL Bugs]]></category>

		<guid isPermaLink="false">http://blog.jcole.us/?p=1004</guid>
		<description><![CDATA[During the process of researching InnoDB&#8217;s storage formats and building the innodb_ruby and innodb_diagrams projects discussed in my series of InnoDB blog posts, Davi Arnaut and I found a number of InnoDB bugs. I thought I&#8217;d bring up a few of them, as they are fairly interesting. These bugs were largely discoverable due to the [&#8230;]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=blog.jcole.us&#038;blog=30683698&#038;post=1004&#038;subd=jcoledotus&#038;ref=&#038;feed=1" width="1" height="1" />]]></description>
				<content:encoded><![CDATA[<p>During the process of researching InnoDB&#8217;s storage formats and building the <a href="http://github.com/jeremycole/innodb_ruby">innodb_ruby</a> and <a href="http://github.com/jeremycole/innodb_diagrams">innodb_diagrams</a> projects discussed in <a href="http://blog.jcole.us/innodb/">my series of InnoDB blog posts</a>, <a href="http://darnaut.blogspot.com/">Davi Arnaut</a> and I found a number of InnoDB bugs. I thought I&#8217;d bring up a few of them, as they are fairly interesting.</p>
<p>These bugs were largely discoverable due to the <tt>innodb_space</tt> utility making important internal information visible in a way that it had never been visible in the past. Using it to examine production tables provided many leads to go on to find the bugs responsible. When we initially looked at a graphical plot of free space by page produced from <tt>innodb_space</tt> data, we were quite surprised to see so many pages less than half filled (including many nearly empty). After much research we were able to track down all of the causes for the anomalies we discovered.</p>
<h3><a href="http://bugs.mysql.com/bug.php?id=67718">Bug #67718</a>: InnoDB drastically under-fills pages in certain conditions</h3>
<p>Due to overly-aggressive attempts to optimize page split based on insertion order during insertion, InnoDB could leave pages under-filled with as few as one record in each page. This was observed in several production systems in two cases which I believe could be quite common for others:</p>
<ol>
<li><i>Mostly-increasing keys</i> &mdash; Twitter uses <a href="https://github.com/twitter/snowflake">Snowflake</a> for ID generation in a distributed way. Overall it&#8217;s quite nice. Snowflake generates 64-bit mostly-incrementing IDs that contain a timestamp component. Insertion is typically happening via queues and other non-immediate mechanisms, so IDs will find their way to the database slightly out of order.</li>
<li><i>Nearly-ordered keys</i> &mdash; Another schema has a Primary Key and Secondary Key which are similarly&mdash;but not exactly&mdash; ordered. Insertion into a table to copy data in either order ends up nearly ordered by the other key.</li>
</ol>
<p>Both of these circumstances ended up tripping over this bug and causing drastically under-filled pages to appear in production databases, consuming large amounts of disk space.</p>
<h3><a href="http://bugs.mysql.com/bug.php?id=67963">Bug #67963</a>: InnoDB wastes 62 out of every 16384 pages</h3>
<p>InnoDB needs to occasionally allocate some internal bookkeeping pages; two for every 256 MiB of data. In order to do so, it allocates an extent (64 pages), allocates the two pages it needed, and then adds the remainder of the extent (62 free pages) to a list of extents to be used for single page allocations called <tt>FREE_FRAG</tt>. Almost nothing allocates pages from that list, so these pages go to waste.</p>
<p>This is fairly subtle, wasting only 0.37% of disk space in any large InnoDB table, but nonetheless interesting and quite fixable.</p>
<h3><a href="http://bugs.mysql.com/bug.php?id=68023">Bug #68023</a>: InnoDB reserves an excessive amount of disk space for write operations</h3>
<p>InnoDB attempts to ensure write operations will always succeed after they&#8217;ve reached a certain point by pre-reserving 1% of the tablespace size for the write operation. This is an excessive amount; 1% of every large table in a production system really adds up. This should be capped at some reasonable amount.</p>
<h3><a href="http://bugs.mysql.com/bug.php?id=68501">Bug #68501</a>: InnoDB fails to merge under-filled pages depending on deletion order</h3>
<p>Depending on the order that records are deleted from pages, InnoDB may not merge multiple adjacent under-filled pages together, wasting disk space.</p>
<h3><a href="http://bugs.mysql.com/bug.php?id=68545">Bug #68545</a>: InnoDB should check left/right pages when target page is full to avoid splitting</h3>
<p>During an insertion operation, only one of two outcomes is currently possible:</p>
<ol>
<li><i>The record fits in the target page</i> and is inserted without splitting the page.</li>
<li><i>The record does not fit in the target page</i> and the page is then split into two pages, each with half of the records on the original page. After the page is split, the insertion will happen into one of the two resulting pages two pages.</li>
</ol>
<p>This misses a very common case in practice, when the target page is full but one or more of its adjacent pages have free space or may even be nearly empty. A more intelligent alternative would be to consider merging the adjacent pages in order to make free space on the target page, rather than split the target page, creating a completely new half-full page.</p>
<h3><a href="http://bugs.mysql.com/bug.php?id=68546">Bug #68546</a>: InnoDB stores unnecessary PKV fields in unique SK non-leaf pages</h3>
<p>Non-leaf pages in Secondary Keys need a key that is guaranteed to be unique even though there may be many child pages with the same minimum key value. InnoDB adds all Primary Key fields to the key, but when the Secondary Key is already unique this is unnecessary. For systems with unique Secondary Keys and a large Primary Key, this can add up to a lot of disk space to store the unnecessary fields. Fixing this in a compatible way would be complex, and most users are unaffected, so I&#8217;d say it&#8217;s unlikely to be fixed.</p>
<h3><a href="http://bugs.mysql.com/bug.php?id=68868">Bug #68868</a>: Documentation for InnoDB tablespace flags for file format incorrect</h3>
<p>As I wrote in <a href="http://blog.jcole.us/2013/04/04/how-innodb-accidentally-reserved-only-1-bit-for-table-format/">How InnoDB accidentally reserved only 1 bit for table format</a>, InnoDB purportedly reserved 6 bits of a field for storing the table format (Antelope, Barracuda, etc.), but due to a bug in the C <tt>#define</tt>s only reserved 1 bit.</p>
<br />  <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=blog.jcole.us&#038;blog=30683698&#038;post=1004&#038;subd=jcoledotus&#038;ref=&#038;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://blog.jcole.us/2013/04/09/innodb-bugs-found-during-research-on-innodb-data-storage/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/37cd63a9fd0344804fd6a991a55c283a?s=96&#38;d=http%3A%2F%2F0.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D96&#38;r=R" medium="image">
			<media:title type="html">jeremycole</media:title>
		</media:content>
	</item>
		<item>
		<title>Idea: A &#8220;system&#8221; localization for MySQL</title>
		<link>http://blog.jcole.us/2013/04/08/idea-a-system-localization-for-mysql/</link>
		<comments>http://blog.jcole.us/2013/04/08/idea-a-system-localization-for-mysql/#comments</comments>
		<pubDate>Tue, 09 Apr 2013 00:35:05 +0000</pubDate>
		<dc:creator>Jeremy Cole</dc:creator>
				<category><![CDATA[MySQL]]></category>

		<guid isPermaLink="false">http://blog.jcole.us/?p=997</guid>
		<description><![CDATA[Currently the English error messages are embedded in all of the tests in MySQL. This means that you can&#8217;t really update the English translations without breaking a bunch of tests. I&#8217;m not sure if there&#8217;s a standard way to fix this, but it occurs to me that it would be quite easy to have a [&#8230;]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=blog.jcole.us&#038;blog=30683698&#038;post=997&#038;subd=jcoledotus&#038;ref=&#038;feed=1" width="1" height="1" />]]></description>
				<content:encoded><![CDATA[<p>Currently the English error messages are embedded in all of the tests in MySQL. This means that you can&#8217;t really update the English translations without breaking a bunch of tests. I&#8217;m not sure if there&#8217;s a standard way to fix this, but it occurs to me that it would be quite easy to have a &#8220;system&#8221; localization which just prints a language-neutral version of the error, meaning that any version of it can be updated without breaking any tests.</p>
<p>For example, the following simple syntax error gives a message in English:</p>
<blockquote><pre>
mysql&gt; select foo;
ERROR 1054 (42S22): Unknown column 'foo' in 'field list'
</pre>
</blockquote>
<p>This is based on the following definition in the <tt>errmsg-utf8.txt</tt> file:</p>
<blockquote><pre>
ER_BAD_FIELD_ERROR 42S22 S0022
        eng "Unknown column '%-.192s' in '%-.192s'"
</pre>
</blockquote>
<p>In a test case this might be codified as:</p>
<blockquote><pre>
--echo # Test that ER_BAD_FIELD_ERROR works.
--error ER_BAD_FIELD_ERROR
SELECT foo;
</pre>
</blockquote>
<p>The <tt>--error</tt> allows the error to be ignored (as an expected error); however the text of the English error message still ends up in the test result file:</p>
<blockquote><pre>
# Test that ER_BAD_FIELD_ERROR works.
SELECT foo;
ERROR 42S22: Unknown column 'foo' in 'field list'
</pre>
</blockquote>
<p>Changing the text of the message even in a trivial way (fixing a typo) will cause the test to fail due to a mismatch on the error message string, since the result files are just compared as text when running tests:</p>
<blockquote><pre>
main.test_message                        [ fail ]
        Test ended at 2013-04-08 17:29:30

CURRENT_TEST: main.test_message
--- mysql-test/r/test_message.result	2013-04-09 03:26:27.516721785 +0300
+++ mysql-test/r/test_message.reject	2013-04-09 03:29:30.360718783 +0300
@@ -1,3 +1,3 @@
 # Test that ER_BAD_FIELD_ERROR works.
 SELECT foo;
-ERROR 42S22: Unknown column 'foo' in 'field list'
+ERROR 42S22: Unknown column 'foo' found in 'field list'

mysqltest: Result length mismatch
</pre>
</blockquote>
<p>A <tt>sys</tt> &#8220;language&#8221; could easily be added, however:</p>
<blockquote><pre>
ER_BAD_FIELD_ERROR 42S22 S0022
        sys "ER_BAD_FIELD_ERROR({%-.192s}, {%-.192s})"
        eng "Unknown column '%-.192s' in '%-.192s'"
</pre>
</blockquote>
<p>Ideally, these could of course be auto-generated based on all the context present already. When running with this localization the same error would result in:</p>
<blockquote><pre>
mysql&gt; select foo;
ERROR 1054 (42S22): ER_BAD_FIELD_ERROR({foo}, {field list})
</pre>
</blockquote>
<p>Thus preserving the language-neutrality of the tests and allowing the English versions of them to be tweaked for better readability without breaking the world.</p>
<p>This would of course require one massive commit to fix the tests when changing the language the tests run under to the new &#8220;sys&#8221; language&#8230;</p>
<p>What do you think? How do other systems (especially databases) handle this?</p>
<br />  <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=blog.jcole.us&#038;blog=30683698&#038;post=997&#038;subd=jcoledotus&#038;ref=&#038;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://blog.jcole.us/2013/04/08/idea-a-system-localization-for-mysql/feed/</wfw:commentRss>
		<slash:comments>8</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/37cd63a9fd0344804fd6a991a55c283a?s=96&#38;d=http%3A%2F%2F0.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D96&#38;r=R" medium="image">
			<media:title type="html">jeremycole</media:title>
		</media:content>
	</item>
		<item>
		<title>Regression in MySQL server localization from 5.0 to 5.6</title>
		<link>http://blog.jcole.us/2013/04/06/regression-in-mysql-server-localization-from-5-0-to-5-6/</link>
		<comments>http://blog.jcole.us/2013/04/06/regression-in-mysql-server-localization-from-5-0-to-5-6/#comments</comments>
		<pubDate>Sat, 06 Apr 2013 20:15:59 +0000</pubDate>
		<dc:creator>Jeremy Cole</dc:creator>
				<category><![CDATA[MySQL]]></category>

		<guid isPermaLink="false">http://blog.jcole.us/?p=984</guid>
		<description><![CDATA[MySQL server has supported localization of error messages since the very beginning, and its implementation has gone through a few revisions: Through 4.1, a separate language/errmsg.txt file for each language, with one message per line, and each file in a language-appropriate character set. In 5.0 and 5.1, a single errmsg.txt file with a group of [&#8230;]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=blog.jcole.us&#038;blog=30683698&#038;post=984&#038;subd=jcoledotus&#038;ref=&#038;feed=1" width="1" height="1" />]]></description>
				<content:encoded><![CDATA[<p>MySQL server has supported localization of error messages since the very beginning, and its implementation has gone through a few revisions:</p>
<ul>
<li>Through 4.1, a separate <tt><i>language</i>/errmsg.txt</tt> file for each language, with one message per line, and each file in a language-appropriate character set.</li>
<li>In 5.0 and 5.1, a single <tt>errmsg.txt</tt> file with a group of translations for each message, but with different character sets  for each language (making the file very difficult to edit with any editor).</li>
<li>In 5.5 and 5.6, a single <tt>errmsg-utf8.txt</tt> file with the same structure as in 5.0 and 5.1, but with all messages in UTF-8 (whew!).</li>
</ul>
<p>In the early days, folks at MySQL tried to translate all of the error messages fairly frequently, keeping most localizations relatively up to date. Many volunteers also translated the messages into their favorite language and contributed those files.</p>
<p>In recent years, however, the vast majority of error messages added to the message file are in English only, or at most English and one other language<sup>1</sup> (presumably the author&#8217;s native language, often German). While the number of unique error messages in English has increased from 481 to 862 between 5.0 to 5.6, all other translations with the exception of German, Swedish, and Japanese<sup>2</sup> have been almost entirely stagnant.</p>
<p>This chart shows the percentage of translated messages available by MySQL version from 5.0 through 5.6:</p>
<p><a href="https://docs.google.com/a/jcole.us/spreadsheet/ccc?key=0Ak69OGWTdlptdEljdTc2LVZETnlxMkFaMkhKaWpxLVE#gid=1"><img src="http://jcole.us/blog/files/mysql_l10n_regression_all.png"></a></p>
<p>This chart shows a few of the major supported languages, showing the utter stagnation of translated messages for all languages since 5.0, and for German since 5.5:</p>
<p><a href="https://docs.google.com/a/jcole.us/spreadsheet/ccc?key=0Ak69OGWTdlptdEljdTc2LVZETnlxMkFaMkhKaWpxLVE#gid=4"><img src="http://jcole.us/blog/files/mysql_l10n_regression_major.png"></a></p>
<p>(Click on the graphs to see the Google Docs Spreadsheet, which is rendered a lot better than its image export.)</p>
<p>The best-supported language (after English) is German, but even it has fallen from 94% translated in MySQL 5.0 to only 77% translated in MySQL 5.6. Swedish, which was once one of the sacred translations, has fallen from 53% translated in 5.0 to only 39% in 5.6. Eliminating English and German (as high outliers) and Bulgarian (as a low outlier), the average translation completeness in MySQL 5.6 is less than 25%.</p>
<p>Is it useful to actually <em>have</em> multiple language support if it is this woefully incomplete<sup>3</sup>? For most of these languages, even if the user goes to the trouble to enable their alternate language, 75% on average of the messages they see will be in English. Is that really any better than 100%?</p>
<p>Have Oracle given up on maintaining the error message translations? Would community effort to get them all updated be welcome? Would it be useful to rip out this mess and start over with a more standardized and mature localization framework?</p>
<p>&mdash;</p>
<p><sup>1</sup> Bizarrely, in MySQL 5.6, <a href="https://twitter.com/gkodinov">Georgi Kodinov</a> added Bulgarian as a supported language, with exactly one translated message supported.</p>
<p><sup>2</sup> It appears that Japanese <a href="http://bazaar.launchpad.net/~mysql/mysql-server/5.6/revision/3690.34.120">got a major overhaul</a> by <a href="http://www.percona.com/about-us/our-team/yasufumi-kinoshita">Yasufumi Kinoshita</a>, removing the unused &#8220;jps&#8221; variant and adding and adding a bunch more translations to the &#8220;jpn&#8221; variant. Alas, it is still quite incomplete at only 34% translated in 5.6.</p>
<p><sup>3</sup> Leaving aside the any discussion about the way that languages are implemented in MySQL currently, which is not awesome.</p>
<br />  <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=blog.jcole.us&#038;blog=30683698&#038;post=984&#038;subd=jcoledotus&#038;ref=&#038;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://blog.jcole.us/2013/04/06/regression-in-mysql-server-localization-from-5-0-to-5-6/feed/</wfw:commentRss>
		<slash:comments>16</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/37cd63a9fd0344804fd6a991a55c283a?s=96&#38;d=http%3A%2F%2F0.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D96&#38;r=R" medium="image">
			<media:title type="html">jeremycole</media:title>
		</media:content>

		<media:content url="http://jcole.us/blog/files/mysql_l10n_regression_all.png" medium="image" />

		<media:content url="http://jcole.us/blog/files/mysql_l10n_regression_major.png" medium="image" />
	</item>
		<item>
		<title>How InnoDB accidentally reserved only 1 bit for table format</title>
		<link>http://blog.jcole.us/2013/04/04/how-innodb-accidentally-reserved-only-1-bit-for-table-format/</link>
		<comments>http://blog.jcole.us/2013/04/04/how-innodb-accidentally-reserved-only-1-bit-for-table-format/#comments</comments>
		<pubDate>Thu, 04 Apr 2013 21:46:20 +0000</pubDate>
		<dc:creator>Jeremy Cole</dc:creator>
				<category><![CDATA[InnoDB]]></category>
		<category><![CDATA[MySQL]]></category>
		<category><![CDATA[MySQL Bugs]]></category>

		<guid isPermaLink="false">http://blog.jcole.us/?p=972</guid>
		<description><![CDATA[The MySQL 5.5 (and 5.6) documentation says, in Identifying the File Format in Use: &#8220;&#8230; Otherwise, the least significant bit should be set in the tablespace flags, and the file format identifier is written in the bits 5 through 11. &#8230;&#8221; This is incorrect for any version due to a bug in how the tablespace [&#8230;]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=blog.jcole.us&#038;blog=30683698&#038;post=972&#038;subd=jcoledotus&#038;ref=&#038;feed=1" width="1" height="1" />]]></description>
				<content:encoded><![CDATA[<p>The MySQL 5.5 (and 5.6) documentation says, in <a href="http://dev.mysql.com/doc/refman/5.5/en/innodb-file-format-identifying.html">Identifying the File Format in Use</a>:</p>
<blockquote><p>
&#8220;&#8230; Otherwise, the least significant bit should be set in the tablespace flags, and the file format identifier is written in the bits 5 through 11. &#8230;&#8221;
</p></blockquote>
<p>This is incorrect for any version due to a bug in how the tablespace flags were stored (which caused only 1 bit to be reserved, rather than 6). This was all re-worked in MySQL 5.6, so someone obviously noticed it, but the documentation has been left incorrect for all versions, and the incorrect and misleading code has been left in MySQL 5.5. I filed <a href="http://bugs.mysql.com/bug.php?id=68868">MySQL Bug #68868</a> about the documentation.</p>
<h2>File formats and names</h2>
<p>There are file format names in the documentation and code for values 0 through 25 (letters &#8220;A&#8221; through &#8220;Z&#8221;), although only <tt>0</tt> (&#8220;Antelope&#8221;) and <tt>1</tt> (&#8220;Barracuda&#8221;) are currently used. They are all defined in <tt>storage/innobase/trx/trx0sys.c</tt>:</p>
<blockquote><pre>
    97  /** List of animal names representing file format. */
    98  static const char*      file_format_name_map[] = {
    99          "Antelope",
   100          "Barracuda",
   101          "Cheetah",
   102          "Dragon",
   103          "Elk",
   104          "Fox",
   105          "Gazelle",
   106          "Hornet",
   107          "Impala",
   108          "Jaguar",
   109          "Kangaroo",
   110          "Leopard",
   111          "Moose",
   112          "Nautilus",
   113          "Ocelot",
   114          "Porpoise",
   115          "Quail",
   116          "Rabbit",
   117          "Shark",
   118          "Tiger",
   119          "Urchin",
   120          "Viper",
   121          "Whale",
   122          "Xenops",
   123          "Yak",
   124          "Zebra"
   125  };
</pre>
</blockquote>
<h2>How only one bit was reserved</h2>
<p>The code to store the file format identifier into an InnoDB tablespace file&#8217;s tablespace flags is in <tt>storage/innobase/include/dict0mem.h</tt> and follows, with my commentary.</p>
<p>The first bit is reserved for 1 = compact, 0 = redundant format:</p>
<blockquote><pre>
    70  /** Table flags.  All unused bits must be 0. */
    71  /* @{ */
    72  #define DICT_TF_COMPACT                 1       /* Compact page format.
    73                                                  This must be set for
    74                                                  new file formats
    75                                                  (later than
    76                                                  DICT_TF_FORMAT_51). */
</pre>
</blockquote>
<p>The next 4 bits are reserved for the compressed page size:</p>
<blockquote><pre>
    78  /** Compressed page size (0=uncompressed, up to 15 compressed sizes) */
    79  /* @{ */
    80  #define DICT_TF_ZSSIZE_SHIFT            1
    81  #define DICT_TF_ZSSIZE_MASK             (15 &lt;&lt; DICT_TF_ZSSIZE_SHIFT)
    82  #define DICT_TF_ZSSIZE_MAX (UNIV_PAGE_SIZE_SHIFT - PAGE_ZIP_MIN_SIZE_SHIFT + 1)
    83  /* @} */
</pre>
</blockquote>
<p>Next we&#8217;re <em>supposed</em> to reserve 6 bits for the file format (up to 64 formats):</p>
<blockquote><pre>
    85  /** File format */
    86  /* @{ */
    87  #define DICT_TF_FORMAT_SHIFT            5       /* file format */
    88  #define DICT_TF_FORMAT_MASK             \
    89  ((~(~0 &lt;&lt; (DICT_TF_BITS - DICT_TF_FORMAT_SHIFT))) &lt;&lt; DICT_TF_FORMAT_SHIFT)
</pre>
</blockquote>
<p>Two values are currently defined, which correspond to Antelope and Barracuda (with rather strange names &#8220;51&#8243; and &#8220;ZIP&#8221; as defined):</p>
<blockquote><pre>
    90  #define DICT_TF_FORMAT_51               0       /*!&lt; InnoDB/MySQL up to 5.1 */
    91  #define DICT_TF_FORMAT_ZIP              1       /*!&lt; InnoDB plugin for 5.1:
    92                                                  compressed tables,
    93                                                  new BLOB treatment */
    94  /** Maximum supported file format */
    95  #define DICT_TF_FORMAT_MAX              DICT_TF_FORMAT_ZIP
    96
    97  /** Minimum supported file format */
    98  #define DICT_TF_FORMAT_MIN              DICT_TF_FORMAT_51
</pre>
</blockquote>
<p>This is where things get interesting. It is not clear if <tt>DICT_TF_BITS</tt> (defined below) is supposed to represent the total number of flag bits (11 so far!), or the number of bits for the format above (6, but then shouldn&#8217;t it be called <tt>DICT_TF_FORMAT_BITS</tt>?). However since 6 is larger than the non­-format related bits (5), and only 1 bit has actually been used for format in practice (0..1), nothing will blow up here, and the <tt>#error</tt> check passes cleanly.</p>
<blockquote><pre>
   100  /* @} */
   101  #define DICT_TF_BITS                    6       /*!&lt; number of flag bits */
   102  #if (1 &lt;&lt; (DICT_TF_BITS - DICT_TF_FORMAT_SHIFT)) &lt;= DICT_TF_FORMAT_MAX
   103  # error "DICT_TF_BITS is insufficient for DICT_TF_FORMAT_MAX"
   104  #endif
   105  /* @} */
</pre>
</blockquote>
<p>Also note that the <tt>#error</tt> there is easy enough to calculate. It works out to:</p>
<ol>
<li><tt>(1 &lt;&lt; (DICT_TF_BITS - DICT_TF_FORMAT_SHIFT)) &lt;= DICT_TF_FORMAT_MAX</tt></li>
<li><tt>(1 &lt;&lt; (6 - 5)) &lt;= 1</tt></li>
<li><tt>(1 &lt;&lt; 1) &lt;= 1</tt></li>
<li><tt>2 &lt;= 1</tt></li>
<li><tt><b>FALSE</b></tt></li>
</ol>
<p>The &#8220;<tt>6 - 5</tt>&#8221; in the calculation above represents essentially the number of bits reserved for the table format flag, which turns out to be only 1.</p>
<p>The above defines go on to be used by <tt>DICT_TF2</tt> (another set of flags) which currently only uses a single bit:</p>
<blockquote><pre>
   107  /** @brief Additional table flags.
   108
   109  These flags will be stored in SYS_TABLES.MIX_LEN.  All unused flags
   110  will be written as 0.  The column may contain garbage for tables
   111  created with old versions of InnoDB that only implemented
   112  ROW_FORMAT=REDUNDANT. */
   113  /* @{ */
   114  #define DICT_TF2_SHIFT                  DICT_TF_BITS
   115                                                  /*!flags. */
   117  #define DICT_TF2_TEMPORARY              1       /*!&lt; TRUE for tables from
   118                                                  CREATE TEMPORARY TABLE. */
   119  #define DICT_TF2_BITS                   (DICT_TF2_SHIFT + 1)
   120                                                  /*!flags. */
   122  /* @} */
</pre>
</blockquote>
<p>It&#8217;s very easy to see here that if <tt>DICT_TF2_SHIFT</tt> is <tt>DICT_TF_BITS</tt>, which is 6, the <tt>DICT_TF2_TEMPORARY</tt> flag is being stored at <tt>1 &lt;&lt; 6</tt>, which is only leaving the file format a single bit, when it should be reserving 6 bits.</p>
<p>The end result of this is that the <tt>DICT_TF2_TEMPORARY</tt> bit is being stored into a bit reserved for the table format, rather than after the table format. The <tt>DICT_TF2</tt> stuff seems to only be stored in the data dictionary, and never in the IBD file, so this would I guess manifest when Cheetah would be implemented and a temporary table is created.</p>
<h2>Why this could happen</h2>
<p>This code is unnecessarily complex and confusing, and to make matters worse it is inconsistent. There is no concise description of the fields being stored; only the code documents the structure, and since it is badly written, its value as documentation is low.</p>
<p>The bug is two­-fold:</p>
<ol>
<li>There should be a <tt>DICT_TF_FORMAT_BITS</tt> define to capture the expected number of bits required to store the <tt>DICT_TF_FORMAT_*</tt> structure (dictionary, table flags, format) which is defined to 6, and that should be used in the masks associated with <tt>DICT_TF_FORMAT_*</tt>.</li>
<li>The <tt>DICT_TF_BITS</tt> define should mean the total size of the <tt>DICT_TF</tt> structures (which precede the <tt>DICT_TF2</tt> structures obviously), and should be 1 + 4 + 6 = 11 bits, but this should be defined only by summing the previous structures sizes.</li>
</ol>
<p>Because of the way this is written, it&#8217;s actually quite difficult to discern that there is a bug present visually, so I am not surprised that this was not caught &mdash; however I am dismayed about the code quality and clarity, and that this passes any sort of code review.</p>
<br />  <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=blog.jcole.us&#038;blog=30683698&#038;post=972&#038;subd=jcoledotus&#038;ref=&#038;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://blog.jcole.us/2013/04/04/how-innodb-accidentally-reserved-only-1-bit-for-table-format/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/37cd63a9fd0344804fd6a991a55c283a?s=96&#38;d=http%3A%2F%2F0.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D96&#38;r=R" medium="image">
			<media:title type="html">jeremycole</media:title>
		</media:content>
	</item>
	</channel>
</rss>
