<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet href="http://feeds.zawodny.com/~d/styles/rss2full.xsl" type="text/xsl" media="screen"?><?xml-stylesheet href="http://feeds.zawodny.com/~d/styles/itemcontent.css" type="text/css" media="screen"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:sy="http://purl.org/rss/1.0/modules/syndication/" xmlns:admin="http://webns.net/mvcb/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" version="2.0">

  <channel>
    <title>Jeremy Zawodny's blog</title>
    <link>http://jeremy.zawodny.com/blog/</link>
    <description>Random thoughts on technology, aviation, and life in general...</description>
    <dc:language>en-us</dc:language>
    <dc:creator>Jeremy@Zawodny.com</dc:creator>
    <dc:rights>Copyright 2008</dc:rights>
    <dc:date>2008-09-02T14:10:48-08:00</dc:date>
    <admin:generatorAgent rdf:resource="http://www.movabletype.org/?v=3.16" />
    <admin:errorReportsTo rdf:resource="mailto:Jeremy@Zawodny.com" />
    <sy:updatePeriod>hourly</sy:updatePeriod>
    <sy:updateFrequency>1</sy:updateFrequency>
    <sy:updateBase>2000-01-01T12:00+00:00</sy:updateBase>

    <atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" href="http://jeremy.zawodny.com/blog/rss2.xml" type="application/rss+xml" /><feedburner:feedFlare href="http://add.my.yahoo.com/rss?url=http%3A%2F%2Fjeremy.zawodny.com%2Fblog%2Frss2.xml" src="http://us.i1.yimg.com/us.yimg.com/i/us/my/addtomyyahoo4.gif">Subscribe with My Yahoo!</feedburner:feedFlare><feedburner:feedFlare href="http://www.newsgator.com/ngs/subscriber/subext.aspx?url=http%3A%2F%2Fjeremy.zawodny.com%2Fblog%2Frss2.xml" src="http://www.newsgator.com/images/ngsub1.gif">Subscribe with NewsGator</feedburner:feedFlare><feedburner:feedFlare href="http://feeds.my.aol.com/add.jsp?url=http%3A%2F%2Fjeremy.zawodny.com%2Fblog%2Frss2.xml" src="http://o.aolcdn.com/favorites.my.aol.com/webmaster/ffclient/webroot/locale/en-US/images/myAOLButtonSmall.gif">Subscribe with My AOL</feedburner:feedFlare><feedburner:feedFlare href="http://www.rojo.com/add-subscription?resource=http%3A%2F%2Fjeremy.zawodny.com%2Fblog%2Frss2.xml" src="http://blog.rojo.com/RojoWideRed.gif">Subscribe with Rojo</feedburner:feedFlare><feedburner:feedFlare href="http://www.bloglines.com/sub/http://jeremy.zawodny.com/blog/rss2.xml" src="http://www.bloglines.com/images/sub_modern11.gif">Subscribe with Bloglines</feedburner:feedFlare><feedburner:feedFlare href="http://www.netvibes.com/subscribe.php?url=http%3A%2F%2Fjeremy.zawodny.com%2Fblog%2Frss2.xml" src="http://www.netvibes.com/img/add2netvibes.gif">Subscribe with Netvibes</feedburner:feedFlare><feedburner:feedFlare href="http://fusion.google.com/add?feedurl=http%3A%2F%2Fjeremy.zawodny.com%2Fblog%2Frss2.xml" src="http://buttons.googlesyndication.com/fusion/add.gif">Subscribe with Google</feedburner:feedFlare><feedburner:feedFlare href="http://www.pageflakes.com/subscribe.aspx?url=http%3A%2F%2Fjeremy.zawodny.com%2Fblog%2Frss2.xml" src="http://www.pageflakes.com/ImageFile.ashx?instanceId=Static_4&amp;fileName=ATP_blu_91x17.gif">Subscribe with Pageflakes</feedburner:feedFlare><item>
      <title>The Perl UTF-8 and utf8 Encoding Mess</title>
      <link>http://feeds.zawodny.com/~r/jzawodn/rss2/~3/381711038/010546.html</link>
      <description><![CDATA[<p>I've been hacking on some Perl code that extracts data that comes
  from web users around the world and been stored
  into <a href="http://dev.mysql.com/downloads/">MySQL</a> (with no
  real encoding information, of course).  My goal it to generate
  well-formed, valid XML that can be read
  by <a href="http://www.sphinxsearch.com">another tool</a>.</p>

<p>Now I'll be the first to admit that I never really took the time to
  like, understand, or pay much attention to all the changes in Perl's
  character and byte handling over the years.  I'm one of those
  developers that, I suspect, is representative of the majority (at
  least in this self-centered country).  I think it's all stupid and
  complicated and should Just Work... somehow.</p>

<p>But at the same time I know it's not.</p>

<p>Anyway, after importing lots of data I came across my first bug.
  Well, okay... not my first bug.  My first bug related to this
  encoding stuff.  The <a href="http://xmlsoft.org/">XML parser</a> on
  the receiving end raised hell about some weird characters coming
  in.</p>

<p>Oh, crap.  That's right.  This is the big bad Internet and I forgot
  to do anything to scrub the data so that it'd look like the sort of
  thing you can cram into XML and expect to maybe work.</p>

<p>A little searching around managed to jog my memory and I updated my
  code to include something like this:</p>

<pre>
  use Encode;

  ...

  my $data = Encode::decode('utf8', $row->{'Stuff'});
</pre>

<p>And all was well for quite some time.  I got a lot farther with
  that until this weekend when Perl itself began to blow up on me,
  throwing fatal exceptions like this:</p>

<pre>
  Malformed UTF-8 character (fatal) ...
</pre>

<p>My first reaction, like yours probably, was WTF?!?!  How on god's
  green earth is this a FATAL error?</p>

<p>After much
  swearing, <a href="http://twitter.com/jzawodn/statuses/906486538">a
  Twitter plea</a>, and some reading (thanks Twitter world!), I came
  across a section of
  the <a href="http://perldoc.perl.org/Encode.html">Encode manual page
  from Perl</a>.</p>

<p>I'm going to quote from it a fair amount here because I know you're
  as lazy as I am and won't go read it if I just link here.  The
  relevant section is at the very end (just before SEE ALSO) and
  titled <strong>UTF-8 vs. utf8</strong>.</p>

<pre>
    ....We now view strings not as sequences of bytes, but as
    sequences of numbers in the range 0 .. 2**32&#8208;1 (or in the case of
    64&#8208;bit computers, 0 .. 2**64&#8208;1) &#8208;&#8208; Programming Perl, 3rd ed.

  That has been the perls notion of UTF&#8722;8 but official UTF&#8722;8 is more
  strict; Its ranges is much narrower (0 .. 10FFFF), some sequences
  are not allowed (i.e. Those used in the surrogate pair, 0xFFFE, et
  al).

  Now that is overruled by Larry Wall himself.

    From: Larry Wall <larry@wall.org>
    Date: December 04, 2004 11:51:58 JST
    To: perl&#8208;unicode@perl.org
    Subject: Re: Make Encode.pm support the real UTF&#8208;8
    Message&#8208;Id: <20041204025158.GA28754@wall.org>

    On Fri, Dec 03, 2004 at 10:12:12PM +0000, Tim Bunce wrote:
    : Ive no problem with utf8 being perls unrestricted uft8 encoding,
    : but "UTF&#8208;8" is the name of the standard and should give the
    : corresponding behaviour.

    For what its worth, thats how Ive always kept them straight in my
    head.

    Also for what its worth, Perl 6 will mostly default to strict but
    make it easy to switch back to lax.

    Larry

  Do you copy?  As of Perl 5.8.7, UTF&#8722;8 means strict, official UTF&#8722;8
  while utf8 means liberal, lax, version thereof.  And Encode version
  2.10 or later thus groks the difference between "UTF&#8722;8" and "utf8".

    encode("utf8",  "\x{FFFF_FFFF}", 1); # okay
    encode("UTF&#8208;8", "\x{FFFF_FFFF}", 1); # croaks

  "UTF&#8722;8" in Encode is actually a canonical name for "utf&#8722;8&#8722;strict".
  Yes, the hyphen between "UTF" and "8" is important.  Without it
  Encode goes "liberal"

    find_encoding("UTF&#8208;8")&#8208;>name # is utf&#8208;8&#8208;strict
    find_encoding("utf&#8208;8")&#8208;>name # ditto. names are case insensitive
    find_encoding("utf8")&#8208;>name  # ditto. "_" are treated as "&#8208;"
    find_encoding("UTF8")&#8208;>name  # is utf8.
</pre>

<p>Got all that?</p>

<p>The sound you heard last night was me banging my head on a desk.
Repeatedly.</p>

<p>I mean, how could I have <em>possibly</em> noticed the massive
  difference between <strong>utf8</strong> and <strong>UTF-8</strong>?
  Really.  I must have been on some serious crack.</p>

<p>Sigh!</p>

<p>Needless to say my code now looks more like this:</p>

<pre>
  use Encode;

  ...

  my $data = Encode::decode('UTF-8', $row->{'Stuff'}); ## fuck!
</pre>

<p>Actually, I was kidding about the "fuck!"  I
wouldn't <a href="http://thedailywtf.com/Articles/We-Burned-the-Poop.aspx">swear
in code</a>.  <p>(<a href="http://jeremy.zawodny.com/blog/archives/010546.html#comments">comments</a>)</p>]]></description>
      <guid isPermaLink="false">10546@http://jeremy.zawodny.com/blog/</guid>
      <content:encoded><![CDATA[<p>I've been hacking on some Perl code that extracts data that comes
  from web users around the world and been stored
  into <a href="http://dev.mysql.com/downloads/">MySQL</a> (with no
  real encoding information, of course).  My goal it to generate
  well-formed, valid XML that can be read
  by <a href="http://www.sphinxsearch.com">another tool</a>.</p>

<p>Now I'll be the first to admit that I never really took the time to
  like, understand, or pay much attention to all the changes in Perl's
  character and byte handling over the years.  I'm one of those
  developers that, I suspect, is representative of the majority (at
  least in this self-centered country).  I think it's all stupid and
  complicated and should Just Work... somehow.</p>

<p>But at the same time I know it's not.</p>

<p>Anyway, after importing lots of data I came across my first bug.
  Well, okay... not my first bug.  My first bug related to this
  encoding stuff.  The <a href="http://xmlsoft.org/">XML parser</a> on
  the receiving end raised hell about some weird characters coming
  in.</p>

<p>Oh, crap.  That's right.  This is the big bad Internet and I forgot
  to do anything to scrub the data so that it'd look like the sort of
  thing you can cram into XML and expect to maybe work.</p>

<p>A little searching around managed to jog my memory and I updated my
  code to include something like this:</p>

<pre>
  use Encode;

  ...

  my $data = Encode::decode('utf8', $row->{'Stuff'});
</pre>

<p>And all was well for quite some time.  I got a lot farther with
  that until this weekend when Perl itself began to blow up on me,
  throwing fatal exceptions like this:</p>

<pre>
  Malformed UTF-8 character (fatal) ...
</pre>

<p>My first reaction, like yours probably, was WTF?!?!  How on god's
  green earth is this a FATAL error?</p>

<p>After much
  swearing, <a href="http://twitter.com/jzawodn/statuses/906486538">a
  Twitter plea</a>, and some reading (thanks Twitter world!), I came
  across a section of
  the <a href="http://perldoc.perl.org/Encode.html">Encode manual page
  from Perl</a>.</p>

<p>I'm going to quote from it a fair amount here because I know you're
  as lazy as I am and won't go read it if I just link here.  The
  relevant section is at the very end (just before SEE ALSO) and
  titled <strong>UTF-8 vs. utf8</strong>.</p>

<pre>
    ....We now view strings not as sequences of bytes, but as
    sequences of numbers in the range 0 .. 2**32&#8208;1 (or in the case of
    64&#8208;bit computers, 0 .. 2**64&#8208;1) &#8208;&#8208; Programming Perl, 3rd ed.

  That has been the perls notion of UTF&#8722;8 but official UTF&#8722;8 is more
  strict; Its ranges is much narrower (0 .. 10FFFF), some sequences
  are not allowed (i.e. Those used in the surrogate pair, 0xFFFE, et
  al).

  Now that is overruled by Larry Wall himself.

    From: Larry Wall <larry@wall.org>
    Date: December 04, 2004 11:51:58 JST
    To: perl&#8208;unicode@perl.org
    Subject: Re: Make Encode.pm support the real UTF&#8208;8
    Message&#8208;Id: <20041204025158.GA28754@wall.org>

    On Fri, Dec 03, 2004 at 10:12:12PM +0000, Tim Bunce wrote:
    : Ive no problem with utf8 being perls unrestricted uft8 encoding,
    : but "UTF&#8208;8" is the name of the standard and should give the
    : corresponding behaviour.

    For what its worth, thats how Ive always kept them straight in my
    head.

    Also for what its worth, Perl 6 will mostly default to strict but
    make it easy to switch back to lax.

    Larry

  Do you copy?  As of Perl 5.8.7, UTF&#8722;8 means strict, official UTF&#8722;8
  while utf8 means liberal, lax, version thereof.  And Encode version
  2.10 or later thus groks the difference between "UTF&#8722;8" and "utf8".

    encode("utf8",  "\x{FFFF_FFFF}", 1); # okay
    encode("UTF&#8208;8", "\x{FFFF_FFFF}", 1); # croaks

  "UTF&#8722;8" in Encode is actually a canonical name for "utf&#8722;8&#8722;strict".
  Yes, the hyphen between "UTF" and "8" is important.  Without it
  Encode goes "liberal"

    find_encoding("UTF&#8208;8")&#8208;>name # is utf&#8208;8&#8208;strict
    find_encoding("utf&#8208;8")&#8208;>name # ditto. names are case insensitive
    find_encoding("utf8")&#8208;>name  # ditto. "_" are treated as "&#8208;"
    find_encoding("UTF8")&#8208;>name  # is utf8.
</pre>

<p>Got all that?</p>

<p>The sound you heard last night was me banging my head on a desk.
Repeatedly.</p>

<p>I mean, how could I have <em>possibly</em> noticed the massive
  difference between <strong>utf8</strong> and <strong>UTF-8</strong>?
  Really.  I must have been on some serious crack.</p>

<p>Sigh!</p>

<p>Needless to say my code now looks more like this:</p>

<pre>
  use Encode;

  ...

  my $data = Encode::decode('UTF-8', $row->{'Stuff'}); ## fuck!
</pre>

<p>Actually, I was kidding about the "fuck!"  I
wouldn't <a href="http://thedailywtf.com/Articles/We-Burned-the-Poop.aspx">swear
in code</a>. <p>(<a href="http://jeremy.zawodny.com/blog/archives/010546.html#comments">comments</a>)</p><img src="http://feeds.zawodny.com/~r/jzawodn/rss2/~4/381711038" height="1" width="1"/>]]></content:encoded>
      <dc:subject>Perl</dc:subject>
      <dc:date>2008-09-02T14:10:48-08:00</dc:date>
    <feedburner:origLink>http://jeremy.zawodny.com/blog/archives/010546.html</feedburner:origLink></item>
    <item>
      <title>Dumber is Faster with Large Data Sets (and Disk Seeks)</title>
      <link>http://feeds.zawodny.com/~r/jzawodn/rss2/~3/371283474/010523.html</link>
      <description><![CDATA[<p><a href="http://flickr.com/photos/laughingsquid/350999258/"><img width="173" height="240" src="http://farm1.static.flickr.com/161/350999258_7b8d7cb581_m.jpg" hspace="5" border="0" align="right" alt="dumb" /></a> I remember
  reading <a href="http://stuartsierra.com/2008/04/17/disk-is-the-new-tape">Disk
  is the new Tape</a> earlier this year and how much it resonated.
  That's probably because I was working for Yahoo at the time and
  hearing a lot about their use
  of <a href="http://hadoop.apache.org/core/">Hadoop</a> for data
  processing.  In fact, I even did a couple videos
  (<a href="http://developer.yahoo.net/blogs/theater/archives/2007/11/experts_work_eric_baldeschwieler.html">1</a>
  and <a href="http://developer.yahoo.com/blogs/hadoop/2008/02/yahoo-worlds-largest-production-hadoop.html">2</a>)
  about that.</p>

<p>Anyway, I recently faced the reality of this myself.  When I wrote
  about <a href="http://jeremy.zawodny.com/blog/archives/010504.html">The
  Long Term Performance of InnoDB</a> I'd been beating my head against
  a wall trying to get millions of records out of InnoDB
  efficiently.</p>

<p>It was taking days to get all the records.  Yes, <em>days</em>!</p>

<p>After joking that it'd probably be faster to just dump the tables
  out and do the work myself in Perl, I thought about <em>Disk is the
  new Tape</em> and realized what I was doing wrong.</p>

<p>Allow me to offer some background and explain...</p>

<p>There are several tables involved in the queries I needed to run.
  Two of them are "core" tables and the other two are LEFT JOINed
  because they hold optional data for the rows I'm pulling.  There are
  well over a hundred million records to consider and I need only
  about 10-15% of them.</p>

<p>And these records fall into roughly 500 categories.  So what I'd
  been doing is fetching a list of categories, running a query for
  each category to find the rows I actually need, processing the
  results, and writing them to disk for further processing.</p>

<p>The query looked something like this:</p>

<pre>
    SELECT field1, field2, field3, ... field N
      FROM stuff_meta sm, stuff s
 LEFT JOIN stuff_attributes sa ON sm.item_id = sa.item_id
 LEFT JOIN stuff_dates      sd ON sm.item_id = sd.item_id
     WHERE sm.item_id = s.item_id
       AND sm.cat_id  = ?
       AND sm.status IN ('A', 'B', 'C')
</pre>

<p>That seemed, at least in theory, to be the <em>obvious</em> way to
  approach the problem.  But the idea of waiting several days for the
  results led me to think a bit more about it (and to try some
  InnoDB tuning along the way).</p>

<p>While it seems very counter-intuitive, this was sticking in my
  head:</p>

<blockquote>Im still trying to get my head around this concept of
  "linear" data processing.  But I have found that I can do some
  things faster by reading sequentially through a batch of files
  rather than trying to stuff everything in a database (RDF or SQL)
  and doing big join queries.</blockquote>

<p>So I gave it a try.  I wrote a new version of the code that
  eliminated the two AND bits in the WHERE clause.  Combining that
  with
  using <a href="http://dev.mysql.com/doc/refman/5.0/en/mysql-use-result.html">mysql_use_result</a>
  in the client API, meant it had to process a stream of many tens of
  millions of records, handle the status filtering and shorting
  records into buckets based on cat_id (and some extra
  bookkeeping).</p>

<p>As an aside, I should note that there used to be an ORDER BY on
  that original query, but I abandoned that early on when I saw how
  much work MySQL was doing to sort the records.  While it made my
  code a bit easier, it was far more efficient to track things outside
  the database.</p>

<p>Anyway, the end result was that I was able to get all the data I
  needed in merely 8 hours.  In other words, treating MySQL as an SQL
  powered tape drive yielded a <strong>12 fold improvement in
  performance</strong>.</p>

<p>Put another way, taking the brain-dead stupid, non-SQL,
  mainframe-like approach got me results 12 times faster than doing it

  the seemingly "correct" way.</p>

<p>Now this isn't <em>exactly</em> what the whole disk vs. tape thing
  is about but it's pretty close.  I'm aware that InnoDB works with
  pages (that will contain multiple records, some of which I don't
  need) and that's part of the problem in this scenario.  But it's a
  really interesting data point.  And it's certainly going to change
  my thinking about working with our data in the future.</p>

<p>Actually, it already has. :-)</p>

<p>Dumber is faster.</p>

<p>As <a href="http://jeremy.zawodny.com/blog/archives/010472.html">I've
  mentioned before</a>, <a href="http://craigslist.org/">craigslist</a> is hiring.  We like good Perl/MySQL
  hackers.  And good sysadmin and network types too.</p>

<p><a href="mailto:Jeremy@Zawodny.com">Ping me</a> if you're
  interested in either role.</p>
  <p>(<a href="http://jeremy.zawodny.com/blog/archives/010523.html#comments">comments</a>)</p>]]></description>
      <guid isPermaLink="false">10523@http://jeremy.zawodny.com/blog/</guid>
      <content:encoded><![CDATA[<p><a href="http://flickr.com/photos/laughingsquid/350999258/"><img width="173" height="240" src="http://farm1.static.flickr.com/161/350999258_7b8d7cb581_m.jpg" hspace="5" border="0" align="right" alt="dumb" /></a> I remember
  reading <a href="http://stuartsierra.com/2008/04/17/disk-is-the-new-tape">Disk
  is the new Tape</a> earlier this year and how much it resonated.
  That's probably because I was working for Yahoo at the time and
  hearing a lot about their use
  of <a href="http://hadoop.apache.org/core/">Hadoop</a> for data
  processing.  In fact, I even did a couple videos
  (<a href="http://developer.yahoo.net/blogs/theater/archives/2007/11/experts_work_eric_baldeschwieler.html">1</a>
  and <a href="http://developer.yahoo.com/blogs/hadoop/2008/02/yahoo-worlds-largest-production-hadoop.html">2</a>)
  about that.</p>

<p>Anyway, I recently faced the reality of this myself.  When I wrote
  about <a href="http://jeremy.zawodny.com/blog/archives/010504.html">The
  Long Term Performance of InnoDB</a> I'd been beating my head against
  a wall trying to get millions of records out of InnoDB
  efficiently.</p>

<p>It was taking days to get all the records.  Yes, <em>days</em>!</p>

<p>After joking that it'd probably be faster to just dump the tables
  out and do the work myself in Perl, I thought about <em>Disk is the
  new Tape</em> and realized what I was doing wrong.</p>

<p>Allow me to offer some background and explain...</p>

<p>There are several tables involved in the queries I needed to run.
  Two of them are "core" tables and the other two are LEFT JOINed
  because they hold optional data for the rows I'm pulling.  There are
  well over a hundred million records to consider and I need only
  about 10-15% of them.</p>

<p>And these records fall into roughly 500 categories.  So what I'd
  been doing is fetching a list of categories, running a query for
  each category to find the rows I actually need, processing the
  results, and writing them to disk for further processing.</p>

<p>The query looked something like this:</p>

<pre>
    SELECT field1, field2, field3, ... field N
      FROM stuff_meta sm, stuff s
 LEFT JOIN stuff_attributes sa ON sm.item_id = sa.item_id
 LEFT JOIN stuff_dates      sd ON sm.item_id = sd.item_id
     WHERE sm.item_id = s.item_id
       AND sm.cat_id  = ?
       AND sm.status IN ('A', 'B', 'C')
</pre>

<p>That seemed, at least in theory, to be the <em>obvious</em> way to
  approach the problem.  But the idea of waiting several days for the
  results led me to think a bit more about it (and to try some
  InnoDB tuning along the way).</p>

<p>While it seems very counter-intuitive, this was sticking in my
  head:</p>

<blockquote>Im still trying to get my head around this concept of
  "linear" data processing.  But I have found that I can do some
  things faster by reading sequentially through a batch of files
  rather than trying to stuff everything in a database (RDF or SQL)
  and doing big join queries.</blockquote>

<p>So I gave it a try.  I wrote a new version of the code that
  eliminated the two AND bits in the WHERE clause.  Combining that
  with
  using <a href="http://dev.mysql.com/doc/refman/5.0/en/mysql-use-result.html">mysql_use_result</a>
  in the client API, meant it had to process a stream of many tens of
  millions of records, handle the status filtering and shorting
  records into buckets based on cat_id (and some extra
  bookkeeping).</p>

<p>As an aside, I should note that there used to be an ORDER BY on
  that original query, but I abandoned that early on when I saw how
  much work MySQL was doing to sort the records.  While it made my
  code a bit easier, it was far more efficient to track things outside
  the database.</p>

<p>Anyway, the end result was that I was able to get all the data I
  needed in merely 8 hours.  In other words, treating MySQL as an SQL
  powered tape drive yielded a <strong>12 fold improvement in
  performance</strong>.</p>

<p>Put another way, taking the brain-dead stupid, non-SQL,
  mainframe-like approach got me results 12 times faster than doing it

  the seemingly "correct" way.</p>

<p>Now this isn't <em>exactly</em> what the whole disk vs. tape thing
  is about but it's pretty close.  I'm aware that InnoDB works with
  pages (that will contain multiple records, some of which I don't
  need) and that's part of the problem in this scenario.  But it's a
  really interesting data point.  And it's certainly going to change
  my thinking about working with our data in the future.</p>

<p>Actually, it already has. :-)</p>

<p>Dumber is faster.</p>

<p>As <a href="http://jeremy.zawodny.com/blog/archives/010472.html">I've
  mentioned before</a>, <a href="http://craigslist.org/">craigslist</a> is hiring.  We like good Perl/MySQL
  hackers.  And good sysadmin and network types too.</p>

<p><a href="mailto:Jeremy@Zawodny.com">Ping me</a> if you're
  interested in either role.</p>
 <p>(<a href="http://jeremy.zawodny.com/blog/archives/010523.html#comments">comments</a>)</p><img src="http://feeds.zawodny.com/~r/jzawodn/rss2/~4/371283474" height="1" width="1"/>]]></content:encoded>
      <dc:subject>MySQL</dc:subject>
      <dc:date>2008-08-21T14:21:36-08:00</dc:date>
    <feedburner:origLink>http://jeremy.zawodny.com/blog/archives/010523.html</feedburner:origLink></item>
    <item>
      <title>Lembert Dome Hike in Yosemite</title>
      <link>http://feeds.zawodny.com/~r/jzawodn/rss2/~3/369083543/010514.html</link>
      <description><![CDATA[<p>Last weekend afforded an opportunity to explore the <a href="http://www.summitpost.org/mountain/rock/151389/lembert-dome.html">Lembert Dome Hike</a> in Yosemite National Park.</p>

<blockquote>Lembert Dome is the monolithic dome that dominates the eastern end of Tuolumne Meadows in Yosemite National Park. It's a justifiably popular ascent, particularly among day hikers in the area, with the summit offering magnificent views of Tuolumne Meadows to the west, the Cathedral Range to the south, and the Sierra crest to the east.</blockquote>

<p>The trail starts out a bit steep but the views are definitely worth the trek up, as is a quick side trip to <a href="http://www.localhikes.com/Hikes/DogLake_0000.asp">Dog Lake</a>.</p>

<p>Here are a few pictures.</p>

<p><a href="http://www.flickr.com/photos/jzawodn/2771822572/" title="Pile of Rocks by jzawodn, on Flickr"><img src="http://farm4.static.flickr.com/3097/2771822572_f1fed05489.jpg" width="375" height="500" alt="Pile of Rocks" /></a><br />
Some rocks to mark the start of the trial...</p>

<p><a href="http://www.flickr.com/photos/jzawodn/2771824890/" title="Lembert Dome Hike in Yosemite by jzawodn, on Flickr"><img src="http://farm4.static.flickr.com/3170/2771824890_fceda39244.jpg" width="500" height="375" alt="Lembert Dome Hike in Yosemite" /></a><br />
The clouds helped keep the heat down.</p>

<p><a href="http://www.flickr.com/photos/jzawodn/2771836836/" title="Lembert Dome Hike in Yosemite by jzawodn, on Flickr"><img src="http://farm4.static.flickr.com/3001/2771836836_0ee9f6d256.jpg" width="500" height="375" alt="Lembert Dome Hike in Yosemite" /></a><br />
Almost there!</p>

<p><a href="http://www.flickr.com/photos/jzawodn/2770993827/" title="Lembert Dome Hike in Yosemite by jzawodn, on Flickr"><img src="http://farm4.static.flickr.com/3172/2770993827_fe25e8fc3a.jpg" width="500" height="375" alt="Lembert Dome Hike in Yosemite" /></a><br />
Looking back where we came from.</p>

<p><a href="http://www.flickr.com/photos/jzawodn/2770997815/" title="Me Looking Goofy by jzawodn, on Flickr"><img src="http://farm4.static.flickr.com/3252/2770997815_7a95b89d40.jpg" width="500" height="375" alt="Me Looking Goofy" /></a><br />
Hey, it's me!</p>

<p><a href="http://www.flickr.com/photos/jzawodn/2771846644/" title="Lembert Dome Hike in Yosemite by jzawodn, on Flickr"><img src="http://farm4.static.flickr.com/3177/2771846644_10a70ba3dd.jpg" width="500" height="375" alt="Lembert Dome Hike in Yosemite" /></a><br />
Look at all those trees...</p>

<p><a href="http://www.flickr.com/photos/jzawodn/2771878206/" title="Dog Lake by jzawodn, on Flickr"><img src="http://farm4.static.flickr.com/3214/2771878206_c5d511a749.jpg" width="500" height="375" alt="Dog Lake" /></a><br />
Dog Lake</p>

<p><a href="http://www.flickr.com/photos/jzawodn/2771884064/" title="Farm Near Evergreen Lodge by jzawodn, on Flickr"><img src="http://farm4.static.flickr.com/3219/2771884064_74c97d3f3c.jpg" width="500" height="375" alt="Farm Near Evergreen Lodge" /></a><br />
Farm near <a href="http://www.evergreenlodge.com/">Evergreen Lodge</a> (just outside the park)</p>

<p>The rest are here: <a href="http://flickr.com/photos/jzawodn/sets/72157606788965813/">Lembert Dome Hike in Yosemite on Flickr</a></p>  <p>(<a href="http://jeremy.zawodny.com/blog/archives/010514.html#comments">comments</a>)</p>]]></description>
      <guid isPermaLink="false">10514@http://jeremy.zawodny.com/blog/</guid>
      <content:encoded><![CDATA[<p>Last weekend afforded an opportunity to explore the <a href="http://www.summitpost.org/mountain/rock/151389/lembert-dome.html">Lembert Dome Hike</a> in Yosemite National Park.</p>

<blockquote>Lembert Dome is the monolithic dome that dominates the eastern end of Tuolumne Meadows in Yosemite National Park. It's a justifiably popular ascent, particularly among day hikers in the area, with the summit offering magnificent views of Tuolumne Meadows to the west, the Cathedral Range to the south, and the Sierra crest to the east.</blockquote>

<p>The trail starts out a bit steep but the views are definitely worth the trek up, as is a quick side trip to <a href="http://www.localhikes.com/Hikes/DogLake_0000.asp">Dog Lake</a>.</p>

<p>Here are a few pictures.</p>

<p><a href="http://www.flickr.com/photos/jzawodn/2771822572/" title="Pile of Rocks by jzawodn, on Flickr"><img src="http://farm4.static.flickr.com/3097/2771822572_f1fed05489.jpg" width="375" height="500" alt="Pile of Rocks" /></a><br />
Some rocks to mark the start of the trial...</p>

<p><a href="http://www.flickr.com/photos/jzawodn/2771824890/" title="Lembert Dome Hike in Yosemite by jzawodn, on Flickr"><img src="http://farm4.static.flickr.com/3170/2771824890_fceda39244.jpg" width="500" height="375" alt="Lembert Dome Hike in Yosemite" /></a><br />
The clouds helped keep the heat down.</p>

<p><a href="http://www.flickr.com/photos/jzawodn/2771836836/" title="Lembert Dome Hike in Yosemite by jzawodn, on Flickr"><img src="http://farm4.static.flickr.com/3001/2771836836_0ee9f6d256.jpg" width="500" height="375" alt="Lembert Dome Hike in Yosemite" /></a><br />
Almost there!</p>

<p><a href="http://www.flickr.com/photos/jzawodn/2770993827/" title="Lembert Dome Hike in Yosemite by jzawodn, on Flickr"><img src="http://farm4.static.flickr.com/3172/2770993827_fe25e8fc3a.jpg" width="500" height="375" alt="Lembert Dome Hike in Yosemite" /></a><br />
Looking back where we came from.</p>

<p><a href="http://www.flickr.com/photos/jzawodn/2770997815/" title="Me Looking Goofy by jzawodn, on Flickr"><img src="http://farm4.static.flickr.com/3252/2770997815_7a95b89d40.jpg" width="500" height="375" alt="Me Looking Goofy" /></a><br />
Hey, it's me!</p>

<p><a href="http://www.flickr.com/photos/jzawodn/2771846644/" title="Lembert Dome Hike in Yosemite by jzawodn, on Flickr"><img src="http://farm4.static.flickr.com/3177/2771846644_10a70ba3dd.jpg" width="500" height="375" alt="Lembert Dome Hike in Yosemite" /></a><br />
Look at all those trees...</p>

<p><a href="http://www.flickr.com/photos/jzawodn/2771878206/" title="Dog Lake by jzawodn, on Flickr"><img src="http://farm4.static.flickr.com/3214/2771878206_c5d511a749.jpg" width="500" height="375" alt="Dog Lake" /></a><br />
Dog Lake</p>

<p><a href="http://www.flickr.com/photos/jzawodn/2771884064/" title="Farm Near Evergreen Lodge by jzawodn, on Flickr"><img src="http://farm4.static.flickr.com/3219/2771884064_74c97d3f3c.jpg" width="500" height="375" alt="Farm Near Evergreen Lodge" /></a><br />
Farm near <a href="http://www.evergreenlodge.com/">Evergreen Lodge</a> (just outside the park)</p>

<p>The rest are here: <a href="http://flickr.com/photos/jzawodn/sets/72157606788965813/">Lembert Dome Hike in Yosemite on Flickr</a></p> <p>(<a href="http://jeremy.zawodny.com/blog/archives/010514.html#comments">comments</a>)</p><img src="http://feeds.zawodny.com/~r/jzawodn/rss2/~4/369083543" height="1" width="1"/>]]></content:encoded>
      <dc:subject>Random</dc:subject>
      <dc:date>2008-08-19T07:35:36-08:00</dc:date>
    <feedburner:origLink>http://jeremy.zawodny.com/blog/archives/010514.html</feedburner:origLink></item>
    <item>
      <title>Open Source Queueing and Messaging Systems?</title>
      <link>http://feeds.zawodny.com/~r/jzawodn/rss2/~3/368338935/010511.html</link>
      <description><![CDATA[<p>Dear Lazyweb,</p>

<p>I'm interested getting an idea of what open
  source <a href="http://en.wikipedia.org/wiki/Message_queue">message
  queueing</a> systems exist that are fast, stable, and have some good
  replication (think multi-colo) and fault tolerance built-in.  The
  idea being, of course, that some processes want to send messages
  into a queue (of work to be done) and other processes will fetch
  those and do stuff with them.</p>

<p>Ideally, I'm looking for a system that allows for different message
  priorities--meaning that I'd like to be able to mark some messages
  as less important, so it's okay if we lose them in a crash.  It'd
  also be handy to have the ability to set expiation times on
  messages.</p>

<p>Bonus points for stuff with good Perl libraries.</p>

<p>Put another way, if you wanted to run something
  like <a href="http://www.amazon.com/Simple-Queue-Service-home-page/b?ie=UTF8&node=13584001">Amazon's
    SQS</a> on your own infrastructure, what would you use as the
  building blocks?</p>

<p>Stuff I already know of (some of which doesn't meet my own
criteria):</p>

<ul>
<li><a href="http://www.openamq.org/">Open AMQ</a></li>
<li><a href="http://activemq.apache.org/amq-message-store.html">Apache
    ActiveMQ</a></li>
<li><a href="http://www.ejabberd.im/">ejabberd</a></li>
<li><a href="http://search.cpan.org/~jmay/Spread-Queue-0.4/">Spread::Queue</a>
  which uses <a href="http://www.spread.org/">the Spread
  Toolkit</a></li>
<li><a href="http://www.rabbitmq.com/">RabbitMQ</a></li>
</ul>

<p>But surely there's more.  Feel free to spew others in the comments
  below...</p>

<p>And even if you don't know of any others, I'd love to hear about
  your experience with any of the above or already commented
  systems.</p>

<p><strong>Update:</strong> A lot of folks are replying with "what's wrong with XXX in your list?"  I haven't tested these yet.  I'm looking to see what the landscape looks like before I dive in.</p>  <p>(<a href="http://jeremy.zawodny.com/blog/archives/010511.html#comments">comments</a>)</p>]]></description>
      <guid isPermaLink="false">10511@http://jeremy.zawodny.com/blog/</guid>
      <content:encoded><![CDATA[<p>Dear Lazyweb,</p>

<p>I'm interested getting an idea of what open
  source <a href="http://en.wikipedia.org/wiki/Message_queue">message
  queueing</a> systems exist that are fast, stable, and have some good
  replication (think multi-colo) and fault tolerance built-in.  The
  idea being, of course, that some processes want to send messages
  into a queue (of work to be done) and other processes will fetch
  those and do stuff with them.</p>

<p>Ideally, I'm looking for a system that allows for different message
  priorities--meaning that I'd like to be able to mark some messages
  as less important, so it's okay if we lose them in a crash.  It'd
  also be handy to have the ability to set expiation times on
  messages.</p>

<p>Bonus points for stuff with good Perl libraries.</p>

<p>Put another way, if you wanted to run something
  like <a href="http://www.amazon.com/Simple-Queue-Service-home-page/b?ie=UTF8&node=13584001">Amazon's
    SQS</a> on your own infrastructure, what would you use as the
  building blocks?</p>

<p>Stuff I already know of (some of which doesn't meet my own
criteria):</p>

<ul>
<li><a href="http://www.openamq.org/">Open AMQ</a></li>
<li><a href="http://activemq.apache.org/amq-message-store.html">Apache
    ActiveMQ</a></li>
<li><a href="http://www.ejabberd.im/">ejabberd</a></li>
<li><a href="http://search.cpan.org/~jmay/Spread-Queue-0.4/">Spread::Queue</a>
  which uses <a href="http://www.spread.org/">the Spread
  Toolkit</a></li>
<li><a href="http://www.rabbitmq.com/">RabbitMQ</a></li>
</ul>

<p>But surely there's more.  Feel free to spew others in the comments
  below...</p>

<p>And even if you don't know of any others, I'd love to hear about
  your experience with any of the above or already commented
  systems.</p>

<p><strong>Update:</strong> A lot of folks are replying with "what's wrong with XXX in your list?"  I haven't tested these yet.  I'm looking to see what the landscape looks like before I dive in.</p> <p>(<a href="http://jeremy.zawodny.com/blog/archives/010511.html#comments">comments</a>)</p><img src="http://feeds.zawodny.com/~r/jzawodn/rss2/~4/368338935" height="1" width="1"/>]]></content:encoded>
      <dc:subject>Toys</dc:subject>
      <dc:date>2008-08-18T11:49:07-08:00</dc:date>
    <feedburner:origLink>http://jeremy.zawodny.com/blog/archives/010511.html</feedburner:origLink></item>
    <item>
      <title>The Long Term Performance of InnoDB</title>
      <link>http://feeds.zawodny.com/~r/jzawodn/rss2/~3/363228703/010504.html</link>
      <description><![CDATA[<p>The <a href="http://www.innodb.com/">InnoDB</a> storage engine has
done wonders for <a href="http://www.mysql.com/">MySQL</a> users that
needed higher concurrency than MyISAM could provide for demanding web
applications.  And the automatic crash recovery is a real bonus
too.</p>

<p>But InnoDB's performance (in terms of concurrency, not really raw
speed) comes at a cost: disk space.  The technique for achieving
this, <a
href="http://en.wikipedia.org/wiki/Multiversion_concurrency_control">multiversion
concurrency control</a>, can chew up a lot of space.  In fact, that
Wikipedia article says:</p>

<blockquote>The obvious drawback to this system is the cost of storing
multiple versions of objects in the database. On the other hand reads
are never blocked, which can be important for workloads mostly
involving reading values from the database.</blockquote>

<p>Indeed.</p>

<p>Imagine a set of database tables will tens of millions of rows and
a non-trivial amount of churn (new records coming in and old ones being
expired or removed all the time).  You might see this in something
like <a href="http://craigslist.org/">a large classifieds site</a>,
for example.</p>

<p>Furthermore imagine that you're using master-slave replication and
the majority of reads hit the slaves.  And some of those slaves are
specifically used for longer running queries.  It turns out that the
combination of versioning, heavy churn, and long running queries can
lead to a substantial difference in the size of a given InnoDB data
file (.ibd) on disk.</p>

<p>Just how much of a difference are we talking about?  Easily a
factor of 4-5x or more.  And when you're dealing with hundreds of
gigabytes, that starts to add up!</p>

<p>It's no secret that InnoDB isn't the best choice for <a
href="http://en.wikipedia.org/wiki/Data_warehouse">data warehouse</a>
looking applications.  But the disk bloat, fragmentation, and ongoing
degradation in performance may be an argument for having some slaves
that keep the same data in MyISAM tables.</p>

<p>I know, I know.  I can do the ALTER TABLE trick to make InnoDB
shrink the table by copying all the rows to a new one, but that does
take time.  Using InnoDB is definitely not a use it and forget about
it choice--but what database engine is, really?.</p>

<p>Looking at <a
href="http://www.innodb.com/doc/innodb_plugin-1.0/">the documentation
for the InnoDB plug-in</a>, I expect to see a real reduction in I/O
when using the new indexes and compression on a data set like this.
(<a
href="http://www.mysqlperformanceblog.com/2008/04/23/testing-innodb-barracuda-format-with-compression/">Others</a>
<a href="http://blog.spacemonkeylabs.com/2008/04/performance-stats-of-barracuda-innodb-compression/">sure</a> <a href="http://venublog.com/2008/04/25/innodb-plugin-row-format-performance/">have</a>.)  But I don't yet have a sense of how stable it
is.</p>

<p>Anyone out there in blog-land have much experience with it?</p>  <p>(<a href="http://jeremy.zawodny.com/blog/archives/010504.html#comments">comments</a>)</p>]]></description>
      <guid isPermaLink="false">10504@http://jeremy.zawodny.com/blog/</guid>
      <content:encoded><![CDATA[<p>The <a href="http://www.innodb.com/">InnoDB</a> storage engine has
done wonders for <a href="http://www.mysql.com/">MySQL</a> users that
needed higher concurrency than MyISAM could provide for demanding web
applications.  And the automatic crash recovery is a real bonus
too.</p>

<p>But InnoDB's performance (in terms of concurrency, not really raw
speed) comes at a cost: disk space.  The technique for achieving
this, <a
href="http://en.wikipedia.org/wiki/Multiversion_concurrency_control">multiversion
concurrency control</a>, can chew up a lot of space.  In fact, that
Wikipedia article says:</p>

<blockquote>The obvious drawback to this system is the cost of storing
multiple versions of objects in the database. On the other hand reads
are never blocked, which can be important for workloads mostly
involving reading values from the database.</blockquote>

<p>Indeed.</p>

<p>Imagine a set of database tables will tens of millions of rows and
a non-trivial amount of churn (new records coming in and old ones being
expired or removed all the time).  You might see this in something
like <a href="http://craigslist.org/">a large classifieds site</a>,
for example.</p>

<p>Furthermore imagine that you're using master-slave replication and
the majority of reads hit the slaves.  And some of those slaves are
specifically used for longer running queries.  It turns out that the
combination of versioning, heavy churn, and long running queries can
lead to a substantial difference in the size of a given InnoDB data
file (.ibd) on disk.</p>

<p>Just how much of a difference are we talking about?  Easily a
factor of 4-5x or more.  And when you're dealing with hundreds of
gigabytes, that starts to add up!</p>

<p>It's no secret that InnoDB isn't the best choice for <a
href="http://en.wikipedia.org/wiki/Data_warehouse">data warehouse</a>
looking applications.  But the disk bloat, fragmentation, and ongoing
degradation in performance may be an argument for having some slaves
that keep the same data in MyISAM tables.</p>

<p>I know, I know.  I can do the ALTER TABLE trick to make InnoDB
shrink the table by copying all the rows to a new one, but that does
take time.  Using InnoDB is definitely not a use it and forget about
it choice--but what database engine is, really?.</p>

<p>Looking at <a
href="http://www.innodb.com/doc/innodb_plugin-1.0/">the documentation
for the InnoDB plug-in</a>, I expect to see a real reduction in I/O
when using the new indexes and compression on a data set like this.
(<a
href="http://www.mysqlperformanceblog.com/2008/04/23/testing-innodb-barracuda-format-with-compression/">Others</a>
<a href="http://blog.spacemonkeylabs.com/2008/04/performance-stats-of-barracuda-innodb-compression/">sure</a> <a href="http://venublog.com/2008/04/25/innodb-plugin-row-format-performance/">have</a>.)  But I don't yet have a sense of how stable it
is.</p>

<p>Anyone out there in blog-land have much experience with it?</p> <p>(<a href="http://jeremy.zawodny.com/blog/archives/010504.html#comments">comments</a>)</p><img src="http://feeds.zawodny.com/~r/jzawodn/rss2/~4/363228703" height="1" width="1"/>]]></content:encoded>
      <dc:subject>MySQL</dc:subject>
      <dc:date>2008-08-12T13:05:19-08:00</dc:date>
    <feedburner:origLink>http://jeremy.zawodny.com/blog/archives/010504.html</feedburner:origLink></item>
    <item>
      <title>Fun with Network Programming, race conditions, and recv() flags</title>
      <link>http://feeds.zawodny.com/~r/jzawodn/rss2/~3/359054943/010484.html</link>
      <description><![CDATA[<p><a href="http://flickr.com/photos/10459273@N05/1730144429/"><img width="240" height="180" src="http://farm3.static.flickr.com/2155/1730144429_285d37f77e_m.jpg" alt="internet tubes" align="right" hspace="5" border="0" /></a> Last week I had the opportunity to do a bit of protocol hacking and found myself stymied by what seemed like a <a href="http://en.wikipedia.org/wiki/Race_condition">race condition</a>.  As with most race conditions, it didn't happen often--anywhere from 1 in 300 to 1 in 5,000 runs.  But it did happen and I couldn't really ignore it.</p>

<p>So I did what I often do when faced with code that's doing seemingly odd things: insert lots of debugging (otherwise known as "print statements").  Since I didn't know if the bug was in the <a href="http://search.cpan.org/~jjschutz/Sphinx-Search-0.12/lib/Sphinx/Search.pm">client</a> (<a href="http://www.perl.org/">Perl</a>) or <a href="http://www.sphinxsearch.com/">server</a> (C++), I had to instrument both of them.  I'd changed both of them a bit, so they were equally likely in my mind.</p>

<p>Well, to make a long, boring, and potentially embarrassing story sort,  I soon figured out that the server was not at fault.  The changes I made to the client were the real problem.</p>

<p>I had forgotten about how the <a href="http://linux.die.net/man/2/recv">recv()</a> system call really works.  I had code that looked something like this (in Perl):</p>

<pre>
recv($socket, $buffer, $length, 0);
...
if (length($buffer) != $length) {
    # complain here
}
</pre>

<p>The value of $length was provided by the server as part of its response.  So the idea was that the client would read exactly $length bytes and then move on.  If it read fewer, we'd be stuck checking again for more data.  And if we did something like this:</p>

<pre>
while (my $chunk = <$socket>) {
    $buffer .= $chunk;
}
</pre>

<p>There's a good chance it could block forever and end up in a sort of <a href="http://en.wikipedia.org/wiki/Deadlock">deadlock</a>, each waiting for the other to do something.  The sever would be waiting for the next request and the client would be waiting for the sever to be "done."</p>

<p>Unfortunately for me, the default behavior of recv() is not to block.  That means the code can't get stuck there--it simply does a best effort read.  If you ask for 2048 bytes to be ready but only 1536 are currently available, you'll end up with 1536 bytes.  And that's exactly the sort of thing that'd happen every once in a while.</p>

<p>The <strong>MSG_WAITALL</strong> flag turned out to be the solution.  You can probably guess what it does...</p>

<blockquote>This flag requests that the operation block until the full request is satisfied. However, the call may still return less data than requested if a signal is caught, an error or disconnect occurs, or the next data to be received is of a different type than that returned.</blockquote>

<p>That's pretty much exactly what I wanted in this situation.  I'm willing to handle the signal, disconnect, and error cases.  Once I made that change, the client and server never missed a beat.  All the weird debugging code and attempts to "detect and fix" the problem were promptly ripped out and the code started to look correct again.</p>

<p>The moral of this story is that you should never assume that the default behavior is what you want.  Check those flags.</p>

<p>Now don't get me started about quoting and database queries...</p>  <p>(<a href="http://jeremy.zawodny.com/blog/archives/010484.html#comments">comments</a>)</p>]]></description>
      <guid isPermaLink="false">10484@http://jeremy.zawodny.com/blog/</guid>
      <content:encoded><![CDATA[<p><a href="http://flickr.com/photos/10459273@N05/1730144429/"><img width="240" height="180" src="http://farm3.static.flickr.com/2155/1730144429_285d37f77e_m.jpg" alt="internet tubes" align="right" hspace="5" border="0" /></a> Last week I had the opportunity to do a bit of protocol hacking and found myself stymied by what seemed like a <a href="http://en.wikipedia.org/wiki/Race_condition">race condition</a>.  As with most race conditions, it didn't happen often--anywhere from 1 in 300 to 1 in 5,000 runs.  But it did happen and I couldn't really ignore it.</p>

<p>So I did what I often do when faced with code that's doing seemingly odd things: insert lots of debugging (otherwise known as "print statements").  Since I didn't know if the bug was in the <a href="http://search.cpan.org/~jjschutz/Sphinx-Search-0.12/lib/Sphinx/Search.pm">client</a> (<a href="http://www.perl.org/">Perl</a>) or <a href="http://www.sphinxsearch.com/">server</a> (C++), I had to instrument both of them.  I'd changed both of them a bit, so they were equally likely in my mind.</p>

<p>Well, to make a long, boring, and potentially embarrassing story sort,  I soon figured out that the server was not at fault.  The changes I made to the client were the real problem.</p>

<p>I had forgotten about how the <a href="http://linux.die.net/man/2/recv">recv()</a> system call really works.  I had code that looked something like this (in Perl):</p>

<pre>
recv($socket, $buffer, $length, 0);
...
if (length($buffer) != $length) {
    # complain here
}
</pre>

<p>The value of $length was provided by the server as part of its response.  So the idea was that the client would read exactly $length bytes and then move on.  If it read fewer, we'd be stuck checking again for more data.  And if we did something like this:</p>

<pre>
while (my $chunk = <$socket>) {
    $buffer .= $chunk;
}
</pre>

<p>There's a good chance it could block forever and end up in a sort of <a href="http://en.wikipedia.org/wiki/Deadlock">deadlock</a>, each waiting for the other to do something.  The sever would be waiting for the next request and the client would be waiting for the sever to be "done."</p>

<p>Unfortunately for me, the default behavior of recv() is not to block.  That means the code can't get stuck there--it simply does a best effort read.  If you ask for 2048 bytes to be ready but only 1536 are currently available, you'll end up with 1536 bytes.  And that's exactly the sort of thing that'd happen every once in a while.</p>

<p>The <strong>MSG_WAITALL</strong> flag turned out to be the solution.  You can probably guess what it does...</p>

<blockquote>This flag requests that the operation block until the full request is satisfied. However, the call may still return less data than requested if a signal is caught, an error or disconnect occurs, or the next data to be received is of a different type than that returned.</blockquote>

<p>That's pretty much exactly what I wanted in this situation.  I'm willing to handle the signal, disconnect, and error cases.  Once I made that change, the client and server never missed a beat.  All the weird debugging code and attempts to "detect and fix" the problem were promptly ripped out and the code started to look correct again.</p>

<p>The moral of this story is that you should never assume that the default behavior is what you want.  Check those flags.</p>

<p>Now don't get me started about quoting and database queries...</p> <p>(<a href="http://jeremy.zawodny.com/blog/archives/010484.html#comments">comments</a>)</p><img src="http://feeds.zawodny.com/~r/jzawodn/rss2/~4/359054943" height="1" width="1"/>]]></content:encoded>
      <dc:subject>Perl</dc:subject>
      <dc:date>2008-08-07T20:42:48-08:00</dc:date>
    <feedburner:origLink>http://jeremy.zawodny.com/blog/archives/010484.html</feedburner:origLink></item>
    <item>
      <title>I'm Thinking</title>
      <link>http://feeds.zawodny.com/~r/jzawodn/rss2/~3/355359804/010481.html</link>
      <description><![CDATA[<p><img width="299" height="383" src="http://www.goodcommitment.tv/wordpress/wp-content/uploads/2007/10/chimpanzee_thinking_poster.jpg" alt="thinking" align="right" hspace="5" /> In <a href="http://www.feld.com/blog/archives/2008/08/amazing_powers.html">Amazing Powers of Concentration</a>, Brad Feld says something that resonated with me.</p>

<blockquote>I've never really understood the phrase "I'm thinking."  It's too abstract for me.  I like to think I think all the time.  So "I'm thinking" doesn't feel like it applies to anything.  For example, when "I'm running", it's pretty clear what I'm doing.  "I'm thinking" - not so much so.</blockquote>

<p>That's so true.  Thinking is an ongoing and difficult to see activity.</p>

<p>In fact, I know of some people who are so busy thinking at times that they find it difficult to sleep at night.  I used to have that problem a lot.  However, it's rare these days.  I'm not sure why.  Maybe I'm just more fond of sleep than I used to be.</p>

<p>I suppose that if you're into meditation, there is a time during the day when you force yourself not to think.  But that's pretty rare, I suspect.</p>

<p>Oh, I almost forgot about <a href="http://jeremy.zawodny.com/blog/archives/002434.html">television</a>...</p>  <p>(<a href="http://jeremy.zawodny.com/blog/archives/010481.html#comments">comments</a>)</p>]]></description>
      <guid isPermaLink="false">10481@http://jeremy.zawodny.com/blog/</guid>
      <content:encoded><![CDATA[<p><img width="299" height="383" src="http://www.goodcommitment.tv/wordpress/wp-content/uploads/2007/10/chimpanzee_thinking_poster.jpg" alt="thinking" align="right" hspace="5" /> In <a href="http://www.feld.com/blog/archives/2008/08/amazing_powers.html">Amazing Powers of Concentration</a>, Brad Feld says something that resonated with me.</p>

<blockquote>I've never really understood the phrase "I'm thinking."  It's too abstract for me.  I like to think I think all the time.  So "I'm thinking" doesn't feel like it applies to anything.  For example, when "I'm running", it's pretty clear what I'm doing.  "I'm thinking" - not so much so.</blockquote>

<p>That's so true.  Thinking is an ongoing and difficult to see activity.</p>

<p>In fact, I know of some people who are so busy thinking at times that they find it difficult to sleep at night.  I used to have that problem a lot.  However, it's rare these days.  I'm not sure why.  Maybe I'm just more fond of sleep than I used to be.</p>

<p>I suppose that if you're into meditation, there is a time during the day when you force yourself not to think.  But that's pretty rare, I suspect.</p>

<p>Oh, I almost forgot about <a href="http://jeremy.zawodny.com/blog/archives/002434.html">television</a>...</p> <p>(<a href="http://jeremy.zawodny.com/blog/archives/010481.html#comments">comments</a>)</p><img src="http://feeds.zawodny.com/~r/jzawodn/rss2/~4/355359804" height="1" width="1"/>]]></content:encoded>
      <dc:subject>Personal</dc:subject>
      <dc:date>2008-08-04T07:02:16-08:00</dc:date>
    <feedburner:origLink>http://jeremy.zawodny.com/blog/archives/010481.html</feedburner:origLink></item>
    <item>
      <title>Feline Diabetes or Living with a Diabetic Cat</title>
      <link>http://feeds.zawodny.com/~r/jzawodn/rss2/~3/354462151/010473.html</link>
      <description><![CDATA[<p>About a week and a half ago, I noticed that Barnes (one of our two older cats) was thinner than he used to be--so much so that I felt his bones when I gave him the sort of back scratching that he loves so much.</p>

<p>Both <a href="http://flickr.com/photos/jzawodn/2659295989/">he and his brother</a> (Noble) are about 10 years old and have nearly always been on the heavy site.  And, of course, don't get to a vet regularly because they utterly detest cat trips.</p>

<p><a href="http://www.flickr.com/photos/jzawodn/2660150364/" title="Barnes and Noble by jzawodn, on Flickr"><img src="http://farm4.static.flickr.com/3179/2660150364_b5a6a06d26.jpg" width="500" height="375" alt="Barnes and Noble" border="0"/></a></p>

<p>Last Thursday we realized that it wasn't getting any better and took him over to the vet (<a href="http://local.yahoo.com/info-21564656-kirkwood-animal-hospital-campbell?csz=San+Jose%2C+CA+95125">Kirkwood Animal Hospital</a> and Dr. Ueno) to see what was going on.  Some on-line reading led me to believe that it was likely a case of <a href="http://en.wikipedia.org/wiki/Hyperthyroidism">Hyperthyroidism</a>, which I'd heard of and thought was somewhat common in aging cats.</p>

<p>However, the doctor called back on Friday morning to tell me that Barnes was <a href="http://en.wikipedia.org/wiki/Diabetes_in_cats_and_dogs">diabetic</a>. :-(  Not only did that mean another trip to the vet and a 6-8 hour stay for glucose testing, it also likely meant insulin shots for the rest of his hopefully long life.</p>

<p>It wasn't long before I found the <a href="http://felinediabetes.com/">FelineDiabetes.com</a> web site and began reading about what this was likely to mean: dietary changes, closer monitoring, daily shots, and so on.</p>

<p>To make a long story short, Barnes is doing better now.  He and the other three cats are adjusting to eating a low-carb cat food (<a href="http://www.purinaveterinarydiets.com/FelineProductDetail.aspx?prod=233">Purina DM</a>).  I have an appointment for his brother Noble to get checked out next week.  If he's headed down the same path, a distinct possibility given the role that genetics can play, we'd like to catch it ASAP.</p>

<p>The food is more expensive and the insulin shots aren't nearly as bad as I expected.  But I really wish this hadn't happened.  Diabetes puts him at risk for other complications down the road--just like in humans.</p>

<h4>What you need to know...</h4>

<p>If you're a cat owner, here are a few suggestions from our experience:</p>

<ol>
<li>Feed your cats a <a href="http://www.felinediabetes.com/diabetic-cat-diets.htm">good diet</a>--onc they were designed to eat.  That means avoiding the cheap foods and excessive snacking.</li>
<li>Help them get lots of exercise.  Use cat toys, catnip, a laser pointer, whatever works for them.</li>
<li>Keep your cats indoors--they'll live much longer lives.</li>
<li>Get you cats to the vet yearly.  Eventually they'll get used to it.  And even if they don't, it's for their own good.</li>
</ol>

<p>Oh, I just dug up <a href="http://flickr.com/photos/jzawodn/sets/72157606520272207/">some of the pictures I took of Barnes and Noble back in 1999</a> when I first adopted them.  There were about 3-6 months old at the time.</p>

<p>Just to lighten things up a bit, if you haven't already seen it, check out <a href="http://www.youtube.com/watch?v=mHXBL6bzAR4">An Engineer's Guide to Cats</a>.</p>

<p>There's probably a lot more I could say about this but will save it for another time.  I'm sure we have much to learn yet.  Now I'm off to get an injection ready.</p>  <p>(<a href="http://jeremy.zawodny.com/blog/archives/010473.html#comments">comments</a>)</p>]]></description>
      <guid isPermaLink="false">10473@http://jeremy.zawodny.com/blog/</guid>
      <content:encoded><![CDATA[<p>About a week and a half ago, I noticed that Barnes (one of our two older cats) was thinner than he used to be--so much so that I felt his bones when I gave him the sort of back scratching that he loves so much.</p>

<p>Both <a href="http://flickr.com/photos/jzawodn/2659295989/">he and his brother</a> (Noble) are about 10 years old and have nearly always been on the heavy site.  And, of course, don't get to a vet regularly because they utterly detest cat trips.</p>

<p><a href="http://www.flickr.com/photos/jzawodn/2660150364/" title="Barnes and Noble by jzawodn, on Flickr"><img src="http://farm4.static.flickr.com/3179/2660150364_b5a6a06d26.jpg" width="500" height="375" alt="Barnes and Noble" border="0"/></a></p>

<p>Last Thursday we realized that it wasn't getting any better and took him over to the vet (<a href="http://local.yahoo.com/info-21564656-kirkwood-animal-hospital-campbell?csz=San+Jose%2C+CA+95125">Kirkwood Animal Hospital</a> and Dr. Ueno) to see what was going on.  Some on-line reading led me to believe that it was likely a case of <a href="http://en.wikipedia.org/wiki/Hyperthyroidism">Hyperthyroidism</a>, which I'd heard of and thought was somewhat common in aging cats.</p>

<p>However, the doctor called back on Friday morning to tell me that Barnes was <a href="http://en.wikipedia.org/wiki/Diabetes_in_cats_and_dogs">diabetic</a>. :-(  Not only did that mean another trip to the vet and a 6-8 hour stay for glucose testing, it also likely meant insulin shots for the rest of his hopefully long life.</p>

<p>It wasn't long before I found the <a href="http://felinediabetes.com/">FelineDiabetes.com</a> web site and began reading about what this was likely to mean: dietary changes, closer monitoring, daily shots, and so on.</p>

<p>To make a long story short, Barnes is doing better now.  He and the other three cats are adjusting to eating a low-carb cat food (<a href="http://www.purinaveterinarydiets.com/FelineProductDetail.aspx?prod=233">Purina DM</a>).  I have an appointment for his brother Noble to get checked out next week.  If he's headed down the same path, a distinct possibility given the role that genetics can play, we'd like to catch it ASAP.</p>

<p>The food is more expensive and the insulin shots aren't nearly as bad as I expected.  But I really wish this hadn't happened.  Diabetes puts him at risk for other complications down the road--just like in humans.</p>

<h4>What you need to know...</h4>

<p>If you're a cat owner, here are a few suggestions from our experience:</p>

<ol>
<li>Feed your cats a <a href="http://www.felinediabetes.com/diabetic-cat-diets.htm">good diet</a>--onc they were designed to eat.  That means avoiding the cheap foods and excessive snacking.</li>
<li>Help them get lots of exercise.  Use cat toys, catnip, a laser pointer, whatever works for them.</li>
<li>Keep your cats indoors--they'll live much longer lives.</li>
<li>Get you cats to the vet yearly.  Eventually they'll get used to it.  And even if they don't, it's for their own good.</li>
</ol>

<p>Oh, I just dug up <a href="http://flickr.com/photos/jzawodn/sets/72157606520272207/">some of the pictures I took of Barnes and Noble back in 1999</a> when I first adopted them.  There were about 3-6 months old at the time.</p>

<p>Just to lighten things up a bit, if you haven't already seen it, check out <a href="http://www.youtube.com/watch?v=mHXBL6bzAR4">An Engineer's Guide to Cats</a>.</p>

<p>There's probably a lot more I could say about this but will save it for another time.  I'm sure we have much to learn yet.  Now I'm off to get an injection ready.</p> <p>(<a href="http://jeremy.zawodny.com/blog/archives/010473.html#comments">comments</a>)</p><img src="http://feeds.zawodny.com/~r/jzawodn/rss2/~4/354462151" height="1" width="1"/>]]></content:encoded>
      <dc:subject>Personal</dc:subject>
      <dc:date>2008-08-03T08:23:46-08:00</dc:date>
    <feedburner:origLink>http://jeremy.zawodny.com/blog/archives/010473.html</feedburner:origLink></item>
    <item>
      <title>Two weeks into my new job at craigslist...</title>
      <link>http://feeds.zawodny.com/~r/jzawodn/rss2/~3/353668223/010472.html</link>
      <description><![CDATA[<p>Many people have asked (via IM, email, Twitter) how my new job is going, what craigslist is like, etc.  So here are a few thoughts about my first two weeks in the new job.</p>

<h4>The Commute</h4>

<p>Despite what folks said <a href="http://jeremy.zawodny.com/blog/archives/010361.html#comments">in the comments of my little announcement</a>, the commute really isn't that bad.  Taking I-280 from Willow Glen (San Jose) up to near Golden Gate Park is about 55 minutes from pulling out of the garage to parking in San Francisco.  And I've been able to find parking on Lincoln each time I've gone up--usually within 4-6 blocks from the office.</p>

<p>So 55 minutes of driving plus about 10 minutes of walking (which is good for me anyway) is very manageable if you're not doing it every day.  If I did, I'd be less up-beat about it, I'm sure.</p>

<p>Having said that, I <em>am</em> going to experiment with the mass transit options as well.  I'd like to give all the reasonable options a fair shake.</p>

<h4>The Hardware</h4>

<p>My laptop, a <a href="http://shop.lenovo.com/us/notebooks/thinkpad/t-series">Lenovo ThinkPad T61</a> running Ubuntu Linux is performing quite well.  It's had one lockup that I cannot attribute to anything in particular.  But other than that, it's a joy to work on--especially with <a href="http://emacs.orebokech.com/">Emacs Snapshot</a> and it's most excellent font rendering.   (Learning VIM is still on my todo list...)</p>

<p>The biggest hassle so far has been VPN related.  Every once in a while my laptop decides to reconnect to my wireless router at home and when it does it replaces the custom <em>resolv.conf</em> file with my "normal" home one.  That results in a VPN that sort of works and sort of doesn't.  I'm getting better at noticing when this happens and fixing it, but I really need to find a way to keep that from happening at all.</p>

<h4>The Culture</h4>

<p>In two weeks, I've only had one experience that I would come close to classifying as a "meeting."  There really aren't conference rooms (yay!) but it did involve a whiteboard.  However, unlike meetings I'm used to, it involved only the most essential people, had a clearly defined goal, and was very useful to me.</p>

<p>The engineering team has a great old-school Perl and Unix mentality (and sense of humor) to it that I really dig.  Our private IRC channel is filled with a mix of useful information sharing and old fashioned joking, complaining, and ranting.  It reminds me a lot of Yahoo in the 1999-2000 time frame.</p>

<h4>The Food</h4>

<p>Unlike Yahoo, craigslist has an abundance of nearby eating establishments within very short walking distance.  I suspect that it'll take months of time before I've sampled what's nearby.</p>

<h4>The Work</h4>

<p>What am I actually doing?</p>

<p>Well, it's a mix of things at this stage.  Since I know only a little bit about how things actually work, I'm asking a lot of questions and trying to get a sense of what's what and where.  That always takes time in a new environment and with a new code base.  But eventually the day does come when you suddenly realize that it's not an issue anymore and you must have things mostly figured out.</p>

<p>I'm also playing with alternatives to our current search.  I've spent a week or so getting to know <a href="http://www.sphinxsearch.com/">Sphinx</a>, the open source search engine by Andrew Aksyonoff.  People often use it as a replacement for <a href="http://dev.mysql.com/doc/refman/5.0/en/fulltext-search.html">MySQL's full-text search</a> capabilities.</p>

<p>So far I'm quite impressed with it's speed and capabilities, not to mention Andrew's willingness to offer advice and suggestions.  I've also been using Jon Schutz's <a href="http://search.cpan.org/~jjschutz/Sphinx-Search-0.12/">Sphinx::Search</a> Perl module.  I've had to slightly modify the code of both to get them to perform the way we'd like, but that modifications aren't terribly extensive.  As is often the case, what took the most time was figuring out what I really wanted to do and then how to do it.</p>

<p>I may have more to say about all this later.</p>

<h4>Hiring</h4>

<p>It looks like we've got a bit more room at craigslist.  As Jim mentioned <a href="http://blog.craigslist.org/2008/06/new-recruit/">on the craigslist blog</a>:</p>

<blockquote>Worth mentioning that the CL tech hiring bit remains set to "1" for star LAMPerl developers, systems heavyweights, and networking wizards.</blockquote>

<p>If you're a great Perl hacker, amazingly skilled networking geek, or someone who really knows systems and data center stuff, we may be waiting for you.</p>

<p><a href="mailto:Jeremy@Zawodny.com">Ping me</a> if you're interested and we'll get the ball rolling.</p>

<h4>Finally...</h4>

<p>Anyway, that's the story so far.</p>

<p>Am I happy in my new role?  You bet.</p>

<p>Do I miss some of my old colleagues at Yahoo?  Of course.  In fact, I missed <a href="http://www.chaddickerson.com/blog/2008/08/01/and-in-the-end/">Chad's going away party</a> due to a sick cat, which is a whole separate and sad story I need to tell.</p>

<p>See Also: <a href="http://jeremy.zawodny.com/blog/archives/010461.html">Settling in to a New Environment at Craigslist</a></p>  <p>(<a href="http://jeremy.zawodny.com/blog/archives/010472.html#comments">comments</a>)</p>]]></description>
      <guid isPermaLink="false">10472@http://jeremy.zawodny.com/blog/</guid>
      <content:encoded><![CDATA[<p>Many people have asked (via IM, email, Twitter) how my new job is going, what craigslist is like, etc.  So here are a few thoughts about my first two weeks in the new job.</p>

<h4>The Commute</h4>

<p>Despite what folks said <a href="http://jeremy.zawodny.com/blog/archives/010361.html#comments">in the comments of my little announcement</a>, the commute really isn't that bad.  Taking I-280 from Willow Glen (San Jose) up to near Golden Gate Park is about 55 minutes from pulling out of the garage to parking in San Francisco.  And I've been able to find parking on Lincoln each time I've gone up--usually within 4-6 blocks from the office.</p>

<p>So 55 minutes of driving plus about 10 minutes of walking (which is good for me anyway) is very manageable if you're not doing it every day.  If I did, I'd be less up-beat about it, I'm sure.</p>

<p>Having said that, I <em>am</em> going to experiment with the mass transit options as well.  I'd like to give all the reasonable options a fair shake.</p>

<h4>The Hardware</h4>

<p>My laptop, a <a href="http://shop.lenovo.com/us/notebooks/thinkpad/t-series">Lenovo ThinkPad T61</a> running Ubuntu Linux is performing quite well.  It's had one lockup that I cannot attribute to anything in particular.  But other than that, it's a joy to work on--especially with <a href="http://emacs.orebokech.com/">Emacs Snapshot</a> and it's most excellent font rendering.   (Learning VIM is still on my todo list...)</p>

<p>The biggest hassle so far has been VPN related.  Every once in a while my laptop decides to reconnect to my wireless router at home and when it does it replaces the custom <em>resolv.conf</em> file with my "normal" home one.  That results in a VPN that sort of works and sort of doesn't.  I'm getting better at noticing when this happens and fixing it, but I really need to find a way to keep that from happening at all.</p>

<h4>The Culture</h4>

<p>In two weeks, I've only had one experience that I would come close to classifying as a "meeting."  There really aren't conference rooms (yay!) but it did involve a whiteboard.  However, unlike meetings I'm used to, it involved only the most essential people, had a clearly defined goal, and was very useful to me.</p>

<p>The engineering team has a great old-school Perl and Unix mentality (and sense of humor) to it that I really dig.  Our private IRC channel is filled with a mix of useful information sharing and old fashioned joking, complaining, and ranting.  It reminds me a lot of Yahoo in the 1999-2000 time frame.</p>

<h4>The Food</h4>

<p>Unlike Yahoo, craigslist has an abundance of nearby eating establishments within very short walking distance.  I suspect that it'll take months of time before I've sampled what's nearby.</p>

<h4>The Work</h4>

<p>What am I actually doing?</p>

<p>Well, it's a mix of things at this stage.  Since I know only a little bit about how things actually work, I'm asking a lot of questions and trying to get a sense of what's what and where.  That always takes time in a new environment and with a new code base.  But eventually the day does come when you suddenly realize that it's not an issue anymore and you must have things mostly figured out.</p>

<p>I'm also playing with alternatives to our current search.  I've spent a week or so getting to know <a href="http://www.sphinxsearch.com/">Sphinx</a>, the open source search engine by Andrew Aksyonoff.  People often use it as a replacement for <a href="http://dev.mysql.com/doc/refman/5.0/en/fulltext-search.html">MySQL's full-text search</a> capabilities.</p>

<p>So far I'm quite impressed with it's speed and capabilities, not to mention Andrew's willingness to offer advice and suggestions.  I've also been using Jon Schutz's <a href="http://search.cpan.org/~jjschutz/Sphinx-Search-0.12/">Sphinx::Search</a> Perl module.  I've had to slightly modify the code of both to get them to perform the way we'd like, but that modifications aren't terribly extensive.  As is often the case, what took the most time was figuring out what I really wanted to do and then how to do it.</p>

<p>I may have more to say about all this later.</p>

<h4>Hiring</h4>

<p>It looks like we've got a bit more room at craigslist.  As Jim mentioned <a href="http://blog.craigslist.org/2008/06/new-recruit/">on the craigslist blog</a>:</p>

<blockquote>Worth mentioning that the CL tech hiring bit remains set to "1" for star LAMPerl developers, systems heavyweights, and networking wizards.</blockquote>

<p>If you're a great Perl hacker, amazingly skilled networking geek, or someone who really knows systems and data center stuff, we may be waiting for you.</p>

<p><a href="mailto:Jeremy@Zawodny.com">Ping me</a> if you're interested and we'll get the ball rolling.</p>

<h4>Finally...</h4>

<p>Anyway, that's the story so far.</p>

<p>Am I happy in my new role?  You bet.</p>

<p>Do I miss some of my old colleagues at Yahoo?  Of course.  In fact, I missed <a href="http://www.chaddickerson.com/blog/2008/08/01/and-in-the-end/">Chad's going away party</a> due to a sick cat, which is a whole separate and sad story I need to tell.</p>

<p>See Also: <a href="http://jeremy.zawodny.com/blog/archives/010461.html">Settling in to a New Environment at Craigslist</a></p> <p>(<a href="http://jeremy.zawodny.com/blog/archives/010472.html#comments">comments</a>)</p><img src="http://feeds.zawodny.com/~r/jzawodn/rss2/~4/353668223" height="1" width="1"/>]]></content:encoded>
      <dc:subject>craigslist</dc:subject>
      <dc:date>2008-08-02T09:08:22-08:00</dc:date>
    <feedburner:origLink>http://jeremy.zawodny.com/blog/archives/010472.html</feedburner:origLink></item>
    <item>
      <title>Great Pancakes with the Presto Cool Touch 20 Inch Electric Griddle</title>
      <link>http://feeds.zawodny.com/~r/jzawodn/rss2/~3/350556086/010470.html</link>
      <description><![CDATA[<p><img width="280" height="280" src="http://ecx.images-amazon.com/images/I/31YllmBO8HL._SL500_AA280_.jpg" alt="griddle" border="0" align="right" hspace="5" /> We recently bought an electric griddle so that I could make more than one pancake at a time.  After reading a few reviews, I confirmed that the 20 inch electric model <a href="http://www.gopresto.com/products/products_search.php?search_value=46&operation=Search&search_type=category">from Presto</a> was the way to go.</p>

<p>While it's available <a href="http://www.amazon.com/Presto-07034-Jumbo-Electric-Griddle/dp/B00006F7C2/ref=pd_bbs_sr_2?ie=UTF8&tag=jeremydzawodny&s=home-garden&qid=1217343499&sr=8-2">on Amazon.com</a> (and <a href="http://www.amazon.com/Presto-07030-20-Inch-Electric-Griddle/dp/B001078UCC/ref=pd_bbs_1?ie=UTF8&tag=jeremydzawodny&s=home-garden&qid=1217343499&sr=8-1">here</a>), I bought locally and got the chance to put it to use last weekend when some of the family were visiting.  I was surprised and impressed by how quickly and evenly it heated.  But that was really just the beginning.</p>

<p>It turns out that this little electric wonder makes pancakes that light, fluffy, and far more evenly cooked than anything I've even been able to do on the stove top.  And to put icing on the cake, the manual provides temperature settings so that you can cook a few dozen other things: eggs, sausage, bacon, and so on.</p>

<p>The non-stick coating is trivial to clean and the grease catcher appears to do it's job well too.</p>

<p>In summary, if you ever find yourself needing to make pancakes for more than a couple people at once, get yourself an electric griddle!</p>

<p>Damn, now I'm hungry for a pancake...</p>  <p>(<a href="http://jeremy.zawodny.com/blog/archives/010470.html#comments">comments</a>)</p>]]></description>
      <guid isPermaLink="false">10470@http://jeremy.zawodny.com/blog/</guid>
      <content:encoded><![CDATA[<p><img width="280" height="280" src="http://ecx.images-amazon.com/images/I/31YllmBO8HL._SL500_AA280_.jpg" alt="griddle" border="0" align="right" hspace="5" /> We recently bought an electric griddle so that I could make more than one pancake at a time.  After reading a few reviews, I confirmed that the 20 inch electric model <a href="http://www.gopresto.com/products/products_search.php?search_value=46&operation=Search&search_type=category">from Presto</a> was the way to go.</p>

<p>While it's available <a href="http://www.amazon.com/Presto-07034-Jumbo-Electric-Griddle/dp/B00006F7C2/ref=pd_bbs_sr_2?ie=UTF8&tag=jeremydzawodny&s=home-garden&qid=1217343499&sr=8-2">on Amazon.com</a> (and <a href="http://www.amazon.com/Presto-07030-20-Inch-Electric-Griddle/dp/B001078UCC/ref=pd_bbs_1?ie=UTF8&tag=jeremydzawodny&s=home-garden&qid=1217343499&sr=8-1">here</a>), I bought locally and got the chance to put it to use last weekend when some of the family were visiting.  I was surprised and impressed by how quickly and evenly it heated.  But that was really just the beginning.</p>

<p>It turns out that this little electric wonder makes pancakes that light, fluffy, and far more evenly cooked than anything I've even been able to do on the stove top.  And to put icing on the cake, the manual provides temperature settings so that you can cook a few dozen other things: eggs, sausage, bacon, and so on.</p>

<p>The non-stick coating is trivial to clean and the grease catcher appears to do it's job well too.</p>

<p>In summary, if you ever find yourself needing to make pancakes for more than a couple people at once, get yourself an electric griddle!</p>

<p>Damn, now I'm hungry for a pancake...</p> <p>(<a href="http://jeremy.zawodny.com/blog/archives/010470.html#comments">comments</a>)</p><img src="http://feeds.zawodny.com/~r/jzawodn/rss2/~4/350556086" height="1" width="1"/>]]></content:encoded>
      <dc:subject>Toys</dc:subject>
      <dc:date>2008-07-30T07:42:26-08:00</dc:date>
    <feedburner:origLink>http://jeremy.zawodny.com/blog/archives/010470.html</feedburner:origLink></item>


  </channel>
</rss>
