<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/atom10full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><feed xmlns="http://www.w3.org/2005/Atom" xmlns:openSearch="http://a9.com/-/spec/opensearch/1.1/" xmlns:georss="http://www.georss.org/georss" xmlns:gd="http://schemas.google.com/g/2005" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" gd:etag="W/&quot;CE8EQnw5fyp7ImA9WxBSFE8.&quot;"><id>tag:blogger.com,1999:blog-8523046672726455213</id><updated>2009-12-21T11:13:23.227-08:00</updated><title>Mailinator(tm) Blog</title><subtitle type="html">I'm in your Internetz, protectin' yer emailz!</subtitle><link rel="http://schemas.google.com/g/2005#feed" type="application/atom+xml" href="http://mailinator.blogspot.com/feeds/posts/default" /><link rel="alternate" type="text/html" href="http://mailinator.blogspot.com/" /><link rel="hub" href="http://pubsubhubbub.appspot.com/" /><link rel="next" type="application/atom+xml" href="http://www.blogger.com/feeds/8523046672726455213/posts/default?start-index=26&amp;max-results=25&amp;redirect=false&amp;v=2" /><author><name>Paul Tyma</name><uri>http://www.blogger.com/profile/11412172362500455307</uri><email>noreply@blogger.com</email></author><generator version="7.00" uri="http://www.blogger.com">Blogger</generator><openSearch:totalResults>52</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/atom+xml" href="http://feeds.feedburner.com/MailinatorBlog" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com" /><entry gd:etag="W/&quot;DUQCRXs6eip7ImA9WxNUGUs.&quot;"><id>tag:blogger.com,1999:blog-8523046672726455213.post-2502378411995767520</id><published>2009-11-11T11:10:00.001-08:00</published><updated>2009-11-11T11:22:44.512-08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-11-11T11:22:44.512-08:00</app:edited><title>Mailinator for Testing</title><content type="html">Recently I implemented a captcha system in Mailinator.&lt;br /&gt;&lt;br /&gt;If you're a normal user - you've probably never seen it. That's because it doesn't get activated until emails with the same subject get read more than like 10 times in a minute. Needless to say, if you're using Mailinator to sign-up for something here and there, that's not a normal use case.&lt;br /&gt;&lt;br /&gt;But if you're a script - or a person signing up for some website over and over and over (and over) - you hit this pretty fast. It has done a fantastic job of stopping scripts pretty succinctly and slowing down humans zealously working over some site. The main problem with the latter is that many of those sites don't like that and may then ban Mailinator. That's not good for anyone.&lt;br /&gt;&lt;br /&gt;What surprised me about the captcha system is how many people emailed me that I broke their test scripts. That is, they had email system tests (i.e. "Thanks for registering!") that use Mailinator as an end point. Their test then (with variation per user of course) checks the Mailinator inbox that their system correctly sent the email. &lt;br /&gt;&lt;br /&gt;ManyBrain, Inc. (the company that owns Mailinator) has offered for a long time testing packages that completely bypass Mailinator's abuse system for high-volume testing or other emailing. &lt;br /&gt;&lt;br /&gt;I'd be interested in however in improving this service and making it more mainstream. If you use Mailinator for testing - or would like to - I'd like to hear from you.&lt;br /&gt;&lt;br /&gt;How would you use it? What kind of volume? I can't believe anyone is excited about scraping HTML (that wasn't particularly designed to be scraped) to get test results. Mailinator already has a (secret, shhh) JSON interface thats not public. That would seem to be the way to go.&lt;br /&gt;&lt;br /&gt;My thoughts is a JSON-based SOAP/REST/whatever API that allows testing scripts to read emails. Whats a reasonable method and threshold of use to start charging? Possibly a sister site to Mailinator itself would be a better home for the testing service.&lt;br /&gt;&lt;br /&gt;If there's enough interest to support the development, I'd be excited to get this up and running.&lt;br /&gt;&lt;br /&gt;Email me at paul@manybrain.com&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8523046672726455213-2502378411995767520?l=mailinator.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/MailinatorBlog/~4/kmZcIIw5NMg" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://mailinator.blogspot.com/feeds/2502378411995767520/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=8523046672726455213&amp;postID=2502378411995767520" title="3 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/8523046672726455213/posts/default/2502378411995767520?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/8523046672726455213/posts/default/2502378411995767520?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/MailinatorBlog/~3/kmZcIIw5NMg/mailinator-for-testing.html" title="Mailinator for Testing" /><author><name>Paul Tyma</name><uri>http://www.blogger.com/profile/11412172362500455307</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="10507225897651170435" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">3</thr:total><feedburner:origLink>http://mailinator.blogspot.com/2009/11/mailinator-for-testing.html</feedburner:origLink></entry><entry gd:etag="W/&quot;A0QCQ3s7fCp7ImA9WxNQFUw.&quot;"><id>tag:blogger.com,1999:blog-8523046672726455213.post-3709615047508610893</id><published>2009-09-21T00:45:00.000-07:00</published><updated>2009-09-21T00:49:22.504-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-09-21T00:49:22.504-07:00</app:edited><title>More Alternate Domains !</title><content type="html">I've added a few more alternate domains. If you've never used them, they are simply other domains (for example, sogetthis.com) that forward all email to Mailinator.&lt;br /&gt;&lt;br /&gt;Simply, if you send email to fred@mailinator.com  - or - fred@sogetthis.com it works exactly the same way and your email will arrive in the "fred" inbox at Mailinator both ways.&lt;br /&gt;&lt;br /&gt;You can find alternate domains (including the new ones mixed in) on the front page of Mailinator on the left column.&lt;br /&gt;&lt;br /&gt;I'll be sneaking more into the rotation soon!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8523046672726455213-3709615047508610893?l=mailinator.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/MailinatorBlog/~4/bbtYPNZXlb8" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://mailinator.blogspot.com/feeds/3709615047508610893/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=8523046672726455213&amp;postID=3709615047508610893" title="6 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/8523046672726455213/posts/default/3709615047508610893?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/8523046672726455213/posts/default/3709615047508610893?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/MailinatorBlog/~3/bbtYPNZXlb8/more-alternate-domains.html" title="More Alternate Domains !" /><author><name>Paul Tyma</name><uri>http://www.blogger.com/profile/11412172362500455307</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="10507225897651170435" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">6</thr:total><feedburner:origLink>http://mailinator.blogspot.com/2009/09/more-alternate-domains.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CE8NR30-eyp7ImA9WxJWFkQ.&quot;"><id>tag:blogger.com,1999:blog-8523046672726455213.post-6527250340197240435</id><published>2009-06-22T10:16:00.000-07:00</published><updated>2009-06-22T10:48:16.353-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-06-22T10:48:16.353-07:00</app:edited><title>You can't type "mailinator.com" in Facebook</title><content type="html">I've known for awhile that Facebook directly bans signing up with a mailinator address (several of the alternate domains work - and more are on the way).&lt;br /&gt;&lt;br /&gt;Interestingly, I commonly attend San Francisco &amp; Silicon Valley entrepreneur events and I've met a few facebook people. In one instance, I had a fun jabbing match with a Facebooker who ended up being a friend. He assured me that Facebook will ban mailinator for good and I assured him I'll be working to get around that as a personal challenge :)&lt;br /&gt;&lt;br /&gt;(I then sent a box full of Mailinator t-shirts to his office)&lt;br /&gt;&lt;br /&gt;In any case, what I didn't know is that in Facebook chat (or wall posts) you cannot actually type "mailinator.com". It prevents you. Wow. Paranoid much?  (Somehow I don't think "mailinator.com" is abusive as the message that pops up says - and note that you can type "mailinator" (without the ".com") which is apparently fine and dandy - for the moment anyway).&lt;br /&gt;&lt;br /&gt;I did successfully create a &lt;a href=http://www.facebook.com/pages/Mailinator/90939329099?ref=ts&gt;Mailinator&lt;/a&gt; facebook page (feel free to become a fan!) and so far its still up. We'll see how long that lasts :)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8523046672726455213-6527250340197240435?l=mailinator.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/MailinatorBlog/~4/cOd1_wXyyZY" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://mailinator.blogspot.com/feeds/6527250340197240435/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=8523046672726455213&amp;postID=6527250340197240435" title="10 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/8523046672726455213/posts/default/6527250340197240435?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/8523046672726455213/posts/default/6527250340197240435?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/MailinatorBlog/~3/cOd1_wXyyZY/mailinator-and-facebook.html" title="You can't type &quot;mailinator.com&quot; in Facebook" /><author><name>Paul Tyma</name><uri>http://www.blogger.com/profile/11412172362500455307</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="10507225897651170435" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">10</thr:total><feedburner:origLink>http://mailinator.blogspot.com/2009/06/mailinator-and-facebook.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DEMCSX04fip7ImA9WxJXFks.&quot;"><id>tag:blogger.com,1999:blog-8523046672726455213.post-6164665296772570477</id><published>2009-06-09T05:53:00.000-07:00</published><updated>2009-06-10T13:41:08.336-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-06-10T13:41:08.336-07:00</app:edited><title>A Beautiful Race Condition</title><content type="html">I recently gave a keynote at the ICIS 2009 conference in Shanghai. The topic was why multithreaded programming seemed so easy, yet turned out to be so hard. The fun part was I investigated (per my last post and this one) several old, personal concurrency demons I knew existed but wanted to know more about.&lt;br /&gt;&lt;br /&gt;One of those was, indeed, my favorite race condition. It doesn't escape me that its probably wholly unhealthy to even *have* a favorite race condition (akin to having a favorite pimple or something) - but nonetheless, the elegance of this one still makes my heart aflutter.&lt;br /&gt;&lt;br /&gt;The scenario of this race is that we assume, not terribly inaccurately, that race conditions at times, can cause corrupted data. However, what if we have a situation where we sort of don't mind some corrupted data? A "good enough" application as it were.&lt;br /&gt;&lt;br /&gt;The dangerous part of all this is if we assume (without digging in) what kind of data corruption can happen. As you'll see, you might just not get the type of data corruption you were hoping for (which is one of the sillier sentences I've ever written).&lt;br /&gt;&lt;br /&gt;The particular instance of this kind of happy racing I've encountered is where someone   uses a java.util.HashMap as a cache. I've never done such a thing myself, but I heard about this race and thus this analysis. They may use it with a linked-list or maybe just raw, but the baseline is that they figure a synchronized HashMap will be expensive - and in their case, a race condition inside the HashMap will just lose (or double up on) an entry now and then.&lt;br /&gt;&lt;br /&gt;That is - a race condition between two (or more) threads might accidentally drop an entry causing an extra cache miss - no biggie. Or, it may cause one thread to re-cache an entry that didn't need it. Also no biggie. In other words, a slightly imprecise, yet very fast cache is ok by them. (of course, this assumption is dead wrong - don't do that - read on for why!)&lt;br /&gt;&lt;br /&gt;So they setup a HashMap in some global manner, and allow any number of nefarious threads bang away on it. Let them put and get to their hearts content.&lt;br /&gt;&lt;br /&gt;Now if you happen to know how HashMap works, if the size of the map exceeds a given threshold, it will act to resize the map. It does that by creating a new bucket array of twice the previous size, and then putting every old element into that new bucket array.&lt;br /&gt;&lt;br /&gt;Here's the core of the loop that does that resize:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;font-size:75%;"&gt;&lt;br /&gt;&lt;b&gt;1:&lt;/b&gt;&amp;nbsp;&amp;nbsp;// Transfer method in java.util.HashMap -&lt;br /&gt;&lt;b&gt;2:&lt;/b&gt;&amp;nbsp;&amp;nbsp;// called to resize the hashmap&lt;br /&gt;&lt;b&gt;3:&lt;/b&gt;&amp;nbsp;&amp;nbsp;&lt;br /&gt;&lt;b&gt;4:&lt;/b&gt;&amp;nbsp;&amp;nbsp;for (int j = 0; j &lt; src.length; j++) {&lt;br /&gt;&lt;b&gt;5:&lt;/b&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Entry&lt;K,V&gt; e = src[j];&lt;br /&gt;&lt;b&gt;6:&lt;/b&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if (e != null) {&lt;br /&gt;&lt;b&gt;7:&lt;/b&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;src[j] = null;&lt;br /&gt;&lt;b&gt;8:&lt;/b&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;do {&lt;br /&gt;&lt;b&gt;9:&lt;/b&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Entry&lt;K,V&gt; next = e.next; &lt;br /&gt;&lt;b&gt;10:&lt;/b&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;int i = indexFor(e.hash, newCapacity);&lt;br /&gt;&lt;b&gt;11:&lt;/b&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;e.next = newTable[i];&lt;br /&gt;&lt;b&gt;12:&lt;/b&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;newTable[i] = e;&lt;br /&gt;&lt;b&gt;13:&lt;/b&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;e = next;&lt;br /&gt;&lt;b&gt;14:&lt;/b&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;} while (e != null);&lt;br /&gt;&lt;b&gt;15:&lt;/b&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;&lt;b&gt;16:&lt;/b&gt;&amp;nbsp;} &lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Simply, after line 9, variable &lt;span style="font-family: courier new;font-size:85%;"&gt;e&lt;/span&gt; points to a node that is about to be put into the new (double-wide) bucket array. Variable &lt;span style="font-family: courier new;font-size:75%;"&gt;&lt;br /&gt;next&lt;/span&gt; holds a reference to the  next node in  the existing table (because in line 11, we'll destroy that relation). &lt;br /&gt;&lt;br /&gt;The goal is that nodes in the new table get scattered around a bit. There's no care to keep any ordering within a bucket  (nor  should there be). HashMap's don't care about ordering, they care about constant time access.&lt;br /&gt;&lt;br /&gt;Graphically, let's say we start with the HashMap  below. This one only has 2 buckets  (the default of java.util.HashMap is 16) which will suffice for explanatory purposes (and save room).&lt;br /&gt;&lt;br /&gt;As our loop starts, we assign &lt;span style="font-family: courier new;font-size:85%;"&gt;e&lt;/span&gt; and &lt;span style="font-family: courier new;font-size:85%;"&gt;next&lt;/span&gt; to A and B, respectively. The A node is about to be moved,  the B node is next.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_wdOYAcPCMJE/Si5j5YJz7lI/AAAAAAAAB3k/oxnIwWL8vdk/s1600-h/originalmap.gif"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 118px;" src="http://1.bp.blogspot.com/_wdOYAcPCMJE/Si5j5YJz7lI/AAAAAAAAB3k/oxnIwWL8vdk/s400/originalmap.gif" border="0" alt=""id="BLOGGER_PHOTO_ID_5345319645122653778" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;We have created  a double-sized bucket array (in this case size=4) and migrate node A  in  iteration 1.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_wdOYAcPCMJE/Si5klTGlUJI/AAAAAAAAB3s/nzKz7jpnymw/s1600-h/iteration1.gif"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 217px; height: 374px;" src="http://3.bp.blogspot.com/_wdOYAcPCMJE/Si5klTGlUJI/AAAAAAAAB3s/nzKz7jpnymw/s400/iteration1.gif" border="0" alt=""id="BLOGGER_PHOTO_ID_5345320399681179794" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Iteration 2 moves node B and Iteration 3 moves node C. Note that next=null  is the ending condition of our while loop for migrating any given bucket (read that again, its important  to the end of the story).&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_wdOYAcPCMJE/Si5lku8IzkI/AAAAAAAAB30/NlbmTFfaOSk/s1600-h/iteration2.gif"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 344px; height: 238px;" src="http://3.bp.blogspot.com/_wdOYAcPCMJE/Si5lku8IzkI/AAAAAAAAB30/NlbmTFfaOSk/s400/iteration2.gif" border="0" alt=""id="BLOGGER_PHOTO_ID_5345321489485319746" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Also important to the story, note that the  migration inverted the  order of  Node's A  and B. This was incidental to the smart idea  of  inserting  new nodes at the  top of the list instead of traversing  to  find the end each time and plunking them there. A normal put operation would  still have  to  check that its inserting  (and not replacing) but given a resize can't replace, this  saves us  a lot of "find the end" traversals.&lt;br /&gt;&lt;br /&gt;Finally, after iteration 3, our new HashMap looks like this:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_wdOYAcPCMJE/Si5l3LIJgRI/AAAAAAAAB38/_BjK6cHX_KA/s1600-h/iteration3.gif"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 393px; height: 292px;" src="http://2.bp.blogspot.com/_wdOYAcPCMJE/Si5l3LIJgRI/AAAAAAAAB38/_BjK6cHX_KA/s400/iteration3.gif" border="0" alt=""id="BLOGGER_PHOTO_ID_5345321806289535250" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Our resize accomplished precisely the mission  it  set out to. It  took  our 3-deep bucket and morphed it into a 2-deep and 1-deep one. &lt;br /&gt;&lt;br /&gt;Now, that's all well and good, but this article isn't about HashMap resizing (exactly),  its  about a race condition.&lt;br /&gt;&lt;br /&gt;So, let's assume  that in our original happy HashMap (the one above with just 2 buckets) we  have two threads. And both of those threads enter the map for some operation. And both of those threads simultaneously realize the map needs a resize. So, simultaneously they  both go  try  to do that.&lt;br /&gt;&lt;br /&gt;As an aside, the fact that this HashMap is unsynchronized opens it up to a scary  array  of unimaginable visibility  issues  but that's another story. I'm sure that using an unsynchronized HashMap in this fashion can wrack evil in ways unlike man has ever seen, I'm just addressing one possible race in one possible scenario.&lt;br /&gt;&lt;br /&gt;Ok.. back to the story.&lt;br /&gt;&lt;br /&gt;So two threads, which we'll cleverly name Thread1 and Thread2 are off to do a resize. Let's say Thread1 beats Thread2 by a moment. And  let's say  Thread1 (by the way, the fun part about analyzing race conditions is that nearly anything can happen - so you can say "Let's say" all darn day long and you'll  probably be right!) gets to line 10 and stops. Thats right, after executing line 9, Thread1 gets kicked out of the (proverbial) CPU.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;font-size:75%;"&gt;&lt;br /&gt;&lt;b&gt;1:&lt;/b&gt;&amp;nbsp;&amp;nbsp;// Transfer method in java.util.HashMap -&lt;br /&gt;&lt;b&gt;2:&lt;/b&gt;&amp;nbsp;&amp;nbsp;// called to resize the hashmap&lt;br /&gt;&lt;b&gt;3:&lt;/b&gt;&amp;nbsp;&amp;nbsp;&lt;br /&gt;&lt;b&gt;4:&lt;/b&gt;&amp;nbsp;&amp;nbsp;for (int j = 0; j &lt; src.length; j++) {&lt;br /&gt;&lt;b&gt;5:&lt;/b&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Entry&lt;K,V&gt; e = src[j];&lt;br /&gt;&lt;b&gt;6:&lt;/b&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if (e != null) {&lt;br /&gt;&lt;b&gt;7:&lt;/b&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;src[j] = null;&lt;br /&gt;&lt;b&gt;8:&lt;/b&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;do {&lt;br /&gt;&lt;b&gt;9:&lt;/b&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Entry&lt;K,V&gt; next = e.next; &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;b&gt; // Thread1 STOPS RIGHT HERE&lt;/b&gt;&lt;br /&gt;&lt;b&gt;10:&lt;/b&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;int i = indexFor(e.hash, newCapacity);&lt;br /&gt;&lt;b&gt;11:&lt;/b&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;e.next = newTable[i];&lt;br /&gt;&lt;b&gt;12:&lt;/b&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;newTable[i] = e;&lt;br /&gt;&lt;b&gt;13:&lt;/b&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;e = next;&lt;br /&gt;&lt;b&gt;14:&lt;/b&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;} while (e != null);&lt;br /&gt;&lt;b&gt;15:&lt;/b&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;&lt;b&gt;16:&lt;/b&gt;&amp;nbsp;} &lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Since it passed line 9,  Thread1 did get to set its &lt;span style="font-family: courier new;font-size:85%;"&gt;e&lt;/span&gt; and &lt;span style="font-family: courier new;font-size:85%;"&gt;next&lt;/span&gt; variables. The situation looks like this (I've renamed &lt;span style="font-family: courier new;font-size:85%;"&gt;e&lt;/span&gt; and &lt;span style="font-family: courier new;font-size:85%;"&gt;next&lt;/span&gt; to &lt;span style="font-family: courier new;font-size:85%;"&gt;e1&lt;/span&gt; and &lt;span style="font-family: courier new;font-size:85%;"&gt;next1&lt;/span&gt; to keep them straight between the two threads as both threads have their own &lt;span style="font-family: courier new;font-size:85%;"&gt;e&lt;/span&gt; and &lt;span style="font-family: courier new;font-size:85%;"&gt;next&lt;/span&gt;).&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_wdOYAcPCMJE/Si5olSzF2_I/AAAAAAAAB4E/zZ7_blOpKuU/s1600-h/e1next1.gif"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 122px;" src="http://3.bp.blogspot.com/_wdOYAcPCMJE/Si5olSzF2_I/AAAAAAAAB4E/zZ7_blOpKuU/s400/e1next1.gif" border="0" alt=""id="BLOGGER_PHOTO_ID_5345324797645937650" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Again, Thread1 didn't actually get to move any nodes (by this time in the code, it did allocate a new bucket array).&lt;br /&gt;&lt;br /&gt;What happens next? Thread2, that's what. Luckily, what Thread2 does is simple - let's say it runs  through the full  resize. All the  way.  It completes.&lt;br /&gt;&lt;br /&gt;We get this:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_wdOYAcPCMJE/Si5pbiDeonI/AAAAAAAAB4M/LDLIjceSEjU/s1600-h/thread2done.gif"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 241px;" src="http://1.bp.blogspot.com/_wdOYAcPCMJE/Si5pbiDeonI/AAAAAAAAB4M/LDLIjceSEjU/s400/thread2done.gif" border="0" alt=""id="BLOGGER_PHOTO_ID_5345325729454137970" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Note that &lt;span style="font-family: courier new;font-size:85%;"&gt;e1&lt;/span&gt; and &lt;span style="font-family: courier new;font-size:85%;"&gt;next1&lt;/span&gt; still point to the same nodes. But those nodes got shuffled around. And &lt;b&gt;most importantly&lt;/b&gt; the next relation got reversed.&lt;br /&gt;&lt;br /&gt;That is, when Thread1 started, it had node A with its next as node B. Now, its the opposite, node B has its next as node A.&lt;br /&gt;&lt;br /&gt;Sadly (and paramount to the plot of this story) is that Thread1 doesn't know that. If you're thinking that the invertedness of Thread1's &lt;span style="font-family: courier new;font-size:85%;"&gt;e1&lt;/span&gt; and &lt;span style="font-family: courier new;font-size:85%;"&gt;next1&lt;/span&gt; are important, you're right.&lt;br /&gt;&lt;br /&gt;Here's Thread1's next few iterations. We start with Thread2's bucket picture because thats really the correct "next" relations for our nodes now.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_wdOYAcPCMJE/Si5rwdS02tI/AAAAAAAAB4U/OZJsfnKYow8/s1600-h/thread1-1.gif"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 209px;" src="http://2.bp.blogspot.com/_wdOYAcPCMJE/Si5rwdS02tI/AAAAAAAAB4U/OZJsfnKYow8/s400/thread1-1.gif" border="0" alt=""id="BLOGGER_PHOTO_ID_5345328287976839890" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_wdOYAcPCMJE/Si5r9eZF4qI/AAAAAAAAB4c/gDcJMcwKjSc/s1600-h/thread1-2.gif"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 331px; height: 301px;" src="http://3.bp.blogspot.com/_wdOYAcPCMJE/Si5r9eZF4qI/AAAAAAAAB4c/gDcJMcwKjSc/s400/thread1-2.gif" border="0" alt=""id="BLOGGER_PHOTO_ID_5345328511609856674" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_wdOYAcPCMJE/Si5sLrrwh0I/AAAAAAAAB4k/1lK6serDlaY/s1600-h/thread1-3.gif"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 255px;" src="http://3.bp.blogspot.com/_wdOYAcPCMJE/Si5sLrrwh0I/AAAAAAAAB4k/1lK6serDlaY/s400/thread1-3.gif" border="0" alt=""id="BLOGGER_PHOTO_ID_5345328755695978306" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Everything sort  of looking ok.. except  for our &lt;span style="font-family: courier new;font-size:85%;"&gt;e&lt;/span&gt; and &lt;span style="font-family: courier new;font-size:85%;"&gt;next&lt;/span&gt; at this  point. The next iteration will plunk A into the front of the bucket 3 list (it is after all, next). And will assign its next to whatever happens to already be there - that  is, node B.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_wdOYAcPCMJE/Si5skScRmnI/AAAAAAAAB4s/k7djpnVbcqU/s1600-h/thread1-4.gif"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 192px;" src="http://3.bp.blogspot.com/_wdOYAcPCMJE/Si5skScRmnI/AAAAAAAAB4s/k7djpnVbcqU/s400/thread1-4.gif" border="0" alt=""id="BLOGGER_PHOTO_ID_5345329178416880242" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Woah. Thar she blows.&lt;br /&gt;&lt;br /&gt;So right about now  Thread1 goes into, what we like to call in the biz, an "infinite loop". Any subsequent get operations that  hit this bucket start searching down the list and, go into, yep - an infinite loop.  Any put operation that first needs to scan the nodes to see if its going to do a replace, will, you guessed it, go into an infinite loop. Basically, this map is a pit of infinite loopeness.&lt;br /&gt;&lt;br /&gt;If you remember we noted that race conditions cause data corruption. Well, yeah, thats what we have here  - just very unlucky data corruption on pointer structures. I'm the  first to admit this stuff is  tricky - if you found errors in my analysis I'll happily fix this post.&lt;br /&gt;&lt;br /&gt;Now I  had the happy fortune for a time of sharing an office with Josh Bloch who wrote java.util.HashMap. When I innocently mentioned he had a bug in his code given this behavior, he did indeed (to use Josh's word's) go non-linear on me.&lt;br /&gt;&lt;br /&gt;And he was right. This is not a bug. HashMap is built specifically for its purpose and this implementation is not intended as threadsafe.  There's a gaggle of ways to make it threadsafe, but in plain, vanilla,  (and very  fast)  form  - its not. And needless to say, you shouldn't be using it that way.&lt;br /&gt;&lt;br /&gt;Race conditions are nothing to  mess with and the worst ones are the  ones that don't crash your program but let it wander down some unintended path. Synchronization isn't just for fun you know.&lt;br /&gt;&lt;br /&gt;And nefarious uses of HashMap aside, I still attest  -  this is, indeed, a beautiful race.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8523046672726455213-6164665296772570477?l=mailinator.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/MailinatorBlog/~4/CrUZoZWfwIM" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://mailinator.blogspot.com/feeds/6164665296772570477/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=8523046672726455213&amp;postID=6164665296772570477" title="12 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/8523046672726455213/posts/default/6164665296772570477?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/8523046672726455213/posts/default/6164665296772570477?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/MailinatorBlog/~3/CrUZoZWfwIM/beautiful-race-condition.html" title="A Beautiful Race Condition" /><author><name>Paul Tyma</name><uri>http://www.blogger.com/profile/11412172362500455307</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="10507225897651170435" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://1.bp.blogspot.com/_wdOYAcPCMJE/Si5j5YJz7lI/AAAAAAAAB3k/oxnIwWL8vdk/s72-c/originalmap.gif" height="72" width="72" /><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">12</thr:total><feedburner:origLink>http://mailinator.blogspot.com/2009/06/beautiful-race-condition.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CE4AQHo-fyp7ImA9WxJXFEQ.&quot;"><id>tag:blogger.com,1999:blog-8523046672726455213.post-4097908200161572929</id><published>2009-06-08T08:00:00.000-07:00</published><updated>2009-06-08T13:29:01.457-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-06-08T13:29:01.457-07:00</app:edited><title>On Java Visibility</title><content type="html">A semi-famous example of broken Java synchronization is this:&lt;br /&gt;&lt;span style="font-family: courier new;font-size:85%;"&gt;&lt;br /&gt;class SomeClass {&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;private boolean keepGoing = true;&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public boolean get() {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return keepGoing;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public synchronized boolean set(boolean x) {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;keepGoing =  x;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;}&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;I believe this example is in Josh Bloch's book "Effective Java" (which I now notice I  somehow lost my copy in my most recent move - don't tell Josh).&lt;br /&gt;&lt;br /&gt;The idea is here that someone (ostensibly) thought that they'd save some performance by not synchronizing a getter and just synchronizing the setter. There definitely is a cost to synchronization and needless to say, getting doesn't change anything - so why bother paying that cost for gets?&lt;br /&gt;&lt;br /&gt;As has been pointed out long before this post, without a synchronize on a getter, there is no guarantee of visibility when doing the get. That is, if one thread calls set(false), there's no guarantee that any other thread will know it happened.&lt;br /&gt;&lt;br /&gt;Consider code that might use the code above:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;font-size:85%;"&gt;&lt;br /&gt;class SomeOtherClass {&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;SomeClass keepGoing = new SomeClass();&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;class Thread1 implements Runnable {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public void run() {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;while (keepGoing.get()) x++;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;System.out.println("done1");&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;&lt;br /&gt;class Thread2 implements Runnable {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public void run() {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;keepGoing.set(false);&lt;br /&gt;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;}&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Let's say you start a Thread1 running. And of course, keepGoing.get() is true, so it just keeps looping along.  Then lets say an eternity (or maybe 2 seconds) later you start Thread2.&lt;br /&gt;&lt;br /&gt;If we had reliable visibility, Thread1 would end the moment after Thread2 sets keepGoing to false.&lt;br /&gt;&lt;br /&gt;If you've read Josh's book, its no surprise that it doesn't. Specifically, Thread1 doesn't end. It keeps going. Thread2 ends happily and Thread1 never ends.&lt;br /&gt;&lt;br /&gt;The only interesting part to me was that this always worked. Always. Adding to the complexity of visibility concerns is that memory is "leaky". That is, even without guaranteed visibility you often get unreliable visiblity. &lt;br /&gt;&lt;br /&gt;So, I dug a little deeper. If you're adventurous enough to grab a debug-version of the JDK and run it with the -XX:+PrintOptoAssembly option. You get to see the optimizations the JIT are making. That is, you see the assembly code version of your Java code - post-optimization. Check out &lt;a href=http://weblogs.java.net/blog/kohsuke/archive/2008/03/deep_dive_into.html&gt;Koshuke Kawaguchi's Blog&lt;/a&gt; for some instructions.&lt;br /&gt;&lt;br /&gt;So here's Thread1's loop code after JIT optimization at runtime:&lt;br /&gt;&lt;span style="font-family: courier new;font-size:75%;"&gt;&lt;br /&gt;02c     movq    R10, precise klass manybrain/test/Main: 0x0000000040a50968:Constant:exact *     # ptr&lt;br /&gt;036     movsbl  R8, [R10 + #596 (32-bit)]       # byte ! Field manybrain/test/Main.keepGoing&lt;br /&gt;03e     testl   R8, R8&lt;br /&gt;&lt;b&gt;041     je,s   B4  P=0.000000 C=147944.000000&lt;/b&gt;&lt;br /&gt;041&lt;br /&gt;&lt;b&gt;043   B2: #     B3 &lt;- B1  Freq: 1&lt;/b&gt;&lt;br /&gt;043     movl    R8, [R10 + #592 (32-bit)]       # int ! Field manybrain/test/Main.x&lt;br /&gt;043&lt;br /&gt;04a   B3: #     B3 &lt;- B2 B3  top-of-loop Freq: 1e-35&lt;br /&gt;04a     incl    R8      # int&lt;br /&gt;04d     movl    [R10 + #592 (32-bit)], R8       # int ! Field manybrain/test/Main.x&lt;br /&gt;054     testl   rax, [rip + #offset_to_poll_page]       # Safepoint: poll for GC        # manybrain.test.Main$Thread1::run @ bci:14  L[0]=_&lt;br /&gt;        # OopMap{r10=Oop off=84}&lt;br /&gt;&lt;b&gt;05a     jmp,s   B3&lt;/b&gt;&lt;br /&gt;05a&lt;br /&gt;05c   B4: #     N53 &lt;- B1  Freq: 4.76837e-07&lt;br /&gt;05c     movl    RSI, #27        # int&lt;br /&gt;061     nop     # 2 bytes pad for loops and calls&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;If you're old school, welcome home.&lt;br /&gt;&lt;br /&gt;If you're not, then this might look like a lot of goop. So let's parse out just the interesting parts.&lt;br /&gt;&lt;br /&gt;Line 41 is an conditional jump. Basically, if keepGoing (per the comment in line 36) is false, we jump to line 5C (label B4) and end the code segment. You and I know that keepGoing started true, so basically that jump isn't followed.&lt;br /&gt;&lt;br /&gt;Lines 43-5a are the loop that does x++.&lt;br /&gt;&lt;br /&gt;And checkout line 5a. That is an unconditional jump back to the top of the loop. So what does all this mean? That the JIT did some very aggressive optimization. In fact, remember our original loop from Thread1?&lt;br /&gt; &lt;br /&gt;&lt;span style="font-family: courier new;font-size:85%;"&gt;&lt;br /&gt;while (keepGoing.get()) x++&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;The JIT has optimized this to:&lt;br /&gt;&lt;span style="font-family: courier new;font-size:85%;"&gt;&lt;br /&gt;if (keepGoing.get()) {&lt;br /&gt;&amp;nbsp;&amp;nbsp;while (true) x++;&lt;br /&gt;}&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;No wonder  the loop never ends. You've got bigger problems now than a little leaky visibility issue. I'm positive I'm oversimplifying, but effectively the JIT saw your get method wasn't synchronized and made the assumption that it could optimize as such. If you didn't guarantee visibility, it didn't need to either. Obviously, add the synchronization modifier to the get method and all this badness won't happen.&lt;br /&gt;&lt;br /&gt;Moral of the story is much like the inevitable topics discussed at a lunch with &lt;a href=http://jeremymanson.blogspot.com&gt;Jeremy Manson&lt;/a&gt; - you can't optimize away correct synchronization; as all you'll probably do is optimize the "correctness" part away.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8523046672726455213-4097908200161572929?l=mailinator.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/MailinatorBlog/~4/6n13xapVNnU" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://mailinator.blogspot.com/feeds/4097908200161572929/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=8523046672726455213&amp;postID=4097908200161572929" title="4 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/8523046672726455213/posts/default/4097908200161572929?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/8523046672726455213/posts/default/4097908200161572929?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/MailinatorBlog/~3/6n13xapVNnU/on-java-visibility.html" title="On Java Visibility" /><author><name>Paul Tyma</name><uri>http://www.blogger.com/profile/11412172362500455307</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="10507225897651170435" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">4</thr:total><feedburner:origLink>http://mailinator.blogspot.com/2009/06/on-java-visibility.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CEcGQX47fyp7ImA9WxJRGU8.&quot;"><id>tag:blogger.com,1999:blog-8523046672726455213.post-8031319583188332177</id><published>2009-05-21T08:43:00.001-07:00</published><updated>2009-05-21T09:07:00.007-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-05-21T09:07:00.007-07:00</app:edited><title>Talkinator on 5 Watts</title><content type="html">I've written previously about the architecture of the Talkinator server. As a synopsis, the entire thing is basically completely custom. Custom webserver, custom comet server, custom RPC, custom encoding, custom everything (to the Java programmer, this translates as it needing no other jars to run apart from me deciding to use Cliff Click's NonBlockingHashMap instead of Doug Lea's ConcurrentHashMap). &lt;br /&gt;&lt;br /&gt;I also pointed out that the only reason you'd want to do something like that is for fun or experimentation or well, ok, that's about it. In any case, this also has a nice side-effect of making everything rather wee. The Talkinator server is strikingly frugal in terms of memory and cpu.&lt;br /&gt;&lt;br /&gt;Fast forward to today and I recently found GlobalScale's plug computer.  (Url is &lt;a href="http://www.globalscaletechnologies.com/p-22-sheevaplug-dev-kit.aspx"&gt;http://www.globalscaletechnologies.com/p-22-sheevaplug-dev-kit.aspx&lt;/a&gt; ). &lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://www.globalscaletechnologies.com/skins/skin_1/images/sheeva_front.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 650px; height: 150px;" src="http://www.globalscaletechnologies.com/skins/skin_1/images/sheeva_front.jpg" border="0" alt="" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Simply put, its a 512M ram, 512M disk, custom CPU that pretty much only has a USB and ethernet connector. It has Ubuntu 9.04 (minimized) installed on it, costs about $120, and runs on an advertised 5W of power (of course, the crappy lightbulb in my room is probably 60W). Pretty much you plug in ethernet, plug in power - and then go ask your router where it DHCP'd to.&lt;br /&gt;&lt;br /&gt;Then you ssh in.  Voila! &lt;br /&gt;&lt;br /&gt;I did some linux reconfig and thought about what to install...  (a common dilemma when you buy a server without having a purpose). Well, how about the Talkinator server?&lt;br /&gt;&lt;br /&gt;Installed Java, unzipped the server - and we're off to the races.&lt;br /&gt;&lt;br /&gt;As a test, I made it available on the net and put a second chat box on the front page of &lt;a href="http://www.talkinator.com"&gt;http://www.talkinator.com&lt;/a&gt;. No one will tell you this is  a powerhouse machine - but clearly its  specs do allow  for  some  applications to do just fine. (Please allow for some slowness on the plugcomputer because, unlike the regular Talkinator server, its not in a datacenter - its  in my bedroom. And its on a dedicated, but still not uber, DSL line)&lt;br /&gt;&lt;br /&gt;I went ahead  and ran some very informal  benchmarks on it.  I ran a simple test of how  many 404's my custom webserver could push  on the plug computer and on a dual-core Opteron rackmount server  (which also happens to be in my bedroom - dont ask).&lt;br /&gt;&lt;br /&gt;Plug-computer:  550 requests  per second&lt;br /&gt;Dual-core Opt:  7700 requests per second (possibly just saturating bandwidth)&lt;br /&gt;&lt;br /&gt;Not bad for 5W.&lt;br /&gt;&lt;br /&gt;PS: As you can imagine,  I  probably wont run this test forever, so  if you  read this  entry at some point in the future, the 2nd talkinator box on the home page might be gone.&lt;br /&gt;&lt;br /&gt;PPS: Because  I'm lazy, the talkinator  server on the plugcomputer is running on a  non-standard port. So if you're coming in from behind a proxy or firewall or something  - you might not  see  it.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8523046672726455213-8031319583188332177?l=mailinator.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/MailinatorBlog/~4/5jJ9bJJ9Y34" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://mailinator.blogspot.com/feeds/8031319583188332177/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=8523046672726455213&amp;postID=8031319583188332177" title="5 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/8523046672726455213/posts/default/8031319583188332177?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/8523046672726455213/posts/default/8031319583188332177?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/MailinatorBlog/~3/5jJ9bJJ9Y34/talkinator-on-5-watts.html" title="Talkinator on 5 Watts" /><author><name>Paul Tyma</name><uri>http://www.blogger.com/profile/11412172362500455307</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="10507225897651170435" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">5</thr:total><feedburner:origLink>http://mailinator.blogspot.com/2009/05/talkinator-on-5-watts.html</feedburner:origLink></entry><entry gd:etag="W/&quot;D04CQnkzfSp7ImA9WxVRGUQ.&quot;"><id>tag:blogger.com,1999:blog-8523046672726455213.post-5266434126738542841</id><published>2009-01-26T10:38:00.000-08:00</published><updated>2009-01-26T10:52:43.785-08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-01-26T10:52:43.785-08:00</app:edited><title>How long before an email is removed from the system?</title><content type="html">I get this question a fair bit.  How long, exactly, is an email available to be read after it enters the system?&lt;br /&gt;&lt;br /&gt;Its hard to answer because its literally dependent upon the incoming rate at which email arrives. In effect, new email "pushes out" old email. That's a bit simplified as some email is thrown away based upon spam rules (if you get 100,000 emails with the same subject, you can probably say they aren't all going to be read). &lt;br /&gt;&lt;br /&gt;So, whats the average?  This weekend, email was lasting around 10 hours before getting "pushed out" of memory.  I've seen that jump down to an hour - but mostly its around 5-7 hours. &lt;br /&gt;&lt;br /&gt;I'll note that the primary Mailinator use case is that people tend to read email soon after it arrives. In other words, if email only lasted 15 minutes, we'd actually fill the needs of many users.&lt;br /&gt;&lt;br /&gt;(I'd be *very* interested in hearing ways you use Mailinator that need mail to stick around longer.)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8523046672726455213-5266434126738542841?l=mailinator.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/MailinatorBlog/~4/TqV0d1anxFo" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://mailinator.blogspot.com/feeds/5266434126738542841/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=8523046672726455213&amp;postID=5266434126738542841" title="12 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/8523046672726455213/posts/default/5266434126738542841?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/8523046672726455213/posts/default/5266434126738542841?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/MailinatorBlog/~3/TqV0d1anxFo/how-long-before-email-is-removed-from.html" title="How long before an email is removed from the system?" /><author><name>Paul Tyma</name><uri>http://www.blogger.com/profile/11412172362500455307</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="10507225897651170435" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">12</thr:total><feedburner:origLink>http://mailinator.blogspot.com/2009/01/how-long-before-email-is-removed-from.html</feedburner:origLink></entry><entry gd:etag="W/&quot;AkMAQX89eip7ImA9WxVSFkw.&quot;"><id>tag:blogger.com,1999:blog-8523046672726455213.post-7902337155998939941</id><published>2009-01-08T22:04:00.000-08:00</published><updated>2009-01-10T12:14:00.162-08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-01-10T12:14:00.162-08:00</app:edited><title>No, Mailinator didn't spam you</title><content type="html">I must say, it's rare these days but I still now and then get emails from folks that think Mailinator spammed them. As it says on our contact page, this is pretty unlikely. I say that because Mailinator is custom software and that software contains no specific way to actually have a user "send" email.  There's no chance of Mailinator being an open-relay as it stands. And of course, there is no place at all on the site to accept an email for sending.&lt;br /&gt;&lt;br /&gt;I suppose its possible, but it would involve a hacker breaking into the server, installing some other email server (which would likely conflict with mailinator itself), configuring it, and then start pummeling it for their nefarious purposes. Given that any self-respecting spammer has a billion zombies at their disposal and that this would definitely be discovered very quickly (my colo vendor loves to watch my bandwidth), it doesn't seem like an efficient way to spam. &lt;br /&gt;&lt;br /&gt;In any case, I still get accused of spamming at times. And all that accusation takes is for a spammer to forge the return address as a mailinator address. Let me tell you, forging a return address is stunningly easy.  Here's &lt;a href=http://www.google.com/search?q=email+forging+websites&amp;ie=utf-8&amp;oe=utf-8&amp;aq=t&amp;rls=org.mozilla:en-US:official&amp;client=firefox-a&gt;3 million or so guides&lt;/a&gt; how to do it if you're wondering.&lt;br /&gt;&lt;br /&gt;Below is an actual email header someone sent me. &lt;br /&gt;&lt;br /&gt;The interesting parts are really the first two lines. As you see the forged return path is ronb@mailinator.com. Now if you know mailinator, you know ANYONE can check that box. It belongs to no one and everyone (as outlined in the FAQ - Mailinator guarantees NO PRIVACY. All emails are viewable by ANYONE).&lt;br /&gt;&lt;br /&gt;The 2nd line (i.e. Received:) shows the IP (and dns) of the server that actually sent the email. Something at abac.net.  That looks like a hosting company somewhere. One thing I can tell you though is that that server has zero to do with mailinator. The spam email never ever touched the mailinator server. So even if I devoted my life to stopping this email, there's nothing I could do.&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;&lt;br /&gt;&lt;span style="font-family: courier new;font-size:85%;"&gt;&lt;br /&gt;Return-Path: ronb@mailinator.com&lt;br /&gt;Received: from 216.55.169.94 (216-55-169-94.dedicated.abac.net&lt;br /&gt;216.55.169.94)&lt;br /&gt;by smtpin4.mail.de.uu.net (8.14.1/8.14.1) with SMTP id n083RPV6001157;&lt;br /&gt;Thu, 8 Jan 2009 03:27:26 GMT&lt;br /&gt;Message-Id: 200901080327.n083RPV6001157@smtpin4.mail.de.uu.net&lt;br /&gt;From: "RON" ronb@mailinator.com&lt;br /&gt;Reply-To: "RON" ronb@mailinator.com&lt;br /&gt;To: xxxxxxxxxxxxxx --&gt; &lt;i&gt;edited&lt;/i&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;This is sort of similar to a phishing attack. Someone gets an email from their bank, then goes to the phish site, then loses all their money. In truth their bank had nothing to do whatsoever with any of that but the bank still gets blamed.&lt;br /&gt;&lt;br /&gt;The saddest part for me is that even after I respond to people showing them the real culprit, its not uncommon for them to stay mad at me. I suppose its because they then don't know who they're going to yell at now and I'm still available for the job.&lt;br /&gt;&lt;br /&gt;Mailinator is about letting you protect your real email address. It might be to prevent spam but at times it might even be to receive spammy email they really want (just not at their primary address).&lt;br /&gt;&lt;br /&gt;Regardless what you use it for, it won't email you. It just doesn't do that.&lt;br /&gt;&lt;br /&gt;Plenty of people threaten to blacklist Mailinator from ever sending them email again. Yes, please do! As I've said in the past, feel free to put mailinator.com on the tippy-tippy-top of all your spam blacklists. Mailinator doesn't send any email at all - so you can be sure any email that looks like it came from a mailinator address is forged. And I'll sleep just fine if such email gets blacklisted.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8523046672726455213-7902337155998939941?l=mailinator.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/MailinatorBlog/~4/fb4MUQ03yYU" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://mailinator.blogspot.com/feeds/7902337155998939941/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=8523046672726455213&amp;postID=7902337155998939941" title="5 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/8523046672726455213/posts/default/7902337155998939941?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/8523046672726455213/posts/default/7902337155998939941?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/MailinatorBlog/~3/fb4MUQ03yYU/no-mailinator-didnt-spam-you.html" title="No, Mailinator didn't spam you" /><author><name>Paul Tyma</name><uri>http://www.blogger.com/profile/11412172362500455307</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="10507225897651170435" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">5</thr:total><feedburner:origLink>http://mailinator.blogspot.com/2009/01/no-mailinator-didnt-spam-you.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CEUBR389cSp7ImA9WxRbGE0.&quot;"><id>tag:blogger.com,1999:blog-8523046672726455213.post-5149447360505851565</id><published>2008-12-08T15:34:00.000-08:00</published><updated>2008-12-08T21:57:36.169-08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2008-12-08T21:57:36.169-08:00</app:edited><title>Dear World, email addresses are not identity</title><content type="html">Its no secret that part of putting up any website or service is the consideration of security measures to stop people from abusing the system. And as you can imagine, those particular issues are probably doubled or tripled with a site like &lt;a href=http://www.mailinator.com&gt;Mailinator&lt;/a&gt; (and of course &lt;a href=http://www.talkinator.com&gt;Talkinator&lt;/a&gt;). Needless to say, I've gotten pretty good at unorthodox security.&lt;br /&gt;&lt;br /&gt;Anonymity does indeed breed bravery. &lt;br /&gt;&lt;br /&gt;The normal Mailinator use case is that you have a need for a quick email address to sign-up for some web service. Some people however, use Mailinator as an actual primary email repository. With the RSS feed, it acts as a convenient dropbox for newsletters or other semi-private email needs.&lt;br /&gt;&lt;br /&gt;Unfortunately, there are some wacky funsters out there that think it might be fun to sign-up for some website over and over and over and over (and over). Often this is for some site that has "vote for your favorite band" or "sign up for a free gift" or some such thing.&lt;br /&gt;&lt;br /&gt;The primary flaws of these systems is not Mailinator - its that these websites equate the idea of identity with email addresses. Seriously, long before Mailinator existed I had 3 or 4 email accounts that I actively used and another 10 I had probably abandoned. I'm not sure what those site designers were thinking - Mailinator or not, email addresses are FREE.&lt;br /&gt;&lt;br /&gt;If you give someone something that has any value at all in exchange for free email addresses, they're going to ask for lots. I'm probably in a unique position to view this, but I see this idea as incredibly broken.&lt;br /&gt;&lt;br /&gt;One option I had was to simply ignore this idea. Let crafty script-writers create systems that sign up for Wink accounts 1000 times an hour. (As I write this, I'm watching some automated system using several hundred IPs trying to sign-up for wink.com using Mailinator - and watching the Mailinator system dutifully send each request to the abuse page).&lt;br /&gt;&lt;br /&gt;The problem with this is that someday, wink.com will catch on. And they'll ban Mailinator. This is sadly, a wonderfully broken solution to a still existing broken site design.&lt;br /&gt;&lt;br /&gt;The problem for me is that I likely have legitimate users that want to sign up for Wink - and I want them able to do so (and I imagine Wink might want more users too, so by extension they'll lose some or all of the ones I lost). What's insanely broken for sites banning Mailinator is that there are tens of Mailinator-copy-cat disposable web services out there. Or even worse, someone with access to a server and a domain, who can install sendmail and create a few thousand accounts. Simply put, banning mailinator is like catching a single mouse and thinking you've solved the mouse problem. &lt;br /&gt;&lt;br /&gt;You stop the bad guys, but for about a day until they implement a new system.&lt;br /&gt; &lt;br /&gt;I had an interesting discussion with an acquaintance recently. During the conversation I described Mailinator to him. His mouth gaped open and told me he would look into it and probably ban it from his site. I asked what he would be banning it "from". He said he had a trial piece of software that people could sign-up for and download. And he wanted their real information to email them later (i.e. I did my best not to say that he was sending "spam") to see if they wanted to buy.&lt;br /&gt;&lt;br /&gt;I noted that sometimes when I download software to try, I do want to enter my real email. I'm interested enough to want to be registered. But other times, I'm just in browsing mode. If given the chance I'd download and check it out, but if you give me too much impedance I'll probably just go check out his competitor. &lt;br /&gt;&lt;br /&gt;In those cases when I'm just browsing, I'll use mailinator.&lt;br /&gt;&lt;br /&gt;In other words, there are 3 types of potential customers. Those that don't care about his software. Those who really love the idea of trying his software and will do anything to do so. And those who are on the fence.&lt;br /&gt;&lt;br /&gt;For obvious reasons, Mailinator is my "on-the-fence" tool of choice. If he banned it, he'd be refusing some subset of those potential customers. So it basically comes down to the question - whats better? &lt;br /&gt;&lt;br /&gt;1) Definitely get user information you can spam later - or &lt;br /&gt;2) get your product in front of as many eyeballs as possible. &lt;br /&gt;&lt;br /&gt;Also noting the fact that NO email insures any relation to an actual person whatsoever (including yahoo, gmail, hotmail, etc.) - whats the point?&lt;br /&gt;&lt;br /&gt;We continued our discussion and agreed that from a marketing perspective, you actually don't want to remove the email sign-up altogether. It actually brings value to some customers. If you remove it or make it optional, most everyone will skip it just to get to the goodies. But by leaving it and knowing that some people, using Mailinator or Yahoo or whatever, will give you temporary email addresses, you're maximizing your potential customer base. &lt;br /&gt;&lt;br /&gt;It didn't hurt my argument to mention a few other disposable email services that he'd have to ban too. I sure don't know them all - they seem to come and go a lot. And that surely doesn't count ones that run semi-privately. Basically, it would be a fulltime job to keep up.&lt;br /&gt;&lt;br /&gt;Oh. So, back to our script kiddies above. Mailinator includes a system to stop scripts from signing up for websites over and over. I love fun algorithms/data-structures so your homework can be to design something like Mailinator's abuse trigger system - a key-value datastruct that ages with time and is refreshed by lookups that come in at some notable (and tweaked) rate (in the same ballpark as a LRU cache, but definitely more dynamic).&lt;br /&gt;&lt;br /&gt;Its unlikely a human will set-off the triggers but its possible. The sad part (for script writers) is that the algorithm doesn't trigger until their script gets going, so its probably a bit heart-breaking to spend a few hours perfecting a script to scrape Mailinator and then have Mailinator detect it only once it gets going and shut it down hard.&lt;br /&gt;&lt;br /&gt;The first level is the &lt;a href=http://www.mailinator.com/stinky.jsp&gt;Abuse Page&lt;/a&gt;. If you push it, Mailinator will ban IP addresses - but only under certain conditions. That's rather an imprecise way of stopping abuse. In addition, it looks for patterns of mailbox usage regardless of IP. An obvious one is that if one subject "Welcome to Wink!" shows up a lot in the read emails. Sadly, its difficult to distinguish valid users trying to sign-up for wink amongst the botnet hitting right now - so they'll probably get the abuse page too for the time being.&lt;br /&gt;&lt;br /&gt;Potential site abusers taught me a lot and hardened the site considerably. Abuse attempts are still a common occurrence but far less normal than a few years ago. I assume many scripters went to less caring disposable services.&lt;br /&gt;&lt;br /&gt;I often get asked if I care if sites ban Mailinator. I don't really. In some cases its prudent if you really do need to email people that use your service. In most cases however, its simply a knee-jerk reaction attempting to patch an otherwise flawed system. Not only is it a sure way to eliminate some potential customers, the flaw will show up again soon when the abusers shift to another method - and probably another method without Mailinator's facilities to stop scripts. &lt;br /&gt;&lt;br /&gt;In the end, there is no real identity on the Internet. At least none past an IP address and a subpoena. At best, email is optional identity. And prudently, it should probably be treated that way.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8523046672726455213-5149447360505851565?l=mailinator.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/MailinatorBlog/~4/3UFhJNrMppA" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://mailinator.blogspot.com/feeds/5149447360505851565/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=8523046672726455213&amp;postID=5149447360505851565" title="6 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/8523046672726455213/posts/default/5149447360505851565?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/8523046672726455213/posts/default/5149447360505851565?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/MailinatorBlog/~3/3UFhJNrMppA/dear-world-email-addresses-are-not.html" title="Dear World, email addresses are not identity" /><author><name>Paul Tyma</name><uri>http://www.blogger.com/profile/11412172362500455307</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="10507225897651170435" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">6</thr:total><feedburner:origLink>http://mailinator.blogspot.com/2008/08/dear-world-email-addresses-are-not.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DkUCRHg8fCp7ImA9WxRbFEw.&quot;"><id>tag:blogger.com,1999:blog-8523046672726455213.post-4194485010606376631</id><published>2008-12-04T10:04:00.000-08:00</published><updated>2008-12-04T10:11:05.674-08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2008-12-04T10:11:05.674-08:00</app:edited><title>Reserved Names in Talkinator</title><content type="html">Talkinator now includes a beta feature (ok, all features are beta) to allow reserved names. Each room can have only one and the person owning the site (and cut and pasting the code) designates the reserved name and the password to access it.&lt;br /&gt;&lt;br /&gt;If you already have a Talkinator in your site, just click the &amp;lt;/&amp;gt; icon (i.e. get the code!) in the upper right of any talkinator chatbox and create your Talkinator with your reserved name!&lt;br /&gt;&lt;br /&gt;Please let us know how it works and especially if you find any bugs!  (email to support@manybrain.com)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8523046672726455213-4194485010606376631?l=mailinator.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/MailinatorBlog/~4/wkkcTmSjKw0" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://mailinator.blogspot.com/feeds/4194485010606376631/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=8523046672726455213&amp;postID=4194485010606376631" title="1 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/8523046672726455213/posts/default/4194485010606376631?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/8523046672726455213/posts/default/4194485010606376631?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/MailinatorBlog/~3/wkkcTmSjKw0/reserved-names-in-talkinator.html" title="Reserved Names in Talkinator" /><author><name>Paul Tyma</name><uri>http://www.blogger.com/profile/11412172362500455307</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="10507225897651170435" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">1</thr:total><feedburner:origLink>http://mailinator.blogspot.com/2008/12/reserved-names-in-talkinator.html</feedburner:origLink></entry><entry gd:etag="W/&quot;A0UBRXc4eSp7ImA9WxRVFEk.&quot;"><id>tag:blogger.com,1999:blog-8523046672726455213.post-7837892926454551160</id><published>2008-11-11T15:55:00.000-08:00</published><updated>2008-11-11T16:20:54.931-08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2008-11-11T16:20:54.931-08:00</app:edited><title>So, Mailinator's core-duo server now gets 3 Terabyte a month</title><content type="html">Its been awhile since I've updated my article &lt;a href="http://mailinator.blogspot.com/2007/01/architecture-of-mailinator.html"&gt;The Architecture of Mailinator&lt;/a&gt;. That was a long time ago and really and tons has changed. To save you reading that article if you're in a hurry, the crux was that Mailinator was originally based on the unix email program sendmail, which pretty much died at around 800,000 emails a day. And then it discusses the design of the fully custom SMTP server designed for mailinator.&lt;br /&gt;&lt;br /&gt;In that article, Mailinator was running on a single AMD cpu and processing 3 million emails a day or so. Well, somewhere in there I got a deal with my &lt;a href="http://www.serverbeach.com/catalog/index.php?REF=BA83A6U6H2"&gt;hosting company&lt;/a&gt; and was running a dual dual-core opteron machine. Mailinator ran on that for about a year as our email load doubled a time or two.&lt;br /&gt;&lt;br /&gt;Eventually I needed a server for another project and realized that giving Mailinator that dual-opteron was pretty overkill. So I "downgraded" the machine to a core-duo. Which is where it runs now. In the aforementioned article we were getting 3 million emails a day - now I sometimes see 2 million an &lt;span style="font-weight:bold;"&gt;hour&lt;/span&gt;. &lt;br /&gt;&lt;br /&gt;For the geeks out there, this is still of course a highly-multithreaded java implementation often running 4000 simultaneous threads. Pure Java I/O  (not that stinky and slow &lt;a href="http://mailinator.blogspot.com/2008/02/kill-myth-please-nio-is-not-faster-than.html"&gt;NIO&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Today I got an email from my hosting server that I "surpassed my allotted bandwidth". I'm pretty used to getting subpoena's and such, but not so many of these. &lt;br /&gt;&lt;br /&gt;Apparently, Mailinator received 3.1 Terabytes of email in the last 4 weeks. &lt;br /&gt;&lt;br /&gt;Thats (ballpark) 480 million emails or so in that 4 weeks. As I've said before, that doesn't compare to any bigger email service, but then again, I bet they have more than one server :)  I'll also emphasize that numbers I usually throw up here were measured or calculated by me - that 3T number comes from my provider so I hope its accurate as they want money for it !&lt;br /&gt;&lt;br /&gt;Thats a LOT of spam (sure there's web traffic in there which might be hefty in other circumstances, but it doesn't hold a candle against the mail traffic).&lt;br /&gt;&lt;br /&gt;I've priced things out and although my server still has plenty of computing capacity left, I'm clearly hitting an artificial (i.e. pay for more) bandwidth limit. It makes far more economical sense to simply get another server (per all pricing schemes I find) than to buy more bandwidth on this one.&lt;br /&gt;&lt;br /&gt;So, someday I'll get around to writing the next "Architecture of Mailinator" article and although it almost sounds funny to me after all this time, I'll likely be talking about "both" Mailinator servers. Not just our trust little core duo.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8523046672726455213-7837892926454551160?l=mailinator.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/MailinatorBlog/~4/vXTqxJfOc04" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://mailinator.blogspot.com/feeds/7837892926454551160/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=8523046672726455213&amp;postID=7837892926454551160" title="4 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/8523046672726455213/posts/default/7837892926454551160?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/8523046672726455213/posts/default/7837892926454551160?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/MailinatorBlog/~3/vXTqxJfOc04/so-our-core-duo-server-now-gets-3.html" title="So, Mailinator's core-duo server now gets 3 Terabyte a month" /><author><name>Paul Tyma</name><uri>http://www.blogger.com/profile/11412172362500455307</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="10507225897651170435" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">4</thr:total><feedburner:origLink>http://mailinator.blogspot.com/2008/11/so-our-core-duo-server-now-gets-3.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DkIFQX46eSp7ImA9WxRVFUw.&quot;"><id>tag:blogger.com,1999:blog-8523046672726455213.post-2184012266225007668</id><published>2008-11-03T07:52:00.000-08:00</published><updated>2008-11-12T10:28:30.011-08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2008-11-12T10:28:30.011-08:00</app:edited><title>The Revolutionary Fuzzy-Logical Super-Duper Mailinator Captcha System(tm)</title><content type="html">So, after many years of resistance for various reasons, Mailinator has finally implemented a &lt;font color=red&gt;&lt;b&gt;DELETE&lt;/b&gt;&lt;/font&gt; button. That's right. The number one frequently-asked-question that isn't in the &lt;a href=http://www.mailinator.com/faq.jsp&gt;FAQ&lt;/a&gt; has been answered.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_wdOYAcPCMJE/SQ8gh-5Qa3I/AAAAAAAABI0/Jjlb6pCIFbA/s1600-h/captcha1.gif"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 80px; height: 24px;" src="http://1.bp.blogspot.com/_wdOYAcPCMJE/SQ8gh-5Qa3I/AAAAAAAABI0/Jjlb6pCIFbA/s400/captcha1.gif" border="0" alt=""id="BLOGGER_PHOTO_ID_5264462257610320754" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;The reasons for its delay are many. In the early days I was too worried that someone would write a script that would attack the system and delete every email out there. Then after a year or two of people writing scripts to attack Mailinator in every other way - I had enough AI built into the system to stop most of it. (As always, I define "attack" as something that could bring the system down or ruin its use for other users - spamming Mailinator is really not on the radar, its not our place to define what is spam in this context).&lt;br /&gt;&lt;br /&gt;Subsequently, I looked at implementing it a few times but tended to back off. If you've read this blog awhile you know that Mailinator and Talkinator at least partially existed as a testbed for implementing server ideas (some earlier articles: &lt;a href=http://mailinator.blogspot.com/2007/01/architecture-of-mailinator.html&gt;The Architecture of Mailinator&lt;/a&gt; and &lt;a href=http://mailinator.blogspot.com/2008/08/benchmarking-talkinator.html&gt;Benchmarking Talkinator&lt;/a&gt;).&lt;br /&gt;&lt;br /&gt;And while implementing a delete function might sound simple - it had some interesting complexities in the architecture. In any case I'm happy to say - its finally here.&lt;br /&gt;&lt;br /&gt;And here's the best news. To thwart all those rascally script-kiddies (who probably have seen the rather hidden but sometimes funny &lt;a href=http://www.mailinator.com/stinky.jsp&gt;Mailinator Abuse Page&lt;/a&gt;) we're proud to announce the &lt;span style="font-weight:bold;"&gt;"Revolutionary Fuzzy-Logical Super-Duper Mailinator Captcha System(tm)"&lt;/span&gt; !!!!!&lt;br /&gt;&lt;br /&gt;Thats right. The great service and ironclad spam (fighting/loving/tolerating, your call) abilities of Mailinator are now in a REVOLUTIONARY captcha system!  We could have used a pre-written captcha system but that would have been sadly inferior and very non-mailinatory!&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_wdOYAcPCMJE/SQ3abQybIjI/AAAAAAAABIs/cx7HSG7gnTM/s1600-h/screenie.gif"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 109px;" src="http://4.bp.blogspot.com/_wdOYAcPCMJE/SQ3abQybIjI/AAAAAAAABIs/cx7HSG7gnTM/s400/screenie.gif" border="0" alt=""id="BLOGGER_PHOTO_ID_5264103701363761714" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Just look at it and you'll know that this is going to take some major AI, image processing and statistical analysis to crack past this sucker.&lt;br /&gt;&lt;br /&gt;Oh. And one more thing.... (got that from Steve Jobs)&lt;br /&gt;&lt;br /&gt;We at Mailinator are happy to announce that this Captcha system is just &lt;span style="font-weight:bold;"&gt;TOO GOOD&lt;/span&gt; not to share with the world. So, you guessed it, we're releasing it as a web service !&lt;br /&gt;&lt;br /&gt;You can now include The Revolutionary Fuzzy-Logical Super-Duper Mailinator Captcha System(tm) in your websites too !!!&lt;br /&gt;&lt;br /&gt;Here's the highly-technical, low-level URL:&lt;br /&gt;&lt;br /&gt;(edit: url momentarily removed due to immense user respo.. ok.. just a bug... be bak soon)&lt;br /&gt;&lt;br /&gt;(where yourDestination.html is where you want the captcha to go after very securely and precisely verifying the humanness (and also non-computerness) of your user).&lt;br /&gt;&lt;br /&gt;Put this in your web pages and sleep well! &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;(Disclaimer: This captcha system, although highly-advanced and chock-full of the latest advances in modern artificial intelligence does a better-than-expected job of verifying humans are humans.  However we've noticed an eensy bug that seems to prevent it from sometimes (or "usually" really (actually its probably more like "mostly" (sometimes its pretty "always" tho))) figuring out that computers aren't humans. So consider this and "alpha" release.. or maybe "pre-alpha" or something like that. A "prototype", yeah, its a "prototype").&lt;br /&gt;&lt;br /&gt;PS: Have your own idea for a captcha? Make the image 80x24 pixels and send it to support@manybrain.com !&lt;br /&gt;&lt;br /&gt;PPS: The delete function is in beta. Please let us know of any bugs.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8523046672726455213-2184012266225007668?l=mailinator.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/MailinatorBlog/~4/Rx2F5xTgKME" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://mailinator.blogspot.com/feeds/2184012266225007668/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=8523046672726455213&amp;postID=2184012266225007668" title="8 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/8523046672726455213/posts/default/2184012266225007668?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/8523046672726455213/posts/default/2184012266225007668?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/MailinatorBlog/~3/Rx2F5xTgKME/revolutionary-fuzzy-logical-super-duper.html" title="The Revolutionary Fuzzy-Logical Super-Duper Mailinator Captcha System(tm)" /><author><name>Paul Tyma</name><uri>http://www.blogger.com/profile/11412172362500455307</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="10507225897651170435" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://1.bp.blogspot.com/_wdOYAcPCMJE/SQ8gh-5Qa3I/AAAAAAAABI0/Jjlb6pCIFbA/s72-c/captcha1.gif" height="72" width="72" /><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">8</thr:total><feedburner:origLink>http://mailinator.blogspot.com/2008/11/revolutionary-fuzzy-logical-super-duper.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CEEHSHc4eyp7ImA9WxRXF0U.&quot;"><id>tag:blogger.com,1999:blog-8523046672726455213.post-7183778299091005492</id><published>2008-10-23T10:17:00.000-07:00</published><updated>2008-10-23T10:23:59.933-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2008-10-23T10:23:59.933-07:00</app:edited><title>The Developer's Mailinator</title><content type="html">I get a surprising number of emails from developers testing some sort of emailing system and wondering if its "ok" to send those emails to Mailinator.&lt;br /&gt;&lt;br /&gt;Of course - the answer is yes!&lt;br /&gt;&lt;br /&gt;In fact, thanks to an email from one of those developers named Dave, I've actived port 587 on Mailinator to be an active receiving port (in addition to port 25).&lt;br /&gt;&lt;br /&gt;Mailinator has always accepted email addressed to any domain - (i.e. have a domain name? point your MX record to the mailinator server and it will arrive just fine) so it really is a pretty solid testbed. Remember, you can see the raw email (headers and all) by clicking the "text" link on any mailinator show-email page.&lt;br /&gt;&lt;br /&gt;The only caveat here is that Mailinator's defenses don't come down ever - even for testing. If you want to send a few thousand emails to Mailinator, it very well might start throwing emails away.  As is sort of our goal - we don't mind spam (actually - given the nature of Mailinator - who are we to even define what spam is?). But we ARE interested in the Mailinator service staying up and running. Any legal (and nice - please read terms of service) use is fine by us - but if Mailinator thinks you're being overzealous, we'll probably side with it :)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8523046672726455213-7183778299091005492?l=mailinator.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/MailinatorBlog/~4/5ZMsyyjAmRw" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://mailinator.blogspot.com/feeds/7183778299091005492/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=8523046672726455213&amp;postID=7183778299091005492" title="1 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/8523046672726455213/posts/default/7183778299091005492?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/8523046672726455213/posts/default/7183778299091005492?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/MailinatorBlog/~3/5ZMsyyjAmRw/developers-mailinator.html" title="The Developer's Mailinator" /><author><name>Paul Tyma</name><uri>http://www.blogger.com/profile/11412172362500455307</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="10507225897651170435" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">1</thr:total><feedburner:origLink>http://mailinator.blogspot.com/2008/10/developers-mailinator.html</feedburner:origLink></entry><entry gd:etag="W/&quot;Dk8GRXY6eip7ImA9WxRXF0U.&quot;"><id>tag:blogger.com,1999:blog-8523046672726455213.post-7929685856633073886</id><published>2008-09-02T08:12:00.000-07:00</published><updated>2008-10-23T11:00:24.812-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2008-10-23T11:00:24.812-07:00</app:edited><title>Mailinator for your IGoogle Homepage</title><content type="html">Frank Ellermann has created a very pretty integration of Mailinator into the iGoogle homepage. It now installs with just a click!&lt;br /&gt;&lt;br /&gt;Thanks Frank!&lt;br /&gt;&lt;br /&gt;See it here: &lt;a href=http://www.googleminiapps.com/tools/mailinator-mobile-reader-gadget/#&gt;Mailinator iGoogle&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8523046672726455213-7929685856633073886?l=mailinator.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/MailinatorBlog/~4/Ur4MxCDjL98" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://mailinator.blogspot.com/feeds/7929685856633073886/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=8523046672726455213&amp;postID=7929685856633073886" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/8523046672726455213/posts/default/7929685856633073886?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/8523046672726455213/posts/default/7929685856633073886?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/MailinatorBlog/~3/Ur4MxCDjL98/mailinator-for-you-igoogle-homepage.html" title="Mailinator for your IGoogle Homepage" /><author><name>Paul Tyma</name><uri>http://www.blogger.com/profile/11412172362500455307</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="10507225897651170435" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><feedburner:origLink>http://mailinator.blogspot.com/2008/09/mailinator-for-you-igoogle-homepage.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DkICQ30zeCp7ImA9WxdaGUg.&quot;"><id>tag:blogger.com,1999:blog-8523046672726455213.post-8610791721571229931</id><published>2008-08-20T14:08:00.000-07:00</published><updated>2008-08-28T13:16:02.380-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2008-08-28T13:16:02.380-07:00</app:edited><title>Benchmarking Talkinator</title><content type="html">I really wrote &lt;a href=http://www.talkinator.com&gt;Talkinator&lt;/a&gt; for one reason - to play around with some server architectures I had bouncing around in my head. Now, any programmer in almost any language will tell you that it would take just a few hours on a Saturday to write a chat server. Its really not that hard.&lt;br /&gt;&lt;br /&gt;If you add in the fact of using Ajax and then emulating sessions over a stateless protocol, and then  add in a mildly usable client, you're probably up to a weekend or two. But its still not rocket science.&lt;br /&gt;&lt;br /&gt;The Talkinator server in reality took me over a year to write. Partially because it was a weekend project and I surely didn't give every weekend to it. Also, because I ripped out the architecture more than once. At first it was a Java applet that did nice pretty TCP communication. I made a false assumption that applets, maybe after 10 years, didn't suck anymore. But I was wrong. They still suck - and a lot.&lt;br /&gt;&lt;br /&gt;Finally, I settled on the ajax client model it is on now. I also really didn't want to use asynchronous/NIO networking. The world seems to still fight me (without doing their own benchmarking) but NIO only makes sense when you can't do Thread-per-connection. On linux, threads (using NPTL and kernel 2.6) are cheap now. And Java IO (synchronous I/O) is measurably faster than Java NIO (asynchronous I/O). In fact, this has nothing to do with Java, I've had many great conversations with C++ folks who find the same thing.&lt;br /&gt;&lt;br /&gt;This is where chat becomes mildly interesting. Chat is of course, a "broadcast" networking model. That is, one user sends a message and that message must be propagated to some number of other users. Clearly, many networking applications follow this model, but given that chat is just text - its a rather pure form. It has comparably few details and I could focus just on the data pushing part.&lt;br /&gt;&lt;br /&gt;As I said, writing a chat server is easy. However, like many things, writing a chat server that scales is harder. And because of its combinatorial nature, it grows dangerously fast. For this reason, it seemed like a fun project to make a fast broadcast server.&lt;br /&gt;&lt;br /&gt;I mentioned that asynchronous/NIO is still suitable when you cant do Thread-per-connection and for Java you soft-max at around 12000 threads (in my testing) and hard-max at 16383 (JVM just wont make more - although some JVMs goto 32767).  A chat server is almost the canonical example of a server that has very many, low traffic connections. Its a perfect candidate for NIO.&lt;br /&gt;&lt;br /&gt;The trick with synchronous I/O is that a thread will block on every read and every write to the clients. A chat server has the bandwidth to handle 10's of thousands of users, but not if every user equals a thread.&lt;br /&gt;&lt;br /&gt;Although synchronous IO reads and writes are blocking, the sequence of conversation events (avoiding the word "protocol" here) in this scenario is clearly defined. Once a client opens a socket and sends a message (on a blocking read), the thread can basically abandon that client. Simply put the client in a data structure and go off and service other clients. The client connection then "hangs open" until some thread comes back and gives it some data (i.e. someone in the same room sent a message). Note that the thread does block on that initial read, but in essence, we know its coming right away. And if it doesn't, we be sure to have a fast socket timeout for this particular wait.&lt;br /&gt;&lt;br /&gt;In effect, Talkinator is a synchronous IO system which can support tens of thousands of open connections, running on just a few hundred threads (on a LAN it only needs a few tens of threads). &lt;br /&gt;&lt;br /&gt;The weird part to me is that this is a blocking-IO but non-thread-per-connection server. &lt;br /&gt;&lt;br /&gt;Every incoming message wakes up a thread to do the data read. Now each incoming message causes the need for (on average lets say) 10 outgoing messages. So sending is a lot of work as compared to reading. But we only wake threads for &lt;span style="font-weight:bold;"&gt;incoming&lt;/span&gt; messages - so once a thread enters the system when you say "Hello there", it has a lot of work to do on the sending side. The threads however, aren't picky about who's sending work they do. A thread you woke might remain active for a long time sending messages in rooms you've never heard of. If one thread incites the need for 100 outgoing messages, a small army of threads spawned from previous incoming messages jump in to help with the sending work. Once the current mound of sending work subsides, threads start going inactive (until more messages arrive).&lt;br /&gt;&lt;br /&gt;Messages are queued for each user. When the system isn't too busy, most messages go out by themselves with very low latency. But as the system gets busy, message queues might grow a bit. Thus when a send finally happens, all those messages get sent at once. In effect, its sort of a "dynamic batching" system. We trade latency for throughput (and memory) on a dynamic basis. Room merges cause 30 deep queues but those are rare. Even in busy times I don't see deep queues at all - this implies low latency.&lt;br /&gt;&lt;br /&gt;We call many pieces of software out there "engines". But to me, this really &lt;span style="font-weight:bold;"&gt;is&lt;/span&gt; like an engine. The faster it goes - the faster it will go. It is its own chain reaction.&lt;br /&gt;&lt;br /&gt;One final note on this engine - I use no blocking queues (in the synchronization sense, not the IO sense). To me, blocking queues are simply a forced thread context switch. I let the thread that did the accept then jump in and do the read and subsequent work. On linux, a thread timeslice is on the order of 10ms before its forcibly swapped out. You can service a lot of messages in 10ms. A context switch isn't hugely expensive but its not free either and I see no reason to force more than will already happen.&lt;br /&gt;&lt;br /&gt;Also, a socket accept followed by an immediate read is &lt;span style="font-weight:bold;"&gt;also&lt;/span&gt; probably a context switch. Because chances are, the read data isn't here yet (although we know its coming) so I'm right now playing with the idea of a thread accepting, then going off to help other threads do some sending, then coming back to do its read. Hopefully giving the read a chance to have its data in incoming-buffers first.&lt;br /&gt;&lt;br /&gt;I started the project with Tomcat but quickly moved away and wrote my own webserver. Of course, using blocking IO.  I found quickly that my little webserver could serve at most about 25000 web requests per second. It turns out that this isn't a limitation of my webserver. Socket accepts in linux (and probably everywhere) are damn expensive. &lt;br /&gt;&lt;br /&gt;I expanded Talkinator's webserver to use keepalive (a fundamental feature on every contemporary webserver). In my benchmarks now, on my quad-core desktop the talkinator server can push about 39000 messages per second. Keep in mind this is processed messages as in decoded, packaged, and queued for particular recipients. (I often see claims of people sending millions of messages per second on various non-chat systems - this is quite easy if you don't have an incoming request to parse and are sending one-to-one endpoints - simply fill a 10G buffer with pre-formatted messages, start the timer, and hit "send" - basically your CPU is doing nothing and all you're measuring is the speed of your network).&lt;br /&gt;&lt;br /&gt;I'll note that pretty much the entire software stack of Talkinator is custom. The webserver, the RPC, the cometd mechanism, and even the message encoding. Apart from an exercise in performance and me having fun, there was no particularly good reason to re-invent all those wheels. Just "adding another server or 3" would have probably worked equally well.&lt;br /&gt;&lt;br /&gt;The ajaxian portion of the system requires that a message is sent per user every so often regardless of activity. If in fact, if we make an aggressive estimate that each user gets a message every 10 seconds, then one talkinator server could handle 390,000 users. This is an interesting thought exercise but its my expectation that the bottleneck of the system will be bandwidth or memory long before we ever run into an actual CPU problem.&lt;br /&gt;&lt;br /&gt;I'll specifically note here that this discussion was not about scalability at all. It was about per server throughput. The talkinator scalability model is orthogonal would probably warrant its own blog entry.&lt;br /&gt;&lt;br /&gt;This server would be faster if written in C++ or C. But the threading techniques I employed here were only possible (for me I mean) in Java. If this performance seems out-of-whack to you in any way, simply write a server in your favorite language that reads but ignores the incoming request and returns a tiny html webpage as fast as it can. This will give you a feel for the "fastest possible webserver". After that, every feature is slowing you down.&lt;br /&gt;&lt;br /&gt;I don't suppose there is a moral here other than this is an experiential report of one of my weekend projects. Seriously, if you still believe asynchrounous/NIO beats synchronous/IO (and it did when linux threads killed the system after just a few hundred were started) you might want to do some research. Threaded socket programming is back.. and with a vengeance.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8523046672726455213-8610791721571229931?l=mailinator.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/MailinatorBlog/~4/IkOCTb_WUbo" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://mailinator.blogspot.com/feeds/8610791721571229931/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=8523046672726455213&amp;postID=8610791721571229931" title="9 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/8523046672726455213/posts/default/8610791721571229931?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/8523046672726455213/posts/default/8610791721571229931?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/MailinatorBlog/~3/IkOCTb_WUbo/benchmarking-talkinator.html" title="Benchmarking Talkinator" /><author><name>Paul Tyma</name><uri>http://www.blogger.com/profile/11412172362500455307</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="10507225897651170435" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">9</thr:total><feedburner:origLink>http://mailinator.blogspot.com/2008/08/benchmarking-talkinator.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DkEGQXk6eSp7ImA9WxdUFE4.&quot;"><id>tag:blogger.com,1999:blog-8523046672726455213.post-4497452454785002572</id><published>2008-07-30T09:12:00.000-07:00</published><updated>2008-07-30T09:17:00.711-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2008-07-30T09:17:00.711-07:00</app:edited><title>Bob Cringely on Talkinator</title><content type="html">Bob Cringely, well-known computer industry guy wrote a nice &lt;a href=http://www.pbs.org/cringely/pulpit/2008/pulpit_20080728_005308.html&gt;article&lt;/a&gt; about the "Five percent solution". He uses Talkinator as prime example!&lt;br /&gt;&lt;br /&gt;I like this idea - I remember many years ago someone telling me about Google and I thought they were nuts - "I have Altavista - why do I need this Google thing? (silly name by the way)". Or even a bigger one for me was when I first heard of YouTube - so some little guy is going against an already established Google Video with their only real distinguishing feature is that they only allow "short videos"?&lt;br /&gt;&lt;br /&gt;Bob's right - sometimes a very established idea simply needs a 5% twist to take it to the next level.&lt;br /&gt;&lt;br /&gt;Thanks Bob !&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8523046672726455213-4497452454785002572?l=mailinator.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/MailinatorBlog/~4/m-Ehxha5Olg" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://mailinator.blogspot.com/feeds/4497452454785002572/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=8523046672726455213&amp;postID=4497452454785002572" title="1 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/8523046672726455213/posts/default/4497452454785002572?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/8523046672726455213/posts/default/4497452454785002572?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/MailinatorBlog/~3/m-Ehxha5Olg/bob-cringely-on-talkinator.html" title="Bob Cringely on Talkinator" /><author><name>Paul Tyma</name><uri>http://www.blogger.com/profile/11412172362500455307</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="10507225897651170435" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">1</thr:total><feedburner:origLink>http://mailinator.blogspot.com/2008/07/bob-cringely-on-talkinator.html</feedburner:origLink></entry><entry gd:etag="W/&quot;AkYMSHw7eip7ImA9WxdVGUk.&quot;"><id>tag:blogger.com,1999:blog-8523046672726455213.post-448848722723660508</id><published>2008-07-24T18:06:00.001-07:00</published><updated>2008-07-24T18:09:49.202-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2008-07-24T18:09:49.202-07:00</app:edited><title>Talkinator notes</title><content type="html">When Mailinator came out, people simply couldn't get over the fact that there was no login - I mean, how can you have email that doesn't have a login and password?  It was a very strong paradigm shift for some folks.&lt;br /&gt;&lt;br /&gt;For Talkinator, this paradigm shift has so far been the shock of "all of a sudden" being in a live discussion in a Talkinator room. Again, they didn't sign in or realize it would happen.  Its rather  common for people to not believe its actually live (often they assume its some sort of advertisement).&lt;br /&gt;&lt;br /&gt;It took awhile for people to get-it as far as how Mailinator works. Paradigm shifts come slow - but they're often a lot of fun.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8523046672726455213-448848722723660508?l=mailinator.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/MailinatorBlog/~4/rycePnc5k_A" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://mailinator.blogspot.com/feeds/448848722723660508/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=8523046672726455213&amp;postID=448848722723660508" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/8523046672726455213/posts/default/448848722723660508?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/8523046672726455213/posts/default/448848722723660508?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/MailinatorBlog/~3/rycePnc5k_A/talkinator-notes.html" title="Talkinator notes" /><author><name>Paul Tyma</name><uri>http://www.blogger.com/profile/11412172362500455307</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="10507225897651170435" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><feedburner:origLink>http://mailinator.blogspot.com/2008/07/talkinator-notes.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DkIMQng-cCp7ImA9WxdXE0g.&quot;"><id>tag:blogger.com,1999:blog-8523046672726455213.post-84007311449980811</id><published>2008-06-24T11:39:00.000-07:00</published><updated>2008-06-24T17:43:03.658-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2008-06-24T17:43:03.658-07:00</app:edited><title>Introducing... Talkinator(tm)</title><content type="html">Mailinator's creation was rather an exercise in disbelief. After all, there isn't much to it - in fact, its just email with some key components removed. That is, no sign-in, no registration, and no passwords.  At first glance, it seemed like there'd be no purpose for such a thing - but people on the Internet have a sneaky way of finding uses for new paradigms.&lt;br /&gt;&lt;br /&gt;From that idea, Mailinator has a new little brother - &lt;a href=http://www.talkinator.com&gt;Talkinator&lt;/a&gt;.  If you've used Mailinator in the past few days its likely you've bumped into it. Its doing for internet chat what Mailinator did for email. No sign-in, no registration, no passwords. Fully embeddable in any website you want - or use it right from the Talkinator site.&lt;br /&gt;&lt;br /&gt;As with Mailinator, privacy is &lt;b&gt;not&lt;/b&gt; guaranteed or even implied(in the current incarnation, it sort of can't be) - so never put any personal information in Talkinator (or anywhere else on the Internet for that matter).&lt;br /&gt;&lt;br /&gt;Talkinator is partially a part-two of the Mailinator experiment. Its also partially a logical extension - and also partially just the result of me tinkering around with a lot of ideas. It took a surprisingly long time to write, but thats partially because I wasn't in a hurry. Its using what is to me, a very experimental server architecture (which I'll write about eventually.. if it ends up working :) ).&lt;br /&gt;&lt;br /&gt;Almost everything is custom including the webserver right down to the http parsing. That includes the RPC mechanism and even the http encoding. Non-custom parts include using the GWT to create the javascript client (which rocks) and Cliff Click's non-blocking hash map (which also rocks). It is in essence, an exercise in re-inventing the wheel AND premature optimization (or at least "meticulous optimization" - whether or not its premature is up to debate).&lt;br /&gt;&lt;br /&gt;There's plenty more to say here from a user and technical standpoint, but I'll stop talking for now - so that you can start.&lt;br&gt;&lt;br /&gt;&lt;center&gt;&lt;br /&gt;&lt;iframe width=350 height=350 marginwidth=0 marginheight=0 scrolling=no style='border: 1px solid #819dd4' frameborder=0 src='http://www.t8r2.info/$r?s=0&amp;t=h&amp;w=350&amp;h=350&amp;c=9dd0ff&amp;b=talky'&gt; &lt;/iframe&gt;&lt;br /&gt;&lt;/center&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8523046672726455213-84007311449980811?l=mailinator.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/MailinatorBlog/~4/AArjNhWBHzY" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://mailinator.blogspot.com/feeds/84007311449980811/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=8523046672726455213&amp;postID=84007311449980811" title="2 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/8523046672726455213/posts/default/84007311449980811?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/8523046672726455213/posts/default/84007311449980811?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/MailinatorBlog/~3/AArjNhWBHzY/introducing-talkinatortm.html" title="Introducing... Talkinator(tm)" /><author><name>Paul Tyma</name><uri>http://www.blogger.com/profile/11412172362500455307</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="10507225897651170435" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">2</thr:total><feedburner:origLink>http://mailinator.blogspot.com/2008/06/introducing-talkinatortm.html</feedburner:origLink></entry><entry gd:etag="W/&quot;A0UBQHY4fSp7ImA9WxZUGUU.&quot;"><id>tag:blogger.com,1999:blog-8523046672726455213.post-6414596267881295467</id><published>2008-04-12T01:33:00.000-07:00</published><updated>2008-04-12T01:34:11.835-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2008-04-12T01:34:11.835-07:00</app:edited><title>Mobile Mailinator</title><content type="html">Great idea - a nice write-up on how to use Mailinator on your mobile phone!   &lt;br /&gt;&lt;br /&gt;http://ergo.rydlr.net/?p=63&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8523046672726455213-6414596267881295467?l=mailinator.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/MailinatorBlog/~4/6HpIbM2knsw" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://mailinator.blogspot.com/feeds/6414596267881295467/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=8523046672726455213&amp;postID=6414596267881295467" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/8523046672726455213/posts/default/6414596267881295467?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/8523046672726455213/posts/default/6414596267881295467?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/MailinatorBlog/~3/6HpIbM2knsw/mobile-mailinator.html" title="Mobile Mailinator" /><author><name>Paul Tyma</name><uri>http://www.blogger.com/profile/11412172362500455307</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="10507225897651170435" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><feedburner:origLink>http://mailinator.blogspot.com/2008/04/mobile-mailinator.html</feedburner:origLink></entry><entry gd:etag="W/&quot;AkIESX86eCp7ImA9WxRbGEg.&quot;"><id>tag:blogger.com,1999:blog-8523046672726455213.post-7486689174746338786</id><published>2008-03-30T14:18:00.001-07:00</published><updated>2008-12-09T13:35:08.110-08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2008-12-09T13:35:08.110-08:00</app:edited><title>How fast is Java Volatile? or Atomic? or Synchronized?</title><content type="html">This is a question I've wondered awhile.  And I've gone ahead and made a stab at finding out. One question that I had was I had always heard that AMD chips have an on-cpu memory controller and Intel's don't (at  least not until they're upcoming Nehalem line). Now I'm first to admit I'm talking above my knowledge (please correct profusely).&lt;br /&gt;&lt;br /&gt;But the idea was that some operations (notably I've heard volatile reads which I didnt test here) are very similar regardless of volatility.&lt;br /&gt;&lt;br /&gt;I spent a few hours making up a benchmark. I'm publishing the benchmark below for one important reason - to get it right. This is big disclaimer: Don't trust these results - at least with any precision. I do conclude that contended synchronization is expensive - thats a pretty expected result so hopefully we're somewhere on the right track.&lt;br /&gt;&lt;br /&gt;However, Java benchmarks are very hard to right. So hard in fact that they do a hardness-overflow and end up looking easy - which is precisely what makes them so hard to get right. Hence - given that only I have seen this benchmark, its pretty likely to be broken some (and hence why its published here for public review to help fix).&lt;br /&gt;&lt;br /&gt;With all that...&lt;br /&gt;&lt;br /&gt;What I've tested here are storage operations. Specifically:&lt;br /&gt;&lt;br /&gt;Storage to a local variable (mostly used as a control)&lt;br /&gt;Storage to an instance variable&lt;br /&gt;Storage to a static variable&lt;br /&gt;Storage to a static volatile variable&lt;br /&gt;Storage to a static AtomicLong variable&lt;br /&gt;Storage to a static variable protected by syncrhonization&lt;br /&gt;&lt;br /&gt;I tested this on 3 different CPUs, all with JDK1.6 and variously on Linux and Windows. One very important point is do *not* compare the absolute numbers in the graphs directly. In no case are comparing the same CPU across 2 operating systems. The CPUs are wildly different in capability.&lt;br /&gt;&lt;br /&gt;So we can explain more with a graph:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_wdOYAcPCMJE/R_AEwsFQNBI/AAAAAAAAA8k/G0p9UwcEqpw/s1600-h/opteronall.jpg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://1.bp.blogspot.com/_wdOYAcPCMJE/R_AEwsFQNBI/AAAAAAAAA8k/G0p9UwcEqpw/s400/opteronall.jpg" alt="" id="BLOGGER_PHOTO_ID_5183648405616866322" border="0" /&gt;&lt;/a&gt;This is the run on a dual-core dual-Opteron machine. Note the blue-bar is local variable storage. As you'd expect it simply destroys everything else. This is very probably because the smart JVM went in and realized it could optimize the assignment out of the loop. Note the blue-bar just gets happier and happier as we add cores. The threads are completely unaffected by each other and we get actual linear increases in power. Even at 5 threads (note we have 4 cores) we get some speedup.&lt;br /&gt;&lt;br /&gt;The orange and yellow bars are instance variable and static variable stores respectively. Some level of indirection or inability to optimize jumps in and makes things a bit more sane.  Surprising we get little or no improvement as we add threads.&lt;br /&gt;&lt;br /&gt;The three thread-visible methods of store are so slow they barely show up. This brings up an important point, let's assume you wrote an application and made it  correctly thread safe. Using synchronization or volatiles or whatever. You *cannot* optimize away synchronization in the name of performance. It simply can't be done. (conversely, if you could then it wasn't correctly thread-safe to start). You can however, at times, replace one type of synchronization primitive with another.&lt;br /&gt;&lt;br /&gt;That being said, lets take a closer look at the same graph with just the barrier memory store operations.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_wdOYAcPCMJE/R_AExMFQNCI/AAAAAAAAA8s/0nuE0i5yJKM/s1600-h/opteronbarrier.jpg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://3.bp.blogspot.com/_wdOYAcPCMJE/R_AExMFQNCI/AAAAAAAAA8s/0nuE0i5yJKM/s400/opteronbarrier.jpg" alt="" id="BLOGGER_PHOTO_ID_5183648414206800930" border="0" /&gt;&lt;/a&gt;Volatile and Atomic are neck-and-neck. Synchronization is still a big loser, especially after we contend giving it two threads.&lt;br /&gt;&lt;br /&gt;One other anecdote - while running the non-memory-barrier benchmarks, my CPU meter showed 100% user space usage. With these benchmarks however, it went to 30-40% kernel cpu usage.&lt;br /&gt;&lt;br /&gt;Ok, jumping to the Core2Quad Extreme CPU. Definitely a faster processor but with a different memory architecture.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_wdOYAcPCMJE/R_AExcFQNDI/AAAAAAAAA80/ImaQFqsMjiY/s1600-h/corequadall.jpg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://4.bp.blogspot.com/_wdOYAcPCMJE/R_AExcFQNDI/AAAAAAAAA80/ImaQFqsMjiY/s400/corequadall.jpg" alt="" id="BLOGGER_PHOTO_ID_5183648418501768242" border="0" /&gt;&lt;/a&gt;Local store again goes flying. Oddly the instance store doesn't do much but the static store increases nicely with the cores.  And, once again, we can't even fricken see the barriered writes.. so here they are.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_wdOYAcPCMJE/R_AExcFQNEI/AAAAAAAAA88/C4FX1-gB230/s1600-h/corequadbarrier.jpg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://4.bp.blogspot.com/_wdOYAcPCMJE/R_AExcFQNEI/AAAAAAAAA88/C4FX1-gB230/s400/corequadbarrier.jpg" alt="" id="BLOGGER_PHOTO_ID_5183648418501768258" border="0" /&gt;&lt;/a&gt;Look how great the JVM does knowing that just one thread is out there. It can really optimize the code to elide or at least marginalize the impact. Surprisingly, synchronization still gets nailed across the board.&lt;br /&gt;&lt;br /&gt;Note that according to what I have so far, a synchronized static store is something 50 times slower than a simple static store. And 10 or so times slower than a volatile static store.&lt;br /&gt;&lt;br /&gt;One more.. and its a fun one. Windows XP running on a Dothan. (Funny, I realized I hadn't directly known that Dothan was single core, but I just assumed it after I saw the graphs.)&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_wdOYAcPCMJE/R_AExsFQNFI/AAAAAAAAA9E/ZA0Noi6XZhI/s1600-h/dothanall.jpg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://1.bp.blogspot.com/_wdOYAcPCMJE/R_AExsFQNFI/AAAAAAAAA9E/ZA0Noi6XZhI/s400/dothanall.jpg" alt="" id="BLOGGER_PHOTO_ID_5183648422796735570" border="0" /&gt;&lt;/a&gt;Crazy. Add a few threads and performance doesn't even budge. Of course, with only one core a system can completely avoid all the complex architecture keeping cores in sync. Why its local writes are worse as compared to instance beats me.&lt;br /&gt;&lt;br /&gt;Also, although I said don't compare graphs, this little single core Dothan beats the Core2Quad in all barrier-ed writes after 2 threads. Note that on the local writes, the Core2Quad is something like 50 time faster. But even on the simple static volatile store - at 2 threads, the Dothan is now twice as fast.&lt;br /&gt;&lt;br /&gt;So. Pardon my informalness here - I'm actually quite expecting feedback to break this code in grand ways and force me to redo all the runs and rewrite all the text (which I'll be happy to do if we get a clean bench out of this).  I have no intention of making very specific claims once this benchmark is firmed up - but I would like to have a "sense" of the costs of these different operations.&lt;br /&gt;&lt;br /&gt;Source code for the &lt;a href="http://www.mailinator.com/VariableStorage.java"&gt;Benchmark&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8523046672726455213-7486689174746338786?l=mailinator.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/MailinatorBlog/~4/Vda739KLqeA" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://mailinator.blogspot.com/feeds/7486689174746338786/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=8523046672726455213&amp;postID=7486689174746338786" title="3 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/8523046672726455213/posts/default/7486689174746338786?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/8523046672726455213/posts/default/7486689174746338786?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/MailinatorBlog/~3/Vda739KLqeA/how-fast-is-java-volatile-or-atomic-or.html" title="How fast is Java Volatile? or Atomic? or Synchronized?" /><author><name>Paul Tyma</name><uri>http://www.blogger.com/profile/11412172362500455307</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="10507225897651170435" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://1.bp.blogspot.com/_wdOYAcPCMJE/R_AEwsFQNBI/AAAAAAAAA8k/G0p9UwcEqpw/s72-c/opteronall.jpg" height="72" width="72" /><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">3</thr:total><feedburner:origLink>http://mailinator.blogspot.com/2008/03/how-fast-is-java-volatile-or-atomic-or.html</feedburner:origLink></entry><entry gd:etag="W/&quot;C0YFQXo4eip7ImA9WxZVF0o.&quot;"><id>tag:blogger.com,1999:blog-8523046672726455213.post-8601749959190789236</id><published>2008-03-27T22:26:00.000-07:00</published><updated>2008-03-28T23:11:50.432-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2008-03-28T23:11:50.432-07:00</app:edited><title>Introducing: Alternate Inbox Names</title><content type="html">Mailinator helps thousands of people every day avoid spam. It's been a great success.&lt;br /&gt;&lt;br /&gt;One point that always sort of bothered me however was that by giving out a Mailinator address, you were basically telling people not only how to email you, but also how they can check *your* email. If I say "Email me at binkypop@mailinator.com", the whole world knows where to send and &lt;b&gt;read &lt;/b&gt; my email!&lt;br /&gt;&lt;br /&gt;Well, this is no longer a problem.  Today we added "Alternate Inboxes" to Mailinator. We've always had alternate domains, but this is quite different.&lt;br /&gt;&lt;br /&gt;Now, if you check any inbox on Mailinator (say, binkypop), listed on the page is the alternate inbox name. All alternate inbox names start with "M8R-".  For example, for binkypop, the alternate inbox name is &lt;span class="small"&gt; &lt;span style="color:red;"&gt;M8R-yg1hkn&lt;/span&gt;@mailinator.com.&lt;br /&gt;&lt;br /&gt;So simply put, if you email binkypop@mailinator OR M8R-yg1hkn@mailinator.com it doesn't matter. Both emails would end up in the binkypop inbox (and nothing in the &lt;/span&gt;&lt;span class="small"&gt; &lt;span style="color:red;"&gt;M8R-yg1hkn&lt;/span&gt; inbox).  The only way to find out an alternate inbox name is to check the inbox here first - thus if you give out the alternate address, there is no way for anyone to guess that it actually goes to binkypop.&lt;br /&gt;&lt;br /&gt;So.. pick yourself a favorite Mailinator inbox name (make it big, long, and hard-to-guess please!), go check the inbox to find out the alternate inbox name, and hand it out all over the web (of course, alternate domains work on alternate inboxes too!).&lt;br /&gt;&lt;br /&gt;Then check the box (or RSS it) knowing only you know thats the real destination. Also, keep in mind - you don't have to remember the alternate inbox name ever - you just have to remember the real destination address. You can always go to Mailinator and get the alternate anytime just by checking the inbox. And of course, the regular think-up-on-the-fly-and-use Mailinator you know and love hasn't changed a bit. This feature is purely optional (I'm surprised how fast people started using it!)&lt;br /&gt;&lt;br /&gt;(This feature is in beta and we might end up changing the alternate address scheme some)&lt;br /&gt;&lt;br /&gt;This is cool. Alternate inboxes really do up the ante in Mailinator's spam fighting abilities. Enjoy !&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span class="small"&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8523046672726455213-8601749959190789236?l=mailinator.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/MailinatorBlog/~4/WNjXESQkX0w" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://mailinator.blogspot.com/feeds/8601749959190789236/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=8523046672726455213&amp;postID=8601749959190789236" title="63 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/8523046672726455213/posts/default/8601749959190789236?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/8523046672726455213/posts/default/8601749959190789236?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/MailinatorBlog/~3/WNjXESQkX0w/introducing-alternate-inbox-names.html" title="Introducing: Alternate Inbox Names" /><author><name>Paul Tyma</name><uri>http://www.blogger.com/profile/11412172362500455307</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="10507225897651170435" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">63</thr:total><feedburner:origLink>http://mailinator.blogspot.com/2008/03/introducing-alternate-inbox-names.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DUQHR3o9eSp7ImA9WxZXFko.&quot;"><id>tag:blogger.com,1999:blog-8523046672726455213.post-5811608553357229263</id><published>2008-03-04T16:14:00.001-08:00</published><updated>2008-03-04T16:35:36.461-08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2008-03-04T16:35:36.461-08:00</app:edited><title>Fun Mailinator server stats</title><content type="html">&lt;span style="font-family: courier new;"&gt;All averages have some fuzziness in them. Max numbers were observed but are unlikely the actual max.&lt;br /&gt;&lt;br /&gt;100% custom SMTP Server written in Java using blocking I/O, multiple (at times thousands) of threads, and liberal use of non-blocking data structures.&lt;br /&gt;------------------------------------------------------------&lt;br /&gt;&lt;br /&gt;Average daily incoming emails:              6.5 million&lt;br /&gt;Average daily incoming bandwidth:           18.4G&lt;br /&gt;Average # of threads running at any time:   ~450&lt;br /&gt;load average: (uptime cmd)                  0.04, 0.05, 0.00&lt;br /&gt;&lt;br /&gt;Average email size:                         2194 bytes&lt;br /&gt;Ram devoted to email storage (compressed):  400M-500M&lt;br /&gt;Average number of stored messages:          218,675&lt;br /&gt;Average number of active inboxes:           94.575&lt;br /&gt;Average memory allocated to Java VM:        880M&lt;br /&gt;&lt;br /&gt;M&lt;/span&gt;&lt;span style="font-family: courier new;"&gt;ax observed emails in one hour:            1,000,085&lt;br /&gt;Max observed emails in one second:           1,274&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8523046672726455213-5811608553357229263?l=mailinator.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/MailinatorBlog/~4/GbgPqGtOWUU" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://mailinator.blogspot.com/feeds/5811608553357229263/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=8523046672726455213&amp;postID=5811608553357229263" title="1 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/8523046672726455213/posts/default/5811608553357229263?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/8523046672726455213/posts/default/5811608553357229263?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/MailinatorBlog/~3/GbgPqGtOWUU/fun-mailinator-server-stats.html" title="Fun Mailinator server stats" /><author><name>Paul Tyma</name><uri>http://www.blogger.com/profile/11412172362500455307</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="10507225897651170435" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">1</thr:total><feedburner:origLink>http://mailinator.blogspot.com/2008/03/fun-mailinator-server-stats.html</feedburner:origLink></entry><entry gd:etag="W/&quot;Dk4NQHw_cCp7ImA9WxZQE0o.&quot;"><id>tag:blogger.com,1999:blog-8523046672726455213.post-5348138759440584588</id><published>2008-02-18T14:39:00.000-08:00</published><updated>2008-02-18T14:49:51.248-08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2008-02-18T14:49:51.248-08:00</app:edited><title>Kill the myth please. NIO is *not* faster than IO</title><content type="html">I'm giving 3 talks at the Software Developer's Conference West in Santa Clara, CA on March 3-7.&lt;br /&gt;&lt;br /&gt;One of them is a tutorial on how to interview in Silicon Valley (fun stuff).&lt;br /&gt;&lt;br /&gt;Another is how to write high-performance servers in Java. Specifically, why NIO is really not the best way anymore (post linux 2.6 kernel and NPTL) and multithreaded I/O is the new old-way of doing things. Its a fun talk and largely discusses the internals of Mailinator and how it runs a few thousand simultaneous threads without breaking a sweat.&lt;br /&gt;&lt;br /&gt;On top of that, as it turns out, in pure throughput, IO smokes NIO in all tests I tried. And I'm not alone - Rahul Bhargava of Rascal Systems did a very nice analysis of this and posted it, sadly, in some forums at theserverside.com.&lt;br /&gt;&lt;br /&gt;The post is solid gold and I'm posting it below just for posterity as I'd hate to see those forums come down some day and I lose access to that post. Incidentally, I disagree with Rahul that "fewer threads are easier to debug". It only takes 2 to make a deadlock or race condition. &lt;br /&gt;&lt;br /&gt;The original URL for this post is:&lt;br /&gt;&lt;span style="font-size:78%;"&gt;http://www.theserverside.com/discussions/thread.tss?thread_id=26700&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;And like I said, it was written by Rahul Bhargava of Rascal Systems. Here it is:&lt;br /&gt;&lt;br /&gt;-------------------------------------------------&lt;br /&gt;&lt;br /&gt;I have been benchmarking Java NIO with various JDKs on Linux. Server is&lt;br /&gt;running on a 2 CPU 1.7 GHz, 1GB RAM, Ultra160 SCSI 36GB disk&lt;br /&gt;&lt;br /&gt;With Linux kernel 2.6.5 (Gentoo) I had NPTL turned on and support for&lt;br /&gt;epoll compiled in. The server application was designed to support&lt;br /&gt;multiple disptach models :&lt;br /&gt;&lt;br /&gt;1. Reactor with Iterative Disptach with multiple selector threads. Essentially&lt;br /&gt;the accepted connections were load-balanced between varying number of&lt;br /&gt;selector threads. The benchmark then applied a step function to experimentally&lt;br /&gt;determine the optimal # of threads and connection per selector ratio.&lt;br /&gt;&lt;br /&gt;2. Also a simple concurrent blocking disptach model was supported. This is&lt;br /&gt;essentially a reader thread per connection model.&lt;br /&gt;&lt;br /&gt;Client application opens concurrent persistent connections to the server&lt;br /&gt;and starts blasting messages. Server just reads the messages and does&lt;br /&gt;basic un-marshalling to ensure message is ok.&lt;br /&gt;&lt;br /&gt;Results were interesting:&lt;br /&gt;&lt;br /&gt;1. With NPTL on, Sun and Blackwidow JVM 1.4.2 scaled easily to 5000+ threads. Blocking&lt;br /&gt;model was consistently 25-35% faster than using NIO selectors. Lot of techniques suggested&lt;br /&gt;by EmberIO folks were employed - using multiple selectors, doing multiple (2) reads if the first&lt;br /&gt;read returned EAGAIN equivalent in Java. Yet we couldn't beat the plain thread per connection model&lt;br /&gt;with Linux NPTL.&lt;br /&gt;&lt;br /&gt;2. To work around not so performant/scalable poll() implementation on Linux's we tried using&lt;br /&gt;epoll with Blackwidow JVM on a 2.6.5 kernel. While epoll improved the over scalability, the&lt;br /&gt;performance still remained 25% below the vanilla thread per connection model. With epoll&lt;br /&gt;we needed lot fewer threads to get to the best performance mark that we could get out of NIO.&lt;br /&gt;&lt;br /&gt;Here are some numbers:&lt;br /&gt;&lt;br /&gt;(cc = Concurrent Persistent Connections, bs = Is blocking server mode on Flag,&lt;br /&gt;st = Number of server threads, ct = Connections handled per thread,&lt;br /&gt;thruput = thruput of the server )&lt;br /&gt;&lt;br /&gt;cc, bs,st,ct, thruput&lt;br /&gt;1700,N,2,850,1379&lt;br /&gt;1700,N,4,425,1214&lt;br /&gt;1700,N,8,212,1240&lt;br /&gt;1700,N,16,106,1140&lt;br /&gt;1700,N,32,53,1260&lt;br /&gt;1700,N,64,26,1115&lt;br /&gt;1700,N,128,13,886&lt;br /&gt;1700,N,256,6,618&lt;br /&gt;1700,N,512,3,184&lt;br /&gt;1700,Y,1700,1,1737&lt;br /&gt;&lt;br /&gt;As you can see the last line indicates vanilla blocking server (thread per connection)&lt;br /&gt;produced the best thruput even with 1700 threads active in the JVM.&lt;br /&gt;&lt;br /&gt;With epoll, the best run was with 2 threads each handling around 850 connections in&lt;br /&gt;their selector set. But the thruput is below the blocking server thruput by 25%!&lt;br /&gt;&lt;br /&gt;Results shows that the cost of NIO selectors coupled with OS polling mechanism (in&lt;br /&gt;this case efficient epoll VS selector/poll) has a significant overhead compared to&lt;br /&gt;the cost of context switching 1700 threads on an NPTL Linux kernel.&lt;br /&gt;&lt;br /&gt;Without NPTL of course it's a different story. The blocking server just melts at 400 concurrent&lt;br /&gt;connections! We have run the test upto 10K connections and the blocking server outperformed&lt;br /&gt;NIO driven selector based server by same margin. Moral of the story - NIO arrives at the scene&lt;br /&gt;a little too late - with adequate RAM and better threading models (NPTL), performance gains&lt;br /&gt;of NIO don't show up.&lt;br /&gt;&lt;br /&gt;Sun's JVM doesn't support epoll() so we couldn't use epoll with it. Normal poll() based&lt;br /&gt;selector from Sun didn't perform as well. We needed to reduce the number of connections&lt;br /&gt;per thread to a small number (~ 6-10) to get comprabale numbers to epoll based selector.&lt;br /&gt;That meant running lot more selector threads kind of defeats the purpose of multiplexed IO.&lt;br /&gt;The benchmarks also dispell the myth created by Matt Welsh et al (SEDA) that a single&lt;br /&gt;threaded reactor can keep up with the network. On a 100Mbps ethernet that was true: network&lt;br /&gt;got saturated prior to server CPUs but with &gt; 1Gbps network, we needed multiple selectors&lt;br /&gt;to saturate the network. One single selector's performance was abysmal (5-6x slower than&lt;br /&gt;concurrent connections)&lt;br /&gt;&lt;br /&gt;For application that want to have fewer number of threads for debuggability etc, NIO may be&lt;br /&gt;the way to go. The 25-35% performance hit may be acceptable to many apps. Fewer threads&lt;br /&gt;also means easier debugging, it's a pain to attach a profiler or a debugger to a server hosting&lt;br /&gt;1000+ threads :-) . Bottom line with better MT support in kernels (Linux already with NPTL), one&lt;br /&gt;needs to re-consider the thread per connection model&lt;br /&gt;&lt;br /&gt;Rahul Bhargava&lt;br /&gt;CTO, Rascal Systems&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8523046672726455213-5348138759440584588?l=mailinator.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/MailinatorBlog/~4/jWcpwGyt_fM" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://mailinator.blogspot.com/feeds/5348138759440584588/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=8523046672726455213&amp;postID=5348138759440584588" title="5 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/8523046672726455213/posts/default/5348138759440584588?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/8523046672726455213/posts/default/5348138759440584588?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/MailinatorBlog/~3/jWcpwGyt_fM/kill-myth-please-nio-is-not-faster-than.html" title="Kill the myth please. NIO is *not* faster than IO" /><author><name>Paul Tyma</name><uri>http://www.blogger.com/profile/11412172362500455307</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="10507225897651170435" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">5</thr:total><feedburner:origLink>http://mailinator.blogspot.com/2008/02/kill-myth-please-nio-is-not-faster-than.html</feedburner:origLink></entry><entry gd:etag="W/&quot;C0EGR3c9cCp7ImA9WxZRFE8.&quot;"><id>tag:blogger.com,1999:blog-8523046672726455213.post-107507736225734255</id><published>2008-02-07T13:01:00.000-08:00</published><updated>2008-02-07T14:00:26.968-08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2008-02-07T14:00:26.968-08:00</app:edited><title>Mailinator allows 831375028249471605232943589 trillion different email addresses. Please choose a good one.</title><content type="html">Thats just an approximation really (allowing for 36 possible characters (there's more really) and email names of up to 25 characters).&lt;br /&gt;&lt;br /&gt;Regardless, there's a lot of possibilities.  So just a friendly reminder - please use Mailinator !!!  But choose an offbeat name.                &lt;br /&gt;There's plenty to choose from :)&lt;br /&gt;&lt;br /&gt;&lt;i&gt;Update: math error, number was too low  &lt;/i&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8523046672726455213-107507736225734255?l=mailinator.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/MailinatorBlog/~4/Oj37Ni9NwbI" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://mailinator.blogspot.com/feeds/107507736225734255/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=8523046672726455213&amp;postID=107507736225734255" title="2 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/8523046672726455213/posts/default/107507736225734255?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/8523046672726455213/posts/default/107507736225734255?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/MailinatorBlog/~3/Oj37Ni9NwbI/mailinator-allows-230937507847075445898.html" title="Mailinator allows 831375028249471605232943589 trillion different email addresses. Please choose a good one." /><author><name>Paul Tyma</name><uri>http://www.blogger.com/profile/11412172362500455307</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="10507225897651170435" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">2</thr:total><feedburner:origLink>http://mailinator.blogspot.com/2008/02/mailinator-allows-230937507847075445898.html</feedburner:origLink></entry><entry gd:etag="W/&quot;D04GSX04eSp7ImA9WxZSGEQ.&quot;"><id>tag:blogger.com,1999:blog-8523046672726455213.post-8989667076420941871</id><published>2008-02-01T11:34:00.000-08:00</published><updated>2008-02-01T11:58:48.331-08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2008-02-01T11:58:48.331-08:00</app:edited><title>More on the "pen1s" post</title><content type="html">In my post about searching &lt;a href=http://mailinator.blogspot.com/2008/01/how-to-search-for-word-pen1s-in-185.html&gt;185 mailinator emails per second in Mailinator&lt;/a&gt;,  I think I failed to adequately explain the goal of it. Its intent was to  document a thought process - it was not intended nor tried to be a taxonomy of search algorithms (I gave some very nice links if you're looking for that). I really don't think the world needs another taxonomy of string searching algorithms, or at least not one written by me.. Nor does it need another academic analysis of any existing algorithms - there are plenty of those out there (and I linked Wikipedia in that post too where appropriate to describe specific algorithms).&lt;br /&gt;&lt;br /&gt;Over a long history of reading about algorithms, I realized that I rarely found many analysis of algorithms from an engineer viewpoint. I am a recovering academician, but engineering is where you get to tinker with things. I've read many times Boyer-moore's best case is O(n/m) - but whats the *real* case? The usual case? How can that influence me in using any of these algorithms? Many searching algorithms display their worst case when you search for stuff like "AAAA" and your search string is "AAAABAAAABAAAAAB" - well guess what, I don't often search for that kind of thing in practice.&lt;br /&gt;&lt;br /&gt;Also many people don't truly understand Big O notation (my great aunt made incredible homemade donuts, but ask her about algorithmic analysis? not so much). Considering some examples in the concrete, especially realistic cases can provide insight. For example, tell your favorite non-algorithmic person that there is an algorithm called "bubble sort", and it sorts numbers for you. But in order to sort 100 numbers, it has to look at &lt;span style="font-weight:bold;"&gt;each&lt;/span&gt; of those numbers on the order of 100 times. Effectively it must do on the order of 10,000 comparisons to sort 100 numbers - they'd look at you like you're crazy.&lt;br /&gt;&lt;br /&gt;That post (and future ones in the series if i write them) attempts to detail an evolutionary engineering thought process on designing an algorithm for a specific purpose. The article started with the canonical "naive" but undeniably correct solution. When considering any problem, correctness is in my opinion, an excellent place to start.&lt;br /&gt;&lt;br /&gt;I did not "forgot" to mention any other searching algorithms. They simply didn't not yet arise in this thought process (several people mentioned Aho-Corasick, which I didnt mention by name but certainly alluded to its features when I mentioned the finite state machines of regular expressions). A Trie is a basis for AC, but its definitely not AC (which others seemed confused about).&lt;br /&gt;&lt;br /&gt;As I said, we're by far mostly interested in the "usual case" running time (which future installments will empirically demonstrate). I was also pretty clear in the last installment that what I had presented so far was *not* was I was using in Mailinator. Some people seemed to miss that (they people seem so excited to comment, they must have not actually read much of the post). I'm not sure how far this thread of blog posts will go - again, I'm documenting my thinking. &lt;br /&gt;&lt;br /&gt;And very importantly, I was also clear (and trying to be clearer) that I am in some sense over-engineering this problem. I know that - that is basically a goal here. I likely don't need the performance I ultimately will end up with. This is not science - its fun.&lt;br /&gt;&lt;br /&gt;So to concisely re-state the purpose of the blog entry - I'm documenting the thought process that coincided with evolving needs for an over-engineered multi-term string searching algorithm. Thought processes almost by nature go down wrong avenues - which isn't bad, its educational. The interesting parameters are such that we have a hundred or so words (expecting that to grow) and rarely find any of them. Engineering analysis is limited as compared to academic analysis in that you give specific cases and values - you are really only able to look at one instance of a big problem. But again, that all I'm trying to do here.&lt;br /&gt;&lt;br /&gt;Thus, If you're looking for a in-depth explanation of Boyer-Moore (which some people who didn't read the sentence in the last post where I said I wasn't providing that) seemed to want, or you want a nice taxonomy of effective string searching algorithms, then you should probably go read something like that. Because this.. wasn't that.&lt;br /&gt;&lt;br /&gt;As other interesting facts, I chose 185 emails/second because it was a relatively representative rate for Mailinator. I truly don't know Mailinator's max rate - I've seen 1200 emails/second and I've seen 10 emails/second. The number 185 was chosen as representative, not as the only possibility.&lt;br /&gt;&lt;br /&gt;Finally, as I said, I'm aware of algorithms such as Rabin-Karp, Aho-Corasick, and Wu-Manber (in fact, I see Udi most days at work). From a storytelling standpoint, it wouldn't be much of a tale if I didn't get an interesting result in the end. Aho-Corasick is linear on the search space and Wu-Manber is nicely sub-linear. Not to give it away, but Mailinator's algorithm is also sub-linear. It isn't Wu-Manber and all truth be told, Wu-Manber is notably better in memory use and worst case running time.&lt;br /&gt;&lt;br /&gt;If you're asking then why should you use such a thing? I'm not advocating you should. Again, the idea here isn't so much the final algorithm (which is really just the punchline). Its really way more about how we get there.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8523046672726455213-8989667076420941871?l=mailinator.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/MailinatorBlog/~4/acmfNug_qRo" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://mailinator.blogspot.com/feeds/8989667076420941871/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=8523046672726455213&amp;postID=8989667076420941871" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/8523046672726455213/posts/default/8989667076420941871?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/8523046672726455213/posts/default/8989667076420941871?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/MailinatorBlog/~3/acmfNug_qRo/more-on-pen1s-post.html" title="More on the &quot;pen1s&quot; post" /><author><name>Paul Tyma</name><uri>http://www.blogger.com/profile/11412172362500455307</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="10507225897651170435" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><feedburner:origLink>http://mailinator.blogspot.com/2008/02/more-on-pen1s-post.html</feedburner:origLink></entry></feed>
