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

<channel>
	<title>MoMolog</title>
	<atom:link href="http://momolog.info/feed/" rel="self" type="application/rss+xml" />
	<link>http://momolog.info</link>
	<description>MoMolog aus Berlin stellt sich vor. Projekte, Ideen, Referenzen.</description>
	<lastBuildDate>Sun, 18 Jul 2010 22:13:17 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0</generator>
		<item>
		<title>Copying Files between S3 buckets</title>
		<link>http://momolog.info/2010/07/08/copying-files-between-s3-buckets/</link>
		<comments>http://momolog.info/2010/07/08/copying-files-between-s3-buckets/#comments</comments>
		<pubDate>Thu, 08 Jul 2010 10:27:26 +0000</pubDate>
		<dc:creator>aljoscha</dc:creator>
				<category><![CDATA[AWS]]></category>
		<category><![CDATA[Ruby]]></category>

		<guid isPermaLink="false">http://momolog.info/?p=268</guid>
		<description><![CDATA[Building on this article here is a simple ruby script, that copies files between two buckets of the same S3 account, omitting files already present (by name). This variant adds a list of path prefixes, so you can selectively copy only certain directories of your buckets. Furthermore it copies the original buckets ACLs for each [...]]]></description>
			<content:encoded><![CDATA[<p>Building on <a href="http://www.lakedenman.com/2009/10/27/copying-files-between-s3-buckets.html">this article</a> here is a simple ruby script, that copies files between two buckets of the same S3 account, omitting files already present (by name).<br />
This variant adds a list of path prefixes, so you can selectively copy only certain directories of your buckets.<br />
Furthermore it copies the original buckets ACLs for each key.</p>
<p><pre><code>
require &#039;rubygems&#039;
require &#039;right_aws&#039;

aws_access_key_id&nbsp;&nbsp;&nbsp;&nbsp; = &#039;YOUR AMAZON ACCESS KEY&#039;
aws_secret_access_key = &#039;YOUR AMAZON SECRET ACCESS KEY&#039;
source_bucket&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; = &#039;SOURCE BUCKET NAME&#039;
target_bucket&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; = &#039;TARGET BUCKET NAME&#039;
prefixes&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;= [PATH_PREFIX1, PATH_PREFIX2, ...]

s3 = RightAws::S3Interface.new(aws_access_key_id, aws_secret_access_key)

copied_keys = Array.new
(prefixes || [&#039;&#039;]).each do |prefix|
&nbsp;&nbsp;s3.incrementally_list_bucket(target_bucket, {:prefix =&gt; prefix}) do |key_set|
&nbsp;&nbsp;&nbsp;&nbsp;copied_keys &lt;&lt; key_set[:contents].map{|k| k[:key]}.flatten
&nbsp;&nbsp;end
end
copied_keys.flatten!

(prefixes || [&#039;&#039;]).each do |prefix|
&nbsp;&nbsp;s3.incrementally_list_bucket(source_bucket, {:prefix =&gt; prefix}) do |key_set|
&nbsp;&nbsp;&nbsp;&nbsp;key_set[:contents].each do |key|
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;key = key[:key]
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if copied_keys.include?(key)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;puts &quot;#{target_bucket} #{key} already exists. Skipping...&quot;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;puts &quot;Copying #{source_bucket} #{key}, setting acl&quot;

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;retries=0
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;begin
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;s3.copy(source_bucket, key, target_bucket)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;acl = s3.get_acl(source_bucket, key)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;s3.put_acl(target_bucket, key, acl[:object])
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;rescue Exception =&gt; e
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;puts &quot;cannot copy key, #{e.inspect}\nretrying #{retries} out of 10 times...&quot;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;retries += 1
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;retry if retries &lt;= 10
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end
&nbsp;&nbsp;&nbsp;&nbsp;end
&nbsp;&nbsp;end
end
</code></pre></p>
]]></content:encoded>
			<wfw:commentRss>http://momolog.info/2010/07/08/copying-files-between-s3-buckets/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>MomoFlow</title>
		<link>http://momolog.info/2009/11/28/momoflow/</link>
		<comments>http://momolog.info/2009/11/28/momoflow/#comments</comments>
		<pubDate>Sat, 28 Nov 2009 10:26:22 +0000</pubDate>
		<dc:creator>aljoscha</dc:creator>
				<category><![CDATA[Allgemein]]></category>
		<category><![CDATA[Javascript]]></category>

		<guid isPermaLink="false">http://momolog.info/?p=219</guid>
		<description><![CDATA[Coverflow has become a de facto visualization standard for the presentation of collections of images, be it covers or portraits. There are a number of implementations for usage on web pages (e.g. this one) but the usable ones require Adobes Flash and thus won&#8217;t run on the iPhone. When looking for HTML5 canvas based implementations [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://en.wikipedia.org/wiki/Cover_Flow">Coverflow</a> has become a  de facto visualization standard for the presentation of collections of images, be it covers or portraits.<br />
There are a number of implementations for usage on web pages (e.g. <a href="http://www.flashloaded.com/flashcomponents/photoflow/example1.html">this one</a>) but the usable ones require Adobes Flash and thus won&#8217;t run on the iPhone.</p>
<p>When looking for HTML5 canvas based implementations I found <a href="http://elmasse.gaver.nl/projects/Coverflow0.1/test.html">this promising implementation</a> based on the YUI library.<br />
Though workig, it has three major drawbacks: It is rather overengineered and difficult to tweak, it uses YUI (whereas I prefer the more lightweight jQuery) and it performs poorly with image sizes bigger than thumbnails.</p>
<p>After trying to change the code for a while I decided to do a reimplementation in jQuery. The result can be seen on the <a href="http://flow.momolog.info">MomoFlow demo page</a>. Here are two screenshots:</p>
<p><div id="attachment_229" class="wp-caption aligncenter" style="width: 310px"><img class="size-medium wp-image-229" title="MomoFlow I" src="http://momolog.info/wp-content/uploads/2009/11/Bildschirmfoto-2009-11-22-um-09.01.33-300x240.png" alt="CoverFlow using canvas and jQuery" width="300" height="240" /><p class="wp-caption-text">CoverFlow using canvas and jQuery</p></div></p>
<p><div id="attachment_226" class="wp-caption aligncenter" style="width: 310px"><img class="size-medium wp-image-226" title="MomoFlow II" src="http://momolog.info/wp-content/uploads/2009/11/Bildschirmfoto-2009-11-22-um-09.01.20-300x240.png" alt="Quicklook mode" width="300" height="240" /><p class="wp-caption-text">Quicklook mode</p></div></p>
<p>The used 3D transformation is superbly described on the <a href="http://yuiblog.com/blog/2008/06/23/slicing/">YUI blog</a> .</p>
<p>My implementation caches the rendered canvases per rendering angle. Further speed increments are made possible by adjusting the mesh width used for the slicing transformation depending on the achieved framerate.</p>
<p>The result performs beautifully in recent Safari, Chrome and Opera, decently on Firefox. It also works flawlessly on the iPhone. Keyboard control is coming soon.</p>
<p>I do still need help on IE, maybe the image composition is too demanding for <a href="http://excanvas.sourceforge.net/">ExplorerCanvas</a>? <br />
The code is available on github: <a href="http://github.com/momolog/momoflow">http://github.com/momolog/momoflow</a>.<br />
Comments and improvements are very much welcome!</p>
]]></content:encoded>
			<wfw:commentRss>http://momolog.info/2009/11/28/momoflow/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>MySQL BEFORE INSERT trigger as check constraint</title>
		<link>http://momolog.info/2009/10/21/mysql-before-insert-trigger-as-check-constraint/</link>
		<comments>http://momolog.info/2009/10/21/mysql-before-insert-trigger-as-check-constraint/#comments</comments>
		<pubDate>Wed, 21 Oct 2009 09:03:55 +0000</pubDate>
		<dc:creator>aljoscha</dc:creator>
				<category><![CDATA[Allgemein]]></category>

		<guid isPermaLink="false">http://momolog.info/?p=212</guid>
		<description><![CDATA[Since MySQL does neither have real check constraints nor a way to raise an exception in a stored procedure, we found it not instantly obvious, how we could *reject* a certain row on insert, based on a certain condition. A nice way we found was to set the value in question to NULL, based on [...]]]></description>
			<content:encoded><![CDATA[<p>Since MySQL does neither have real check constraints nor a way to raise an exception in a stored procedure, we found it not instantly obvious, how we could *reject* a certain row on insert, based on a certain condition.</p>
<p>A nice way we found was to set the value in question to NULL, based on the condition and let the NOT NULL constraint do its work.</p>
<p><pre><pre>
ALTER TABLE sessions MODIFY session_id varchar(255) NOT NULL;
DROP TRIGGER IF EXISTS check_sessionid;
DELIMITER $$
CREATE TRIGGER check_sessionid BEFORE INSERT ON sessions&nbsp;&nbsp;
FOR EACH ROW BEGIN
&nbsp;&nbsp;IF NOT NEW.session_id REGEXP &#039;^[[:xdigit:]]{32}$&#039; THEN
&nbsp;&nbsp;&nbsp;&nbsp;SET NEW.session_id = NULL;
&nbsp;&nbsp;END IF;
END;
$$
DELIMITER ;
</pre></pre><br />
The trigger will let any 32 character string with only HEX characters for the column session_id pass and rejects the rest.<br />
<pre><pre>
&gt; INSERT INTO sessions (session_id) VALUES (&#039;ffffffffffffffffffffffffffffffff&#039;);
Query OK, 1 row affected (0.01 sec)
</pre></pre><br />
<pre><pre>
&gt; INSERT INTO sessions (session_id) VALUES (&#039;fffffffffffffffffffffffffffffffg&#039;);
ERROR 1048 (23000): Column &#039;session_id&#039; cannot be null
</pre></pre><br />
Happy triggering.</p>
]]></content:encoded>
			<wfw:commentRss>http://momolog.info/2009/10/21/mysql-before-insert-trigger-as-check-constraint/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Vor kurzem dazugelernt:</title>
		<link>http://momolog.info/2009/10/18/vor-kurzem-dazugelernt/</link>
		<comments>http://momolog.info/2009/10/18/vor-kurzem-dazugelernt/#comments</comments>
		<pubDate>Sun, 18 Oct 2009 15:46:19 +0000</pubDate>
		<dc:creator>aljoscha</dc:creator>
				<category><![CDATA[Allgemein]]></category>
		<category><![CDATA[MacOSX]]></category>
		<category><![CDATA[Note to self]]></category>
		<category><![CDATA[Ruby]]></category>

		<guid isPermaLink="false">http://momolog.info/?p=204</guid>
		<description><![CDATA[Suche nach Wort unter dem Cursor in vim: #. jssh ist eine JavaScript Shell, die den Firefox per Port 9997 fernsteuerbar macht. Download z.B. hier. y erzeugt einen YAML dump auf der Rails console, mehr dazu hier. =3D ist ein escaptes &#8220;=&#8221; in quoted_printable. sudo /usr/libexec/locate.updatedb aktualisiert unter MacOSX sofort die locate Datenbank. rake db:migrate:redo [...]]]></description>
			<content:encoded><![CDATA[<p>Suche nach Wort unter dem Cursor in vim: <code>#</code>.</p>
<p><code>jssh</code> ist eine JavaScript Shell, die den Firefox per Port 9997 fernsteuerbar macht.<br />
Download z.B. <a href="http://wiki.openqa.org/display/WTR/FireWatir+Installation">hier</a>.</p>
<p><code>y</code> erzeugt einen YAML dump auf der Rails console, mehr dazu <a href="http://blog.floehopper.org/articles/2006/12/22/rails-console-shortcuts">hier</a>.</p>
<p><code>=3D</code> ist ein escaptes &#8220;=&#8221; in <a href="http://de.wikipedia.org/wiki/Quoted-printable">quoted_printable</a>.</p>
<p><code>sudo /usr/libexec/locate.updatedb</code> aktualisiert unter MacOSX sofort die <code>locate</code> Datenbank.</p>
<p><code>rake db:migrate:redo</code> führt unter rails die letzte Migration rückwärts und sofort wieder vorwärts aus, so dass sich die Vorwärts-Action korrigieren läßt </p>
<p><code>ack -Q</code> bringt <a href="http://betterthangrep.com/">ack</a> dazu, <em>literal</em>, also ohne RegExp zu suchen.</p>
]]></content:encoded>
			<wfw:commentRss>http://momolog.info/2009/10/18/vor-kurzem-dazugelernt/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>MacOSX Boot-Tastenkombinationen: single user, verbose, safe</title>
		<link>http://momolog.info/2009/10/01/single-user-vs-verbose-vs-safe/</link>
		<comments>http://momolog.info/2009/10/01/single-user-vs-verbose-vs-safe/#comments</comments>
		<pubDate>Thu, 01 Oct 2009 09:24:26 +0000</pubDate>
		<dc:creator>aljoscha</dc:creator>
				<category><![CDATA[MacOSX]]></category>
		<category><![CDATA[Note to self]]></category>

		<guid isPermaLink="false">http://momolog.info/?p=187</guid>
		<description><![CDATA[In den single user mode (root shell) starten, beim Neustart: &#60;Cmd&#62;s In den verbose mode (boot log) starten: &#60;Cmd&#62;v In den safe mode (nur core kexts) starten: &#60;Shift&#62;]]></description>
			<content:encoded><![CDATA[<p>In den <a href="http://support.apple.com/kb/HT1492">single user mode (root shell)</a> starten, beim Neustart:<br />
<pre><code>&lt;Cmd&gt;s
</code></pre><br />
In den <a href="http://support.apple.com/kb/HT1492">verbose mode (boot log)</a> starten:<br />
<pre><code>&lt;Cmd&gt;v
</code></pre><br />
In den <a href="http://support.apple.com/kb/HT1564">safe mode (nur core kexts)</a> starten:<br />
<pre><code>&lt;Shift&gt;
</code></pre></p>
]]></content:encoded>
			<wfw:commentRss>http://momolog.info/2009/10/01/single-user-vs-verbose-vs-safe/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Javascript function names</title>
		<link>http://momolog.info/2009/09/04/javascript-function-names/</link>
		<comments>http://momolog.info/2009/09/04/javascript-function-names/#comments</comments>
		<pubDate>Fri, 04 Sep 2009 09:05:36 +0000</pubDate>
		<dc:creator>aljoscha</dc:creator>
				<category><![CDATA[Javascript]]></category>

		<guid isPermaLink="false">http://momolog.info/?p=149</guid>
		<description><![CDATA[Javascript allows naming and assigning functions at the same time like: var vname = function fname() {} The function name fname is available only inside the function as a local variable: var vname = function fname(){ &#160;&#160;console.log(typeof vname);&#160;&#160;// function &#160;&#160;console.log(typeof fname);&#160;&#160;// function } console.log(typeof vname);&#160;&#160;&#160;&#160;// function console.log(typeof fname);&#160;&#160;&#160;&#160;// undefined If we &#8220;redefine&#8221; this local variable [...]]]></description>
			<content:encoded><![CDATA[<p>Javascript allows naming and assigning functions at the same time like:<br />
<pre>var vname = function fname() {}</pre><br />
The function name <code>fname</code> is available only <em>inside</em> the function as a local variable:<br />
<pre><pre>
var vname = function fname(){
&nbsp;&nbsp;console.log(typeof vname);&nbsp;&nbsp;// function
&nbsp;&nbsp;console.log(typeof fname);&nbsp;&nbsp;// function
}
console.log(typeof vname);&nbsp;&nbsp;&nbsp;&nbsp;// function
console.log(typeof fname);&nbsp;&nbsp;&nbsp;&nbsp;// undefined
</pre></pre><br />
If we &#8220;redefine&#8221; this local variable inside of the function, we get a strange effect:<br />
<pre><pre>
var vname = function fname(){
&nbsp;&nbsp;console.log(typeof vname);&nbsp;&nbsp;// function
&nbsp;&nbsp;console.log(typeof fname);&nbsp;&nbsp;// undefined !!!
&nbsp;&nbsp;var fname = 1;
&nbsp;&nbsp;console.log(typeof fname);&nbsp;&nbsp;// number
}
console.log(typeof vname);&nbsp;&nbsp;&nbsp;&nbsp;// function
console.log(typeof fname);&nbsp;&nbsp;&nbsp;&nbsp;// undefined
</pre></pre><br />
Obviously the interpreter  sees the variable declaration <code>var fname</code> </em>on entrance</em> into the function and does not provide the function variable at all.</p>
]]></content:encoded>
			<wfw:commentRss>http://momolog.info/2009/09/04/javascript-function-names/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Accidentally unpacked a jar into home dir?</title>
		<link>http://momolog.info/2009/08/27/accidentally-unpacked-a-jar-into-home-dir/</link>
		<comments>http://momolog.info/2009/08/27/accidentally-unpacked-a-jar-into-home-dir/#comments</comments>
		<pubDate>Thu, 27 Aug 2009 09:01:08 +0000</pubDate>
		<dc:creator>aljoscha</dc:creator>
				<category><![CDATA[Note to self]]></category>

		<guid isPermaLink="false">http://momolog.info/2009/08/27/accidentally-unpacked-a-jar-into-home-dir/</guid>
		<description><![CDATA[find . -newerBt &#039;10 minutes ago&#039; -depth 1 -print&#160;&#160; 2&#62;/dev/null]]></description>
			<content:encoded><![CDATA[<p><code>find . -newerBt &#039;10 minutes ago&#039; -depth 1 -print&nbsp;&nbsp; 2&gt;/dev/null</code></p>
]]></content:encoded>
			<wfw:commentRss>http://momolog.info/2009/08/27/accidentally-unpacked-a-jar-into-home-dir/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Atomares Einfügen in PostgreSQL &#124; Teil 2</title>
		<link>http://momolog.info/2009/06/24/atomares-einfugen-in-postgresql-teil-2/</link>
		<comments>http://momolog.info/2009/06/24/atomares-einfugen-in-postgresql-teil-2/#comments</comments>
		<pubDate>Wed, 24 Jun 2009 19:59:24 +0000</pubDate>
		<dc:creator>aljoscha</dc:creator>
				<category><![CDATA[Postgresql]]></category>

		<guid isPermaLink="false">http://momolog.info/?p=113</guid>
		<description><![CDATA[Die im vorletzten Artikel vorgestellte Lösung hat den Nachteil, den ganzen Table my_table zu locken. Das ist dann ein Problem, wenn criterion mittels unique constraint eindeutig gemacht wird und nach der Funktion eine zeitaufwendige Funktion (z.B. eine Suche) in derselben Transaktion folgt: Dann warten nämlich alle Prozesse, die ein findOrCreate machen wollen, unabhängig mit welchem [...]]]></description>
			<content:encoded><![CDATA[<p>Die im vorletzten Artikel vorgestellte Lösung hat den Nachteil, den ganzen Table <code>my_table</code> zu locken.<br />
Das ist dann ein Problem, wenn <code>criterion</code> mittels unique constraint eindeutig gemacht wird und nach der Funktion eine zeitaufwendige Funktion (z.B. eine Suche) in derselben Transaktion folgt: Dann warten nämlich alle Prozesse, die ein <code>findOrCreate</code> machen wollen, unabhängig mit welchem Wert für <code>criterion</code>, auf den Abschluss der ersten Transaktion, da erst zu diesem Zeitpunkt sichergestellt werden kann, dass die Spalte wirklich unique ist.</p>
<p>Eigentlich sollte es aber möglich sein, dass parallele Transaktionen mit <em>anderen</em> Werten für <code>criterion</code> unbehelligt ausgeführt werden.<br />
Mit dem folgenden, von Martin Heistermann und Stephan Lüderitz vorgeschlagenen Ansatz, umgeht man dieses Problem elegant:<br />
<pre><pre>
CREATE OR REPLACE FUNCTION findOrCreate(
  IN criterion_in text,
  OUT record_id integer, OUT is_new bool) AS
$$
DECLARE
BEGIN
    INSERT INTO
      my_table (criterion)
    VALUES
      (criterion_in)
    RETURNING id INTO record_id;
    SELECT true INTO is_new;
EXCEPTION
    WHEN unique_violation THEN
        SELECT false, id into is_new, record_id FROM my_table 
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;WHERE criterion=criterion_in;
END
$$ language plpgsql;
</pre></pre></p>
<p>Wie in <a href="http://www.postgresql.org/files/developer/concurrency.pdf">dieser Präsentation (PDF)</a> beschrieben, läßt PostgreSQL das parallele Einfügen <em>verschiedener</em> Werte mittels <code>findOrCreate</code> zu, zwingt aber bei zwei Transaktionen, die <em>denselben</em> Wert einfügen wollen, die zweite, mit dem Insert auf das Ende der ersten zu warten. </p>
<p>Findet die (potentiell teure) Suche in der Transaktion <em>nach</em> findOrCreate statt, wird diese gar nicht mehr ausgeführt, da findOrCreate per Exception die von der ersten Transaktion neu eingefügte Zeile ermittelt und gleich mit deren Ergebnissen weitermachen kann.</p>
]]></content:encoded>
			<wfw:commentRss>http://momolog.info/2009/06/24/atomares-einfugen-in-postgresql-teil-2/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Du bist Terrorist.</title>
		<link>http://momolog.info/2009/05/19/du-bist-terrorist/</link>
		<comments>http://momolog.info/2009/05/19/du-bist-terrorist/#comments</comments>
		<pubDate>Tue, 19 May 2009 19:57:16 +0000</pubDate>
		<dc:creator>aljoscha</dc:creator>
				<category><![CDATA[Allgemein]]></category>

		<guid isPermaLink="false">http://momolog.info/?p=111</guid>
		<description><![CDATA[Kampagne gegen Terroristen in Deutschland. Sehr schön.]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.dubistterrorist.de">Kampagne gegen Terroristen in Deutschland</a>. Sehr schön.</p>
]]></content:encoded>
			<wfw:commentRss>http://momolog.info/2009/05/19/du-bist-terrorist/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Atomares Einfügen in PostgreSQL</title>
		<link>http://momolog.info/2009/05/16/atomares-einfugen-in-postgresql/</link>
		<comments>http://momolog.info/2009/05/16/atomares-einfugen-in-postgresql/#comments</comments>
		<pubDate>Sat, 16 May 2009 15:31:26 +0000</pubDate>
		<dc:creator>aljoscha</dc:creator>
				<category><![CDATA[Postgresql]]></category>

		<guid isPermaLink="false">http://momolog.info/?p=15</guid>
		<description><![CDATA[Oft steht man vor dem Problem, einen Datensatz anhand eines Kriteriums zu finden bzw. ihn, falls nicht vorhanden, einzufügen. Bei derartigen Operationen ist es wichtig darauf zu achten, dass nicht mehrere Prozesse, die quasi gleichzeitig diesen Datensatz suchen, eine race condition hervorrufen. Hier eine Lösung mittels stored procedure für postgresql. Dabei wird eine race condition [...]]]></description>
			<content:encoded><![CDATA[<p>Oft steht man vor dem Problem, einen Datensatz anhand eines Kriteriums zu finden bzw. ihn, falls nicht vorhanden, einzufügen. Bei derartigen Operationen ist es wichtig darauf zu achten, dass nicht mehrere Prozesse, die quasi gleichzeitig diesen Datensatz suchen, eine <a href="http://de.wikipedia.org/wiki/Race_Condition">race condition</a> hervorrufen.<br />
Hier eine Lösung mittels stored procedure für postgresql. Dabei wird eine race condition zwischen Suche und Einfügen vermieden und nur minimales Locking gebraucht:<br />
<pre><pre>
CREATE OR REPLACE FUNCTION findOrCreate(
&nbsp;&nbsp;IN criterion_in text, 
&nbsp;&nbsp;OUT id int, OUT is_new bool) AS 
$$
DECLARE 
BEGIN
&nbsp;&nbsp;LOCK TABLE my_table;
&nbsp;&nbsp;SELECT false, id FROM my_table WHERE criterion=criterion_in INTO is_new, id;

&nbsp;&nbsp;IF id IS NULL THEN
&nbsp;&nbsp;&nbsp;&nbsp;INSERT INTO 
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;my_table (criterion) 
&nbsp;&nbsp;&nbsp;&nbsp;VALUES 
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(criterion_in) 
&nbsp;&nbsp;&nbsp;&nbsp;RETURNING id INTO id;
&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;SELECT true INTO is_new;
&nbsp;&nbsp;END IF;

&nbsp;&nbsp;RETURN;
END
$$ language plpgsql;
</pre></pre><br />
Man beachte die praktischen OUT-Parameter, die es ermöglichen, diese Funktion wie folgt aufzurufen:<br />
<pre><pre>
SELECT id, is_new FROM findOrCreate(criterion);
</pre></pre><br />
Rückgabewerte sind <code>id</code> und <code>is_new</code>, die einem die Datenbank-Id angeben, und ob diese neu angelegt wurde.</p>
<p>Der Table-Lock wird beim Beenden der Funktion (die immer implizit eine Transaktion ist) automatisch beendet.</p>
]]></content:encoded>
			<wfw:commentRss>http://momolog.info/2009/05/16/atomares-einfugen-in-postgresql/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
