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

<channel>
	<title>A mind less ordinary</title>
	<atom:link href="http://www.dmi.me.uk/blog/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.dmi.me.uk/blog</link>
	<description></description>
	<lastBuildDate>Thu, 01 Jul 2010 15:47:42 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0</generator>
<creativeCommons:license>http://creativecommons.org/licenses/by-nc-nd/3.0/</creativeCommons:license>
		<item>
		<title>Cloning a git-svn checkout</title>
		<link>http://www.dmi.me.uk/blog/2010/06/29/cloning-a-git-svn-checkout/</link>
		<comments>http://www.dmi.me.uk/blog/2010/06/29/cloning-a-git-svn-checkout/#comments</comments>
		<pubDate>Tue, 29 Jun 2010 14:57:22 +0000</pubDate>
		<dc:creator>Dave</dc:creator>
				<category><![CDATA[Hacks]]></category>
		<category><![CDATA[Tips and Tricks]]></category>
		<category><![CDATA[git]]></category>
		<category><![CDATA[hack]]></category>
		<category><![CDATA[tip]]></category>
		<category><![CDATA[trick]]></category>
		<category><![CDATA[useful]]></category>

		<guid isPermaLink="false">http://www.dmi.me.uk/blog/?p=231</guid>
		<description><![CDATA[<p>The scenario is that you have used git-svn to import an SVN repository, and you want to make use of the already-imported commits elsewhere. Unfortunately, git clone does not (currently) clone the git-svn information. It looks like we have to fully rebuild the git-svn repository, which would then mean pulling every commit from the Subversion server <a href="http://www.dmi.me.uk/blog/2010/06/29/cloning-a-git-svn-checkout/">[...]</a>]]></description>
			<content:encoded><![CDATA[<p>The scenario is that you have used <code class="codecolorer text default"><span class="text">git-svn</span></code> to import an SVN repository, and you want to make use of the already-imported commits elsewhere. Unfortunately, <code class="codecolorer text default"><span class="text">git clone</span></code> does not (currently) clone the <code class="codecolorer text default"><span class="text">git-svn</span></code> information. It looks like we have to fully rebuild the <code class="codecolorer text default"><span class="text">git-svn</span></code> repository, which would then mean pulling every commit from the Subversion server once again. What we&#8217;d really like to do is to make use of history we already have from <code class="codecolorer text default"><span class="text">git</span></code>.</p>
<h2>Quick start</h2>
<p>For those who just want the commands and don&#8217;t want to wait:</p>
<pre>
<div class="codecolorer-container bash twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="bash codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #c20cb9; font-weight: bold;">git</span> clone user<span style="color: #000000; font-weight: bold;">@</span>hostname.tld:<span style="color: #000000; font-weight: bold;">/</span>path<span style="color: #000000; font-weight: bold;">/</span>to<span style="color: #000000; font-weight: bold;">/</span>git-svn.git git-svn-clone<br />
<span style="color: #7a0874; font-weight: bold;">cd</span> git-svn-clone<br />
<span style="color: #c20cb9; font-weight: bold;">git</span> <span style="color: #c20cb9; font-weight: bold;">svn</span> init <span style="color: #660033;">-s</span> <span style="color: #c20cb9; font-weight: bold;">svn</span>:<span style="color: #000000; font-weight: bold;">//</span>hostname.tld<span style="color: #000000; font-weight: bold;">/</span>path<span style="color: #000000; font-weight: bold;">/</span>to<span style="color: #000000; font-weight: bold;">/</span><span style="color: #c20cb9; font-weight: bold;">svn</span><br />
<span style="color: #c20cb9; font-weight: bold;">git</span> config svn.authorsfile $<span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #c20cb9; font-weight: bold;">basename</span> $<span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #7a0874; font-weight: bold;">pwd</span><span style="color: #7a0874; font-weight: bold;">&#41;</span><span style="color: #7a0874; font-weight: bold;">&#41;</span><span style="color: #000000; font-weight: bold;">/</span>git-authors<br />
rsync <span style="color: #660033;">-avpP</span> user<span style="color: #000000; font-weight: bold;">@</span>hostname.tld:<span style="color: #000000; font-weight: bold;">/</span>path<span style="color: #000000; font-weight: bold;">/</span>to<span style="color: #000000; font-weight: bold;">/</span>git-svn.git<span style="color: #000000; font-weight: bold;">/</span><span style="color: #c20cb9; font-weight: bold;">svn</span> .git<span style="color: #000000; font-weight: bold;">/</span><br />
<span style="color: #c20cb9; font-weight: bold;">git</span> update-ref refs<span style="color: #000000; font-weight: bold;">/</span>remotes<span style="color: #000000; font-weight: bold;">/</span>trunk origin<span style="color: #000000; font-weight: bold;">/</span>master<br />
<span style="color: #c20cb9; font-weight: bold;">git</span> <span style="color: #c20cb9; font-weight: bold;">svn</span> fetch <span style="color: #660033;">--all</span> <span style="color: #000000; font-weight: bold;">&amp;&amp;</span> <span style="color: #c20cb9; font-weight: bold;">git</span> <span style="color: #c20cb9; font-weight: bold;">svn</span> rebase</div></div>
</pre>
<h2>Full details</h2>
<p>So,  what does all this do? Let&#8217;s look at it in stages.</p>
<ol>
<li>Clone the existing <code class="codecolorer text default"><span class="text">git-svn</span></code> repository, to get the history and avoid hitting the Subversion server any more than we need to (<code class="codecolorer text default"><span class="text">git clone</span></code>)</li>
<li>Set up the Subversion integration information (<code class="codecolorer text default"><span class="text">git svn init</span></code>)</li>
<li>Set up the translation between Subversion authors (bare username) and git authors (name + email address) (<code class="codecolorer text default"><span class="text">git config svn.authorsfile</span></code>)</li>
<li>Copy the Subversion branch metadata from the original <code class="codecolorer text default"><span class="text">git-svn</span></code> repository</li>
<li>Create the local &#8220;trunk&#8221; reference that <code class="codecolorer text default"><span class="text">git-svn</span></code> will require</li>
<li>Fetch any new revisions from Subversion (and update the revision map between git and Subversion), and then make sure that &#8220;master&#8221; points at the head of the Subversion trunk</li>
</ol>
<h2>Bonus tip</h2>
<p>If you have a number of git branches, it can be a pain to keep rebasing them to the latest trunk (as Subversion doesn&#8217;t like non-linear history). This little script may help:<br />
<script src="http://gist.github.com/460135.js"></script><br />
This will automatically rebase all of the branches onto <kbd>master</kbd>, although it won&#8217;t handle sub-branches very well.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.dmi.me.uk/blog/2010/06/29/cloning-a-git-svn-checkout/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	<creativeCommons:license>http://creativecommons.org/licenses/by-nc-nd/3.0/</creativeCommons:license>
	</item>
		<item>
		<title>Gracefully degrading jQuery edit-in-place</title>
		<link>http://www.dmi.me.uk/blog/2010/02/03/gracefully-degrading-jquery-edit-in-place/</link>
		<comments>http://www.dmi.me.uk/blog/2010/02/03/gracefully-degrading-jquery-edit-in-place/#comments</comments>
		<pubDate>Wed, 03 Feb 2010 22:34:49 +0000</pubDate>
		<dc:creator>Dave</dc:creator>
				<category><![CDATA[Coding]]></category>
		<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[jQuery]]></category>
		<category><![CDATA[code snippet]]></category>
		<category><![CDATA[plugin]]></category>

		<guid isPermaLink="false">http://www.dmi.me.uk/blog/?p=215</guid>
		<description><![CDATA[<p>I recently became curious about creating some edit-in-place controls: things that look like static text until you click them, and they magically become editable. It turns out that creating this sort of thing is almost trivial with jQuery, which is now my favourite JavaScript framework. I&#8217;m a big fan of functional-style programming, and jQuery plays right <a href="http://www.dmi.me.uk/blog/2010/02/03/gracefully-degrading-jquery-edit-in-place/">[...]</a>]]></description>
			<content:encoded><![CDATA[<p>I recently became curious about creating some edit-in-place controls: things that look like static text until you click them, and they magically become editable. It turns out that creating this sort of thing is almost trivial with <a title="jQuery home page" href="http://jquery.com/" target="_blank">jQuery</a>, which is now my favourite JavaScript framework. I&#8217;m a big fan of functional-style programming, and jQuery plays right into that.</p>
<p>It was still surprising that the bulk of what I wanted to do can be done in about 16 lines of code. That&#8217;s right: sixteen.</p>
<p>The plan was to create an edit-in-place system that would degrade nicely in browsers with JavaScript disabled. This isn&#8217;t necessarily as elegant as it could be and it doesn&#8217;t yet handle all input types, but that&#8217;s what version one is for! So without further ado, I present the code:</p>
<pre>
<div class="codecolorer-container javascript twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="javascript codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">$.<span style="color: #660066;">fn</span>.<span style="color: #660066;">in_place_edit</span> <span style="color: #339933;">=</span> <span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; <span style="color: #000066; font-weight: bold;">this</span>.<span style="color: #660066;">each</span><span style="color: #009900;">&#40;</span><span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; <span style="color: #003366; font-weight: bold;">var</span> $eip <span style="color: #339933;">=</span> $<span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'&lt;span&gt;&lt;/span&gt;'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #003366; font-weight: bold;">var</span> $el<span style="color: #339933;">=</span>$<span style="color: #009900;">&#40;</span><span style="color: #000066; font-weight: bold;">this</span><span style="color: #009900;">&#41;</span>.<span style="color: #660066;">hide</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>.<span style="color: #660066;">after</span><span style="color: #009900;">&#40;</span>$eip<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; $eip.<span style="color: #660066;">text</span><span style="color: #009900;">&#40;</span>$el.<span style="color: #660066;">val</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; $eip.<span style="color: #660066;">click</span><span style="color: #009900;">&#40;</span><span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span> $eip.<span style="color: #660066;">hide</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> $el.<span style="color: #660066;">data</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'origval'</span><span style="color: #339933;">,</span> $el.<span style="color: #660066;">val</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span>.<span style="color: #660066;">show</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>.<span style="color: #000066;">focus</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>.<span style="color: #660066;">select</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> <span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; $el.<span style="color: #000066;">blur</span><span style="color: #009900;">&#40;</span><span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #000066; font-weight: bold;">if</span><span style="color: #009900;">&#40;</span>$el.<span style="color: #000066; font-weight: bold;">is</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'select'</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> $el.<span style="color: #660066;">data</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'origval'</span><span style="color: #339933;">,</span> $el.<span style="color: #660066;">val</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; $eip.<span style="color: #660066;">text</span><span style="color: #009900;">&#40;</span>$el.<span style="color: #660066;">data</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'origval'</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span>.<span style="color: #660066;">show</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> $el.<span style="color: #660066;">hide</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>.<span style="color: #660066;">val</span><span style="color: #009900;">&#40;</span>$el.<span style="color: #660066;">data</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'origval'</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; $el.<span style="color: #660066;">keydown</span><span style="color: #009900;">&#40;</span><span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span>e<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #000066; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span>e.<span style="color: #660066;">which</span><span style="color: #339933;">==</span><span style="color: #CC0000;">27</span><span style="color: #009900;">&#41;</span> $el.<span style="color: #660066;">val</span><span style="color: #009900;">&#40;</span>$el.<span style="color: #660066;">data</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'origval'</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span>.<span style="color: #000066;">blur</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #000066; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span>e.<span style="color: #660066;">which</span><span style="color: #339933;">==</span><span style="color: #CC0000;">13</span><span style="color: #339933;">||</span>e.<span style="color: #660066;">which</span><span style="color: #339933;">==</span><span style="color: #CC0000;">9</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; e.<span style="color: #660066;">preventDefault</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; $el.<span style="color: #660066;">data</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'origval'</span><span style="color: #339933;">,</span> $el.<span style="color: #660066;">val</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span>.<span style="color: #000066;">blur</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; <span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<span style="color: #009900;">&#125;</span><span style="color: #339933;">;</span></div></div>
</pre>
<p>Usage:</p>
<pre>
<div class="codecolorer-container javascript twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="javascript codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">$<span style="color: #009900;">&#40;</span><span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span> $<span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'input, select'</span><span style="color: #009900;">&#41;</span>.<span style="color: #660066;">in_place_edit</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> <span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></div></div>
</pre>
<p>So, what does all this do? First of all, we create a new function on the main jQuery object, called <code class="codecolorer text default"><span class="text">in_place_edit</span></code>. This then iterates over elements matching the selector. It hides the input and creates a placeholder <code class="codecolorer html4strict default"><span class="html4strict"><span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">span</span>&gt;</span></span></code> element with the input&#8217;s value. Then we simply set up event handlers to deal with the placeholder being clicked, the input losing focus, and various keypresses (enter/tab to accept, esc to cancel). To see it in action, I&#8217;ve put together a rough-and-ready <a href="http://test.dmi.me.uk/in-place-test.html">demo</a>.</p>
<p>Planned future enhancements:</p>
<ul>
<li>Checkbox input types (display using the labels?)</li>
<li>Radio input types</li>
<li>File input types (if possible)</li>
<li>Textareas</li>
<li>Any other types&#8230;</li>
</ul>
<p>Maybe further updates later on!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.dmi.me.uk/blog/2010/02/03/gracefully-degrading-jquery-edit-in-place/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
	<creativeCommons:license>http://creativecommons.org/licenses/by-nc-nd/3.0/</creativeCommons:license>
	</item>
		<item>
		<title>Recovering from pvmove failure</title>
		<link>http://www.dmi.me.uk/blog/2010/01/07/recovering-from-pvmove-failure/</link>
		<comments>http://www.dmi.me.uk/blog/2010/01/07/recovering-from-pvmove-failure/#comments</comments>
		<pubDate>Thu, 07 Jan 2010 23:25:29 +0000</pubDate>
		<dc:creator>Dave</dc:creator>
				<category><![CDATA[Hacks]]></category>
		<category><![CDATA[Linux]]></category>
		<category><![CDATA[Personal]]></category>
		<category><![CDATA[Tips and Tricks]]></category>
		<category><![CDATA[backup]]></category>
		<category><![CDATA[emergency]]></category>
		<category><![CDATA[lvm]]></category>
		<category><![CDATA[lvm2]]></category>
		<category><![CDATA[restore]]></category>
		<category><![CDATA[tip]]></category>
		<category><![CDATA[trick]]></category>
		<category><![CDATA[tutorial]]></category>
		<category><![CDATA[useful]]></category>

		<guid isPermaLink="false">http://www.dmi.me.uk/blog/?p=203</guid>
		<description><![CDATA[
<p>Note: This is a fairly rambling explanation of recent events. I assume that you have at least a passing knowledge of LVM and its terminology. This was written to prove that it is possible to recover from pvmove failing (in certain cases) due to the way it performs its operations and backs up metadata.</p>
The background
<p>I recently <a href="http://www.dmi.me.uk/blog/2010/01/07/recovering-from-pvmove-failure/">[...]</a>]]></description>
			<content:encoded><![CDATA[
<p>Note: This is a fairly rambling explanation of recent events. I assume that you have at least a passing knowledge of <a title="LVM HOWTO (Chapter 3: Anatomy of LVM)" href="http://tldp.org/HOWTO/LVM-HOWTO/anatomy.html" target="_blank">LVM</a> and its terminology. This was written to prove that it is possible to recover from <code class="codecolorer text default"><span class="text">pvmove</span></code> failing (in certain cases) due to the way it performs its operations and backs up metadata.<span id="more-203"></span></p>
<h2>The background</h2>
<p>I recently received a new hard drive, and so I excitedly partitioned and formatted it, extended my <abbr title="Logical Volume Manager">LVM</abbr> <abbr title="Volume Groups">VGs</abbr> and merrily moved my <abbr title="logical volumes">LVs</abbr> completely across to the new drive using <code class="codecolorer text default"><span class="text">pvmove</span></code>. So far, so wonderful &#8212; I was now ready to rebuild my other two drives so that only critical things were covered by <abbr title="Redundant Array of Inexpensive Disks">RAID</abbr> and everything else was just in a large VG that spanned multiple drives. I now had three drives, all Samsung SpinPoint:</p>
<ol>
<li>500GB  (<code class="codecolorer text default"><span class="text">sdb</span></code>)</li>
<li>1TB (<code class="codecolorer text default"><span class="text">sda</span></code>)</li>
<li>1.5TB (<code class="codecolorer text default"><span class="text">sdc</span></code>, and brand-new)</li>
</ol>
<p>The partition setup I wanted:</p>
<ul>
<li>48MiB RAID-1 across all drives, for <code class="codecolorer text default"><span class="text">/boot</span></code> (already set up across <code class="codecolorer text default"><span class="text">sda</span></code> and <code class="codecolorer text default"><span class="text">sdb</span></code>)</li>
<li>4.8GiB RAID-1 across all drives, for <code class="codecolorer text default"><span class="text">/</span></code>(already set up across <code class="codecolorer text default"><span class="text">sda</span></code> and <code class="codecolorer text default"><span class="text">sdb</span></code>)</li>
<li>50GiB RAID-1 across all drives, for  <code class="codecolorer text default"><span class="text">/usr</span></code>, <code class="codecolorer text default"><span class="text">/opt</span></code>, <code class="codecolorer text default"><span class="text">/var</span></code></li>
<li>50GiB RAID-5 across all drives, for <code class="codecolorer text default"><span class="text">/home</span></code> (giving 100GiB usable space)</li>
<li>The rest of each drive divided into 50/100GiB partitions, to be spread among my large data VG, containing films, music, backups, and other large data.</li>
</ul>
<h2>The disaster</h2>
<p>I moved all of the existing LVs to the new drive, which had plenty of space. Next, I sorted out the partitions for the two older drives, and initialised the RAIDs for my <code class="codecolorer text default"><span class="text">sys</span></code> and <code class="codecolorer text default"><span class="text">safe</span></code> VGs:</p>
<div class="codecolorer-container bash twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="bash codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #666666; font-style: italic;"># set up RAID-1 across /dev/sda3, /dev/sdb3 and (later) /dev/sdc3</span><br />
mdadm <span style="color: #660033;">-C</span> <span style="color: #000000; font-weight: bold;">/</span>dev<span style="color: #000000; font-weight: bold;">/</span>md2 <span style="color: #660033;">-l1</span> <span style="color: #660033;">-n3</span> <span style="color: #000000; font-weight: bold;">/</span>dev<span style="color: #000000; font-weight: bold;">/</span>sda3 <span style="color: #000000; font-weight: bold;">/</span>dev<span style="color: #000000; font-weight: bold;">/</span>sdb3 missing<br />
<span style="color: #666666; font-style: italic;"># initialise the RAID for LVM</span><br />
pvcreate <span style="color: #000000; font-weight: bold;">/</span>dev<span style="color: #000000; font-weight: bold;">/</span>md2<br />
<span style="color: #666666; font-style: italic;"># set up RAID-5 across /dev/sda5, /dev/sdb5 and (later) /dev/sdb5</span><br />
mdadm <span style="color: #660033;">-C</span> <span style="color: #000000; font-weight: bold;">/</span>dev<span style="color: #000000; font-weight: bold;">/</span>md3 <span style="color: #660033;">-l5</span> <span style="color: #660033;">-n3</span> <span style="color: #000000; font-weight: bold;">/</span>dev<span style="color: #000000; font-weight: bold;">/</span>sda5 <span style="color: #000000; font-weight: bold;">/</span>dev<span style="color: #000000; font-weight: bold;">/</span>sdb5 missing<br />
pvcreate <span style="color: #000000; font-weight: bold;">/</span>dev<span style="color: #000000; font-weight: bold;">/</span>md3</div></div>
<p>I then expanded the VGs and started to copy data across. I began with the <code class="codecolorer text default"><span class="text">safe</span></code> VG that contained <code class="codecolorer text default"><span class="text">/home</span></code>, as I wanted to be sure it was indeed safe. I have all of the photos I&#8217;ve ever taken, my email backups and archives, and various private keys and other important data, as well as things that could be replaced due to duplication elsewhere (including working copies of most of my projects). Being LVM, I could move the LVs around without needing to unmount them or reboot into a LiveCD:</p>
<div class="codecolorer-container bash twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="bash codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #666666; font-style: italic;"># extend the volume groups</span><br />
vgextend sys <span style="color: #000000; font-weight: bold;">/</span>dev<span style="color: #000000; font-weight: bold;">/</span>md2<br />
vgextend safe <span style="color: #000000; font-weight: bold;">/</span>dev<span style="color: #000000; font-weight: bold;">/</span>md3<br />
<span style="color: #666666; font-style: italic;"># move all data from /dev/sdc2 to other volumes in the group</span><br />
pvmove <span style="color: #000000; font-weight: bold;">/</span>dev<span style="color: #000000; font-weight: bold;">/</span>sdc2<br />
<span style="color: #666666; font-style: italic;"># ... disaster struck before the second pvmove</span><br />
pvmove <span style="color: #000000; font-weight: bold;">/</span>dev<span style="color: #000000; font-weight: bold;">/</span>sdc1</div></div>
<p>Then, disaster struck:  <code class="codecolorer text default"><span class="text">pvmove</span></code> spat a set of I/O errors at me&#8230; but kept running! I wasn&#8217;t paying attention (as moving 40GiB of data takes quite a while) and so I had just left it to work away.</p>
<div class="codecolorer-container text twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">pvmove: dev_open(/dev/sda) called while suspended<br />
pvmove: dev_open(/dev/sda1) called while suspended<br />
pvmove: dev_open(/dev/sda2) called while suspended<br />
pvmove: dev_open(/dev/sda3) called while suspended<br />
pvmove: dev_open(/dev/sda5) called while suspended<br />
pvmove: dev_open(/dev/md2) called while suspended<br />
pvmove: dev_open(/dev/md3) called while suspended</div></div>
<p>It was only after it had completed and I started getting I/O and &#8220;permission denied&#8221; errors while trying to access my home directory that I first realised anything had gone wrong. After some <a title="Google: pvmove dev_open called while suspended recover" href="http://www.google.com/search?q=pvmove+dev_open+called+while+suspended+recover" target="_blank">frantic searching</a> on the Internet, it seemed that I had to wave goodbye to all of my personal data, including those bits that weren&#8217;t backed up (though I&#8217;ve learned my lesson about backups now!).</p>
<p>I was determined not to give in to data loss, and so I gave myself a few recovery options:</p>
<ol>
<li>Create an image of the partition where the data used to reside.</li>
<li>Try to recover pictures (the most critical thing for me) via <a title="Foremost on SourceForge" href="http://foremost.sourceforge.net/" target="_blank">foremost</a>, which is a non-destructive operation.</li>
<li>Try to rebuild the file system using <code class="codecolorer text default"><span class="text">reiserfsck --rebuild-tree</span></code>.</li>
</ol>
<p>During my investigations and poking around, I discovered that there was another option: I could try to rebuild the VG from an old copy of its metadata.</p>
<h2>Introduction to recovery</h2>
<p>It turns out that many LVM utilities store a backup of the VG&#8217;s metadata before and after performing various operations, so as long as your <code class="codecolorer text default"><span class="text">/etc/lvm</span></code> directory is fine, you have a fighting chance. (Actually, it is theoretically possible to retrieve old versions of the metadata from the LVM partition itself, but this gets much more complex and I won&#8217;t deal with it here.)</p>
<p>The reason for this is that <code class="codecolorer text default"><span class="text">pvmove</span></code> works by creating a temporary target LV, mirroring data from the existing LV to the temporary target (making checkpoints along the way), and only removing the original once the mirroring has completed. This operation can then be interrupted and resumed at any time without loss of data. This also has the advantage that a full copy of the data on the original LV is still available; only the metadata explaining where it begins and ends has changed.</p>
<p>To access the old versions of this metadata, investigate the contents of your <code class="codecolorer text default"><span class="text">/etc/lvm/archive</span></code> directory as root. You should find one or more files of the form <code class="codecolorer text default"><span class="text">volgroup_nnnnn.vg</span></code>, where <code class="codecolorer text default"><span class="text">volgroup</span></code> is the name of the relevant VG and <code class="codecolorer text default"><span class="text">nnnnn</span></code> is a number. These files contain a backup of the volume group&#8217;s metadata, such as which partitions it resides on and where it&#8217;s located. The contents may look something like this:</p>
<div class="codecolorer-container text twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;height:300px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"># Generated by LVM2 version 2.02.56(1) (2009-11-24): Mon Jan &nbsp;4 17:09:24 2010<br />
<br />
contents = &quot;Text Format Volume Group&quot;<br />
version = 1<br />
<br />
description = &quot;Created *before* executing 'vgextend safe /dev/md/3'&quot;<br />
<br />
creation_host = &quot;hostname&quot; &nbsp;# Linux hostname 2.6.31-gentoo-r3 #3 SMP Mon Nov 23 11:31:59 GMT 2009 i686<br />
creation_time = 1262624964 &nbsp;# Mon Jan &nbsp;4 17:09:24 2010<br />
<br />
safe {<br />
id = &quot;zbSAI8-ExUy-PxJw-SHX7-y9PL-AL2y-kiTk8g&quot;<br />
seqno = 10<br />
status = [&quot;RESIZEABLE&quot;, &quot;READ&quot;, &quot;WRITE&quot;]<br />
flags = []<br />
extent_size = 8192 &nbsp; &nbsp;# 4 Megabytes<br />
max_lv = 0<br />
max_pv = 0<br />
<br />
physical_volumes {<br />
<br />
pv0 {<br />
id = &quot;Vw3IF5-U92i-V2aL-9we1-A4E7-7j1P-4G142u&quot;<br />
device = &quot;/dev/sdc1&quot; &nbsp;# Hint only<br />
<br />
status = [&quot;ALLOCATABLE&quot;]<br />
flags = []<br />
dev_size = 199993122 &nbsp;# 95.3642 Gigabytes<br />
pe_start = 384<br />
pe_count = 24413 &nbsp;# 95.3633 Gigabytes<br />
}<br />
}<br />
<br />
logical_volumes {<br />
<br />
home {<br />
id = &quot;glU5zb-l9I7-SzGg-aXx5-lvgL-on4r-Faqkes&quot;<br />
status = [&quot;READ&quot;, &quot;WRITE&quot;, &quot;VISIBLE&quot;]<br />
flags = []<br />
segment_count = 1<br />
<br />
segment1 {<br />
start_extent = 0<br />
extent_count = 12799 &nbsp;# 49.9961 Gigabytes<br />
<br />
type = &quot;striped&quot;<br />
stripe_count = 1 &nbsp;# linear<br />
<br />
stripes = [<br />
&quot;pv0&quot;, 0<br />
]<br />
}<br />
}<br />
}<br />
}</div></div>
<p>I went through the backups for my <code class="codecolorer text default"><span class="text">safe</span></code> volume group, and found the one before I extended the volume group to the (now corrupt) <code class="codecolorer text default"><span class="text">/dev/md3</span></code>, which is actually the example given above.</p>
<h2>Recovering the volume group</h2>
<p>It was at this point that I rebooted and held my breath. I brought the system into runlevel 1 (single-user mode) and logged in as root. Out of curiosity I ran some SMART tests on the drives &#8212; <code class="codecolorer text default"><span class="text">sda</span></code> was reporting no partitions, and internal testing eventually reported a persistent read error at about 80% into the drive. It looked like that drive was toast, which would explain why writing to the RAID-5 had failed.</p>
<div class="codecolorer-container bash twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="bash codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">smartctl <span style="color: #660033;">-t</span> short <span style="color: #000000; font-weight: bold;">/</span>dev<span style="color: #000000; font-weight: bold;">/</span>sda<br />
<span style="color: #c20cb9; font-weight: bold;">sleep</span> <span style="color: #000000;">180</span><br />
smartctl <span style="color: #660033;">--all</span> <span style="color: #000000; font-weight: bold;">/</span>dev<span style="color: #000000; font-weight: bold;">/</span>sda</div></div>
<p>After verifying that it was a hardware issue, I decided to try to point the VG at its previous location (just <code class="codecolorer text default"><span class="text">/dev/sdc1</span></code>), thereby getting it to forget that the <code class="codecolorer text default"><span class="text">home</span></code> LV was on the now-inaccessible RAID-5. This could be accomplished by the magic of <code class="codecolorer text default"><span class="text">vgcfgrestore</span></code>:</p>
<div class="codecolorer-container bash twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="bash codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #666666; font-style: italic;"># restore the VG metadata for the &quot;safe&quot; VG from the given file</span><br />
vgcfgrestore <span style="color: #660033;">-f</span> <span style="color: #000000; font-weight: bold;">/</span>etc<span style="color: #000000; font-weight: bold;">/</span>lvm<span style="color: #000000; font-weight: bold;">/</span>archive<span style="color: #000000; font-weight: bold;">/</span>safe_00006.vg safe<br />
<span style="color: #666666; font-style: italic;"># re-scan for VGs, and &quot;safe&quot; should show up as inactive</span><br />
vgscan<br />
<span style="color: #666666; font-style: italic;"># activate the VG and any LVs inside</span><br />
vgchange <span style="color: #660033;">-ay</span> safe<br />
<span style="color: #666666; font-style: italic;"># re-scan for LVs and verify that safe/home exists</span><br />
lvscan<br />
<span style="color: #666666; font-style: italic;"># not taking any chances -- mount it read-only</span><br />
<span style="color: #c20cb9; font-weight: bold;">mount</span> <span style="color: #660033;">-o</span> ro <span style="color: #000000; font-weight: bold;">/</span>dev<span style="color: #000000; font-weight: bold;">/</span>safe<span style="color: #000000; font-weight: bold;">/</span>home <span style="color: #000000; font-weight: bold;">/</span>home</div></div>
<p>After the <code class="codecolorer text default"><span class="text">mount</span></code> succeeded, I began to copy all of the data to my large partition, where it should be safe. I also copied the major bits I didn&#8217;t want to lose to a USB flash drive as well, just to be certain. Once that was done, I took a deep breath and rebooted again, this time back to the full system.</p>
<h2>Clearing up afterwards</h2>
<p>Fortunately, everything worked fine &#8212; it was as if nothing had ever gone wrong! All that was left now was to rebuild the broken RAID section.</p>
<p>I decided for safety that I would re-initialise the <code class="codecolorer text default"><span class="text">safe</span></code> VG&#8217;s RAID as RAID-1 rather than RAID-5, so that any two of the drives could fail without losing my precious data:</p>
<div class="codecolorer-container bash twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="bash codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #666666; font-style: italic;"># stop the RAID array</span><br />
mdadm <span style="color: #660033;">-S</span> <span style="color: #000000; font-weight: bold;">/</span>dev<span style="color: #000000; font-weight: bold;">/</span>md3<br />
<span style="color: #666666; font-style: italic;"># remove the RAID descriptors from the partitions</span><br />
mdadm <span style="color: #660033;">--zero-superblock</span> <span style="color: #000000; font-weight: bold;">/</span>dev<span style="color: #000000; font-weight: bold;">/</span>sda5<br />
mdadm <span style="color: #660033;">--zero-superblock</span> <span style="color: #000000; font-weight: bold;">/</span>dev<span style="color: #000000; font-weight: bold;">/</span>sdb5<br />
<span style="color: #666666; font-style: italic;"># create as RAID-1</span><br />
mdadm <span style="color: #660033;">-C</span> <span style="color: #000000; font-weight: bold;">/</span>dev<span style="color: #000000; font-weight: bold;">/</span>md3 <span style="color: #660033;">-l1</span> <span style="color: #660033;">-n3</span> <span style="color: #000000; font-weight: bold;">/</span>dev<span style="color: #000000; font-weight: bold;">/</span>sda5 <span style="color: #000000; font-weight: bold;">/</span>dev<span style="color: #000000; font-weight: bold;">/</span>sdb5 missing</div></div>
<p>What I hadn&#8217;t anticipated was that this would rebuild the RAID-1 using the data from the previous RAID-5&#8230; including the LVM descriptors and corrupt content. Once the RAID was online, I ran <code class="codecolorer text default"><span class="text">pvscan</span></code> and received a warning that the VG metadata was inconsistent. For one heart-stopping moment, it also appeared that LVM thought my home partition was on the corrupt RAID! I quickly stopped the array and thought again.</p>
<p>After some further investigation, I discovered that the first 256 sectors of a partition are used by LVM to hold various information (including multiple copies of the VG metadata). All I had to do to fix this was to destroy that information:</p>
<div class="codecolorer-container bash twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="bash codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #666666; font-style: italic;"># ensure the array is stopped</span><br />
mdadm <span style="color: #660033;">-S</span> <span style="color: #000000; font-weight: bold;">/</span>dev<span style="color: #000000; font-weight: bold;">/</span>md3<br />
<span style="color: #666666; font-style: italic;"># zero the first 256 sectors</span><br />
<span style="color: #c20cb9; font-weight: bold;">dd</span> <span style="color: #007800;">if</span>=<span style="color: #000000; font-weight: bold;">/</span>dev<span style="color: #000000; font-weight: bold;">/</span>zero <span style="color: #007800;">of</span>=<span style="color: #000000; font-weight: bold;">/</span>dev<span style="color: #000000; font-weight: bold;">/</span>sda5 <span style="color: #007800;">bs</span>=<span style="color: #000000;">512</span> <span style="color: #007800;">count</span>=<span style="color: #000000;">256</span><br />
<span style="color: #c20cb9; font-weight: bold;">dd</span> <span style="color: #007800;">if</span>=<span style="color: #000000; font-weight: bold;">/</span>dev<span style="color: #000000; font-weight: bold;">/</span>zero <span style="color: #007800;">of</span>=<span style="color: #000000; font-weight: bold;">/</span>dev<span style="color: #000000; font-weight: bold;">/</span>sdb5 <span style="color: #007800;">bs</span>=<span style="color: #000000;">512</span> <span style="color: #007800;">count</span>=<span style="color: #000000;">256</span><br />
<span style="color: #666666; font-style: italic;"># recreate the array -- it may complain that they are already in an array</span><br />
mdadm <span style="color: #660033;">-C</span> <span style="color: #000000; font-weight: bold;">/</span>dev<span style="color: #000000; font-weight: bold;">/</span>md3 <span style="color: #660033;">-l1</span> <span style="color: #660033;">-n3</span> <span style="color: #000000; font-weight: bold;">/</span>dev<span style="color: #000000; font-weight: bold;">/</span>sda5 <span style="color: #000000; font-weight: bold;">/</span>dev<span style="color: #000000; font-weight: bold;">/</span>sdb5 missing</div></div>
<p>Once this was done, I could run <code class="codecolorer text default"><span class="text">pvcreate /dev/md3</span></code> and proceed to extend the VG and <code class="codecolorer text default"><span class="text">pvmove</span></code> data as before, without worrying that <code class="codecolorer text default"><span class="text">sda</span></code> would give out on me and cause everything to fail again.</p>
<p>I hope this helps someone!</p>
<div id="_mcePaste" style="position: absolute; left: -10000px; top: 3427px; width: 1px; height: 1px; overflow-x: hidden; overflow-y: hidden;">mdadm -C /dev/md3 -l1 -n3 /dev/sda5 /dev/sdb5 missing</div>
]]></content:encoded>
			<wfw:commentRss>http://www.dmi.me.uk/blog/2010/01/07/recovering-from-pvmove-failure/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
	<creativeCommons:license>http://creativecommons.org/licenses/by-nc-nd/3.0/</creativeCommons:license>
	</item>
		<item>
		<title>Hearing aid direct audio input</title>
		<link>http://www.dmi.me.uk/blog/2009/11/16/hearing-aid-dai/</link>
		<comments>http://www.dmi.me.uk/blog/2009/11/16/hearing-aid-dai/#comments</comments>
		<pubDate>Mon, 16 Nov 2009 22:59:16 +0000</pubDate>
		<dc:creator>Dave</dc:creator>
				<category><![CDATA[Hacks]]></category>
		<category><![CDATA[Life]]></category>
		<category><![CDATA[Tips and Tricks]]></category>
		<category><![CDATA[dai]]></category>
		<category><![CDATA[direct audio input]]></category>
		<category><![CDATA[europlug]]></category>
		<category><![CDATA[hearing aid]]></category>
		<category><![CDATA[pinout]]></category>

		<guid isPermaLink="false">http://www.dmi.me.uk/blog/?p=195</guid>
		<description><![CDATA[<p>Many hearing aids can handle direct audio input (DAI), often via a &#8220;shoe&#8221; that attaches to contacts on the aid itself. This shoe then provides a DAI jack (sometimes called a europlug or eurojack) that cables can be plugged into.</p>
<p>There seems to be a complete lack of cables designed for people with a single hearing aid, <a href="http://www.dmi.me.uk/blog/2009/11/16/hearing-aid-dai/">[...]</a>]]></description>
			<content:encoded><![CDATA[<p>Many hearing aids can handle direct audio input (DAI), often via a &#8220;shoe&#8221; that attaches to contacts on the aid itself. This shoe then provides a DAI jack (sometimes called a europlug or eurojack) that cables can be plugged into.</p>
<p>There seems to be a complete lack of cables designed for people with a single hearing aid, so one of my upcoming projects will be to convert a Y-cable that can serve two hearing aids into a joint DAI/earphone cable instead.</p>
<div id="attachment_199" class="wp-caption alignright" style="width: 160px"><img class="size-thumbnail wp-image-199" title="DAI connector pinout" src="http://www.dmi.me.uk/blog/wp-content/uploads/2009/11/dai-connector-pinout-150x150.jpg" alt="DAI connector pinout" width="150" height="150" /><p class="wp-caption-text">DAI connector pinout</p></div>
<p>The DAI connector has the following pinout:</p>
<ul>
<li><strong>short/thick pin:</strong> ground</li>
<li><strong>long/thin pin:</strong> VDD (apparently &#8212; doesn&#8217;t seem to actually be connected to anything on a 3.5mm cable)</li>
<li><strong>short/thin pin:</strong> signal</li>
</ul>
<p>Remember that a standard 3.5mm audio plug has the following pinout:</p>
<ul>
<li> <strong>tip:</strong> left signal</li>
<li><strong>inner sheath:</strong> right signal</li>
<li><strong>outer sheath:</strong> ground</li>
</ul>
<p>Next stage: connecting an earphone to the plug on one side of the cable, to see if there are any impedance issues, although the cable I am using (an fmGenie one) is a very low-impedance cable because I have an Oticon hearing aid. Measured with a multimeter, it seems to be around 0Ω, so I think that&#8217;s good enough for me. I believe attenuated cables have a 330kΩ resistor in series with each signal line (according to Neil Ferguson&#8217;s <a href="http://gfern.com/btha/btha.html" target="_blank">bluetooth hearing aid hack</a> page).</p>
<p>My ultimate goal is to get hold of a DAI jack that I can solder directly to an old earphone, so that I can just plug the spare DAI cable into the earphone directly, almost as if it were a hearing aid itself. Unfortunately, it seems that it is impossible to get hold of such things. According to Connevans, DAI jacks are only custom-made for hearing aid shoes. After some discussion, it seems like I should be able to make one myself though (with some help!) so we shall have to see how that turns out.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.dmi.me.uk/blog/2009/11/16/hearing-aid-dai/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	<creativeCommons:license>http://creativecommons.org/licenses/by-nc-nd/3.0/</creativeCommons:license>
	</item>
		<item>
		<title>A content-based file manager</title>
		<link>http://www.dmi.me.uk/blog/2009/06/04/a-content-based-file-manager/</link>
		<comments>http://www.dmi.me.uk/blog/2009/06/04/a-content-based-file-manager/#comments</comments>
		<pubDate>Thu, 04 Jun 2009 22:12:38 +0000</pubDate>
		<dc:creator>Dave</dc:creator>
				<category><![CDATA[Coding]]></category>
		<category><![CDATA[Insight (semantic filesystem)]]></category>
		<category><![CDATA[Projects]]></category>
		<category><![CDATA[Braindump]]></category>
		<category><![CDATA[file manager]]></category>
		<category><![CDATA[ideas]]></category>

		<guid isPermaLink="false">http://www.dmi.me.uk/blog/?p=124</guid>
		<description><![CDATA[<p>I&#8217;ve been thinking recently about Insight again, and I&#8217;ve been considering part of the problem with naming and uniqueness.</p>
<p>Names in a traditional file system are made unique based on a full path to the file, but most people think of a file name as just the final component. This would then cause a problem with the <a href="http://www.dmi.me.uk/blog/2009/06/04/a-content-based-file-manager/">[...]</a>]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve been thinking recently about Insight again, and I&#8217;ve been considering part of the problem with naming and uniqueness.</p>
<p>Names in a traditional file system are made unique based on a full path to the file, but most people think of a file name as just the final component. This would then cause a problem with the move to Insight, as a file could appear in multiple directories, and its only distinguishing feature would be the final component of its path. This is counter-intuitive and can cause all sorts of problems.</p>
<p>Consider makefiles, for example. They rely on a standard named file (<tt>Makefile</tt>) appearing at various levels in the hierarchy in order to work. Obviously, you would want different makefiles at different levels and in different projects, but Insight as it stands has no way to handle this.</p>
<p>I then started thinking about what makes a file unique. In the end, I came up with two things: name and content. This covers the makefile case (same name, different content) as well as the backup case (same content, different name). It then occurred to me that, in the general case, all you need to distinguish a file is its content, and then actually finding it can all be left up to metadata.</p>
<p><span id="more-124"></span>If files are then thought of as containers for data that happen to have a unique internal identifier (which never needs to be exposed to the user, although it can be accessed as, say, the file&#8217;s inode number) then the idea of a content-based file manager comes into play. These examples work best with visual media, particularly images, but there is no reason in principle that this could not be extended.</p>
<p>Imagine searching for a file. You know it&#8217;s a photo, but you have a large collection of them. With a digital camera and a large-capacity memory card, who needs to ever delete a photo? We&#8217;ll assume that you&#8217;ve dilligently tagged the photos with metadata as you&#8217;ve imported them from the camera, through some easy batch process.</p>
<p>On the tagging point: a lot can be taken from the metadata stored by the camera (date/time, resolution, orientation, black and white/colour, perhaps GPS co-ordinates) and with the right tools, more can be inferred (auto-tagging faces, buildings, perhaps recognising common events like football matches, converting GPS co-ordinates to places, &#8230;). As time goes on, people will need to do less and less manual tagging.</p>
<p>Anyway, back to the file manager. You know you are after a picture or a set of pictures. Normal thought processes will probably follow a path similar to: &#8220;Yeah, I wanted to show dad those <strong>photos</strong> from that <strong>holiday</strong> in <strong>Paris</strong> that we had <strong>two months ago</strong>. I think he&#8217;d particularly like the ones we got of the <strong>Louvre</strong>, as well as the ones <strong>with me in</strong>, of course.&#8221; I&#8217;ve highlighted various key words that can be translated directly to metadata searches. Notice how these all involve a narrowing down of the query.</p>
<p>To convert these to filters, we then have:</p>
<ul>
<li>type: <strong>photo</strong></li>
<li><strong>holiday</strong></li>
<li>location: <strong>Paris</strong></li>
<li>date: <strong>two months ago</strong></li>
<li>at least one of:
<ul>
<li>location: <strong>Louvre</strong></li>
<li>person: <strong>Me</strong></li>
</ul>
</li>
</ul>
<p>This could also be represented by a query:</p>
<blockquote>
<div class="codecolorer-container text twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">type:photo AND holiday AND location:Paris AND date:-2m<br />
AND (location:Louvre OR person:me)</div></div>
</blockquote>
<p>Breaking it down in this way feels fairly technical and wordy, however. I&#8217;d much prefer a visual view.</p>
<p>Imagine a black field, speckled with points of light representing your photos:</p>
<p><img class="aligncenter size-full wp-image-131" title="Content File Manager 1" src="http://www.dmi.me.uk/blog/wp-content/uploads/2009/06/content-file-manager-1.png" alt="Content File Manager 1" width="450" height="340" /></p>
<p>You filter by &#8220;holiday&#8221;, and (because it learns based on previous searches) it then groups by location. The ones which have been filtered out fade into nothing, and the photos group into labelled blobs and enlarge slightly:</p>
<p><img class="aligncenter size-full wp-image-132" title="Content File Manager 2" src="http://www.dmi.me.uk/blog/wp-content/uploads/2009/06/content-file-manager-2.png" alt="Content File Manager 2" width="450" height="340" /></p>
<p>You filter by date, and as you drag the slider, irrelevant items fade away and relevant ones enlarge:</p>
<p><img class="aligncenter size-full wp-image-133" title="Content File Manager 3" src="http://www.dmi.me.uk/blog/wp-content/uploads/2009/06/content-file-manager-3.png" alt="Content File Manager 3" width="450" height="340" /></p>
<p>Then you add the final filters and set the photos up for viewing, perhaps as a slideshow&#8230; and you&#8217;re done!</p>
<p>Pretty neat, I think.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.dmi.me.uk/blog/2009/06/04/a-content-based-file-manager/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
	<creativeCommons:license>http://creativecommons.org/licenses/by-nc-nd/3.0/</creativeCommons:license>
	</item>
		<item>
		<title>Restoring from LVM and VMWare disks</title>
		<link>http://www.dmi.me.uk/blog/2009/02/22/restoring-from-lvm-and-vmware-disks/</link>
		<comments>http://www.dmi.me.uk/blog/2009/02/22/restoring-from-lvm-and-vmware-disks/#comments</comments>
		<pubDate>Sun, 22 Feb 2009 13:37:28 +0000</pubDate>
		<dc:creator>Dave</dc:creator>
				<category><![CDATA[Hacks]]></category>
		<category><![CDATA[Tips and Tricks]]></category>
		<category><![CDATA[backup]]></category>
		<category><![CDATA[emergency]]></category>
		<category><![CDATA[hack]]></category>
		<category><![CDATA[lvm]]></category>
		<category><![CDATA[lvm2]]></category>
		<category><![CDATA[restore]]></category>
		<category><![CDATA[tip]]></category>
		<category><![CDATA[trick]]></category>
		<category><![CDATA[useful]]></category>
		<category><![CDATA[vmware]]></category>

		<guid isPermaLink="false">http://www.dmi.me.uk/blog/?p=91</guid>
		<description><![CDATA[<p>I recently had to restore a server that failed to boot after a power cut. This machine was a Linux VMWare host, and it had three Linux guest virtual machines that were running at the time. While we had full backups available, I decided to set myself the challenge of recovering the entire images, to save <a href="http://www.dmi.me.uk/blog/2009/02/22/restoring-from-lvm-and-vmware-disks/">[...]</a>]]></description>
			<content:encoded><![CDATA[<p>I recently had to restore a server that failed to boot after a power cut. This machine was a Linux VMWare host, and it had three Linux guest virtual machines that were running at the time. While we had full backups available, I decided to set myself the challenge of recovering the entire images, to save the pain of a complete rebuild.</p>
<p>The host server partitions were LVM-formatted volumes on top of hardware RAID-1, and each of the virtual hosts were partitioned with LVM too, internally. This means that the restore process will not be at all trivial. With just a complete image of the host system, I would need to restore (deep breath) files on a partition on an LVM logical volume (inside a volume group, on a physical volume) in a VMWare hard disk stored on LVM (logical volume inside volume group of physical volumes) inside a disk image that is itself a file on a disk. How very convoluted.</p>
<p>I used a Gentoo system to restore the data, although any Linux system with the appropriate packages should be able to do it. No searches turned up information on doing all of this, and I had to come up with some of it myself, so I thought I would document the process.</p>
<p><span id="more-91"></span>Just to illustrate the complexity of the data layout:</p>
<p style="text-align: center;"><img class="aligncenter size-full wp-image-174" title="LVM Restore Diagram" src="http://www.dmi.me.uk/blog/wp-content/uploads/2009/07/lvm-restore-diag-2.png" alt="LVM Restore Diagram" width="650" height="250" /></p>
<h2>Requirements</h2>
<p>The machine that is performing the restore requires:</p>
<ul>
<li>Linux</li>
<li>LVM2</li>
<li>VMWare Server</li>
<li>losetup</li>
<li>NBD (Network Block Device) kernel driver</li>
<li>file system drivers (if applicable)</li>
</ul>
<h2>Procedure</h2>
<p>Boot the dead server (<strong>vm-host</strong>) using a Linux LiveCD and copy its partitions to files on another drive. If you don&#8217;t know which partitions the LVM was stored across, you can either copy all of them, or use &lt;tt&gt;pvscan&lt;/tt&gt; (possibly after running &lt;tt&gt;vgscan&lt;/tt&gt;) to work out which belong to the appropriate volume group. This dump may take some time.</p>
<div class="codecolorer-container bash twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="bash codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #c20cb9; font-weight: bold;">dd</span> <span style="color: #007800;">if</span>=<span style="color: #000000; font-weight: bold;">/</span>dev<span style="color: #000000; font-weight: bold;">/</span>sda2 <span style="color: #007800;">of</span>=<span style="color: #000000; font-weight: bold;">/</span>mnt<span style="color: #000000; font-weight: bold;">/</span>ext-drive<span style="color: #000000; font-weight: bold;">/</span>sda2-data<br />
<span style="color: #c20cb9; font-weight: bold;">dd</span> <span style="color: #007800;">if</span>=<span style="color: #000000; font-weight: bold;">/</span>dev<span style="color: #000000; font-weight: bold;">/</span>sda3 <span style="color: #007800;">of</span>=<span style="color: #000000; font-weight: bold;">/</span>mnt<span style="color: #000000; font-weight: bold;">/</span>ext-drive<span style="color: #000000; font-weight: bold;">/</span>sda3-data<br />
<span style="color: #c20cb9; font-weight: bold;">dd</span> <span style="color: #007800;">if</span>=<span style="color: #000000; font-weight: bold;">/</span>dev<span style="color: #000000; font-weight: bold;">/</span>sda5 <span style="color: #007800;">of</span>=<span style="color: #000000; font-weight: bold;">/</span>mnt<span style="color: #000000; font-weight: bold;">/</span>ext-drive<span style="color: #000000; font-weight: bold;">/</span>sda5-data</div></div>
<p>Attach the drive with the partition images to the rescue machine (<strong>rescue-host</strong>), edit <kbd>/etc/lvm/lvm.conf</kbd> on <strong>rescue-host</strong>, and modify the <kbd>filter</kbd> line to allow LVM to scan loopback and network block devices. You&#8217;ll probably want to change this back afterwards, so remember what it was.</p>
<div class="codecolorer-container text twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">filter = [ &quot;a|/dev/nbd.*|&quot;, &quot;a|loop|&quot;, &quot;a|/dev/[hs]d|&quot;, &quot;a/.*/&quot; ]</div></div>
<p>Set up the partition images as loop devices:</p>
<div class="codecolorer-container bash twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="bash codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">losetup <span style="color: #000000; font-weight: bold;">/</span>dev<span style="color: #000000; font-weight: bold;">/</span>loop0 <span style="color: #000000; font-weight: bold;">/</span>mnt<span style="color: #000000; font-weight: bold;">/</span>ext-drive<span style="color: #000000; font-weight: bold;">/</span>sda2-data<br />
losetup <span style="color: #000000; font-weight: bold;">/</span>dev<span style="color: #000000; font-weight: bold;">/</span>loop1 <span style="color: #000000; font-weight: bold;">/</span>mnt<span style="color: #000000; font-weight: bold;">/</span>ext-drive<span style="color: #000000; font-weight: bold;">/</span>sda3-data<br />
losetup <span style="color: #000000; font-weight: bold;">/</span>dev<span style="color: #000000; font-weight: bold;">/</span>loop2 <span style="color: #000000; font-weight: bold;">/</span>mnt<span style="color: #000000; font-weight: bold;">/</span>ext-drive<span style="color: #000000; font-weight: bold;">/</span>sda5-data</div></div>
<p>Scan for and activate the volume group:</p>
<div class="codecolorer-container bash twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="bash codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">vgscan<br />
vgchange <span style="color: #660033;">-ay</span></div></div>
<p>Find the logical volume with the data we&#8217;re after (<strong>LogVol06</strong> in volume group <strong>VolGroup00</strong> in this case) and mount it:</p>
<div class="codecolorer-container bash twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="bash codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">lvscan<br />
<span style="color: #c20cb9; font-weight: bold;">mount</span> <span style="color: #000000; font-weight: bold;">/</span>dev<span style="color: #000000; font-weight: bold;">/</span>VolGroup00<span style="color: #000000; font-weight: bold;">/</span>LogVol06 <span style="color: #000000; font-weight: bold;">/</span>mnt<span style="color: #000000; font-weight: bold;">/</span>rescue</div></div>
<p>Copy the VMWare hard disk files out of the LVM mount, because we know that the volume group stored on them will conflict with the existing one:</p>
<div class="codecolorer-container bash twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="bash codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #c20cb9; font-weight: bold;">cp</span> <span style="color: #000000; font-weight: bold;">/</span>mnt<span style="color: #000000; font-weight: bold;">/</span>rescue<span style="color: #000000; font-weight: bold;">/</span>vmware<span style="color: #000000; font-weight: bold;">/</span>vhostname<span style="color: #000000; font-weight: bold;">/</span>vhostname.vmdk <span style="color: #000000; font-weight: bold;">/</span>rescue<span style="color: #000000; font-weight: bold;">/</span></div></div>
<p>Check the partition table on the virtual hard disk:</p>
<div class="codecolorer-container bash twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="bash codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">vmware-mount <span style="color: #660033;">-p</span> <span style="color: #000000; font-weight: bold;">/</span>rescue<span style="color: #000000; font-weight: bold;">/</span>vhostname.vmdk</div></div>
<p>This will give you something like:</p>
<div class="codecolorer-container text twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">--------------------------------------------<br />
VMware for Linux - Virtual Hard Disk Mounter<br />
Version: 1.0 build-80004<br />
Copyright 1998 VMware, Inc. All rights reserved. -- VMware Confidential<br />
--------------------------------------------<br />
<br />
Nr Start &nbsp; &nbsp; &nbsp;Size &nbsp; &nbsp; &nbsp; Type Id Sytem<br />
-- ---------- ---------- ---- -- ------------------------<br />
1 &nbsp;63 &nbsp; &nbsp; &nbsp; &nbsp; 208782 &nbsp; &nbsp; BIOS 83 Linux<br />
2 &nbsp;208845 &nbsp; &nbsp; 16563015 &nbsp; BIOS 8E Unknown</div></div>
<p>The second partition (with type <kbd>8E</kbd>) is the one we wanted in this case, but it&#8217;s LVM-formatted. This means we can&#8217;t use <kbd>vmware-mount</kbd> because an LVM partition cannot be mounted normally.</p>
<p>We need to unmount the currently-active volume group on the loopback devices (i.e. the LVM from <strong>vm-host</strong>):</p>
<div class="codecolorer-container bash twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="bash codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #c20cb9; font-weight: bold;">umount</span> <span style="color: #000000; font-weight: bold;">/</span>mnt<span style="color: #000000; font-weight: bold;">/</span>rescue<br />
<span style="color: #666666; font-style: italic;"># repeat the next line for all volume groups from the loopback devices</span><br />
vgchange <span style="color: #660033;">-an</span> VolGroup00<br />
losetup <span style="color: #660033;">-d</span> <span style="color: #000000; font-weight: bold;">/</span>dev<span style="color: #000000; font-weight: bold;">/</span>loop0<br />
losetup <span style="color: #660033;">-d</span> <span style="color: #000000; font-weight: bold;">/</span>dev<span style="color: #000000; font-weight: bold;">/</span>loop1<br />
losetup <span style="color: #660033;">-d</span> <span style="color: #000000; font-weight: bold;">/</span>dev<span style="color: #000000; font-weight: bold;">/</span>loop2</div></div>
<p>Now you need a dedicated terminal to mount the LVM partition from the virtual hard disk, as this process must stay running in order to access the virtual drive:</p>
<div class="codecolorer-container bash twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="bash codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">vmware-loop <span style="color: #000000; font-weight: bold;">/</span>rescue<span style="color: #000000; font-weight: bold;">/</span>vhostname.vmdk <span style="color: #000000;">2</span> <span style="color: #000000; font-weight: bold;">/</span>dev<span style="color: #000000; font-weight: bold;">/</span>nbd0</div></div>
<p>If you have more than one virtual partition as part of the LVM, you&#8217;ll need to have one terminal for each, and select partition numbers and NBD device numbers as appropriate.<br />
Now find the volume group again:</p>
<div class="codecolorer-container bash twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="bash codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">vgscan<br />
vgchange <span style="color: #660033;">-ay</span></div></div>
<p>Find the appropriate logical volume and mount it:</p>
<div class="codecolorer-container bash twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="bash codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">lvscan<br />
<span style="color: #c20cb9; font-weight: bold;">mount</span> <span style="color: #000000; font-weight: bold;">/</span>dev<span style="color: #000000; font-weight: bold;">/</span>VolGroup00<span style="color: #000000; font-weight: bold;">/</span>LogVol06 <span style="color: #000000; font-weight: bold;">/</span>mnt<span style="color: #000000; font-weight: bold;">/</span>rescue</div></div>
<p>Do whatever you need to do with the data, then unmount it all:</p>
<div class="codecolorer-container bash twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="bash codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #c20cb9; font-weight: bold;">umount</span> <span style="color: #000000; font-weight: bold;">/</span>mnt<span style="color: #000000; font-weight: bold;">/</span>rescue<br />
vgchange <span style="color: #660033;">-an</span> VolGroup00<br />
<span style="color: #666666; font-style: italic;"># either press ctrl-c in the vmware-loop terminal(s), or:</span><br />
<span style="color: #c20cb9; font-weight: bold;">killall</span> <span style="color: #660033;">-INT</span> vmware-loop<br />
<span style="color: #666666; font-style: italic;"># then finally refresh the volume group list to remove old entries</span><br />
vgscan</div></div>
<p>And that&#8217;s it! I hope this helps someone other than me&#8230;</p>
]]></content:encoded>
			<wfw:commentRss>http://www.dmi.me.uk/blog/2009/02/22/restoring-from-lvm-and-vmware-disks/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
	<creativeCommons:license>http://creativecommons.org/licenses/by-nc-nd/3.0/</creativeCommons:license>
	</item>
		<item>
		<title>mod_sqltemplate: A distraction from work</title>
		<link>http://www.dmi.me.uk/blog/2008/09/10/mod_sqltemplate-a-distraction-from-work/</link>
		<comments>http://www.dmi.me.uk/blog/2008/09/10/mod_sqltemplate-a-distraction-from-work/#comments</comments>
		<pubDate>Wed, 10 Sep 2008 20:48:37 +0000</pubDate>
		<dc:creator>Dave</dc:creator>
				<category><![CDATA[mod_sqltemplate]]></category>
		<category><![CDATA[Apache]]></category>
		<category><![CDATA[API]]></category>
		<category><![CDATA[APR]]></category>
		<category><![CDATA[DBD]]></category>
		<category><![CDATA[tutorial]]></category>

		<guid isPermaLink="false">http://www.dmi.me.uk/blog/?p=86</guid>
		<description><![CDATA[<p>I&#8217;ve begun the long and (hopefully) interesting task of working on mod_sqltemplate.  I have not yet found a tutorial or guide to working with APR&#8217;s DBD API (the database abstraction layer for the Apache Portable Runtime), so I&#8217;ll write one and publish it here as I <a href="http://www.dmi.me.uk/blog/2008/09/10/mod_sqltemplate-a-distraction-from-work/">[...]</a>]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve begun the long and (hopefully) interesting task of working on mod_sqltemplate.  I have not yet found a tutorial or guide to working with APR&#8217;s DBD API (the database abstraction layer for the Apache Portable Runtime), so I&#8217;ll write one and publish it here as I go along&#8230;</p>
]]></content:encoded>
			<wfw:commentRss>http://www.dmi.me.uk/blog/2008/09/10/mod_sqltemplate-a-distraction-from-work/feed/</wfw:commentRss>
		<slash:comments>13</slash:comments>
	<creativeCommons:license>http://creativecommons.org/licenses/by-nc-nd/3.0/</creativeCommons:license>
	</item>
		<item>
		<title>Modules for Apache and PHP</title>
		<link>http://www.dmi.me.uk/blog/2008/08/13/modules-for-apache-and-php/</link>
		<comments>http://www.dmi.me.uk/blog/2008/08/13/modules-for-apache-and-php/#comments</comments>
		<pubDate>Wed, 13 Aug 2008 20:26:54 +0000</pubDate>
		<dc:creator>Dave</dc:creator>
				<category><![CDATA[Coding]]></category>
		<category><![CDATA[Apache]]></category>
		<category><![CDATA[extensions]]></category>
		<category><![CDATA[modules]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[SQL]]></category>

		<guid isPermaLink="false">http://www.dmi.me.uk/blog/?p=74</guid>
		<description><![CDATA[<p>The number of projects I have in mind just keeps growing&#8230; I really need to get something together to organise them, and remember them! But here are two more to add to the list: an Apache module for dynamic configuration generation and a PHP framework inside an extension. Read on for a monster post with more <a href="http://www.dmi.me.uk/blog/2008/08/13/modules-for-apache-and-php/">[...]</a>]]></description>
			<content:encoded><![CDATA[<p>The number of projects I have in mind just keeps growing&#8230; I really need to get something together to organise them, and remember them! But here are two more to add to the list: an Apache module for dynamic configuration generation and a PHP framework inside an extension. Read on for a monster post with more information&#8230;</p>
<p><span id="more-74"></span></p>
<h2>Apache module</h2>
<p>The first thing I have in mind is to create an Apache 2.2 module that uses the APR (Apache Portable Runtime) to make configuration file templating easy.</p>
<p>On my server, there are a lot of very similar Apache configuration files. At the moment, they are semi-automatically generated by running a Perl script that reads the configuration from a database and then creates the output files as required. This is all well and good, but changing anything requires running the Perl script, regenerating all of the configuration files, then prodding Apache to reload its configuration. There has to be a better way, especially one that doesn&#8217;t require elevated permissions like that.</p>
<p>Enter my proposed solution: <tt>mod_sqltemplate</tt>. This module will add a few extra settings and (at least) two extra sections to the standard Apache configuration. The propsed features are:</p>
<ul>
<li><tt>SQLTemplate_DBDriver «driver»</tt> – sets the APR driver to be used</li>
<li><tt>SQLTemplate_DBOpts «option-string»</tt> – options for the driver (e.g. database name, username, password&#8230;)</li>
<li><tt>SQLTemplate_Caching «on|off»</tt> – enable/disable configuration caching</li>
<li><tt>SQLTemplate_CacheDir «path»</tt> – directory in which to save cached configurations</li>
<li><tt>&lt;SQLRepeat «query»&gt;</tt> – new section, as described below</li>
<li><tt>&lt;SQLCatSet «sep» «query»&gt;</tt> – new section, as described below</li>
</ul>
<h3>SQLRepeat</h3>
<p>The <tt>SQLRepeat</tt> section is probably going to be the most-used new directive. It provides templating functionality similar to <a title="mod_macro by Fabien Coelho" href="http://cri.ensmp.fr/~coelho/mod_macro/" target="_blank"><tt>mod_macro</tt></a>, although the template variables are taken from the column names of the query rather than being explicitly specified. The section will then be repeated for each row of the resultset, substitutions occurring as required.</p>
<p>Perhaps an example would help:</p>
<pre lang="apache">&lt;SQLRepeat "SELECT id,hostname,domain FROM apache_hosts"&gt;
&lt;VirtualHost *:80&gt;
  DocumentRoot /var/www/${hostname}.${domain}
  ServerName ${hostname}.${domain}
  # ...
&lt;/VirtualHost&gt;
&lt;/SQLRepeat&gt;</pre>
<p>For this example, I&#8217;ve avoided the configuration directives for clarity, assuming they are specified elsewhere. Supposing the database table contains simply:</p>
<table border="0">
<tbody>
<tr>
<th>ID</th>
<th>hostname</th>
<th>domain</th>
</tr>
<tr>
<td>1</td>
<td>www</td>
<td>example.com</td>
</tr>
<tr>
<td>3</td>
<td>test</td>
<td>example.com</td>
</tr>
<tr>
<td>12</td>
<td>yourhost</td>
<td>somewhere.local</td>
</tr>
</tbody>
</table>
<p>Then this will expand to be equivalent to:</p>
<pre lang="apache">&lt;VirtualHost *:80&gt;
  DocumentRoot /var/www/www.example.com
  ServerName www.example.com
  # ...
&lt;/VirtualHost&gt;
&lt;VirtualHost *:80&gt;
  DocumentRoot /var/www/test.example.com
  ServerName test.example.com
  # ...
&lt;/VirtualHost&gt;
&lt;VirtualHost *:80&gt;
  DocumentRoot /var/www/yourhost.somewhere.local
  ServerName yourhost.somewhere.local
  # ...
&lt;/VirtualHost&gt;</pre>
<p>And so on. These sections can be nested, so if you wanted to store a list of aliases as well:</p>
<table border="0">
<tbody>
<tr>
<th>ID</th>
<th>hostid</th>
<th>alias</th>
<th>target</th>
</tr>
<tr>
<td>1</td>
<td>1</td>
<td>/icons</td>
<td>/var/www/_share/icons</td>
</tr>
<tr>
<td>2</td>
<td>1</td>
<td>/example</td>
<td>/var/www/_share/foo</td>
</tr>
<tr>
<td>5</td>
<td>12</td>
<td>/bar</td>
<td>/var/www/_share/foo</td>
</tr>
</tbody>
</table>
<p>You could use something like this:</p>
<pre lang="apache">&lt;SQLRepeat "SELECT id,hostname,domain FROM apache_hosts"&gt;
&lt;VirtualHost *:80&gt;
  DocumentRoot /var/www/${hostname}.${domain}
  ServerName ${hostname}.${domain}
  # ...
  &lt;SQLRepeat "SELECT alias,target FROM apache_aliases WHERE hostid=?" ${id}&gt;
    Alias "${alias}" "${target}"
  &lt;/SQLRepeat&gt;
&lt;/VirtualHost&gt;
&lt;/SQLRepeat&gt;</pre>
<p>which would then expand to:</p>
<pre lang="apache">&lt;VirtualHost *:80&gt;
  DocumentRoot /var/www/www.example.com
  ServerName www.example.com
  # ...
    Alias "/icons" "/var/www/_share/icons"
    Alias "/example" "/var/www/_share/foo"
&lt;/VirtualHost&gt;
&lt;VirtualHost *:80&gt;
  DocumentRoot /var/www/test.example.com
  ServerName test.example.com
  # ...
&lt;/VirtualHost&gt;
&lt;VirtualHost *:80&gt;
  DocumentRoot /var/www/yourhost.somewhere.local
  ServerName yourhost.somewhere.local
  # ...
    Alias "/bar" "/var/www/_share/foo"
&lt;/VirtualHost&gt;</pre>
<p>So far, so good. Something to note is that the variable names above did not conflict. If we had included &#8220;id&#8221; in the list of columns for the inner <tt>SQLRepeat</tt>, then included <tt>${id}</tt>, the module should use the innermost scope. Disambiguation should be obtained by table alias prefixing (e.g. <tt>${apache_hosts.id}</tt> or <tt>${apache_aliases.id}</tt>). Full variable names should always be specified for clarity. This also shows that if the query returns no results, the repeating section is not included, as you would expect. Also note that queries that use variable substitution should use the prepared statement format, with variables specified afterwards. Variables will be included directly, so anything that might contain spaces must be quoted.</p>
<p>However, there are some directives like <tt>ServerAlias</tt> that must be specified once with a list of space-separated values. Enter <tt>SQLCatSet</tt>&#8230;</p>
<h3>SQLCatSet</h3>
<p>This acts in a similar way to <tt>SQLRepeat</tt>, but it concatenates all of the results for each field before substituting, and it includes its content at most once. If there are no results for the query, then it will not include its content. For example, with a server aliases table like:</p>
<table border="0">
<tbody>
<tr>
<th>ID</th>
<th>hostid</th>
<th>alias</th>
</tr>
<tr>
<td>1</td>
<td>3</td>
<td>test2.example.com</td>
</tr>
<tr>
<td>2</td>
<td>3</td>
<td>test.example.net</td>
</tr>
<tr>
<td>5</td>
<td>12</td>
<td>*.somewhere.local</td>
</tr>
</tbody>
</table>
<p>You could use something like this:</p>
<pre lang="apache">&lt;SQLRepeat "SELECT id,hostname,domain FROM apache_hosts"&gt;
&lt;VirtualHost *:80&gt;
  DocumentRoot /var/www/${hostname}.${domain}
  ServerName ${hostname}.${domain}
  &lt;SQLCatSet " " "SELECT alias FROM apache_server_aliases WHERE hostid=?" ${id}&gt;
    ServerAlias ${alias}
  &lt;/SQLCatSet&gt;
  # ...
  &lt;SQLRepeat "SELECT alias,target FROM apache_aliases WHERE hostid=?" ${id}&gt;
    Alias "${alias}" "${target}"
  &lt;/SQLRepeat&gt;
&lt;/VirtualHost&gt;
&lt;/SQLRepeat&gt;</pre>
<p>which would then expand to:</p>
<pre lang="apache">&lt;VirtualHost *:80&gt;
  DocumentRoot /var/www/www.example.com
  ServerName www.example.com
  # ...
    Alias "/icons" "/var/www/_share/icons"
    Alias "/example" "/var/www/_share/foo"
&lt;/VirtualHost&gt;
&lt;VirtualHost *:80&gt;
  DocumentRoot /var/www/test.example.com
  ServerName test.example.com
    ServerAlias test2.example.com test.example.net
  # ...
&lt;/VirtualHost&gt;
&lt;VirtualHost *:80&gt;
  DocumentRoot /var/www/yourhost.somewhere.local
  ServerName yourhost.somewhere.local
    ServerAlias *.somewhere.local
  # ...
    Alias "/bar" "/var/www/_share/foo"
&lt;/VirtualHost&gt;</pre>
<p>This would seem to cover the major functionality needed for automatically generating configurations in a really flexible way, although I&#8217;m sure more will probably be needed at some point&#8230; like <tt>SQLIf</tt>, perhaps.</p>
<h2>PHP Framework</h2>
<p>It occurs to me that having a framework&#8217;s code in PHP itself could mean that it is quite slow. It would be interesting to put together a framework in C and embedded as a module, to see if there are any memory/speed improvements possible. It might just be a case of implementing an ORM (Object Relational Model) system to begin with. Obviously, this idea is nowhere near as fully-formed!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.dmi.me.uk/blog/2008/08/13/modules-for-apache-and-php/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
	<creativeCommons:license>http://creativecommons.org/licenses/by-nc-nd/3.0/</creativeCommons:license>
	</item>
		<item>
		<title>HackWeekend: an introduction</title>
		<link>http://www.dmi.me.uk/blog/2008/08/08/hackweekend-an-introduction/</link>
		<comments>http://www.dmi.me.uk/blog/2008/08/08/hackweekend-an-introduction/#comments</comments>
		<pubDate>Fri, 08 Aug 2008 16:21:21 +0000</pubDate>
		<dc:creator>Dave</dc:creator>
				<category><![CDATA[HackWeekend]]></category>
		<category><![CDATA[HackWeekend:DDF]]></category>

		<guid isPermaLink="false">http://www.dmi.me.uk/blog/?p=69</guid>
		<description><![CDATA[<p>So I&#8217;ve decided now that, as I have some free time and I will soon have some disposable income, that it&#8217;s time to start on an idea that&#8217;s been brewing for a little while: HackWeekend. This is a radical departure from some of my previous ideas, in that it&#8217;s a social thing.</p>
<p>When we were coming to <a href="http://www.dmi.me.uk/blog/2008/08/08/hackweekend-an-introduction/">[...]</a>]]></description>
			<content:encoded><![CDATA[<p>So I&#8217;ve decided now that, as I have some free time and I will soon have some disposable income, that it&#8217;s time to start on an idea that&#8217;s been brewing for a little while: HackWeekend. This is a radical departure from some of my previous ideas, in that it&#8217;s a social thing.</p>
<p>When we were coming to the end of our time at university (and consequently our time as housemates), my good friend Alex Yong and I decided that this should not be the end, and we should all get together regularly afterwards. As we technical types aren&#8217;t that good at small talk, we thought that rather than just meeting up and chatting, we should actually have an aim in mind. An independent idea from another friend (Dave Durant) around the same time was that he and I should get together for a weekend sometime with lots of Red Bull and pizza and very little sleep, and to see what we could code/prototype.</p>
<p><span id="more-69"></span>The beginnings of HackWeekend came out of these conversations, plus a long-standing desire to build something akin to <a title="The MIT Disco Dance Floor project" href="http://web.mit.edu/storborg/ddf/" target="_blank">a project</a> I had heard about and of which I had seen videos. The aim will be to run from Friday evening to late Sunday, and to see what we can build and get working in 50-odd hours. Projects can be hardware, software&#8230; anything!</p>
<p>Now we&#8217;re beginning to think seriously about organising HackWeekend sometime before the end of 2008 if we can. We have no idea where we&#8217;ll do this (likely to be at someone&#8217;s house) or how many people will be there or anything. Obviously, we want as many people as possible to be involved&#8230; eventually. We&#8217;ll have to start out small just to prove that the idea can work.</p>
<p>Finally, some of the HackWeekend rules/guidelines may include:</p>
<ol>
<li>Everything will be written up/documented in some way, as much as possible</li>
<li>Lots of photos will be taken, possibly even videos (for the physical projects)</li>
<li>Kick back, relax and enjoy yourself!</li>
<li>There are no stupid ideas &#8211; just ones that might</li>
<li>(Until we get some kind of sponsorship&#8230;) please contribute to costs of materials/food/etc</li>
<li>Tell lots of people &#8211; the further this spreads, the more cool projects we&#8217;ll be able to do</li>
<li><strong>The final details (schematics, designs, code, etc) will be released under one or more open licences</strong></li>
</ol>
<p>This last rule, of course, will definitely be included. All project details will be published on the HackWeekend website (when it&#8217;s built), with full attribution.</p>
<h2>Our first project</h2>
<p>Our first project (for now) will be to attempt to build a prototype disco dance floor module, akin to the MIT project linked above. We have plans to make some improvements, including upping the maximum number of supported colours to 8,192 by adding a UV LED to each LED cluster. With 16 bits/pixel, that gives us four bits each for red, green and blue, one bit for UV, and one bit for the pressure sensor&#8230; and two left over for future expansion. Anyway, I&#8217;m getting ahead of myself.</p>
<p>For this project, we&#8217;ll need a lot of people who are good with their hands. We&#8217;re not sure exactly how far we&#8217;ll go with this prototype (updates to follow) but more details will be available soon. The crew list is likely to involve:</p>
<ul>
<li>Electrical engineers (for working out the circuitry)</li>
<li>People who are good at soldering (for small components)</li>
<li>People who can solder (for the larger tasks, like wires)</li>
<li>People with some sense of æsthetic beauty (to make sure the end product looks good)</li>
<li>Perhaps people who can work with wood and plastic (building the frames)</li>
<li>Low-level coders (for developing the microchip firmware)</li>
<li>Software engineers (for developing the client-side software)</li>
</ul>
<p>and that&#8217;s just off the top of my head. There may well be others!</p>
<h2>And now&#8230;</h2>
<p>So, what are you waiting for? Head on over to the current <a title="HackWeekend on GroupSpaces" href="http://groupspaces.com/hackweekend/">HackWeekend</a> page and sign up to get email updates. The main site will be built when I get round to it&#8230;</p>
]]></content:encoded>
			<wfw:commentRss>http://www.dmi.me.uk/blog/2008/08/08/hackweekend-an-introduction/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	<creativeCommons:license>http://creativecommons.org/licenses/by-nc-nd/3.0/</creativeCommons:license>
	</item>
		<item>
		<title>In-place array uniq in C</title>
		<link>http://www.dmi.me.uk/blog/2008/07/10/in-place-uniq-in-c/</link>
		<comments>http://www.dmi.me.uk/blog/2008/07/10/in-place-uniq-in-c/#comments</comments>
		<pubDate>Thu, 10 Jul 2008 21:43:55 +0000</pubDate>
		<dc:creator>Dave</dc:creator>
				<category><![CDATA[Coding]]></category>
		<category><![CDATA[Facebook]]></category>
		<category><![CDATA[Hacks]]></category>
		<category><![CDATA[Insight (semantic filesystem)]]></category>
		<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://www.dmi.me.uk/blog/?p=64</guid>
		<description><![CDATA[<p>I&#8217;ve been developing Insight even though the uni project has come to an end, because it&#8217;s fun! I also want to make it more stable and eventually release it under an open-source licence of some kind. There will be an update coming soon, I promise! I now have Internet, so I can write up some things&#8230; <a href="http://www.dmi.me.uk/blog/2008/07/10/in-place-uniq-in-c/">[...]</a>]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve been developing <strong>Insight</strong> even though the uni project has come to an end, because it&#8217;s fun! I also want to make it more stable and eventually release it under an open-source licence of some kind. There will be an update coming soon, I promise! I now have Internet, so I can write up some things&#8230;  Anyway, one of the interesting things I wanted to do for Insight was an in-place form of <tt>uniq</tt> for an array, ideally without any additional memory allocation. It seems that this is something nobody else has done yet! So I set about doing it myself&#8230;  For those of you who are unfamiliar with the Linux/UNIX command <tt>uniq</tt>, it takes a sorted list and removes any duplicates. This is almost exactly what I&#8217;m trying to do, with one caveat: I need to keep the &#8220;discarded&#8221; duplicates.  What happens is that I have an array containing a number of strings, and these have all been dynamically allocated via <tt>malloc()</tt> or <tt>calloc()</tt>. If I just remove or overwrite their pointers, they&#8217;ll vanish and cause a memory leak. While I&#8217;ve now fixed a large number of leaks thanks to <a title="Valgrind debugger/profiler" href="http://valgrind.org" target="_blank">Valgrind</a>, I&#8217;m trying to actively avoid any possibility of adding them.  Read on for the details&#8230; <span id="more-64"></span></p>
<h2>The Idea</h2>
<p>The basic idea is that we have a sorted list of items that may have some duplicates, say:</p>
<pre>{A<sub>0</sub>, A<sub>1</sub>, B<sub>0</sub>, C<sub>0</sub>, C<sub>1</sub>, E<sub>0</sub>, F<sub>0</sub>, F<sub>1</sub>, F<sub>2</sub>, G<sub>0</sub>, H<sub>0</sub>, H<sub>1</sub>}</pre>
<p>and we want to remove all of the duplicates, so we get two sets:</p>
<pre>{A<sub>0</sub>, B<sub>0</sub>, C<sub>0</sub>, E<sub>0</sub>, F<sub>0</sub>, G<sub>0</sub>, H<sub>0</sub>} {A<sub>1</sub>, C<sub>1</sub>, F<sub>1</sub>, F<sub>2</sub>, H<sub>1</sub>}</pre>
<p>Note that it doesn&#8217;t matter which of the duplicates ends up in which set, just that the items in the first are all unique and that we don&#8217;t lose any. Also, <tt>A<sub>0</sub></tt> and <tt>A<sub>1</sub></tt> have the same value but the subscript will help to distinguish exactly which of the <tt>A</tt>s I&#8217;m talking about.  Now we have the problem, let&#8217;s look at some solutions.</p>
<h3>Lossless solution &#8211; additional lists</h3>
<p>So the first solution uses two temporary lists, <tt>unique</tt> and <tt>duplicate</tt>. We start with two pointers into the original list: <tt>p</tt> and <tt>q</tt>. We set <tt>p</tt> to point to the start of the list, and <tt>q</tt> to point to the element after <tt>p</tt>. We then copy the item <tt>p</tt> points at to our <tt>unique</tt> list. Then, while we still have more items to examine:</p>
<ul>
<li>If the items pointed to by <tt>p</tt> and <tt>q</tt> have the same value, then we copy the item <tt>q</tt> points at to the <tt>duplicate</tt> list and advance <tt>p</tt> and <tt>q</tt>.</li>
<li>If they are different, we copy the item at <tt>q</tt> to our <tt>unique</tt> list, and advance <tt>p</tt> and <tt>q</tt>.</li>
</ul>
<p>We keep doing this until we get to the end of the array, and then copy the <tt>unique</tt> list to the start of the array, the <tt>duplicate</tt> list after that (both overwriting the previous contents) and set the number of unique items to the length of the <tt>unique</tt></p>
<p>list.</p>
<h3>Lossy solution &#8211; one list</h3>
<p>We can do a similar thing in-place, although this will result in data loss. The essential idea is:</p>
<ul>
<li>We start in the same way: <tt>p</tt> pointing to the first element, and <tt>q</tt> to the second</li>
<li>While <tt>q</tt> has the same value as <tt>p</tt>, advance <tt>q</tt> along the list</li>
<li>When they are different, advance <tt>p</tt>, copy <tt>q</tt> to <tt>p</tt>, and advance <tt>q</tt></li>
<li>Once <tt>q</tt> goes past the end of the list, we&#8217;re done, and the offset of <tt>p</tt> is the number of unique items.</li>
</ul>
<p>Now this is quite simple, and only requires one pass through the list, but it results in the loss of information, which is unacceptable in this case.</p>
<h3>Lossless solution &#8211; one list</h3>
<p>For this solution, we can also do it with one pass through the list and two pointers.  The basic intuition is that we&#8217;re going through the array, accumulating a rotating block of stuff that we don&#8217;t want. At any given point:</p>
<ul>
<li>Everything between the start and <tt>p</tt> (not inclusive) is the unique list (so far)</li>
<li>Everything between <tt>p</tt> and <tt>q</tt> (not inclusive) is an unwanted duplicate</li>
<li>Everything between <tt>q</tt> (inclusive) and the end is yet to be processed.</li>
</ul>
<p>At the end, we return the number of unique items at the start of the list; everything above that is a duplicate.</p>
<h2>For integers</h2>
<p>Here is some pseudo-Java that performs my algorithm for a set of integers.</p>
<pre>
<div class="codecolorer-container c twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;height:300px;"><div class="c codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #993333;">int</span> set_uniq<span style="color: #009900;">&#40;</span><span style="color: #993333;">int</span> set<span style="color: #009900;">&#91;</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; <span style="color: #993333;">int</span> count <span style="color: #339933;">=</span> set.<span style="color: #202020;">length</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; <span style="color: #993333;">int</span> tmp<span style="color: #339933;">,</span> p<span style="color: #339933;">=</span><span style="color: #0000dd;">0</span><span style="color: #339933;">,</span> q<span style="color: #339933;">=</span><span style="color: #0000dd;">1</span><span style="color: #339933;">;</span><br />
&nbsp; <span style="color: #b1b100;">while</span> <span style="color: #009900;">&#40;</span>p <span style="color: #339933;">&lt;</span> set.<span style="color: #202020;">length</span> <span style="color: #339933;">&amp;&amp;</span> q <span style="color: #339933;">&lt;</span> set.<span style="color: #202020;">length</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; <span style="color: #b1b100;">while</span> <span style="color: #009900;">&#40;</span>p <span style="color: #339933;">&lt;</span> set.<span style="color: #202020;">length</span> <span style="color: #339933;">&amp;&amp;</span> set<span style="color: #009900;">&#91;</span>p<span style="color: #009900;">&#93;</span> <span style="color: #339933;">!=</span> set<span style="color: #009900;">&#91;</span>q<span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; p <span style="color: #339933;">=</span> p <span style="color: #339933;">+</span> <span style="color: #0000dd;">1</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span>q <span style="color: #339933;">&lt;</span> set.<span style="color: #202020;">length</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span>p <span style="color: #339933;">&lt;</span> q<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; tmp <span style="color: #339933;">=</span> set<span style="color: #009900;">&#91;</span>p<span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; set<span style="color: #009900;">&#91;</span>p<span style="color: #009900;">&#93;</span> <span style="color: #339933;">=</span> set<span style="color: #009900;">&#91;</span>q<span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; set<span style="color: #009900;">&#91;</span>q<span style="color: #009900;">&#93;</span> <span style="color: #339933;">=</span> tmp<span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; q <span style="color: #339933;">=</span> q <span style="color: #339933;">+</span> <span style="color: #0000dd;">1</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #b1b100;">else</span> <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span>count <span style="color: #339933;">&gt;</span> p<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; count <span style="color: #339933;">=</span> p<span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
&nbsp; &nbsp; <span style="color: #b1b100;">while</span> <span style="color: #009900;">&#40;</span>q <span style="color: #339933;">&lt;</span> max <span style="color: #339933;">&amp;&amp;</span> set<span style="color: #009900;">&#91;</span>p<span style="color: #009900;">&#93;</span> <span style="color: #339933;">==</span> set<span style="color: #009900;">&#91;</span>q<span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; q <span style="color: #339933;">=</span> q <span style="color: #339933;">+</span> <span style="color: #0000dd;">1</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
&nbsp; <span style="color: #009900;">&#125;</span><br />
&nbsp; <span style="color: #666666; font-style: italic;">// q hit the end and is still the same as p</span><br />
&nbsp; <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span>count <span style="color: #339933;">&gt;</span> p<span style="color: #009900;">&#41;</span><br />
&nbsp; &nbsp; count <span style="color: #339933;">=</span> p <span style="color: #339933;">+</span> <span style="color: #0000dd;">1</span><span style="color: #339933;">;</span><br />
<br />
&nbsp; <span style="color: #b1b100;">return</span> count<span style="color: #339933;">;</span><br />
<span style="color: #009900;">&#125;</span></div></div>
</pre>
<h2>The general code</h2>
<p>The arguments to the general <tt>set_uniq()</tt> function are very similar to the arguments to standard <tt>qsort()</tt>:</p>
<ul>
<li>The (sorted) array to work on</li>
<li>The number of items in the array</li>
<li>The size of each item in the array</li>
<li>A comparator function that returns a negative integer if the first argument is less than the second, zero if they are equal, and a positive integer if the first argument is greater than the second.</li>
</ul>
<p>So, without further ado, my code:</p>
<pre>
<div class="codecolorer-container c twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="c codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #993333;">int</span> set_uniq<span style="color: #009900;">&#40;</span><span style="color: #993333;">void</span> <span style="color: #339933;">*</span>set<span style="color: #339933;">,</span><br />
&nbsp; &nbsp; size_t count<span style="color: #339933;">,</span><br />
&nbsp; &nbsp; size_t elem_size<span style="color: #339933;">,</span><br />
&nbsp; &nbsp; <span style="color: #993333;">int</span> <span style="color: #009900;">&#40;</span><span style="color: #339933;">*</span>cmp<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#40;</span><span style="color: #993333;">const</span> <span style="color: #993333;">void</span><span style="color: #339933;">*,</span> <span style="color: #993333;">const</span> <span style="color: #993333;">void</span><span style="color: #339933;">*</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; <span style="color: #993333;">void</span> <span style="color: #339933;">*</span>p<span style="color: #339933;">,</span> <span style="color: #339933;">*</span>q<span style="color: #339933;">,</span> <span style="color: #339933;">*</span>max<span style="color: #339933;">;</span><br />
&nbsp; <span style="color: #993333;">void</span> <span style="color: #339933;">*</span>tmp<span style="color: #339933;">=</span>calloc<span style="color: #009900;">&#40;</span><span style="color: #0000dd;">1</span><span style="color: #339933;">,</span> elem_size<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> <span style="color: #808080; font-style: italic;">/* TODO: check for failure */</span><br />
&nbsp; p<span style="color: #339933;">=</span>set<span style="color: #339933;">;</span><br />
&nbsp; q<span style="color: #339933;">=</span>set<span style="color: #339933;">+</span>elem_size<span style="color: #339933;">;</span><br />
&nbsp; max<span style="color: #339933;">=</span>set<span style="color: #339933;">+</span><span style="color: #009900;">&#40;</span>count<span style="color: #339933;">*</span>elem_size<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; <span style="color: #b1b100;">while</span> <span style="color: #009900;">&#40;</span>p<span style="color: #339933;">&lt;</span> p<span style="color: #339933;">-</span>set<span style="color: #009900;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; count <span style="color: #339933;">=</span> <span style="color: #009900;">&#40;</span>p<span style="color: #339933;">-</span>set<span style="color: #009900;">&#41;</span><span style="color: #339933;">/</span>elem_size<span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
&nbsp; &nbsp; <span style="color: #b1b100;">while</span> <span style="color: #009900;">&#40;</span>q p<span style="color: #339933;">-</span>set<span style="color: #009900;">&#41;</span><br />
&nbsp; &nbsp; count <span style="color: #339933;">=</span> <span style="color: #0000dd;">1</span> <span style="color: #339933;">+</span> <span style="color: #009900;">&#40;</span>p<span style="color: #339933;">-</span>set<span style="color: #009900;">&#41;</span><span style="color: #339933;">/</span>elem_size<span style="color: #339933;">;</span><br />
&nbsp; ifree<span style="color: #009900;">&#40;</span>tmp<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; <span style="color: #b1b100;">return</span> count<span style="color: #339933;">;</span><br />
<span style="color: #009900;">&#125;</span></div></div>
</pre>
<h2>Conclusion</h2>
<p>This code is released under a Creative Commons licence (see below). A similar idea will work well for other solutions, like set difference. I&#8217;ll post those later if anyone really cares.  Also, there is a better way of swapping the items by using the fact that:</p>
<pre>
<div class="codecolorer-container c twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="c codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">a <span style="color: #339933;">^=</span> b<span style="color: #339933;">;</span><br />
b <span style="color: #339933;">^=</span> a<span style="color: #339933;">;</span><br />
a <span style="color: #339933;">^=</span> b<span style="color: #339933;">;</span></div></div>
</pre>
<p>swaps a and b without needing a temporary variable. If you just go along the data in 32-bit chunks, performing those XOR operations to swap the data. This actually works out to be 30% or so faster (if I remember correctly).  Finally &#8211; general code like this is always going to be slower than code that&#8217;s been specialised for a particular purpose. Calling this on integers, for example, will be much slower than coding an integer-specific version. I should also point out that you can just overwrite integers, as you don&#8217;t need to free them <img src='http://www.dmi.me.uk/blog/wp-includes/images/smilies/icon_wink.gif' alt=';-)' class='wp-smiley' title="icon wink photo" /> </p>
]]></content:encoded>
			<wfw:commentRss>http://www.dmi.me.uk/blog/2008/07/10/in-place-uniq-in-c/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
	<creativeCommons:license>http://creativecommons.org/licenses/by-nc-nd/3.0/</creativeCommons:license>
	</item>
	</channel>
</rss>
