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

<channel>
	<title>Joe's Blog! &#187; Erlang</title>
	<atom:link href="http://www.joeandmotorboat.com/category/dev/erlang/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.joeandmotorboat.com</link>
	<description></description>
	<lastBuildDate>Fri, 08 Jan 2010 00:00:31 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9.2</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Fun with the CouchDB _changes feed and RabbitMQ.</title>
		<link>http://www.joeandmotorboat.com/2010/01/01/fun-with-the-couchdb-_changes-feed-and-rabbitmq/</link>
		<comments>http://www.joeandmotorboat.com/2010/01/01/fun-with-the-couchdb-_changes-feed-and-rabbitmq/#comments</comments>
		<pubDate>Fri, 01 Jan 2010 23:14:01 +0000</pubDate>
		<dc:creator>joe</dc:creator>
				<category><![CDATA[Dev]]></category>
		<category><![CDATA[Erlang]]></category>
		<category><![CDATA[Ruby]]></category>

		<guid isPermaLink="false">http://www.joeandmotorboat.com/?p=962</guid>
		<description><![CDATA[I was recently introduced to yajl-ruby, ruby bindings to the C based yajl json parsing/encoding libraries. After discovering that it can parse HTTP streams it seemed like it would be a perfect fit for use with CouchDB. A while back I wrote some code to push update notifications to RabbitMQ and a commenter mentioned using [...]]]></description>
			<content:encoded><![CDATA[<p>I was recently <a href="http://ozmm.org/posts/2009_open_source_top_ten.html">introduced</a> to <a href="http://github.com/brianmario/yajl-ruby">yajl-ruby</a>, ruby bindings to the C based yajl json parsing/encoding libraries. After discovering that it can parse HTTP streams it seemed like it would be a perfect fit for use with <a href="http://couchdb.apache.org/">CouchDB</a>. A while back I wrote <a href="http://www.joeandmotorboat.com/2009/06/05/sending-couchdb-update-notifications-to-rabbitmq/">some code to push update notifications</a> to RabbitMQ and a commenter mentioned using the <a href="http://books.couchdb.org/relax/reference/change-notifications">_changes feed</a> instead. Combining the _changes feed and yajl-ruby&#8217;s HttpStream seemed like a good way to do it.</p>
<p>The _changes feed is a running list of all the documents that have changed in a database listed in order by sequence number. This is similar to update notifications but gives more information such as the document IDs and is HTTP based (with multiple feed styles) rather than stdout. Additionally you can create design document filters which can be specified as a query parameter to give you only the parts of the feed you want. All in all _changes is a pretty powerful feature.</p>
<p>Now for the fun stuff, the code. There are a few dependencies I used to do this, specifically focused on making it fast. As such I used EventMachine based libraries for <a href="http://github.com/tmm1/amqp/">AMQP</a> and <a href="http://github.com/igrigorik/em-http-request/">HTTP requests</a>. The first bit of code takes the _changes feed for the &#8220;test&#8221; database, parses the feed, uses the document ID to request that document and publish it to the queue. One key item to note is that this code <strong>requires the latest yajl-ruby</strong> from github to run properly. Additionally, this works nicely with <em>feed=continuous</em> so it grabs the documents as they are changed without a need for polling.</p>
<p><script src="http://gist.github.com/266991.js?file=changes_pub.rb"></script> Note that there is a variable for <em>since</em>, this allows you to start from a specific sequence number so you can skip over old changes.</p>
<p>The next bit of code works from the other side of the queue. It subscribes to the queue, parses the JSON, performs some operations on it and puts the results back into another CouchDB database called &#8220;results&#8221;.  <script src="http://gist.github.com/266991.js?file=changes_sub.rb"></script></p>
<p>What could it be used for? My first thought is some sort of parallel computation, boot up a few dozen EC2 nodes and start dumping data into CouchDB. Have all those nodes pop messages off the queue, process them and dump the results back into Couch. Legitimately one could chain these together to process the results again. The queue ends up being a simple job management system with the EC2 nodes popping new messages as they finish processing them. With a little bit of work, features and the right use case I think could be a pretty powerful system.</p>
<p>Check out the <a href="http://gist.github.com/266991">code</a>, <a href="http://github.com/joewilliams">my other projects</a> and follow me on twitter <a href="http://twitter.com/williamsjoe">@williamsjoe</a>.</p>
<p><em>[edit: made a slight improvement to changes_sub.rb on 20100107]</em></p>
]]></content:encoded>
			<wfw:commentRss>http://www.joeandmotorboat.com/2010/01/01/fun-with-the-couchdb-_changes-feed-and-rabbitmq/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Red Black Trees.</title>
		<link>http://www.joeandmotorboat.com/2009/09/19/red-black-trees/</link>
		<comments>http://www.joeandmotorboat.com/2009/09/19/red-black-trees/#comments</comments>
		<pubDate>Sat, 19 Sep 2009 16:34:16 +0000</pubDate>
		<dc:creator>joe</dc:creator>
				<category><![CDATA[Dev]]></category>
		<category><![CDATA[Erlang]]></category>
		<category><![CDATA[Ruby]]></category>

		<guid isPermaLink="false">http://www.joeandmotorboat.com/?p=945</guid>
		<description><![CDATA[Been reading up on Red-black trees, a self-balancing binary tree. Here are some resources I found interesting.

Multiple posts at Fuad AlTabba, with an erlang implementation.
Ruby rbtree library (uses C).
An implementation in Ruby.
Trees in Erlang.
Red-black trees in two hours, with a link to Chris Okaski&#8217;s Red-Black Trees in a Functional Setting with implementation in Haskell.

]]></description>
			<content:encoded><![CDATA[<p>Been reading up on <a href="http://en.wikipedia.org/wiki/Red_black_tree">Red-black trees</a>, a self-balancing binary tree. Here are some resources I found interesting.</p>
<ul>
<li>Multiple posts at <a href="http://www.altabba.org/">Fuad AlTabba</a>, with an <a href="http://www.cs.auckland.ac.nz/~fuad/rbtree.erl">erlang implementation</a>.</li>
<li>Ruby <a href="http://rubyforge.org/projects/rbtree/">rbtree library</a> (uses C).</li>
<li>An <a href="http://www.dmh2000.com/cjpr/RBRuby.html">implementation</a> in Ruby.</li>
<li><a href="http://mark.aufflick.com/blog/2007/11/30/trees-in-erlang">Trees in Erlang</a>.</li>
<li><a href="http://semanticvector.blogspot.com/2008/05/red-black-tree-in-2-hours.html">Red-black trees in two hours</a>, with a link to Chris Okaski&#8217;s <a name="jfp99"><em>Red-Black Trees in a Functional Setting </em>with implementation in Haskell.</a></li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://www.joeandmotorboat.com/2009/09/19/red-black-trees/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>HAProxy Stats Socket and fun with socat.</title>
		<link>http://www.joeandmotorboat.com/2009/08/20/haproxy-stats-socket-and-fun-with-socat/</link>
		<comments>http://www.joeandmotorboat.com/2009/08/20/haproxy-stats-socket-and-fun-with-socat/#comments</comments>
		<pubDate>Thu, 20 Aug 2009 22:22:40 +0000</pubDate>
		<dc:creator>joe</dc:creator>
				<category><![CDATA[Dev]]></category>
		<category><![CDATA[Erlang]]></category>
		<category><![CDATA[Linux]]></category>
		<category><![CDATA[Ruby]]></category>

		<guid isPermaLink="false">http://www.joeandmotorboat.com/?p=935</guid>
		<description><![CDATA[I&#8217;ve been debugging issues with HTTP, my backend servers and HAProxy. After a quick email to the HAProxy mailing list I found out about a configuration option stats socket PATH. This will create a socket you can send commands to and get more information out of HAProxy. To do this I just used some simle [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve been debugging issues with HTTP, my backend servers and HAProxy. After a quick email to the HAProxy mailing list I found out about a configuration option <em>stats socket PATH</em>. This will create a socket you can send commands to and get more information out of HAProxy. To do this I just used some simle unix tools, the key is <a href="http://www.dest-unreach.org/socat/">socat</a>. From the man:</p>
<blockquote><p>
socat is a relay for bidirectional data transfer between two independent data channels. Each of these data channels may be a file, pipe, device (serial line etc. or a pseudo terminal), a socket (UNIX, IP4, IP6 &#8211; raw, UDP, TCP), an SSL socket, proxy CONNECT connection, a file descriptor (stdin etc.), the GNU line editor (readline), a program, or a combination of two of these. These modes include generation of &#8220;listening&#8221; sockets, named pipes, and pseudo terminals.
</p></blockquote>
<p>Here are a few examples of how to use the stats socket. First, you need to add <em>stats socket PATH</em> to your configuration and restart haproxy. You should then find a socket located at the path specified, I used <em>/tmp/haproxy</em>. Now you can send it commands to get more information and stats from HAProxy.<br />
<code><br />
echo "show stat" | socat unix-connect:/tmp/haproxy stdio<br />
</code></p>
<p>This will give you stats on all of your backends and frontends, some of the same stuff you see on the stats page enabled by the <em>stats uri</em> configuration. As an added bonus it&#8217;s all in CSV.<br />
<code><br />
echo "show errors" | socat unix-connect:/tmp/haproxy stdio<br />
</code></p>
<p><em>show errors</em> will give you a capture of last error on each backend/frontend.<br />
<code><br />
echo "show info" | socat unix-connect:/tmp/haproxy stdio<br />
</code></p>
<p>This will give you information about the running HAProxy process such as pid, uptime and etc.<br />
<code><br />
echo "show sess" | socat unix-connect:/tmp/haproxy stdio<br />
</code></p>
<p>This will dump (possibly huge) info about all know sessions.</p>
<p>For more details check out <a href="http://haproxy.1wt.eu/download/1.3/doc/configuration.txt">the docs</a> section 9 and <em>stats socket</em> in section 3.1.</p>
<p><strong>Bonus socat fun.</strong></p>
<p>socat is a more full featured cousin of <a href="http://netcat.sourceforge.net/">netcat</a>. Both can be used in similar ways, one thing I use them for occasionally is debugging REST and etc. This was a real help when working with an API that didn&#8217;t have a library, I could test things out without needing to make erroneous calls to the API. In the simplest case you can have either of them listen on a port and output all the details of the request. To do this with socat run:</p>
<p><code>socat tcp-listen:8000 stdio</code></p>
<p>This will listen for connections on port 8000. Doing the same thing with netcat is easy as well:</p>
<p><code>netcat -l -p 8000</code></p>
<p>For instance you can see the output from creating a document in CouchDB.</p>
<p>In one terminal:<br />
<code><br />
$ irb<br />
irb(main):001:0> require 'rubygems'<br />
=> true<br />
irb(main):002:0> require 'rest_client'<br />
=> true<br />
irb(main):003:0> RestClient.put("http://localhost:8000/somedb/somedoc", "{\"somekey\": \"somevalue\"}", :content_type => "application/json")<br />
</code></p>
<p>In another run your mock server:<br />
<code><br />
$ socat tcp-listen:8000 stdio<br />
PUT /somedb/somedoc HTTP/1.1<br />
Accept: application/xml<br />
Content-Type: application/json<br />
Accept-Encoding: gzip, deflate<br />
Content-Length: 24<br />
Host: localhost:8000</p>
<p>{"somekey": "somevalue"}<br />
</code></p>
<p>Oh! By the way, if you install netcat from source, don&#8217;t compile with <em>-DGAPING_SECURITY_HOLE</em> unless you know what you are doing. <img src='http://www.joeandmotorboat.com/wp-includes/images/smilies/icon_biggrin.gif' alt=':D' class='wp-smiley' /> </p>
]]></content:encoded>
			<wfw:commentRss>http://www.joeandmotorboat.com/2009/08/20/haproxy-stats-socket-and-fun-with-socat/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Boston Meet-up.</title>
		<link>http://www.joeandmotorboat.com/2009/07/21/boston-meet-up/</link>
		<comments>http://www.joeandmotorboat.com/2009/07/21/boston-meet-up/#comments</comments>
		<pubDate>Tue, 21 Jul 2009 17:01:25 +0000</pubDate>
		<dc:creator>joe</dc:creator>
				<category><![CDATA[Dev]]></category>
		<category><![CDATA[Erlang]]></category>
		<category><![CDATA[Linux]]></category>
		<category><![CDATA[Ruby]]></category>

		<guid isPermaLink="false">http://www.joeandmotorboat.com/?p=929</guid>
		<description><![CDATA[Headed to Boston next week, planning to meet-up next Tuesday (7/28) 7pm at Cambridge Brewing Co. Drop by for a beer, food and maybe a little Erlang.
]]></description>
			<content:encoded><![CDATA[<p>Headed to Boston next week, planning to meet-up next Tuesday (7/28) 7pm at <a href="http://www.cambrew.com/">Cambridge Brewing Co</a>. Drop by for a beer, food and maybe a little Erlang.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.joeandmotorboat.com/2009/07/21/boston-meet-up/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Sending CouchDB Update Notifications to RabbitMQ.</title>
		<link>http://www.joeandmotorboat.com/2009/06/05/sending-couchdb-update-notifications-to-rabbitmq/</link>
		<comments>http://www.joeandmotorboat.com/2009/06/05/sending-couchdb-update-notifications-to-rabbitmq/#comments</comments>
		<pubDate>Sat, 06 Jun 2009 06:09:29 +0000</pubDate>
		<dc:creator>joe</dc:creator>
				<category><![CDATA[Dev]]></category>
		<category><![CDATA[Erlang]]></category>
		<category><![CDATA[Ruby]]></category>

		<guid isPermaLink="false">http://www.joeandmotorboat.com/?p=913</guid>
		<description><![CDATA[Working at Cloudant I use CouchDB on a daily basis. This evening for fun I decided to write some Ruby to take update notifications and push them into RabbitMQ. There are other examples of using the update notifications and Ruby in Couch such as the view updater out on the Couch wiki.  It turned [...]]]></description>
			<content:encoded><![CDATA[<p>Working at <a href="http://cloudant.com/">Cloudant</a> I use <a href="http://couchdb.apache.org/">CouchDB</a> on a daily basis. This evening for fun I decided to write some <a href="http://www.ruby-lang.org/en/">Ruby</a> to take update notifications and push them into <a href="http://www.rabbitmq.com/">RabbitMQ</a>. There are other examples of using the update notifications and Ruby in Couch such as the <a href="http://wiki.apache.org/couchdb/Regenerating_views_on_update">view updater out on the Couch wiki</a>.  It turned out super simple. There are a few AMQP libraries for Ruby, in this example I am going to use <a href="http://github.com/famoseagle/carrot/tree/master">carrot</a>.  It&#8217;s based on the  <a href="http://github.com/tmm1/amqp/tree/master">amqp</a> library without all the <a href="http://rubyeventmachine.com/">eventmachine</a> stuff. So here it goes:</p>
<p><strong><a href="http://gist.github.com/124716">couch_amqp.rb</a></strong> :</p>
<blockquote><p>#!/usr/bin/ruby</p>
<p>require &#8216;rubygems&#8217;<br />
require &#8216;carrot&#8217;</p>
<p>def main<br />
queue = &#8220;couchdb&#8221;<br />
run = true<br />
couchq = Carrot.queue(:queue =&gt; queue)</p>
<p>while run do</p>
<p>notifications = gets</p>
<p>if notifications == nil<br />
run = false<br />
else<br />
couchq.publish(notifications)<br />
end</p>
<p>end<br />
end</p>
<p>main</p></blockquote>
<p>As you can tell we connect to a queue called &#8220;couchdb&#8221; on by default this is on localhost. Next we have a loop that continually runs and grabs updates from stdin. I then publish each notification to the queue and that&#8217;s that. To get the messages out of the queue I used irb and carrot.</p>
<blockquote><p>[user@host ~]$ irb<br />
irb(main):001:0&gt; require &#8216;rubygems&#8217;<br />
=&gt; true<br />
irb(main):002:0&gt; require &#8216;carrot&#8217;<br />
=&gt; true<br />
irb(main):003:0&gt; couchq = Carrot.queue(:queue =&gt; &#8220;couchdb&#8221;)<br />
=&gt; #&lt;Carrot::AMQP::Queue:0&#215;7f8d2284b640 &lt;snip&gt;<br />
irb(main):004:0&gt; couchq.pop<br />
=&gt; &#8220;{\&#8221;type\&#8221;:\&#8221;updated\&#8221;,\&#8221;db\&#8221;:\&#8221;test1\&#8221;}\n&#8221;</p></blockquote>
<p>So yeah, pretty simple stuff. Go ahead relax! <img src='http://www.joeandmotorboat.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<p><em>[EDIT 06/05/2009 2326 PST : Don't forget to add the entry to your local.ini]</em></p>
<blockquote><p>[update_notification]</p>
<p>couch_amqp=/PATH/TO/couch_amqp.rb<em><br />
</em></p></blockquote>
]]></content:encoded>
			<wfw:commentRss>http://www.joeandmotorboat.com/2009/06/05/sending-couchdb-update-notifications-to-rabbitmq/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>Erlang Factory.</title>
		<link>http://www.joeandmotorboat.com/2009/03/11/erlang-factory/</link>
		<comments>http://www.joeandmotorboat.com/2009/03/11/erlang-factory/#comments</comments>
		<pubDate>Wed, 11 Mar 2009 16:04:54 +0000</pubDate>
		<dc:creator>joe</dc:creator>
				<category><![CDATA[Dev]]></category>
		<category><![CDATA[Erlang]]></category>

		<guid isPermaLink="false">http://www.joeandmotorboat.com/?p=883</guid>
		<description><![CDATA[It&#8217;s official I will be giving a talk at the Erlang Factory conference next month. I will be speaking about web server performance with a final round of tests that should be much more complete than the last couple death-matches. Hope to see you there.
]]></description>
			<content:encoded><![CDATA[<p>It&#8217;s official I will be giving a talk at the <a href="http://erlang-factory.com/conference/SFBayAreaErlangFactory2009/">Erlang Factory</a> conference next month. I will be speaking about web server performance with a final round of tests that should be much more complete than the last couple death-matches. Hope to see you there.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.joeandmotorboat.com/2009/03/11/erlang-factory/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Erlang Queue and Merle.</title>
		<link>http://www.joeandmotorboat.com/2009/03/05/erlang-queue-and-merle/</link>
		<comments>http://www.joeandmotorboat.com/2009/03/05/erlang-queue-and-merle/#comments</comments>
		<pubDate>Thu, 05 Mar 2009 17:24:45 +0000</pubDate>
		<dc:creator>joe</dc:creator>
				<category><![CDATA[Dev]]></category>
		<category><![CDATA[Erlang]]></category>

		<guid isPermaLink="false">http://www.joeandmotorboat.com/?p=881</guid>
		<description><![CDATA[Lately I have been playing around with the idea of adding a process pool to merle or at least a layer that allows you to use a process pool. I also happened across Erlang&#8217;s queue implementation. It has all the basic functions you expect from a queue and two API&#8217;s. So I created a branch [...]]]></description>
			<content:encoded><![CDATA[<p>Lately I have been playing around with the idea of adding a process pool to <a href="http://github.com/joewilliams/merle/tree/master">merle</a> or at least a layer that allows you to use a process pool. I also happened across Erlang&#8217;s <a href="http://www.erlang.org/doc/man/queue.html">queue</a> implementation. It has all the basic functions you expect from a queue and two API&#8217;s. So I created a <a href="http://github.com/joewilliams/merle/tree/merle_queue">branch of merle</a> to play around with this idea. There are two main differences from the mainline merle, the first is the pid is always passed to the functions doing the work rather than using <em>?SERVER</em>, for instance.</p>
<blockquote><p>
stats() -><br />
  gen_server2:call(?SERVER, {stats}).
</p></blockquote>
<p>versus</p>
<blockquote><p>
stats(Pid) -><br />
  gen_server2:call(Pid, {stats}).
</p></blockquote>
<p>This allows more than one gen_server process to be started, the down side being you have to pass this Pid variable around. The other change is a new module called <em>queue_merle</em>, this is a sort of the process pool later that interfaces with merle. Obviously this is a <strong>very rough</strong> cut but seems to do the trick. The <em>start</em> function starts five merle processes and adds them to the queue, <em>rotate</em> rotates the queue taking all the head of the queue and inserting it into the bottom. I have impletemeted <em>getkey</em> and <em>set</em> as well. They accept a queue, key and/or value. The downside to this implementation is similar to that of using merle without defining <em>?SERVER</em>, you have to know what, in this case, queue you are using and you need to make sure it is the most current otherwise you will end up getting more calls to one process than another. Here is an example of usage.</p>
<blockquote><p>
1> Queue = queue_merle:start().<br />
{[<0.39.0>,<0.38.0>,<0.37.0>,<0.36.0>],[<0.33.0>]}<br />
2> {Queue1, Result1} = queue_merle:set(Queue, a, &#8220;asdf&#8221;).<br />
{{[<0.33.0>,<0.39.0>,<0.38.0>],[<0.36.0>,<0.37.0>]},ok}<br />
3> {Queue2, Result2} = queue_merle:set(Queue1, b, &#8220;1234&#8243;).<br />
{{[<0.36.0>,<0.33.0>,<0.39.0>,<0.38.0>],[<0.37.0>]},ok}<br />
4> {Queue3, Result3} = queue_merle:getkey(Queue2, a).<br />
{{[<0.37.0>,<0.36.0>,<0.33.0>],[<0.38.0>,<0.39.0>]},&#8221;asdf&#8221;}<br />
5> {Queue4, Result4} = queue_merle:getkey(Queue3, b).<br />
{{[<0.38.0>,<0.37.0>,<0.36.0>,<0.33.0>],[<0.39.0>]},&#8221;1234&#8243;}
</p></blockquote>
<p>As you can see the queue is rotating each time the functions are run but due to not allowing for multiple assignment one has to grab the new version of the queue each time and use it for the next operation. I imagine there is probably a cleaner way to do this, if I come up with one I like it will probably get added to mainline merle. Fun stuff.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.joeandmotorboat.com/2009/03/05/erlang-queue-and-merle/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>New Stuff for merle.</title>
		<link>http://www.joeandmotorboat.com/2009/02/06/new-stuff-for-merle/</link>
		<comments>http://www.joeandmotorboat.com/2009/02/06/new-stuff-for-merle/#comments</comments>
		<pubDate>Fri, 06 Feb 2009 19:45:08 +0000</pubDate>
		<dc:creator>joe</dc:creator>
				<category><![CDATA[Dev]]></category>
		<category><![CDATA[Erlang]]></category>

		<guid isPermaLink="false">http://www.joeandmotorboat.com/?p=845</guid>
		<description><![CDATA[I have been playing around with merle and have switched it from using the normal gen_server to using LShift&#8217;s modified gen_server2. It has a couple of changes to make things faster, the key is:
From a comment in their source file:
More efficient handling of selective receives in callbacks gen_server2 processes drain their message queue into an [...]]]></description>
			<content:encoded><![CDATA[<p>I have been playing around with <a href="http://github.com/joewilliams/merle/tree/master">merle</a> and have switched it from using the normal gen_server to using LShift&#8217;s modified <a href="http://hg.rabbitmq.com/rabbitmq-server/file/b95f2fd4e3f6/src/gen_server2.erl">gen_server2</a>. It has a couple of changes to make things faster, the key is:</p>
<blockquote><p>From a comment in their source file:</p>
<p>More efficient handling of selective receives in callbacks gen_server2 processes drain their message queue into an internal buffer before invoking any callback module functions. Messages are dequeued from the buffer for processing. Thus the effective message queue of a gen_server2 process is the concatenation of the internal buffer and the real message queue. As a result of the draining, any selective receive invoked inside a callback is less likely to have to scan a large message queue.</p></blockquote>
<p>This means if you send a ton of messages at once it can handle this more effectively. In the case of merle this means more gets/puts/deletes/etc in a shorter amount of time. Some of the downsides are stated on the <a href="http://erlang.org/pipermail/erlang-questions/2009-January/041030.html">mailing list</a>. I believe for the workload that merle does (lots of small messages in short time spans) this is a great addition. For other use cases it may not be, <a href="http://whendoitest.com/">you know when you should test</a>.</p>
<p>I have run some tests using gen_server and gen_server2 doing a large number of &#8217;set&#8217; operations to memcached. The test consisted of running <em>merle:set(a, &#8220;1&#8243;)</em> a specific number of times (25k, 50k and 100k) with both gen_server and gen_server2. Since the mailbox gets backed up the Erlang processes are started before the operations complete on the memcached side. I didn&#8217;t have a good way to watch the memcached logs for when the operations completed and log timestamps so I used a simple stopwatch app to physically do the timing. Obviously this isn&#8217;t scientific but as you will see the differences are large enough its not a big deal.</p>
<p><img src="http://www.joeandmotorboat.com/files/merle-gen_server-tests.png" alt="gen_server" width="444" height="333" /></p>
<p><a href="http://www.joeandmotorboat.com/files/merle-gen_server-tests.png"><em>(click here for a larger view)</em></a></p>
<p>As you can see gen_server2 performs much better (almost linearly?), shaving large amounts of time off. Also note that on the gen_server 100k tests I stopped the testing once it reached 5 minutes, so I am unsure how much longer those would have went on. Below is the raw data, I also preformed subsequent tests and found that my initial findings seemed to be accurate.</p>
<table border="0" cellspacing="0" frame="void" rules="none">
<colgroup>
<col width="86"></col>
<col width="130"></col>
<col width="131"></col>
<col width="115"></col>
<col width="122"></col>
</colgroup>
<tbody>
<tr>
<td width="86" height="17" align="left"></td>
<td width="130" align="left">gen_server test 1</td>
<td width="131" align="left">gen_server2 test 1</td>
<td width="115" align="left">gen_server test 2</td>
<td width="122" align="left">gen_server2 test 2</td>
</tr>
<tr>
<td height="17" align="right">25000</td>
<td align="right">24</td>
<td align="right">4</td>
<td align="right">25</td>
<td align="right">4</td>
</tr>
<tr>
<td height="17" align="right">50000</td>
<td align="right">134</td>
<td align="right">8</td>
<td align="right">115</td>
<td align="right">8</td>
</tr>
<tr>
<td height="17" align="right">100000</td>
<td align="right">300</td>
<td align="right">18</td>
<td align="right">300</td>
<td align="right">16</td>
</tr>
</tbody>
</table>
<p>The latest source for merle using gen_server2 has been committed to <a href="http://github.com/joewilliams/merle/tree/master">github</a>, give it shot and let me know if you find any bugs.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.joeandmotorboat.com/2009/02/06/new-stuff-for-merle/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Using Chef Server with RabbitMQ and STOMP.</title>
		<link>http://www.joeandmotorboat.com/2009/02/03/using-chef-server-with-rabbitmq-and-stomp/</link>
		<comments>http://www.joeandmotorboat.com/2009/02/03/using-chef-server-with-rabbitmq-and-stomp/#comments</comments>
		<pubDate>Tue, 03 Feb 2009 05:04:44 +0000</pubDate>
		<dc:creator>joe</dc:creator>
				<category><![CDATA[Dev]]></category>
		<category><![CDATA[Erlang]]></category>
		<category><![CDATA[Ruby]]></category>

		<guid isPermaLink="false">http://www.joeandmotorboat.com/?p=830</guid>
		<description><![CDATA[I decided to play around with RabbitMQ and chef (Opscode recently released new version) this afternoon. My main objective was to see if I could replace stompserver with something a bit more robust. In this case RabbitMQ and it&#8217;s STOMP plugin, the following is a basic outline of what I did. Please note that this [...]]]></description>
			<content:encoded><![CDATA[<p>I decided to play around with <a href="http://www.rabbitmq.com/">RabbitMQ</a> and <a href="http://wiki.opscode.com/display/chef/Home">chef</a> (Opscode <a href="http://blog.opscode.com/2009/01/chef-052-and-ohai-014.html">recently released new version</a>) this afternoon. My main objective was to see if I could replace <a href="http://stompserver.rubyforge.org/">stompserver</a> with something a bit more robust. In this case RabbitMQ and it&#8217;s <a href="http://hg.rabbitmq.com/rabbitmq-stomp/">STOMP plugin</a>, the following is a basic outline of what I did. Please note that this was done on a Ubuntu 8.10 machine, if you are using another non-apt distro you will likely need to adjust the package installation commands and etc.</p>
<p>The first thing that needs to be done, if you do not already have a working chef/chef-server/ohai installation, is to get one up and running. If you already have a working install you should be able to skip down to the Erlang install portion and start from there.</p>
<p>Installing all this is pretty basic, check out the <a href="http://wiki.opscode.com/display/chef/Installation+on+Ubuntu+8.10+with+gems">instructions</a>. You should end up with a working installation with chef-server using stompserver (which we will be replacing) and <a href="http://couchdb.apache.org/">couchdb</a>. Here&#8217;s what I did:</p>
<blockquote><p>sudo apt-get install ruby ruby1.8-dev rubygems libopenssl-ruby1.8 build-essential wget<br />
wget http://rubyforge.org/frs/download.php/45904/rubygems-update-1.3.1.gem<br />
sudo gem install rubygems-update-1.3.1.gem<br />
sudo /var/lib/gems/1.8/bin/update_rubygems<br />
sudo rm /usr/bin/gem<br />
sudo ln -s /usr/bin/gem1.8 /usr/bin/gem<br />
sudo gem sources -a http://gems.opscode.com<br />
sudo gem install chef ohai chef-server<br />
apt-get install couchdb</p></blockquote>
<p>I then added in my configuration for chef-server:</p>
<blockquote><p>vi /etc/chef/server.rb</p>
<p>#<br />
## Chef Server Config File<br />
##<br />
#<br />
log_level          :info<br />
log_location       STDOUT<br />
ssl_verify_mode    :verify_none<br />
registration_url   &#8220;http://localhost:4000&#8243;<br />
openid_url         &#8220;http://localhost:4000&#8243;<br />
template_url       &#8220;http://localhost:4000&#8243;<br />
remotefile_url     &#8220;http://localhost:4000&#8243;<br />
search_url         &#8220;http://localhost:4000&#8243;<br />
cookbook_path      [ "/var/localhost/site-cookbooks", "/var/localhost/cookbooks" ]<br />
merb_log_path      &#8220;/var/log/localhost-server-merb.log&#8221;<br />
queue_user	          &#8220;guest&#8221;<br />
queue_password 	  &#8220;guest&#8221;</p>
<p>Chef::Log::Formatter.show_time = false</p></blockquote>
<p>Since I am using a single machine for my chef server I started two chef-server instances, one with the defaults <em>chef-server</em> and another <em>chef-server -p 4001</em>. Two instances are needed for OpenID to work properly.</p>
<p>The next objective is to install Erlang.</p>
<blockquote><p>sudo apt-get install erlang</p></blockquote>
<p>Now for the RabbitMQ and STOMP plugin install. Per <em>Update 2</em> (below) using the latest plugin and version 1.5.1 of RabbitMQ doesn&#8217;t work. The latest revisions from the repository for both is needed.</p>
<blockquote><p>
apt-get install mercurial<br />
cd /opt/<br />
hg clone http://hg.rabbitmq.com/rabbitmq-codegen<br />
hg clone http://hg.rabbitmq.com/rabbitmq-server<br />
hg clone http://hg.rabbitmq.com/rabbitmq-stomp<br />
apt-get install python-simplejson<br />
make -C rabbitmq-server<br />
make -C rabbitmq-stomp
</p></blockquote>
<p>I used the init script for rabbitmq-server found in debian package for 1.5.1 with a slight change, pointing to my installation in <em>/opt</em>. I put a copy of it <a href="http://www.joeandmotorboat.com/files/rabbitmq-server">here</a>.</p>
<blockquote><p>
DAEMON=/opt/rabbitmq-server/scripts/rabbitmq-multi
</p></blockquote>
<p>You will want to edit the config for rabbitmq to start up with STOMP activated and then restart the service.</p>
<blockquote><p>vi /etc/default/rabbitmq</p>
<p>SERVER_START_ARGS=&#8217;<br />
  -pa /opt/rabbitmq-stomp/ebin<br />
  -rabbit<br />
     stomp_listeners [{"0.0.0.0",61613}]<br />
     extra_startup_steps [{"STOMP-listeners",rabbit_stomp,kickstart,[]}]&#8217;
</p></blockquote>
<p>Finally, start everything up, minus stompserver.</p>
<blockquote><p>
/etc/init.d/couchdb start<br />
/etc/init.d/rabbitmq-server restart<br />
chef-server<br />
chef-server -p 4001<br />
chef-indexer</p></blockquote>
<p>After all that you should have a working chef-server using RabbitMQ/STOMP rather than stompserver. The rest is up to you.</p>
<p><em><strong>Update 2:</strong><br />
It looks like the issue (below) was caused by using incompatible versions of STOMP plugin and RabbitMQ. Using the latest server and plugin from their repository fixes the issue. I have adjusted the above instructions to state this change.</em></p>
<p><em><strong>Update:</strong><br />
It seems that I am having issues with the chef-indexer connecting properly to rabbitmq-stomp. From what I can tell this seems to be an issue with the RabbitMQ STOMP plugin since the stomp ruby client seems to work fine against stompserver. I suppose the RabbitMQ folks do label it &#8220;experimental&#8221;. Perhaps in a future revision it will be corrected. Anywho, here are some examples of what I am seeing.<br />
</em></p>
<blockquote><p>
root@ubuntu-810:~# chef-indexer<br />
/usr/lib/ruby/gems/1.8/gems/stomp-1.0.6/lib/stomp.rb:233:in `write&#8217;: Broken pipe (Errno::EPIPE)<br />
	from /usr/lib/ruby/gems/1.8/gems/stomp-1.0.6/lib/stomp.rb:233:in `puts&#8217;<br />
	from /usr/lib/ruby/gems/1.8/gems/stomp-1.0.6/lib/stomp.rb:233:in `_transmit&#8217;<br />
	from /usr/lib/ruby/gems/1.8/gems/stomp-1.0.6/lib/stomp.rb:232:in `synchronize&#8217;<br />
	from /usr/lib/ruby/gems/1.8/gems/stomp-1.0.6/lib/stomp.rb:232:in `_transmit&#8217;<br />
	from /usr/lib/ruby/gems/1.8/gems/stomp-1.0.6/lib/stomp.rb:220:in `transmit&#8217;<br />
	from /usr/lib/ruby/gems/1.8/gems/stomp-1.0.6/lib/stomp.rb:117:in `subscribe&#8217;<br />
	from /usr/lib/ruby/gems/1.8/gems/chef-0.5.2/lib/chef/queue.rb:79:in `subscribe&#8217;<br />
	from /usr/lib/ruby/gems/1.8/gems/chef-server-0.5.2/bin/chef-indexer:80<br />
	from /usr/bin/chef-indexer:19:in `load&#8217;<br />
	from /usr/bin/chef-indexer:19</p>
<p>root@ubuntu-810:~# irb<br />
irb(main):001:0> require &#8216;rubygems&#8217;<br />
=> true<br />
irb(main):002:0> require &#8217;stomp&#8217;<br />
=> true<br />
irb(main):003:0> conn = Stomp::Connection.open(&#8216;guest&#8217;, &#8216;guest&#8217;, &#8216;localhost&#8217;)<br />
=> #<Stomp::Connection:0x7fdffe651fe0 @read_semaphore=#<Mutex:0x7fdffe651f68>, @login=&#8221;guest&#8221;, @reconnectDelay=5, @transmit_semaphore=#<Mutex:0x7fdffe651f90>, @failure=nil, @port=61613, @connect=#<Stomp::Message:0x7fdffe651bd0 @command="ERROR", @body="{undef,[{rabbit_channel,start_link,n                        [rabbit_stomp,<0.3692.0>,<0.3692.0>,<<"guest">>,n                         <<"/">>]},n        {rabbit_stomp,do_login,5},n        {rabbit_stomp,process_received_bytes,2},n        {rabbit_stomp,init,1},n        {proc_lib,init_p,5}]}n&#8221;, @headers={&#8220;content-type&#8221;=>&#8221;text/plain&#8221;, &#8220;content-length&#8221;=>&#8221;290&#8243;, &#8220;message&#8221;=>&#8221;Processing error&#8221;}>, @reliable=false, @clientId=nil, @subscriptions={}, @host=&#8221;localhost&#8221;, @socket_semaphore=#<Mutex:0x7fdffe651f40>, @socket=#<TCPSocket:0x7fdffe651ec8>, @passcode=&#8221;guest&#8221;, @closed=false></p>
<p>root@ubuntu-810:~# tail /var/log/rabbitmq/rabbit.log<br />
=INFO REPORT==== 3-Feb-2009::02:11:42 ===<br />
starting STOMP connection <0.3746.0> from 127.0.0.1:59035</p>
<p>=ERROR REPORT==== 3-Feb-2009::02:11:42 ===<br />
STOMP error frame sent:<br />
Message: &#8220;Processing error&#8221;<br />
Detail: &#8220;{undef,[{rabbit_channel,start_link,n                        [rabbit_stomp,<0.3746.0>,<0.3746.0>,<<"guest">>,n                         <<"/">>]},n        {rabbit_stomp,do_login,5},n        {rabbit_stomp,process_received_bytes,2},n        {rabbit_stomp,init,1},n        {proc_lib,init_p,5}]}n&#8221;</p>
<p>=INFO REPORT==== 3-Feb-2009::02:11:42 ===<br />
ending STOMP connection <0.3746.0> from 127.0.0.1:59035
</p></blockquote>
]]></content:encoded>
			<wfw:commentRss>http://www.joeandmotorboat.com/2009/02/03/using-chef-server-with-rabbitmq-and-stomp/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>fermal: a last.fm API library for Erlang.</title>
		<link>http://www.joeandmotorboat.com/2009/01/29/fermal-a-lastfm-api-library-for-erlang/</link>
		<comments>http://www.joeandmotorboat.com/2009/01/29/fermal-a-lastfm-api-library-for-erlang/#comments</comments>
		<pubDate>Fri, 30 Jan 2009 03:12:54 +0000</pubDate>
		<dc:creator>joe</dc:creator>
				<category><![CDATA[Dev]]></category>
		<category><![CDATA[Erlang]]></category>

		<guid isPermaLink="false">http://www.joeandmotorboat.com/?p=825</guid>
		<description><![CDATA[I decided to start a new project after the relative success and fun I had writing merle. This time I decided to do something a little more web-centric, a library for last.fm&#8217;s awesomely complete API called fermal. While I doubt it will eventually support the entire API it will likely support a good portion of [...]]]></description>
			<content:encoded><![CDATA[<p>I decided to start a new project after the relative success and fun I had writing <a href="http://github.com/joewilliams/merle/tree/master">merle</a>. This time I decided to do something a little more web-centric, a library for <a href="http://www.last.fm/api">last.fm&#8217;s awesomely complete API</a> called <a href="http://github.com/joewilliams/fermal/tree/master">fermal</a>. While I doubt it will eventually support the entire API it will likely support a good portion of it. I recently made the commits and there is already some usable stuff in there. At the moment there is support for getting album info, artist info and using their <em>tasteometer</em> to compare tastes of two last.fm users. fermal uses last.fm&#8217;s JSON format API and <a href="http://www.lshift.net/blog/2007/02/17/json-and-json-rpc-for-erlang">LShift&#8217;s rfc4627 library</a> to do the dirty work. Here is an example of its usage:</p>
<blockquote><p>
3> fermal:album_info(&#8220;animal%20collective&#8221;, &#8220;feels&#8221;).<br />
[[album,<br />
  {name,"Feels"},<br />
  {artist,"Animal Collective"},<br />
  {id,"2050717"},<br />
  {mbid,"8a9ee208-3c9e-4fec-8f60-9a8b1db39960"},<br />
  {url,"http://www.last.fm/music/Animal+Collective/Feels"},<br />
  {releasedate,"    18 Oct 2005, 00:00"},<br />
  {listeners,"184794"},<br />
  {playcount,"3539880"},<br />
  {toptags,"\n      "}]]
</p></blockquote>
]]></content:encoded>
			<wfw:commentRss>http://www.joeandmotorboat.com/2009/01/29/fermal-a-lastfm-api-library-for-erlang/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
	</channel>
</rss>
