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

<channel>
	<title>chris' random ramblings &#187; Technology</title>
	<atom:link href="http://atlee.ca/blog/category/technology/feed/" rel="self" type="application/rss+xml" />
	<link>http://atlee.ca/blog</link>
	<description>programming, photography, media, and anything else that strikes my fancy</description>
	<lastBuildDate>Sun, 29 Apr 2012 22:06:21 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.2</generator>
		<item>
		<title>Stuff I learned this weekend &#8211; vim, python and more!</title>
		<link>http://atlee.ca/blog/2012/04/29/stuff-i-learned-this-weekend/</link>
		<comments>http://atlee.ca/blog/2012/04/29/stuff-i-learned-this-weekend/#comments</comments>
		<pubDate>Sun, 29 Apr 2012 22:06:21 +0000</pubDate>
		<dc:creator>chris</dc:creator>
				<category><![CDATA[Mozilla]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[Tips]]></category>

		<guid isPermaLink="false">http://atlee.ca/blog/?p=1089</guid>
		<description><![CDATA[Call me strange, but I actually enjoy spending time reading up on programming tools that I use regularly. I think of programming tools as tools in same way that a hammer or a saw is a tool. They both help you to get a job done. You need to learn how to use them properly. [...]]]></description>
			<content:encoded><![CDATA[<p>Call me strange, but I actually enjoy spending time reading up on programming tools that I use regularly. I think of programming tools as tools in same way that a hammer or a saw is a tool. They both help you to get a job done. You need to learn how to use them properly. You need to keep tools well maintained. Sometimes you need to throw a tool away and get a new one.</p>
<p>For my professional and personal programming I spend 99% of my time writing <a href="http://python.org">python</a> with <a href="http://vim.org">vim</a>, and so I really enjoy learning more about them.</p>
<p>Stuff I learned about vim:</p>
<p><a href="http://nvie.com/posts/how-i-boosted-my-vim/">How I boosted my vim</a> &#8211; lots of great vim tips (how did I not know about :set visualbell until now???) and plugins, which introduced me to&#8230;</p>
<p><a href="https://github.com/scrooloose/nerdtree">nerdtree</a> &#8211; for file browsing in vim. It also reminded me to make use of the <a href="https://wincent.com/products/command-t">command-t plugin</a> I had installed a while back.</p>
<p><a href="https://github.com/tpope/vim-surround">surround</a> &#8211; for giving you the ability to work with the surroundings for text objects. Ever wanted to easily add quotes to a word, or change double quotes surrounding a string to single quotes? I know you have &#8211; so go install this plugin now!</p>
<p><a href="http://www.vim.org/scripts/script.php?script_id=2540">snipmate</a> &#8211; lets you define lots of predefined snippets for various languages. Now in python I can type &#8220;def&lt;tab&gt;&#8221; and bam! I get a basic function definition.</p>
<p>I wasn&#8217;t able to get to PyCon US 2012 this year, so I&#8217;m very happy that the sessions were <a href="http://pyvideo.org/category/17/pycon-us-2012">all recorderd.</a></p>
<p><a href="http://pyvideo.org/video/879/the-art-of-subclassing">The art of subclassing</a> &#8211; great tips on how to do subclassing well in python.</p>
<p><a href="http://pyvideo.org/video/880/stop-writing-classes">why classes aren&#8217;t always what you want</a> &#8211; I liked how he emphasized that you should be always be open to refactoring your code. Usually making your own exception classes is a bad idea&#8230;however one great nugget buried in there was if you can&#8217;t decide if you should raise a KeyError, AttributeError or TypeError (for example), make a class that inherits from all 3 and raise that. Then consumers can catch what makes sense to them instead of guessing.</p>
<p><a href="http://pyvideo.org/video/877/introduction-to-metaclasses">introduction to metaclasses</a> &#8211; metaclasses aren&#8217;t so scary after all!</p>
<p><a href="http://pyvideo.org/video/642/throwing-together-distributed-services-with-geven">nice framework for building gevent services</a> I liked the simple examples here. It introduces the <a href="https://github.com/progrium/ginkgo">ginkgo</a> framework, which I&#8217;m hoping to have some time to play with soon.</p>
]]></content:encoded>
			<wfw:commentRss>http://atlee.ca/blog/2012/04/29/stuff-i-learned-this-weekend/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Book review: PHP and MongoDB Web Development</title>
		<link>http://atlee.ca/blog/2012/03/09/php-and-mongodb-web-development-review/</link>
		<comments>http://atlee.ca/blog/2012/03/09/php-and-mongodb-web-development-review/#comments</comments>
		<pubDate>Fri, 09 Mar 2012 21:28:46 +0000</pubDate>
		<dc:creator>chris</dc:creator>
				<category><![CDATA[Books]]></category>
		<category><![CDATA[Technology]]></category>
		<category><![CDATA[mongodb]]></category>

		<guid isPermaLink="false">http://atlee.ca/blog/?p=1081</guid>
		<description><![CDATA[I&#8217;ve been interested in mongodb for quite some time now, so when a co-worker of mine asked if I was interested in reviewing a book about mongodb, I of course said yes! She put me in touch with the publisher of a book on MongoDB and web development entitled, &#8220;PHP and MongoDB Web Development&#8221;. I [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve been interested in <a href="http://www.mongodb.org/">mongodb</a> for quite some time now, so when a <a href="http://sheeri.com/">co-worker</a> of mine asked if I was interested in reviewing a book about mongodb, I of course said yes! She put me in touch with the publisher of a book on MongoDB and web development entitled, <a href="http://www.packtpub.com/php-and-mongodb-web-development-beginners-guide/book">&#8220;PHP and MongoDB Web Development&#8221;.</a> I was given a electronic copy of the book to review, and so here are my thoughts after spending a few weeks reading it and playing around with mongodb independently.</p>
<p>This book is subtitled &#8220;Beginner&#8217;s Guide&#8221;, and I think it achieves its goal of being a good introduction to mongodb for beginners. That being said, my primary criticism of the book is that it should include more information on some more advanced features like <a href="http://www.mongodb.org/display/DOCS/Sharding">sharding</a> and <a href="http://www.mongodb.org/display/DOCS/Replica+Sets">replica sets</a>. It&#8217;s easy to create web applications for small scales, or that don&#8217;t need to be up 99.99% of the time. It&#8217;s much harder to design applications that are robust to bursts in load, and to various kinds of network or hardware failures. Without much discussion on these points, it&#8217;s hard to form an opinion on whether mongodb would be a suitable choice for developing large scale web applications given the information in this book alone.</p>
<p>Other than that, I quite enjoyed the book and found it filled in quite a few gaps in my (limited) knowledge. Seeing full examples of working code on more complex topics like <a href="http://www.mongodb.org/display/DOCS/MapReduce">map reduce</a>, <a href="http://www.mongodb.org/display/DOCS/GridFS">GridFS</a> and <a href="http://www.mongodb.org/display/DOCS/Geospatial+Indexing">geospacial indexing</a> is very helpful to understanding how these features of mongodb could be used in a real application. I found the examples to be a bit verbose at times, although that&#8217;s more a fault of PHP than of the book I think, and the formatting in the examples was inconsistent at times. Fortunately all the examples can be downloaded from the publisher&#8217;s web site, <a href="http://www.packtpub.com/support">http://www.packtpub.com/support</a> saving you from having to type it all in!</p>
<p>The book also covers topics like integrating applications with traditional RDBMS like MySQL, and offers some practical examples of how mongodb could be used to augment an application which already is using SQL. It also includes helpful real world examples of how mongodb is used for web analytics, or by foursquare for 2d geospacial indexing.</p>
<p>In summary, the book is a good introduction to mongodb, especially if you&#8217;re familiar with php. If you&#8217;re looking for more in-depth information about optimizing your queries, or scaling mongodb, or if your language of choice isn&#8217;t php, this probably isn&#8217;t a good book for you.</p>
]]></content:encoded>
			<wfw:commentRss>http://atlee.ca/blog/2012/03/09/php-and-mongodb-web-development-review/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>How RelEng uses mercurial quickly and safely</title>
		<link>http://atlee.ca/blog/2012/01/27/hg-quick-and-safe/</link>
		<comments>http://atlee.ca/blog/2012/01/27/hg-quick-and-safe/#comments</comments>
		<pubDate>Fri, 27 Jan 2012 19:08:20 +0000</pubDate>
		<dc:creator>chris</dc:creator>
				<category><![CDATA[Mozilla]]></category>
		<category><![CDATA[Python]]></category>

		<guid isPermaLink="false">http://atlee.ca/blog/?p=1069</guid>
		<description><![CDATA[Release Engineering uses hg a lot. Every build or test involves code from at least one hg repository. Last year we started using some internal mirrors at the same time as making use of the hg share extension across the board, both of these had a big impact on the load on hg and time [...]]]></description>
			<content:encoded><![CDATA[<p>Release Engineering uses hg <strong>a lot</strong>. Every build or test involves code from at least one hg repository.</p>
<p><a href="http://atlee.ca/blog/2011/11/22/a-small-battle-won-in-the-war-on-build-times/">Last year</a> we started using some internal mirrors at the same time as making use of the hg share extension across the board, both of these had a big impact on the load on hg and time to clone/update local working copies.</p>
<p>I think what we&#8217;ve done is pretty useful and resilient to various types of failure, so I hope this blog post is helpful for others trying to automate processes involving hg!</p>
<p>The primary tool we&#8217;re using for hg operations is called <a href="http://hg.mozilla.org/build/tools/file/437cce872cb7/buildfarm/utils/hgtool.py">hgtool</a> (available from our <a href="http://hg.mozilla.org/build/tools">tools repo</a>). Yes, we&#8217;re very inventive at naming things.</p>
<p>hgtool&#8217;s basic usage is to be given the location of a remote repository, a local directory, and usually a revision. Its job is to make sure that the local directory contains a clean working copy of the repository at the specified revision.</p>
<p>First of all, you don&#8217;t need to worry about doing an &#8216;hg clone&#8217; if the directory doesn&#8217;t exist, or &#8216;hg pull&#8217; if it does exist. This simplifies a lot of build logic!</p>
<p>Next, we&#8217;ve build support for mirrors into hgtool. You can pass one or more mirror repositories to the tool with &#8216;&#8211;mirror&#8217;, and it will attempt to pull/clone from the mirrors before trying to pull/clone from the primary repository. At Mozilla we have several internal hg mirrors that we use to reduce load on the primary public-facing hg servers.</p>
<p>To improve the case when you need to do a full clone, we&#8217;ve added support for importing an hg bundle to initialize the local repository rather than doing a full clone from the mirror or master repositories. You can pass one or more bundle urls with &#8216;&#8211;bundle&#8217;. hgtool will download and import the bundle, and then pull in new changesets from the mirrors and master repositories.</p>
<p>Finally, hgtool supports the &#8216;hg share&#8217; extension. If you specify a base directory for shared repositories, all of the above operations will be run on a locally shared repository first, and then the working copy will be created with &#8216;hg share&#8217;, and updated to the correct revision.</p>
<p>There are all kinds of fallback behaviours specified, like if you fail to import a bundle, try to clone from a mirror; then if you fail to clone from a mirror, try to clone from the master. These fallbacks have resulted in a far more resilient build process.</p>
]]></content:encoded>
			<wfw:commentRss>http://atlee.ca/blog/2012/01/27/hg-quick-and-safe/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Investigating hg performance</title>
		<link>http://atlee.ca/blog/2011/12/09/hg-performance/</link>
		<comments>http://atlee.ca/blog/2011/12/09/hg-performance/#comments</comments>
		<pubDate>Fri, 09 Dec 2011 07:02:28 +0000</pubDate>
		<dc:creator>chris</dc:creator>
				<category><![CDATA[Linux]]></category>
		<category><![CDATA[Mozilla]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[Technology]]></category>
		<category><![CDATA[performance]]></category>

		<guid isPermaLink="false">http://atlee.ca/blog/?p=1035</guid>
		<description><![CDATA[(caveat lector: this is a long post with lots of shell snippets and output; it&#8217;s mostly a brain dump of what I did to investigate performance issues on hg.mozilla.org. I hope you find it useful. Scroll to the bottom for the summary.) Everybody knows that pushing to try can be slow. but why? while waiting [...]]]></description>
			<content:encoded><![CDATA[<p><em>(caveat lector: this is a long post with lots of shell snippets and output; it&#8217;s mostly a brain dump of what I did to investigate performance issues on hg.mozilla.org. I hope you find it useful. Scroll to the bottom for the summary.)</em></p>
<p><a href="https://bugzilla.mozilla.org/show_bug.cgi?id=656757">Everybody</a> <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=676420">knows</a> <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=554656">that</a> <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=708632">pushing</a> <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=688240">to</a> <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=695454">try</a> <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=696682">can</a> <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=672231">be</a> <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=633161">slow</a>. but why?</p>
<p>while waiting for my push to try to complete, I wondered what exactly was slow.</p>
<p>I started by cloning my own version of try:</p>
<pre>
$ hg clone http://hg.mozilla.org try
destination directory: try
requesting all changes
adding changesets
adding manifests
adding file changes
added 95917 changesets with 447521 changes to 89564 files (+2446 heads)
updating to branch default
53650 files updated, 0 files merged, 0 files removed, 0 files unresolved
</pre>
<p>Next I instrumented hg so I could get some profile information:</p>
<pre>
$ sudo vi /usr/local/bin/hg
python -m cProfile -o /tmp/hg.profile /usr/bin/hg $*
</pre>
<p>Then I timed out long it took me to check what would be pushed:</p>
<pre>
$ time hg out ssh://localhost//home/catlee/mozilla/try
hg out ssh://localhost//home/catlee/mozilla/try  0.57s user 0.04s system 54% cpu 1.114 total
</pre>
<p>That&#8217;s not too bad. Let&#8217;s check our profile:</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #dc143c;">pstats</span>
<span style="color: #dc143c;">pstats</span>.<span style="color: black;">Stats</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;/tmp/hg.profile&quot;</span><span style="color: black;">&#41;</span>.<span style="color: black;">strip_dirs</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>.<span style="color: black;">sort_stats</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'time'</span><span style="color: black;">&#41;</span>.<span style="color: black;">print_stats</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">10</span><span style="color: black;">&#41;</span>
Fri Dec  <span style="color: #ff4500;">9</span> 00:<span style="color: #ff4500;">25</span>:02 <span style="color: #ff4500;">2011</span>    /tmp/hg.<span style="color: #dc143c;">profile</span>
&nbsp;
         <span style="color: #ff4500;">38744</span> function calls <span style="color: black;">&#40;</span><span style="color: #ff4500;">37761</span> primitive calls<span style="color: black;">&#41;</span> <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #ff4500;">0.593</span> seconds
&nbsp;
   Ordered by: internal <span style="color: #dc143c;">time</span>
   List reduced <span style="color: #ff7700;font-weight:bold;">from</span> <span style="color: #ff4500;">476</span> to <span style="color: #ff4500;">10</span> due to restriction <span style="color: #66cc66;">&lt;</span><span style="color: #ff4500;">10</span><span style="color: #66cc66;">&gt;</span>
&nbsp;
   ncalls  tottime  percall  cumtime  percall filename:lineno<span style="color: black;">&#40;</span>function<span style="color: black;">&#41;</span>
       <span style="color: #ff4500;">13</span>    <span style="color: #ff4500;">0.462</span>    <span style="color: #ff4500;">0.036</span>    <span style="color: #ff4500;">0.462</span>    <span style="color: #ff4500;">0.036</span> <span style="color: black;">&#123;</span>method <span style="color: #483d8b;">'readline'</span> of <span style="color: #483d8b;">'file'</span> objects<span style="color: black;">&#125;</span>
        <span style="color: #ff4500;">1</span>    <span style="color: #ff4500;">0.039</span>    <span style="color: #ff4500;">0.039</span>    <span style="color: #ff4500;">0.039</span>    <span style="color: #ff4500;">0.039</span> <span style="color: black;">&#123;</span>mercurial.<span style="color: black;">parsers</span>.<span style="color: black;">parse_index2</span><span style="color: black;">&#125;</span>
       <span style="color: #ff4500;">40</span>    <span style="color: #ff4500;">0.031</span>    <span style="color: #ff4500;">0.001</span>    <span style="color: #ff4500;">0.031</span>    <span style="color: #ff4500;">0.001</span> revlog.<span style="color: black;">py</span>:<span style="color: #ff4500;">291</span><span style="color: black;">&#40;</span>rev<span style="color: black;">&#41;</span>
        <span style="color: #ff4500;">1</span>    <span style="color: #ff4500;">0.019</span>    <span style="color: #ff4500;">0.019</span>    <span style="color: #ff4500;">0.019</span>    <span style="color: #ff4500;">0.019</span> revlog.<span style="color: black;">py</span>:<span style="color: #ff4500;">622</span><span style="color: black;">&#40;</span>headrevs<span style="color: black;">&#41;</span>
   <span style="color: #ff4500;">177</span>/<span style="color: #ff4500;">70</span>    <span style="color: #ff4500;">0.009</span>    <span style="color: #ff4500;">0.000</span>    <span style="color: #ff4500;">0.019</span>    <span style="color: #ff4500;">0.000</span> <span style="color: black;">&#123;</span><span style="color: #008000;">__import__</span><span style="color: black;">&#125;</span>
     <span style="color: #ff4500;">6326</span>    <span style="color: #ff4500;">0.004</span>    <span style="color: #ff4500;">0.000</span>    <span style="color: #ff4500;">0.006</span>    <span style="color: #ff4500;">0.000</span> cmdutil.<span style="color: black;">py</span>:<span style="color: #ff4500;">15</span><span style="color: black;">&#40;</span>parsealiases<span style="color: black;">&#41;</span>
       <span style="color: #ff4500;">13</span>    <span style="color: #ff4500;">0.003</span>    <span style="color: #ff4500;">0.000</span>    <span style="color: #ff4500;">0.003</span>    <span style="color: #ff4500;">0.000</span> <span style="color: black;">&#123;</span>method <span style="color: #483d8b;">'read'</span> of <span style="color: #483d8b;">'file'</span> objects<span style="color: black;">&#125;</span>
       <span style="color: #ff4500;">93</span>    <span style="color: #ff4500;">0.002</span>    <span style="color: #ff4500;">0.000</span>    <span style="color: #ff4500;">0.008</span>    <span style="color: #ff4500;">0.000</span> cmdutil.<span style="color: black;">py</span>:<span style="color: #ff4500;">18</span><span style="color: black;">&#40;</span>findpossible<span style="color: black;">&#41;</span>
     <span style="color: #ff4500;">7212</span>    <span style="color: #ff4500;">0.001</span>    <span style="color: #ff4500;">0.000</span>    <span style="color: #ff4500;">0.001</span>    <span style="color: #ff4500;">0.000</span> <span style="color: black;">&#123;</span>method <span style="color: #483d8b;">'split'</span> of <span style="color: #483d8b;">'str'</span> objects<span style="color: black;">&#125;</span>
  <span style="color: #ff4500;">392</span>/<span style="color: #ff4500;">313</span>    <span style="color: #ff4500;">0.001</span>    <span style="color: #ff4500;">0.000</span>    <span style="color: #ff4500;">0.007</span>    <span style="color: #ff4500;">0.000</span> demandimport.<span style="color: black;">py</span>:<span style="color: #ff4500;">92</span><span style="color: black;">&#40;</span>_demandimport<span style="color: black;">&#41;</span></pre></div></div>

<p>The top item is readline() on file objects? I wonder if that&#8217;s socket operations. I&#8217;m ssh&#8217;ing to localhost, so it&#8217;s really fast. Let&#8217;s add 100ms latency:</p>
<pre>
$ sudo tc qdisc add dev lo root handle 1:0 netem delay 100ms
$ time hg out ssh://localhost//home/catlee/mozilla/try
hg out ssh://localhost//home/catlee/mozilla/try  0.58s user 0.05s system 14% cpu 4.339 total
</pre>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #dc143c;">pstats</span>
<span style="color: #dc143c;">pstats</span>.<span style="color: black;">Stats</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;/tmp/hg.profile&quot;</span><span style="color: black;">&#41;</span>.<span style="color: black;">strip_dirs</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>.<span style="color: black;">sort_stats</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'time'</span><span style="color: black;">&#41;</span>.<span style="color: black;">print_stats</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">10</span><span style="color: black;">&#41;</span>
Fri Dec  <span style="color: #ff4500;">9</span> 00:<span style="color: #ff4500;">42</span>:09 <span style="color: #ff4500;">2011</span>    /tmp/hg.<span style="color: #dc143c;">profile</span>
&nbsp;
         <span style="color: #ff4500;">38744</span> function calls <span style="color: black;">&#40;</span><span style="color: #ff4500;">37761</span> primitive calls<span style="color: black;">&#41;</span> <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #ff4500;">2.728</span> seconds
&nbsp;
   Ordered by: internal <span style="color: #dc143c;">time</span>
   List reduced <span style="color: #ff7700;font-weight:bold;">from</span> <span style="color: #ff4500;">476</span> to <span style="color: #ff4500;">10</span> due to restriction <span style="color: #66cc66;">&lt;</span><span style="color: #ff4500;">10</span><span style="color: #66cc66;">&gt;</span>
&nbsp;
   ncalls  tottime  percall  cumtime  percall filename:lineno<span style="color: black;">&#40;</span>function<span style="color: black;">&#41;</span>
       <span style="color: #ff4500;">13</span>    <span style="color: #ff4500;">2.583</span>    <span style="color: #ff4500;">0.199</span>    <span style="color: #ff4500;">2.583</span>    <span style="color: #ff4500;">0.199</span> <span style="color: black;">&#123;</span>method <span style="color: #483d8b;">'readline'</span> of <span style="color: #483d8b;">'file'</span> objects<span style="color: black;">&#125;</span>
        <span style="color: #ff4500;">1</span>    <span style="color: #ff4500;">0.054</span>    <span style="color: #ff4500;">0.054</span>    <span style="color: #ff4500;">0.054</span>    <span style="color: #ff4500;">0.054</span> <span style="color: black;">&#123;</span>mercurial.<span style="color: black;">parsers</span>.<span style="color: black;">parse_index2</span><span style="color: black;">&#125;</span>
       <span style="color: #ff4500;">40</span>    <span style="color: #ff4500;">0.028</span>    <span style="color: #ff4500;">0.001</span>    <span style="color: #ff4500;">0.028</span>    <span style="color: #ff4500;">0.001</span> revlog.<span style="color: black;">py</span>:<span style="color: #ff4500;">291</span><span style="color: black;">&#40;</span>rev<span style="color: black;">&#41;</span>
        <span style="color: #ff4500;">1</span>    <span style="color: #ff4500;">0.019</span>    <span style="color: #ff4500;">0.019</span>    <span style="color: #ff4500;">0.019</span>    <span style="color: #ff4500;">0.019</span> revlog.<span style="color: black;">py</span>:<span style="color: #ff4500;">622</span><span style="color: black;">&#40;</span>headrevs<span style="color: black;">&#41;</span>
   <span style="color: #ff4500;">177</span>/<span style="color: #ff4500;">70</span>    <span style="color: #ff4500;">0.010</span>    <span style="color: #ff4500;">0.000</span>    <span style="color: #ff4500;">0.019</span>    <span style="color: #ff4500;">0.000</span> <span style="color: black;">&#123;</span><span style="color: #008000;">__import__</span><span style="color: black;">&#125;</span>
       <span style="color: #ff4500;">13</span>    <span style="color: #ff4500;">0.006</span>    <span style="color: #ff4500;">0.000</span>    <span style="color: #ff4500;">0.006</span>    <span style="color: #ff4500;">0.000</span> <span style="color: black;">&#123;</span>method <span style="color: #483d8b;">'read'</span> of <span style="color: #483d8b;">'file'</span> objects<span style="color: black;">&#125;</span>
     <span style="color: #ff4500;">6326</span>    <span style="color: #ff4500;">0.002</span>    <span style="color: #ff4500;">0.000</span>    <span style="color: #ff4500;">0.004</span>    <span style="color: #ff4500;">0.000</span> cmdutil.<span style="color: black;">py</span>:<span style="color: #ff4500;">15</span><span style="color: black;">&#40;</span>parsealiases<span style="color: black;">&#41;</span>
       <span style="color: #ff4500;">93</span>    <span style="color: #ff4500;">0.002</span>    <span style="color: #ff4500;">0.000</span>    <span style="color: #ff4500;">0.006</span>    <span style="color: #ff4500;">0.000</span> cmdutil.<span style="color: black;">py</span>:<span style="color: #ff4500;">18</span><span style="color: black;">&#40;</span>findpossible<span style="color: black;">&#41;</span>
  <span style="color: #ff4500;">392</span>/<span style="color: #ff4500;">313</span>    <span style="color: #ff4500;">0.002</span>    <span style="color: #ff4500;">0.000</span>    <span style="color: #ff4500;">0.008</span>    <span style="color: #ff4500;">0.000</span> demandimport.<span style="color: black;">py</span>:<span style="color: #ff4500;">92</span><span style="color: black;">&#40;</span>_demandimport<span style="color: black;">&#41;</span>
     <span style="color: #ff4500;">7212</span>    <span style="color: #ff4500;">0.001</span>    <span style="color: #ff4500;">0.000</span>    <span style="color: #ff4500;">0.001</span>    <span style="color: #ff4500;">0.000</span> <span style="color: black;">&#123;</span>method <span style="color: #483d8b;">'split'</span> of <span style="color: #483d8b;">'str'</span> objects<span style="color: black;">&#125;</span></pre></div></div>

<p>Yep, definitely getting worse with more latency on the network connection.</p>
<p>Oh, and I&#8217;m using a recent version of hg:</p>
<pre>
$ hg --version
Mercurial Distributed SCM (version 2.0)

$ echo hello | ssh localhost hg -R /home/catlee/mozilla/try serve --stdio
145
capabilities: lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch stream unbundle=HG10GZ,HG10BZ,HG10UN httpheader=1024
</pre>
<p>This doesn&#8217;t match what hg.mozilla.org is running:</p>
<pre>
$ echo hello | ssh hg.mozilla.org hg -R /mozilla-central serve --stdio
67
capabilities: unbundle lookup changegroupsubset branchmap stream=1
</pre>
<p>So it must be using an older version. Let&#8217;s see what mercurial 1.6 does:</p>
<pre>
$ mkvirtualenv hg16
New python executable in hg16/bin/python
Installing setuptools...

(hg16)$ pip install mercurial==1.6
Downloading/unpacking mercurial==1.6
  Downloading mercurial-1.6.tar.gz (2.2Mb): 2.2Mb downloaded
...

(hg16)$ hg --version
Mercurial Distributed SCM (version 1.6)

(hg16)$ echo hello | ssh localhost /home/catlee/.virtualenvs/hg16/bin/hg -R /home/catlee/mozilla/mozilla-central serve --stdio
75
capabilities: unbundle lookup changegroupsubset branchmap pushkey stream=1
</pre>
<p>That looks pretty close to what hg.mozilla.org claims it supports, so let&#8217;s time &#8216;hg out&#8217; again:</p>
<pre>
(hg16)$ time hg out ssh://localhost//home/catlee/mozilla/try
hg out ssh://localhost//home/catlee/mozilla/try  0.73s user 0.04s system 3% cpu 24.278 total
</pre>
<h1>tl;dr</h1>
<p>Finding missing changesets between two local repositories is <strong>6x slower with hg 1.6</strong> (4 seconds with hg 2.0 to 24 seconds hg 1.6). Add a few hundred people and machines hitting the same repository at the same time, and I imagine things can get bad pretty quickly.</p>
<p>Some further searching reveals that mercurial does support a <a href="http://mercurial.selenic.com/wiki/WireProtocol">faster</a> method of finding missing changesets in &#8220;newer&#8221; versions, although I can&#8217;t figure out exactly when this change was introduced.  There&#8217;s already a <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=623505">bug on file</a> for upgrading mercurial on hg.mozilla.org, so hopefully that improves the situation for pushes to try.</p>
<p>The tools we use everyday aren&#8217;t magical; they&#8217;re subject to normal debugging and profiling techniques. If a tool you&#8217;re using is holding you back, find out why!</p>
]]></content:encoded>
			<wfw:commentRss>http://atlee.ca/blog/2011/12/09/hg-performance/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Christmas tree preparations with an Arduino</title>
		<link>http://atlee.ca/blog/2011/11/27/christmas-tree-preparations-with-an-arduino/</link>
		<comments>http://atlee.ca/blog/2011/11/27/christmas-tree-preparations-with-an-arduino/#comments</comments>
		<pubDate>Sun, 27 Nov 2011 23:26:18 +0000</pubDate>
		<dc:creator>chris</dc:creator>
				<category><![CDATA[Technology]]></category>
		<category><![CDATA[arduino]]></category>
		<category><![CDATA[christmas]]></category>

		<guid isPermaLink="false">http://atlee.ca/blog/?p=1015</guid>
		<description><![CDATA[We usually get a real Christmas tree if we&#8217;re going to be in town for Christmas. A real tree needs watering though, which is something we&#8217;ve been less than&#8230;consistent with over the past years. I decided to do something about this and build something to alert me when the water level gets too low. Two [...]]]></description>
			<content:encoded><![CDATA[<p>We usually get a real Christmas tree if we&#8217;re going to be in town for Christmas. A real tree needs watering though, which is something we&#8217;ve been less than&#8230;consistent with over the past years.</p>
<p>I decided to do something about this and build something to alert me when the water level gets too low. Two strips of aluminum foil taped to either side of a piece of plastic provide my water sensor. One strip is connected to an analog input on the arduino, and the other strip is connected to +3.3V. When the sensor is submerged I get a reading of around 300 &#8220;units&#8221; from the ADC. When it&#8217;s removed from the water, a 10k pulldown resistor brings the reading down to 0.</p>
<p>I&#8217;ve hooked up a tri-colour LED to indicate various states, and plan to have an audible alert as well.</p>
<p>I&#8217;m not sure if the aluminum will end up corroding, nor if I&#8217;ll be able to power this off batteries for any length of time. Still, I&#8217;m pretty pleased with it so far!</p>
<p><video controls="controls" src='http://atlee.ca/blog/wp-content/uploads/xmas1.webm' width="852" height="480" >Initial tests</video></p>
<p>Here you can see that LED is green when the sensor is submerged, and changes colours (like a traffic light, as per Thomas&#8217; request) when the sensor is removed.</p>
]]></content:encoded>
			<wfw:commentRss>http://atlee.ca/blog/2011/11/27/christmas-tree-preparations-with-an-arduino/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
<enclosure url="http://atlee.ca/blog/wp-content/uploads/xmas1.webm" length="1526745" type="video/webm" />
		</item>
		<item>
		<title>cURL and paste</title>
		<link>http://atlee.ca/blog/2011/08/16/curl-and-paste/</link>
		<comments>http://atlee.ca/blog/2011/08/16/curl-and-paste/#comments</comments>
		<pubDate>Wed, 17 Aug 2011 04:17:31 +0000</pubDate>
		<dc:creator>chris</dc:creator>
				<category><![CDATA[Python]]></category>
		<category><![CDATA[Tips]]></category>
		<category><![CDATA[performance]]></category>

		<guid isPermaLink="false">http://atlee.ca/blog/?p=975</guid>
		<description><![CDATA[cURL and paste&#8230;two great tastes that apparently don&#8217;t go well at all together! I&#8217;ve been writing a bunch of simple wsgi apps lately, some of which handle file uploads. Take this tiny application: import webob &#160; def app&#40;environ, start_response&#41;: req = webob.Request&#40;environ&#41; req.body_file.read&#40;&#41; return webob.Response&#40;&#34;OK!&#34;&#41;&#40;environ, start_response&#41; &#160; import paste.httpserver paste.httpserver.serve&#40;app, port=8090&#41; Then throw some files [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://curl.haxx.se/" target="_blank">cURL</a> and <a href="http://pythonpaste.org/" target="_blank">paste</a>&#8230;two great tastes that apparently don&#8217;t go well at all together!</p>
<p>I&#8217;ve been writing a bunch of simple <a href="http://wsgi.org/wsgi/" target="_blank">wsgi</a> apps lately, some of which handle file uploads.</p>
<p>Take this tiny application:</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">import</span> webob
&nbsp;
<span style="color: #ff7700;font-weight:bold;">def</span> app<span style="color: black;">&#40;</span>environ, start_response<span style="color: black;">&#41;</span>:
    req = webob.<span style="color: black;">Request</span><span style="color: black;">&#40;</span>environ<span style="color: black;">&#41;</span>
    req.<span style="color: black;">body_file</span>.<span style="color: black;">read</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
    <span style="color: #ff7700;font-weight:bold;">return</span> webob.<span style="color: black;">Response</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;OK!&quot;</span><span style="color: black;">&#41;</span><span style="color: black;">&#40;</span>environ, start_response<span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">import</span> paste.<span style="color: black;">httpserver</span>
paste.<span style="color: black;">httpserver</span>.<span style="color: black;">serve</span><span style="color: black;">&#40;</span>app, port=<span style="color: #ff4500;">8090</span><span style="color: black;">&#41;</span></pre></div></div>

<p>Then throw some files at it with cURL:</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;"><span style="color: #7a0874; font-weight: bold;">&#91;</span>catlee<span style="color: #7a0874; font-weight: bold;">&#93;</span> <span style="color: #000000; font-weight: bold;">%</span> <span style="color: #000000; font-weight: bold;">for</span> f <span style="color: #000000; font-weight: bold;">in</span> $<span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #c20cb9; font-weight: bold;">find</span> <span style="color: #660033;">-type</span> f<span style="color: #7a0874; font-weight: bold;">&#41;</span>; <span style="color: #000000; font-weight: bold;">do</span> <span style="color: #000000; font-weight: bold;">time</span> curl <span style="color: #660033;">-s</span> <span style="color: #660033;">-o</span> <span style="color: #000000; font-weight: bold;">/</span>dev<span style="color: #000000; font-weight: bold;">/</span>null <span style="color: #660033;">--data-binary</span> <span style="color: #000000; font-weight: bold;">@</span><span style="color: #007800;">$f</span> http:<span style="color: #000000; font-weight: bold;">//</span>localhost:<span style="color: #000000;">8090</span>; <span style="color: #000000; font-weight: bold;">done</span>
curl <span style="color: #660033;">-s</span> <span style="color: #660033;">-o</span> <span style="color: #000000; font-weight: bold;">/</span>dev<span style="color: #000000; font-weight: bold;">/</span>null <span style="color: #660033;">--data-binary</span> <span style="color: #000000; font-weight: bold;">@</span><span style="color: #007800;">$f</span> http:<span style="color: #000000; font-weight: bold;">//</span>localhost:<span style="color: #000000;">8090</span>  0.00s user 0.00s system <span style="color: #000000;">0</span><span style="color: #000000; font-weight: bold;">%</span> cpu <span style="color: #000000;">1.013</span> total
curl <span style="color: #660033;">-s</span> <span style="color: #660033;">-o</span> <span style="color: #000000; font-weight: bold;">/</span>dev<span style="color: #000000; font-weight: bold;">/</span>null <span style="color: #660033;">--data-binary</span> <span style="color: #000000; font-weight: bold;">@</span><span style="color: #007800;">$f</span> http:<span style="color: #000000; font-weight: bold;">//</span>localhost:<span style="color: #000000;">8090</span>  0.01s user 0.00s system <span style="color: #000000;">63</span><span style="color: #000000; font-weight: bold;">%</span> cpu <span style="color: #000000;">0.013</span> total
curl <span style="color: #660033;">-s</span> <span style="color: #660033;">-o</span> <span style="color: #000000; font-weight: bold;">/</span>dev<span style="color: #000000; font-weight: bold;">/</span>null <span style="color: #660033;">--data-binary</span> <span style="color: #000000; font-weight: bold;">@</span><span style="color: #007800;">$f</span> http:<span style="color: #000000; font-weight: bold;">//</span>localhost:<span style="color: #000000;">8090</span>  0.01s user 0.00s system <span style="color: #000000;">64</span><span style="color: #000000; font-weight: bold;">%</span> cpu <span style="color: #000000;">0.012</span> total
curl <span style="color: #660033;">-s</span> <span style="color: #660033;">-o</span> <span style="color: #000000; font-weight: bold;">/</span>dev<span style="color: #000000; font-weight: bold;">/</span>null <span style="color: #660033;">--data-binary</span> <span style="color: #000000; font-weight: bold;">@</span><span style="color: #007800;">$f</span> http:<span style="color: #000000; font-weight: bold;">//</span>localhost:<span style="color: #000000;">8090</span>  0.01s user 0.00s system <span style="color: #000000;">81</span><span style="color: #000000; font-weight: bold;">%</span> cpu <span style="color: #000000;">0.015</span> total
curl <span style="color: #660033;">-s</span> <span style="color: #660033;">-o</span> <span style="color: #000000; font-weight: bold;">/</span>dev<span style="color: #000000; font-weight: bold;">/</span>null <span style="color: #660033;">--data-binary</span> <span style="color: #000000; font-weight: bold;">@</span><span style="color: #007800;">$f</span> http:<span style="color: #000000; font-weight: bold;">//</span>localhost:<span style="color: #000000;">8090</span>  0.01s user 0.00s system <span style="color: #000000;">0</span><span style="color: #000000; font-weight: bold;">%</span> cpu <span style="color: #000000;">1.014</span> total
curl <span style="color: #660033;">-s</span> <span style="color: #660033;">-o</span> <span style="color: #000000; font-weight: bold;">/</span>dev<span style="color: #000000; font-weight: bold;">/</span>null <span style="color: #660033;">--data-binary</span> <span style="color: #000000; font-weight: bold;">@</span><span style="color: #007800;">$f</span> http:<span style="color: #000000; font-weight: bold;">//</span>localhost:<span style="color: #000000;">8090</span>  0.00s user 0.00s system <span style="color: #000000;">0</span><span style="color: #000000; font-weight: bold;">%</span> cpu <span style="color: #000000;">1.009</span> total</pre></div></div>

<p>Huh? Some files take a second to upload?</p>
<p>I discovered after much digging, and rewriting my (more complicated) app several times, that the problem is that cURL sends an extra &#8220;Expect: 100-continue&#8221; header. This is supposed to let a web server respond with &#8220;100 Continue&#8221; immediately or reject an upload based on the request headers.</p>
<p>The problem is that paste&#8217;s httpserver doesn&#8217;t send this by default, and so cURL will wait for a second before giving up and sending the rest of the request.</p>
<p>The magic to turn this off is the &#8216;-0&#8242; to cURL, which forces HTTP/1.0 mode:</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;"><span style="color: #7a0874; font-weight: bold;">&#91;</span>catlee<span style="color: #7a0874; font-weight: bold;">&#93;</span> <span style="color: #000000; font-weight: bold;">%</span> <span style="color: #000000; font-weight: bold;">for</span> f <span style="color: #000000; font-weight: bold;">in</span> $<span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #c20cb9; font-weight: bold;">find</span> <span style="color: #660033;">-type</span> f<span style="color: #7a0874; font-weight: bold;">&#41;</span>; <span style="color: #000000; font-weight: bold;">do</span> <span style="color: #000000; font-weight: bold;">time</span> curl <span style="color: #660033;">-0</span> <span style="color: #660033;">-s</span> <span style="color: #660033;">-o</span> <span style="color: #000000; font-weight: bold;">/</span>dev<span style="color: #000000; font-weight: bold;">/</span>null <span style="color: #660033;">--data-binary</span> <span style="color: #000000; font-weight: bold;">@</span><span style="color: #007800;">$f</span> http:<span style="color: #000000; font-weight: bold;">//</span>localhost:<span style="color: #000000;">8090</span>; <span style="color: #000000; font-weight: bold;">done</span>
curl <span style="color: #660033;">-0</span> <span style="color: #660033;">-s</span> <span style="color: #660033;">-o</span> <span style="color: #000000; font-weight: bold;">/</span>dev<span style="color: #000000; font-weight: bold;">/</span>null <span style="color: #660033;">--data-binary</span> <span style="color: #000000; font-weight: bold;">@</span><span style="color: #007800;">$f</span> http:<span style="color: #000000; font-weight: bold;">//</span>localhost:<span style="color: #000000;">8090</span>  0.00s user 0.00s system <span style="color: #000000;">66</span><span style="color: #000000; font-weight: bold;">%</span> cpu <span style="color: #000000;">0.012</span> total
curl <span style="color: #660033;">-0</span> <span style="color: #660033;">-s</span> <span style="color: #660033;">-o</span> <span style="color: #000000; font-weight: bold;">/</span>dev<span style="color: #000000; font-weight: bold;">/</span>null <span style="color: #660033;">--data-binary</span> <span style="color: #000000; font-weight: bold;">@</span><span style="color: #007800;">$f</span> http:<span style="color: #000000; font-weight: bold;">//</span>localhost:<span style="color: #000000;">8090</span>  0.01s user 0.00s system <span style="color: #000000;">64</span><span style="color: #000000; font-weight: bold;">%</span> cpu <span style="color: #000000;">0.012</span> total
curl <span style="color: #660033;">-0</span> <span style="color: #660033;">-s</span> <span style="color: #660033;">-o</span> <span style="color: #000000; font-weight: bold;">/</span>dev<span style="color: #000000; font-weight: bold;">/</span>null <span style="color: #660033;">--data-binary</span> <span style="color: #000000; font-weight: bold;">@</span><span style="color: #007800;">$f</span> http:<span style="color: #000000; font-weight: bold;">//</span>localhost:<span style="color: #000000;">8090</span>  0.00s user 0.01s system <span style="color: #000000;">58</span><span style="color: #000000; font-weight: bold;">%</span> cpu <span style="color: #000000;">0.014</span> total
curl <span style="color: #660033;">-0</span> <span style="color: #660033;">-s</span> <span style="color: #660033;">-o</span> <span style="color: #000000; font-weight: bold;">/</span>dev<span style="color: #000000; font-weight: bold;">/</span>null <span style="color: #660033;">--data-binary</span> <span style="color: #000000; font-weight: bold;">@</span><span style="color: #007800;">$f</span> http:<span style="color: #000000; font-weight: bold;">//</span>localhost:<span style="color: #000000;">8090</span>  0.01s user 0.00s system <span style="color: #000000;">66</span><span style="color: #000000; font-weight: bold;">%</span> cpu <span style="color: #000000;">0.012</span> total
curl <span style="color: #660033;">-0</span> <span style="color: #660033;">-s</span> <span style="color: #660033;">-o</span> <span style="color: #000000; font-weight: bold;">/</span>dev<span style="color: #000000; font-weight: bold;">/</span>null <span style="color: #660033;">--data-binary</span> <span style="color: #000000; font-weight: bold;">@</span><span style="color: #007800;">$f</span> http:<span style="color: #000000; font-weight: bold;">//</span>localhost:<span style="color: #000000;">8090</span>  0.00s user 0.00s system <span style="color: #000000;">59</span><span style="color: #000000; font-weight: bold;">%</span> cpu <span style="color: #000000;">0.013</span> total
curl <span style="color: #660033;">-0</span> <span style="color: #660033;">-s</span> <span style="color: #660033;">-o</span> <span style="color: #000000; font-weight: bold;">/</span>dev<span style="color: #000000; font-weight: bold;">/</span>null <span style="color: #660033;">--data-binary</span> <span style="color: #000000; font-weight: bold;">@</span><span style="color: #007800;">$f</span> http:<span style="color: #000000; font-weight: bold;">//</span>localhost:<span style="color: #000000;">8090</span>  0.01s user 0.00s system <span style="color: #000000;">65</span><span style="color: #000000; font-weight: bold;">%</span> cpu <span style="color: #000000;">0.012</span> total</pre></div></div>

]]></content:encoded>
			<wfw:commentRss>http://atlee.ca/blog/2011/08/16/curl-and-paste/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>self-serve builds!</title>
		<link>http://atlee.ca/blog/2011/02/17/self-serve-builds/</link>
		<comments>http://atlee.ca/blog/2011/02/17/self-serve-builds/#comments</comments>
		<pubDate>Thu, 17 Feb 2011 23:14:26 +0000</pubDate>
		<dc:creator>chris</dc:creator>
				<category><![CDATA[Mozilla]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[Work]]></category>
		<category><![CDATA[buildbot]]></category>
		<category><![CDATA[firefox]]></category>
		<category><![CDATA[utilities]]></category>

		<guid isPermaLink="false">http://atlee.ca/blog/?p=816</guid>
		<description><![CDATA[Do you want to be able to cancel your own try server builds? Do you want to be able to re-trigger a failed nightly build before the RelEng sheriff wakes up? Do you want to be able to get additional test runs on your build? If you answered an enthusiastic YES to any or all [...]]]></description>
			<content:encoded><![CDATA[<p>Do you want to be able to cancel your own try server builds?</p>
<p>Do you want to be able to re-trigger a failed nightly build before the RelEng sheriff wakes up?</p>
<p>Do you want to be able to get additional test runs on your build?</p>
<p>If you answered an enthusiastic <strong>YES</strong> to any or all of these questions, then <a href="https://build.mozilla.org/buildapi/self-serve">self-serve</a> is for you.</p>
<p>self-serve was created to provide an API to allow developers to interact with our build infrastructure, with the goal being that others would then create tools against it. It&#8217;s still early days for this self-serve API, so just a few caveats:</p>
<ul>
<li><strong>This is very much pre-alpha</strong> and may cause your computer to explode, your keg to run dry, or may simply hang.</li>
<li>It&#8217;s slower than I want. I&#8217;ve spent a bit of time optimizing and caching, but I think it can be much better. Just look at shaver&#8217;s <a href="http://shaver.off.net/diary/2011/01/22/i-made-a-thing/">bugzilla search</a> to see what&#8217;s possible for speed. Part of the problem here is that it&#8217;s currently running on a VM that&#8217;s doing a few dozen other things. We&#8217;re working on getting faster hardware, but didn&#8217;t want to block this pre-alpha-rollout on that.</li>
<li>You need to log in with your LDAP credentials to work with it.</li>
<li>The HTML interface is teh suck. Good thing I&#8217;m not paid to be a front-end webdev! Really, the goal here wasn&#8217;t to create a fully functional web interface, but rather to provide a functional <em>programmatic</em> interface.</li>
<li>Changing build priorities may run afoul of <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=555664">bug 555664</a>&#8230;haven&#8217;t had a chance to test out exactly what happens right now if a high priority job gets merged with a lower priority one.</li>
</ul>
<p>That being said, I&#8217;m proud to be able to finally make this public. Documentation for the REST API is available as part of the web interface itself, and the code is available as part of the <a href="http://hg.mozilla.org/build/buildapi">buildapi</a> repository on hg.mozilla.org</p>
<p><a href="https://build.mozilla.org/buildapi/self-serve">https://build.mozilla.org/buildapi/self-serve</a></p>
<p>Please be gentle!</p>
<p>Any questions, problems or feedback can be left here, or filed in <a href="https://bugzilla.mozilla.org/enter_bug.cgi?product=mozilla.org&#038;component=Release Engineering">bugzilla.</a></p>
]]></content:encoded>
			<wfw:commentRss>http://atlee.ca/blog/2011/02/17/self-serve-builds/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Just who am I talking to? (verifying https connections with python)</title>
		<link>http://atlee.ca/blog/2011/02/10/verifying-https-python/</link>
		<comments>http://atlee.ca/blog/2011/02/10/verifying-https-python/#comments</comments>
		<pubDate>Thu, 10 Feb 2011 20:43:58 +0000</pubDate>
		<dc:creator>chris</dc:creator>
				<category><![CDATA[Mozilla]]></category>
		<category><![CDATA[Python]]></category>

		<guid isPermaLink="false">http://atlee.ca/blog/?p=918</guid>
		<description><![CDATA[Did you know that python&#8217;s urllib module supports connecting to web servers over HTTPS? It&#8217;s easy! import urllib data = urllib.urlopen&#40;&#34;https://www.google.com&#34;&#41;.read&#40;&#41; print data Did you also know that it provides absolutely zero guarantees that your &#8220;secure&#8221; data isn&#8217;t being observed by a man-in-the-middle? Run this: from paste import httpserver def app&#40;environ, start_response&#41;: start_response&#40;&#34;200 OK&#34;, &#91;&#93;&#41; [...]]]></description>
			<content:encoded><![CDATA[<p>Did you know that python&#8217;s urllib module supports connecting to web servers over HTTPS?  It&#8217;s easy!</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #dc143c;">urllib</span>
data = <span style="color: #dc143c;">urllib</span>.<span style="color: black;">urlopen</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;https://www.google.com&quot;</span><span style="color: black;">&#41;</span>.<span style="color: black;">read</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
<span style="color: #ff7700;font-weight:bold;">print</span> data</pre></div></div>

<p>Did you also know that it provides absolutely zero guarantees that your &#8220;secure&#8221; data isn&#8217;t being observed by a man-in-the-middle?</p>
<p>Run this:</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">from</span> paste <span style="color: #ff7700;font-weight:bold;">import</span> httpserver
<span style="color: #ff7700;font-weight:bold;">def</span> app<span style="color: black;">&#40;</span>environ, start_response<span style="color: black;">&#41;</span>:
    start_response<span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;200 OK&quot;</span>, <span style="color: black;">&#91;</span><span style="color: black;">&#93;</span><span style="color: black;">&#41;</span>
    <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: #483d8b;">&quot;Thanks for your secrets!&quot;</span>
&nbsp;
httpserver.<span style="color: black;">serve</span><span style="color: black;">&#40;</span>app, host=<span style="color: #483d8b;">'127.0.0.1'</span>, port=<span style="color: #483d8b;">'8080'</span>, ssl_pem=<span style="color: #483d8b;">'*'</span><span style="color: black;">&#41;</span></pre></div></div>

<p>This little web app will generate a random SSL certificate for you each time it&#8217;s run. A self-signed, completely untrustworthy certificate.</p>
<p>Now modify your first script to look at https://localhost:8080 instead. Or, for more fun, keep it pointing at google and mess with your IP routing to redirect google.com:443 to localhost:8080.</p>

<div class="wp_syntax"><div class="code"><pre class="sh" style="font-family:monospace;">iptables -t nat -A OUTPUT -d google.com -p tcp --dport 443 -j DNAT --to-destination 127.0.0.1:8080</pre></div></div>

<p>Run your script again, and see what it says.</p>
<p>Instead of the raw HTML of google.com, you now get &#8220;Thanks for your secrets!&#8221;. That&#8217;s right, python will happily accept without complaint or warning the random certificate generated this little python app pretending to be google.com.</p>
<p>Sometimes you want to know who you&#8217;re talking to, you know?</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #dc143c;">httplib</span>, <span style="color: #dc143c;">socket</span>, ssl, <span style="color: #dc143c;">urllib2</span>
<span style="color: #ff7700;font-weight:bold;">def</span> buildValidatingOpener<span style="color: black;">&#40;</span>ca_certs<span style="color: black;">&#41;</span>:
    <span style="color: #ff7700;font-weight:bold;">class</span> VerifiedHTTPSConnection<span style="color: black;">&#40;</span><span style="color: #dc143c;">httplib</span>.<span style="color: black;">HTTPSConnection</span><span style="color: black;">&#41;</span>:
        <span style="color: #ff7700;font-weight:bold;">def</span> connect<span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: black;">&#41;</span>:
            <span style="color: #808080; font-style: italic;"># overrides the version in httplib so that we do</span>
            <span style="color: #808080; font-style: italic;">#    certificate verification</span>
            sock = <span style="color: #dc143c;">socket</span>.<span style="color: black;">create_connection</span><span style="color: black;">&#40;</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span>.<span style="color: black;">host</span>, <span style="color: #008000;">self</span>.<span style="color: black;">port</span><span style="color: black;">&#41;</span>,
                                            <span style="color: #008000;">self</span>.<span style="color: black;">timeout</span><span style="color: black;">&#41;</span>
            <span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: #008000;">self</span>._tunnel_host:
                <span style="color: #008000;">self</span>.<span style="color: black;">sock</span> = sock
                <span style="color: #008000;">self</span>._tunnel<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
&nbsp;
            <span style="color: #808080; font-style: italic;"># wrap the socket using verification with the root</span>
            <span style="color: #808080; font-style: italic;">#    certs in trusted_root_certs</span>
            <span style="color: #008000;">self</span>.<span style="color: black;">sock</span> = ssl.<span style="color: black;">wrap_socket</span><span style="color: black;">&#40;</span>sock,
                                        <span style="color: #008000;">self</span>.<span style="color: black;">key_file</span>,
                                        <span style="color: #008000;">self</span>.<span style="color: black;">cert_file</span>,
                                        cert_reqs=ssl.<span style="color: black;">CERT_REQUIRED</span>,
                                        ca_certs=ca_certs,
                                        <span style="color: black;">&#41;</span>
&nbsp;
    <span style="color: #808080; font-style: italic;"># wraps https connections with ssl certificate verification</span>
    <span style="color: #ff7700;font-weight:bold;">class</span> VerifiedHTTPSHandler<span style="color: black;">&#40;</span><span style="color: #dc143c;">urllib2</span>.<span style="color: black;">HTTPSHandler</span><span style="color: black;">&#41;</span>:
        <span style="color: #ff7700;font-weight:bold;">def</span> <span style="color: #0000cd;">__init__</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, connection_class=VerifiedHTTPSConnection<span style="color: black;">&#41;</span>:
            <span style="color: #008000;">self</span>.<span style="color: black;">specialized_conn_class</span> = connection_class
            <span style="color: #dc143c;">urllib2</span>.<span style="color: black;">HTTPSHandler</span>.<span style="color: #0000cd;">__init__</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: black;">&#41;</span>
&nbsp;
        <span style="color: #ff7700;font-weight:bold;">def</span> https_open<span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, req<span style="color: black;">&#41;</span>:
            <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: #008000;">self</span>.<span style="color: black;">do_open</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span>.<span style="color: black;">specialized_conn_class</span>, req<span style="color: black;">&#41;</span>
&nbsp;
    https_handler = VerifiedHTTPSHandler<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
    url_opener = <span style="color: #dc143c;">urllib2</span>.<span style="color: black;">build_opener</span><span style="color: black;">&#40;</span>https_handler<span style="color: black;">&#41;</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">return</span> url_opener
&nbsp;
opener = buildValidatingOpener<span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;/usr/lib/ssl/certs/ca-certificates.crt&quot;</span><span style="color: black;">&#41;</span>
req = <span style="color: #dc143c;">urllib2</span>.<span style="color: black;">Request</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;https://www.google.com&quot;</span><span style="color: black;">&#41;</span>
<span style="color: #ff7700;font-weight:bold;">print</span> opener.<span style="color: #008000;">open</span><span style="color: black;">&#40;</span>req<span style="color: black;">&#41;</span>.<span style="color: black;">read</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span></pre></div></div>

<p>Using the this new validating url opener, we can make sure we&#8217;re talking to someone with a validly signed certificate. With our IP redirection in place, or pointing at localhost:8080 explicitly we get a certificate invalid error. We <em>still</em> don&#8217;t know for sure that it&#8217;s google (could be some other site with a valid ssl certificate), but maybe we&#8217;ll tackle that in a future post!</p>
]]></content:encoded>
			<wfw:commentRss>http://atlee.ca/blog/2011/02/10/verifying-https-python/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Faster try builds!</title>
		<link>http://atlee.ca/blog/2011/02/04/faster-try-builds/</link>
		<comments>http://atlee.ca/blog/2011/02/04/faster-try-builds/#comments</comments>
		<pubDate>Fri, 04 Feb 2011 22:55:41 +0000</pubDate>
		<dc:creator>chris</dc:creator>
				<category><![CDATA[Mozilla]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[Work]]></category>
		<category><![CDATA[buildbot]]></category>
		<category><![CDATA[performance]]></category>

		<guid isPermaLink="false">http://atlee.ca/blog/?p=868</guid>
		<description><![CDATA[When we run a try build, we wipe out the build directory between each job; we want to make sure that every user&#8217;s build has a fresh environment to build in. Unfortunately this means that we also wipe out the clone of the try repo, and so we have to re-clone try every time. On [...]]]></description>
			<content:encoded><![CDATA[<p>When we run a try build, we wipe out the build directory between each job; we want to make sure that every user&#8217;s build has a fresh environment to build in.</p>
<p>Unfortunately this means that we also wipe out the clone of the try repo, and so we have to re-clone try every time.</p>
<p>On Linux and OSX we were spending an average of 30 minutes to re-clone try, and on Windows 40 minutes.  The majority of that is simply &#8216;hg clone&#8217; time, but a good portion is due to locks: we need to limit how many simultaneous build slaves are cloning from try at once, otherwise the hg server blows up.</p>
<p>Way back in September, Steve Fink <a href="http://groups.google.com/group/mozilla.dev.builds/msg/e2ec789a9011cf3a">suggested using hg&#8217;s share extension</a> to make cloning faster.</p>
<p>Then in November, <a href="http://blog.mozilla.com/bhearsum/">Ben Hearsum</a> <a href="http://groups.google.com/group/mozilla.dev.tree-management/browse_thread/thread/1a984d8bd828e9e7/0f0382923aa9ecc6">landed some changes</a> that paved the way to actually turning this on.</p>
<p>Today we&#8217;ve enabled the share extension for Linux (both 32 and 64-bit) and OSX 10.6 builds on try. Windows and OSX 10.5 are coming too, we need to <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=605292">upgrade hg on the build machines first</a>.</p>
<p>Average times for the &#8216;clone&#8217; step are down to <strong>less than 5 minutes</strong> now.</p>
<p>This means you get your builds <strong>25 minutes faster!</strong>  It also means we&#8217;re not hammering the try repo so badly, and so hopefully won&#8217;t have to reset it for a long long time.</p>
<p>We&#8217;re planning on rolling this out across the board, so nightly builds get faster, release builds get faster, clobber builds get faster, etc&#8230;</p>
<p>Enjoy!</p>
]]></content:encoded>
			<wfw:commentRss>http://atlee.ca/blog/2011/02/04/faster-try-builds/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>3 days of fun: a journey into the bowels of buildbot</title>
		<link>http://atlee.ca/blog/2010/10/29/3-days-of-fun-a-journey-into-the-bowels-of-buildbot/</link>
		<comments>http://atlee.ca/blog/2010/10/29/3-days-of-fun-a-journey-into-the-bowels-of-buildbot/#comments</comments>
		<pubDate>Fri, 29 Oct 2010 15:00:40 +0000</pubDate>
		<dc:creator>chris</dc:creator>
				<category><![CDATA[Mozilla]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[buildbot]]></category>

		<guid isPermaLink="false">http://atlee.ca/blog/?p=780</guid>
		<description><![CDATA[I&#8217;ve just spent 3 days trying to debug some new code in buildbot. The code in question is to implement a change to how we do nightly builds such that they use the same revision for all platforms. I was hitting a KeyError exception inside buildbot&#8217;s util.loop code, specifically at a line where it is [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve just spent 3 days trying to debug some new code in buildbot.</p>
<p>The code in question is to implement a change to how we do nightly builds such that they <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=570814">use the same revision for all platforms.</a></p>
<p>I was hitting a KeyError exception <a href="http://hg.mozilla.org/build/buildbot/file/58225ba72678/master/buildbot/util/loop.py#l153">inside buildbot&#8217;s util.loop code</a>, specifically at a line where it is trying to delete a key from a dictionary.  In simple form, the loop is doing this:</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">for</span> k <span style="color: #ff7700;font-weight:bold;">in</span> d.<span style="color: black;">keys</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>:
    <span style="color: #ff7700;font-weight:bold;">if</span> condition:
        <span style="color: #ff7700;font-weight:bold;">del</span> d<span style="color: black;">&#91;</span>k<span style="color: black;">&#93;</span> <span style="color: #808080; font-style: italic;"># Raises KeyError....sometimes...</span></pre></div></div>

<p>Tricky bit was, it didn&#8217;t happen every time.  I&#8217;d have to wait at least 3 minutes between attempts.</p>
<p>So I added a bunch of debugging code:</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">print</span> d
<span style="color: #ff7700;font-weight:bold;">print</span> d.<span style="color: black;">keys</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
<span style="color: #ff7700;font-weight:bold;">for</span> k <span style="color: #ff7700;font-weight:bold;">in</span> d.<span style="color: black;">keys</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>:
    <span style="color: #ff7700;font-weight:bold;">print</span> k
    <span style="color: #ff7700;font-weight:bold;">if</span> condition:
        <span style="color: #ff7700;font-weight:bold;">try</span>:
            <span style="color: #ff7700;font-weight:bold;">del</span> d<span style="color: black;">&#91;</span>k<span style="color: black;">&#93;</span> <span style="color: #808080; font-style: italic;"># Raises KeyError....sometimes...</span>
        <span style="color: #ff7700;font-weight:bold;">except</span> <span style="color: #008000;">KeyError</span>:
            <span style="color: #ff7700;font-weight:bold;">print</span> k <span style="color: #ff7700;font-weight:bold;">in</span> d <span style="color: #808080; font-style: italic;"># sanity check 1</span>
            <span style="color: #ff7700;font-weight:bold;">print</span> k <span style="color: #ff7700;font-weight:bold;">in</span> d.<span style="color: black;">keys</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span> <span style="color: #808080; font-style: italic;"># sanity check 2</span></pre></div></div>

<p>Can you guess what the results of sanity checks 1 and 2 were?</p>
<p><code>'k in d'</code> is <code>False</code>, but <code>'k in d.keys()'</code> is <code>True</code>.</p>
<p>whhhaaaaa?  Much head scratching and hair pulling ensued.  I tried many different variations of iterating through the loop, all with the same result.</p>
<p>In the end, I posted a question on <a href="http://stackoverflow.com/questions/4036114/how-can-k-in-d-be-false-but-k-in-d-keys-be-true">Stack Overflow</a>.</p>
<p>At the same time, <a href="http://code-bear.com/bearlog/category/mozilla/">Bear</a> and <a href="http://code.v.igoro.us/">Dustin</a> were zeroing in on a solution.  The crucial bit here is that the keys of d are (follow me here&#8230;) methods of instances of my new scheduler classes, which inherit from <code>buildbot.util.ComparableMixin</code>&#8230;which implements <code>__cmp__</code> and <code>__hash__</code>.  <code>__cmp__</code> is used in the <code>'k in d.keys()'</code> test, but <code>__hash__</code> is used in the <code>'k in d'</code> test.</p>
<p>Some further digging revealed that my scheduler was modifying state that <code>ComparableMixin.__hash__</code> was referring to, resulting in the scheduler instances not having stable hashes over time.</p>
<p>Meanwhile, on stackoverflow, <a href="http://stackoverflow.com/users/484688/adw">adw</a> came up with an <a href="http://stackoverflow.com/questions/4036114/how-can-k-in-d-be-false-but-k-in-d-keys-be-true/4036202#4036202">answer</a> that confirmed what Dustin and Bear were saying, and <a href="http://stackoverflow.com/users/398968/katrielalex">katrielalex</a> came up with a <a href="http://stackoverflow.com/questions/4036114/how-can-k-in-d-be-false-but-k-in-d-keys-be-true/4036314#4036314">simple example</a> to reproduce the problem.</p>
<p>In the end, the fix was simple, just a few extra lines of python code.  Too bad it took me 3 days to figure out!</p>
]]></content:encoded>
			<wfw:commentRss>http://atlee.ca/blog/2010/10/29/3-days-of-fun-a-journey-into-the-bowels-of-buildbot/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
	</channel>
</rss>

