<?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 &#187; Personal</title>
	<atom:link href="http://www.dmi.me.uk/blog/category/personal/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.dmi.me.uk/blog</link>
	<description></description>
	<lastBuildDate>Wed, 18 Aug 2010 13:17:48 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0.1</generator>
<creativeCommons:license>http://creativecommons.org/licenses/by-nc-nd/3.0/</creativeCommons:license>
		<item>
		<title>Useful git configuration fragments</title>
		<link>http://www.dmi.me.uk/blog/2010/08/18/useful-git-configuration-fragments/</link>
		<comments>http://www.dmi.me.uk/blog/2010/08/18/useful-git-configuration-fragments/#comments</comments>
		<pubDate>Wed, 18 Aug 2010 13:17:48 +0000</pubDate>
		<dc:creator>Dave</dc:creator>
				<category><![CDATA[Personal]]></category>
		<category><![CDATA[Tips and Tricks]]></category>
		<category><![CDATA[git]]></category>
		<category><![CDATA[tip]]></category>
		<category><![CDATA[trick]]></category>
		<category><![CDATA[useful]]></category>

		<guid isPermaLink="false">http://www.dmi.me.uk/blog/?p=240</guid>
		<description><![CDATA[<p>Time for a quick micro-post, I think. I feel like sharing two useful fragments of my git configuration.</p>
<p>First up, aliases. I have a few useful shortcuts defined, as well as some nice ways of displaying a repository&#8217;s history. I&#8217;ve aliased many of the common commands to two-letter versions which evoke the similar Subversion command aliases:</p>

[alias]
  st <a href="http://www.dmi.me.uk/blog/2010/08/18/useful-git-configuration-fragments/">[...]</a>]]></description>
			<content:encoded><![CDATA[<p>Time for a quick micro-post, I think. I feel like sharing two useful fragments of my git configuration.</p>
<p>First up, aliases. I have a few useful shortcuts defined, as well as some nice ways of displaying a repository&#8217;s history. I&#8217;ve aliased many of the common commands to two-letter versions which evoke the similar Subversion command aliases:</p>
<pre>
<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">[alias]<br />
  st = status<br />
&nbsp; di = diff<br />
&nbsp; co = checkout<br />
&nbsp; ci = commit<br />
&nbsp; br = branch<br />
&nbsp; sta = stash<br />
  graph = log --decorate --oneline --graph --all --date-order<br />
  lg = log --graph --pretty=format:'%C(yellow)%h%Creset -%C(yellow)%d%Creset %s %C(green)(%cr)%Creset %Cred&lt;%an&gt;%Creset' --abbrev-commit --date=relative --date-order</div></div>
</pre>
<p>The last two aliases above provide a nice graphical view of history in the console. <code class="codecolorer text default"><span class="text">git graph</span></code> displays all history of all branches in date order rather than topological order. This means that commits on different branches may be interleaved, rather than grouping commits on different branches. <code class="codecolorer text default"><span class="text">git lg</span></code> displays a little more information (including author and relative timestamps), and allows me to pick which branches I want to see. The examples below are all taken from the <a href="http://github.com/dingram/jerity" target="_blank">Jerity</a> repository.<br />

<a href='http://www.dmi.me.uk/blog/2010/08/18/useful-git-configuration-fragments/screenshot-20100818-140818/' title='git graph example'><img width="150" height="150" src="http://www.dmi.me.uk/blog/wp-content/uploads/2010/08/screenshot-20100818-140818-150x150.png" class="attachment-thumbnail" alt="git graph example" title="git graph example" /></a>
<a href='http://www.dmi.me.uk/blog/2010/08/18/useful-git-configuration-fragments/screenshot-20100818-140906/' title='git graph example with many branches'><img width="150" height="150" src="http://www.dmi.me.uk/blog/wp-content/uploads/2010/08/screenshot-20100818-140906-150x150.png" class="attachment-thumbnail" alt="git graph example with many branches" title="git graph example with many branches" /></a>
<a href='http://www.dmi.me.uk/blog/2010/08/18/useful-git-configuration-fragments/screenshot-20100818-140936/' title='git lg example'><img width="150" height="150" src="http://www.dmi.me.uk/blog/wp-content/uploads/2010/08/screenshot-20100818-140936-150x150.png" class="attachment-thumbnail" alt="git lg example" title="git lg example" /></a>
<br />
The second tip is repository URL rewriting. This tackles the annoying problem of having submodules in projects that you want to be able to commit to, while making sure other people only see/use the read-only URLs. Git will very helpfully rewrite URLs from one form to another, so by having:</p>
<pre>
<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">[url &quot;ssh://git@github.com/dingram/&quot;]<br />
  pushInsteadOf = git://github.com/dingram/</div></div>
</pre>
<p>in my configuration, I can <code class="codecolorer text default"><span class="text">git clone git://github.com/dingram/repository</span></code> and when I push, it will automatically push to <code class="codecolorer text default"><span class="text">git@github.com:dingram/repository</span></code> instead. This can be verified using <code class="codecolorer text default"><span class="text">git remote -v</span></code>. The only thing to beware of is the format: the replacement URL goes in the section header, and the pattern to be replaced appears in the section itself.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.dmi.me.uk/blog/2010/08/18/useful-git-configuration-fragments/feed/</wfw:commentRss>
		<slash:comments>0</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>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>
		<item>
		<title>Insight: An update</title>
		<link>http://www.dmi.me.uk/blog/2008/06/09/insight-an-update/</link>
		<comments>http://www.dmi.me.uk/blog/2008/06/09/insight-an-update/#comments</comments>
		<pubDate>Mon, 09 Jun 2008 16:29:55 +0000</pubDate>
		<dc:creator>Dave</dc:creator>
				<category><![CDATA[Insight (semantic filesystem)]]></category>
		<category><![CDATA[Personal]]></category>
		<category><![CDATA[University]]></category>

		<guid isPermaLink="false">http://www.dmi.me.uk/blog/?p=56</guid>
		<description><![CDATA[<p>Just a very brief update for the last few days:</p>

Files can now be opened and read &#8211; writing and deletion coming soon!
File import does tend to confuse ln, as it expects the new destination to be a symlink rather than a file. Nothing I can really do about this for now though!
I&#8217;ve manually assigned some tags <a href="http://www.dmi.me.uk/blog/2008/06/09/insight-an-update/">[...]</a>]]></description>
			<content:encoded><![CDATA[<p>Just a very brief update for the last few days:</p>
<ul>
<li>Files can now be opened and read &#8211; writing and deletion coming soon!</li>
<li>File import does tend to confuse ln, as it expects the new destination to be a symlink rather than a file. Nothing I can really do about this for now though!</li>
<li>I&#8217;ve manually assigned some tags to files, and queries now work beautifully (apart from subcategory union, which I hope to tackle later tonight).</li>
<li>Having said that, only simple conjunctive queries work, as there&#8217;s no support for negation or disjunction. Yet.</li>
<li>Inode set functions are now in place and working.</li>
</ul>
<p>One more update before I get back to coding&#8230; Insight now has an official logo!</p>
<p><img class="aligncenter size-full wp-image-57" title="Insight logo (blue)" src="http://www.dmi.me.uk/blog/wp-content/uploads/2008/06/insight_blue_letters.png" alt="Insight logo" width="300" height="100" /></p>
]]></content:encoded>
			<wfw:commentRss>http://www.dmi.me.uk/blog/2008/06/09/insight-an-update/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	<creativeCommons:license>http://creativecommons.org/licenses/by-nc-nd/3.0/</creativeCommons:license>
	</item>
		<item>
		<title>Insight: Where am I now, and where next?</title>
		<link>http://www.dmi.me.uk/blog/2008/06/05/insight-where-am-i-now-and-where-next/</link>
		<comments>http://www.dmi.me.uk/blog/2008/06/05/insight-where-am-i-now-and-where-next/#comments</comments>
		<pubDate>Thu, 05 Jun 2008 23:18:29 +0000</pubDate>
		<dc:creator>Dave</dc:creator>
				<category><![CDATA[Insight (semantic filesystem)]]></category>
		<category><![CDATA[Personal]]></category>
		<category><![CDATA[University]]></category>

		<guid isPermaLink="false">http://www.dmi.me.uk/blog/?p=55</guid>
		<description><![CDATA[<p>So I&#8217;ve been in Deep Coding Mode™ for quite a while. What have I got to show for it?</p>
<p>Well, the short answer is that Insight is now a functioning file system&#8230; for a given definition of &#8220;functioning&#8221;.</p>
<p></p>
<p>As of this morning:</p>

It can successfully import files from the rest of the hierarchy
Tags (i.e. directories) can be created and <a href="http://www.dmi.me.uk/blog/2008/06/05/insight-where-am-i-now-and-where-next/">[...]</a>]]></description>
			<content:encoded><![CDATA[<p>So I&#8217;ve been in Deep Coding Mode™ for quite a while. What have I got to show for it?</p>
<p>Well, the short answer is that <strong>Insight</strong> is now a functioning file system&#8230; for a given definition of &#8220;functioning&#8221;.</p>
<p><span id="more-55"></span></p>
<p>As of this morning:</p>
<ul>
<li>It can successfully import files from the rest of the hierarchy</li>
<li>Tags (i.e. directories) can be created and removed at any level.</li>
<li>Tags appear and disappear more or less as you expect (i.e. if you already have a tag in your path, it won&#8217;t show up in listings again).</li>
<li>Tags that are synonyms will show up as symbolic links to the actual target tag (but currently do not obey the rule in the point above, i.e. if their target has been used in the path, they may still appear).</li>
</ul>
<p>So far, so good. Now for the limitations:</p>
<ul>
<li>Files cannot currently be opened, read from, written to, or deleted.</li>
<li>Files must be imported in a strange manner: as absolute symbolic links. They then show up as regular files, although they are actually just links to the originals elsewhere in the filesystem.</li>
<li>Tags cannot be assigned to files (or removed from them)</li>
<li>Files can therefore only be imported at the root level</li>
<li>Queries have no effect on file listing, and so listings just show files in limbo</li>
<li>Of course, there is no subcategory union either.</li>
</ul>
<p>But I am working on all of these things. At the moment, the main thing is sorting out the internal inode lists. Once those are done, then it should be quite straightforward to do tag assignment/removal and import directly into tags. Plan of action, therefore:</p>
<ol>
<li>Implement inode insertion/deletion</li>
<li>Implement inode set functions (intersection, union, difference)</li>
<li>Re-implement query tree builder from path. Currently only deals with building a basic conjunctive query tree and assumes that all components are tags. Should:
<ul>
<li> Take a path</li>
<li>Canonicalise it</li>
<li>Check path components (left-to-right) to ensure tags exist</li>
<li>If last part is an incomplete tag, treat appropriately</li>
<li>If last part is a complete tag, then fine</li>
<li>If last part does not resolve as a tag, then hash it and see if it translates to a known inode</li>
<li>If not, or if any tags in path do not exist, then path is invalid</li>
<li>If it is a valid inode, then add QUERY_IS_INODE node to tree</li>
<li>Otherwise return query tree</li>
</ul>
</li>
<li>Implement query processing:
<ul>
<li>Given input set of inodes, produce an output set at each node of the query tree.</li>
<li>In trivial case with top-level <tt>IS_ANY</tt> node, output set is the set of limbo inodes, with internal negation flag set to false</li>
<li>With an <tt>IS</tt> node, the output set is the recursive union of the inodes belonging to that tag and its subtags, with internal negation flag set to false</li>
<li>With an <tt>IS_NOSUB</tt> node, the output set is the set of inodes belonging tag, with internal negation flag set to false</li>
<li>With an <tt>IS_INODE</tt> node, the output set contains a single element: the inode.</li>
<li>With an <tt>IS_NOT</tt> node with a subquery, the output set is identical to the subquery resultset, with an internal negation flag inverted</li>
<li>With an <tt>IS_NOT</tt> node with a tag, the output set is the same as for an IS node, with an internal negation flag set to true</li>
<li>An <tt>AND</tt> node output depends on the negation flags of its subqueries:
<ul>
<li>Both false: output is the set intersection of its subqueries, with negation flag clear</li>
<li>Both true: output is union of subqueries, with negation flag set</li>
<li>Otherwise: output is set difference, with the negation-true set removed from the negation-false set, and the negation flag cleared</li>
</ul>
</li>
<li>An <tt>OR</tt> node output depends on the negation flags of its subqueries:
<ul>
<li>Both false: output is union of subquery results, with negation flag clear</li>
<li>Both true: output is intersection of subquery results, with negation flag set</li>
<li>Otherwise: output is <strong><span style="color: #ff0000;">???</span></strong></li>
</ul>
</li>
<li>Probably very likely to be an error if the negation flag is found to be set at the top level.</li>
<li>Also have to think about how to build a tree from a bracketed expression. But later. Much later.</li>
</ul>
</li>
<li>Output of query processing is an inode set.</li>
<li>Maybe low-overhead query processing just to see if an inode would match the query?</li>
<li>Implement open/read/write as pass-through operations on the inode symlink targets.</li>
<li>Implement symlinking directories as creating synonyms.</li>
<li>Add <strong>LOTS</strong> of checks.</li>
<li>Note: also have to track inode reference count, so that when it gets to zero the inode is added to the limbo list. Once removed from there, it is removed from the filesystem completely.</li>
</ol>
<p>These should be quite straightforward to do (I hope), especially as I know more or less exactly what I&#8217;m doing. Deadlines are closing in, however, and I have a report and presentation and demo to write yet. Hopefully I can get much of this done by Tuesday, then can spend the day doing bits of my report.</p>
<p>I must say that I do love developing this. It&#8217;s just so amazing to be developing a file system and see it work!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.dmi.me.uk/blog/2008/06/05/insight-where-am-i-now-and-where-next/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
	<creativeCommons:license>http://creativecommons.org/licenses/by-nc-nd/3.0/</creativeCommons:license>
	</item>
		<item>
		<title>Insight: The current plan</title>
		<link>http://www.dmi.me.uk/blog/2008/05/19/insight-the-current-plan/</link>
		<comments>http://www.dmi.me.uk/blog/2008/05/19/insight-the-current-plan/#comments</comments>
		<pubDate>Mon, 19 May 2008 12:51:03 +0000</pubDate>
		<dc:creator>Dave</dc:creator>
				<category><![CDATA[Insight (semantic filesystem)]]></category>
		<category><![CDATA[University]]></category>

		<guid isPermaLink="false">http://www.dmi.me.uk/blog/?p=54</guid>
		<description><![CDATA[<p>As it comes time to work on my project again, it&#8217;s time to take stock and work out what my plan of action should be.</p>
<p>Looking at the code I have already, I think it&#8217;s clear that there is no way I will be able to write a kernel-level file system driver within the 2-3 weeks I <a href="http://www.dmi.me.uk/blog/2008/05/19/insight-the-current-plan/">[...]</a>]]></description>
			<content:encoded><![CDATA[<p>As it comes time to work on my project again, it&#8217;s time to take stock and work out what my plan of action should be.</p>
<p>Looking at the code I have already, I think it&#8217;s clear that there is no way I will be able to write a kernel-level file system driver within the 2-3 weeks I have left. Fortunately, I had more or less expected this (as writing kernel code would be likely to take quite a while and be quite complex!) so I&#8217;m retreating to my fallback position: a FUSE-wrapped program that will interface with the metadata store.</p>
<p>Also on the cards is the use of <a href="http://check.sourceforge.net/" target="_blank">Check</a> as a C unit testing framework for my tree code &#8211; if I have time. At the moment, getting something to work is far more important than proving it is correct or works in all cases.</p>
<p>Finally, I need to come up with and write the demo programs, and I will shortly be posting about this and then asking the Twitterverse for ideas <img src='http://www.dmi.me.uk/blog/wp-includes/images/smilies/icon_smile.gif' alt=':-)' class='wp-smiley' title="icon smile photo" /> </p>
<p>Time to enter Deep Coding Mode.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.dmi.me.uk/blog/2008/05/19/insight-the-current-plan/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	<creativeCommons:license>http://creativecommons.org/licenses/by-nc-nd/3.0/</creativeCommons:license>
	</item>
		<item>
		<title>No more exams!</title>
		<link>http://www.dmi.me.uk/blog/2008/05/16/no-more-exams/</link>
		<comments>http://www.dmi.me.uk/blog/2008/05/16/no-more-exams/#comments</comments>
		<pubDate>Fri, 16 May 2008 10:00:09 +0000</pubDate>
		<dc:creator>Dave</dc:creator>
				<category><![CDATA[Life]]></category>
		<category><![CDATA[Personal]]></category>
		<category><![CDATA[University]]></category>

		<guid isPermaLink="false">http://www.dmi.me.uk/blog/?p=52</guid>
		<description><![CDATA[<p>So my exams have finally finished&#8230; it&#8217;s a very surreal feeling. Still got the project to go, but my time at university is even closer to being over. I don&#8217;t think it&#8217;s really sunk in yet.</p>
<p>Once the exam was over, a group of us headed to get some drinks, and came away with four bottles of <a href="http://www.dmi.me.uk/blog/2008/05/16/no-more-exams/">[...]</a>]]></description>
			<content:encoded><![CDATA[<p>So my exams have finally finished&#8230; it&#8217;s a very surreal feeling. Still got the project to go, but my time at university is even closer to being over. I don&#8217;t think it&#8217;s really sunk in yet.</p>
<p>Once the exam was over, a group of us headed to get some drinks, and came away with four bottles of cheap <span style="text-decoration: line-through;">champagne</span> sparkling white wine (&#8220;We&#8217;ve just finished our exams and want quantity over quality. What have you got?&#8221;) and headed to the Union to consume it. Sadly things got slightly out of hand there, but I eventually headed back home after completely failing to work out how I could get to Camden (because I managed to completely forget the Tube existed).</p>
<p>Came back after the post-exam celebrations to find these stashed in the kitchen:</p>
<p><a href="http://www.dmi.me.uk/blog/wp-content/uploads/2008/05/dsc01157.jpg"><img class="aligncenter size-medium wp-image-53" title="Old Rosie cider" src="http://www.dmi.me.uk/blog/wp-content/uploads/2008/05/dsc01157-300x225.jpg" alt="Six 2L bottles of Old Rosie scrumpy" width="300" height="225" /></a></p>
<p>My cider has arrived!</p>
<p>So, next stop: project. The due date now seems incredibly close!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.dmi.me.uk/blog/2008/05/16/no-more-exams/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	<creativeCommons:license>http://creativecommons.org/licenses/by-nc-nd/3.0/</creativeCommons:license>
	</item>
		<item>
		<title>Life moves on</title>
		<link>http://www.dmi.me.uk/blog/2008/04/23/life-moves-on/</link>
		<comments>http://www.dmi.me.uk/blog/2008/04/23/life-moves-on/#comments</comments>
		<pubDate>Wed, 23 Apr 2008 00:01:39 +0000</pubDate>
		<dc:creator>Dave</dc:creator>
				<category><![CDATA[Life]]></category>
		<category><![CDATA[Personal]]></category>
		<category><![CDATA[Work]]></category>

		<guid isPermaLink="false">http://www.dmi.me.uk/blog/?p=49</guid>
		<description><![CDATA[<p>Wow, it&#8217;s been a long time since I&#8217;ve updated anything here. Insight is moving along, but has currently stalled while I&#8217;m in exam mode. I&#8217;m not going to talk about that though — this is a rare personal post.</p>
<p>I&#8217;ve been looking around for jobs recently, as I will need something to bring in money after I <a href="http://www.dmi.me.uk/blog/2008/04/23/life-moves-on/">[...]</a>]]></description>
			<content:encoded><![CDATA[<p>Wow, it&#8217;s been a long time since I&#8217;ve updated anything here. Insight is moving along, but has currently stalled while I&#8217;m in exam mode. I&#8217;m not going to talk about that though — this is a rare personal post.</p>
<p><span id="more-49"></span>I&#8217;ve been looking around for jobs recently, as I will need something to bring in money after I finish at uni in just over two short months. I had originally planned to work for a company based on Slough with one of my housemates, until I received an offer from an ex-Oxford entrepreneur friend. After meeting this friend and his team within just a day or two of the email, I was very excited at the possibility of working with them, especially as I kept having ideas or suggestions for them.</p>
<p>I knew I would have to wait a while for their response, as they had to okay it with their board, and they weren&#8217;t planning on deciding on a new hire for some time. As the days fluttered by towards the deadline for this other company and these friends flew out to Silicon Valley for Web Mission, I grew more nervous, hoping that they would get back to me with at least some sort of reply&#8230; until yesterday.</p>
<p>I had a phone call (at 7:45am his time) from my main contact there saying they would like to make me an offer! I was overjoyed at this, and was told we&#8217;d have a chat later that evening with details. Later that evening, and after some thought, I decided that this definitely was the right path for me, so I resolved to accept the offer.</p>
<p style="text-align: center;"><a href="http://www.groupspaces.com"><img class="aligncenter" src=" http://www.crunchbase.com/assets/images/resized/0001/6833/16833v3-max-250x250.png" alt="GroupSpaces logo" width="250" height="65" title="16833v3 max 250x250 photo" /></a></p>
<p>It is with great pleasure that I announce that I am now the fourth member of the <a title="GroupSpaces" href="http://www.groupspaces.com/" target="_blank">GroupSpaces</a> team <img src='http://www.dmi.me.uk/blog/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' title="icon smile photo" />  I start on or around 30th June, and I&#8217;m really, really excited about it! I&#8217;ll be moving to Oxford, and living and working there. I can&#8217;t wait to start!</p>
<p>Exams begin soon, though. 30th April &#8211; 15th May.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.dmi.me.uk/blog/2008/04/23/life-moves-on/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	<creativeCommons:license>http://creativecommons.org/licenses/by-nc-nd/3.0/</creativeCommons:license>
	</item>
	</channel>
</rss>
