<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-5635587370432045273</id><updated>2012-01-07T14:51:38.477+01:00</updated><category term='ruby'/><category term='io'/><category term='lisp'/><category term='terracotta'/><category term='c/c++'/><category term='mnapi'/><category term='java'/><category term='python'/><category term='go'/><category term='erlang'/><category term='php'/><category term='mnesia'/><title type='text'>Web λ.0 - Functional programming for the Web</title><subtitle type='html'>"If the only tool you have is a hammer, you tend to see every problem as a nail." - Abraham Maslov</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://weblambdazero.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5635587370432045273/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://weblambdazero.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Krzysztof Kliś</name><uri>http://www.blogger.com/profile/03518001329895236884</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://2.bp.blogspot.com/_CVm77bq8jjg/SNva5QYjDLI/AAAAAAAAABE/NKuv0JSEKuM/S220/calder.jpg'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>44</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-5635587370432045273.post-220589232898405792</id><published>2011-11-02T10:05:00.003+01:00</published><updated>2011-11-02T11:01:05.880+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='go'/><title type='text'>Gomemcache with multiget support</title><content type='html'>It's my pleasure to announce that &lt;a href="http://github.com/kklis/gomemcache/"&gt;gomemcache&lt;/a&gt; already has six contributors that have supplied changes and fixes to the original code base. A recent patch by Arbo von Monkiewitsch adds GetMulti() function that allows fetching values for multiple keys with one function call.&lt;br /&gt;As a side note, one thrid of patches, as well as a few of my commits, are purely compatibility fixes for subsequent &lt;a href="http://golang.org/"&gt;Go&lt;/a&gt; releases. I think that at the moment frequent changes to the standard libraries and the language core are the main blocker preventing wide adoption of Go by the IT industry.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5635587370432045273-220589232898405792?l=weblambdazero.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://weblambdazero.blogspot.com/feeds/220589232898405792/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5635587370432045273&amp;postID=220589232898405792' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5635587370432045273/posts/default/220589232898405792'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5635587370432045273/posts/default/220589232898405792'/><link rel='alternate' type='text/html' href='http://weblambdazero.blogspot.com/2011/11/gomemcache-with-multiget-support.html' title='Gomemcache with multiget support'/><author><name>Krzysztof Kliś</name><uri>http://www.blogger.com/profile/03518001329895236884</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://2.bp.blogspot.com/_CVm77bq8jjg/SNva5QYjDLI/AAAAAAAAABE/NKuv0JSEKuM/S220/calder.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5635587370432045273.post-8204102772071426456</id><published>2011-09-16T14:29:00.009+02:00</published><updated>2011-09-21T14:56:50.425+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='c/c++'/><title type='text'>Human factor</title><content type='html'>Having recently moved to a netbook, I realized again how important performance is for software development. I realized it even more when my Android phone became almost unusable after another software upgrade. As a kid I was a big fan of a &lt;a href="http://en.wikipedia.org/wiki/Demoscene"&gt;computer demoscene&lt;/a&gt; where gifted coders showed to the world how to make the hardware do things unimaginable even by its creators (like a famous &lt;a href="http://en.wikipedia.org/wiki/Commodore_64_demos"&gt;Commodore 64 FLI graphic mode&lt;/a&gt;). Now when the number of small devices connected to the Internet &lt;a href="http://www.osnn.net/submitted-news/100379-5-billion-devices-connected-internet.html"&gt;exceeds the number of computers and laptops&lt;/a&gt; wired to the global network, writing efficient software is a must: Facebook developes HipHop for PHP (written in C++), Google releases Native Development Kit for Android and makes Go the first compiled programming language available for the Google App Engine platform.&lt;br /&gt;&lt;br /&gt;It is commonly argued that ANSI C is the "fastest programming language" that exists. No it's not. The language itself is neither slow nor fast, it's the implementations that are (compare Ruby and JRuby for example). However, it's true that software written in C can be usually compiled to the &lt;a href="http://shootout.alioth.debian.org/u32/which-programming-languages-are-fastest.php"&gt;most efficient executable code&lt;/a&gt; (excluding pure assembly). No wonder that the most efficient pieces of software, like operating system kernels (Linux, BSD, Solaris, Windows, etc) or programming language VMs (Common Lisp, Python, PHP, Ruby, and even Java) are all written almost exclusively in C (not even C++).&lt;br /&gt;&lt;br /&gt;Out of curiosity I started to look around for web software written in C and found a wonderful web server called &lt;a href="http://g-wan.com/"&gt;G-Wan&lt;/a&gt;. It's very small and its performance looks really amazing as &lt;a href="http://g-wan.com/benchmark"&gt;compared to other web servers&lt;/a&gt; - some enthusiastic reviews even call it &lt;a href="http://salem-news.com/articles/august082011/g-wan-internet-ew.php"&gt;The Future of the Internet&lt;/a&gt; and wonder why such a brilliant software is not popular. Well, G-Wan is not popular, because there is a problem. A big problem. And the name of the problem of G-Wan is Pierre Gauthier, its author. If you browse through the G-Wan's website and forum you can learn that he is a man with a really huge ego (he calls himself &lt;a href="http://gwan.ch/about"&gt;one of the best engineers available&lt;/a&gt;), who loves to &lt;a href="http://forum.gwan.com/index.php?p=/discussion/comment/3179/#Comment_3179"&gt;criticize other people's work&lt;/a&gt; (like Poul-Henning Kamp's, the author of &lt;a href="http://www.varnish-cache.org/"&gt;Varnish&lt;/a&gt;). But at the same time he does not want to publish his own source code nor make it open source, because he perceives other developers as &lt;a href="http://forum.gwan.com/index.php?p=/discussion/comment/435/#Comment_435"&gt;inferior idiots&lt;/a&gt;, who would surely break it or at least bring nothing interesting to the existing code base. Moreover, evil government agents will try to introduce backdoors into his software and you are more secure when Pierre hides his code deep under his bed and tells you that you should trust him. And of course you do, don't you? And if you invest your time and money in G-Wan you don't have to worry at all about future development and maintenance, because even though the source code is closed, Pierre also gives you his word that he will not drop the software, and that he will never get hit by a bus (I'm not exaggerating, just read &lt;a href="http://forum.gwan.com/index.php?p=/discussion/comment/709/#Comment_709"&gt;this post&lt;/a&gt;). I will not go deeper into his paranoia of his website being constantly attacked by Microsoft and NSA servers, because you already should have an idea about the way the guy thinks.&lt;br /&gt;&lt;br /&gt;On the other pole there is a true pearl called &lt;a href="http://bellard.org/tcc/"&gt;Tiny C Compiler&lt;/a&gt; created by Fabrice Bellard. It's so insanely fast (it can compile the typical Linux kernel in &lt;a href="http://bellard.org/tcc/tccboot.html"&gt;less than 15 seconds&lt;/a&gt;!) that it can be used to write scripts or servlets in ANSI C (guess what is used internally by G-Wan to compile the servlets). With another open source project, &lt;a href="http://www.gnu.org/s/libmicrohttpd/"&gt;libmicrohttpd&lt;/a&gt;, it can become a good alternative if you want to build a small, fast web server that can use ANSI C servlets (for example as an embedded router software). Libmicrohttpd is fully HTTP 1.0 and 1.1 compliant, and it offers several threading models, so you can tune your software and choose which one suites you best in your environment. If I was supposed to build a tiny embeddable web server, I would definitely choose open source libmicrohttpd + tcc + some personal coding over G-Wan.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5635587370432045273-8204102772071426456?l=weblambdazero.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://weblambdazero.blogspot.com/feeds/8204102772071426456/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5635587370432045273&amp;postID=8204102772071426456' title='7 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5635587370432045273/posts/default/8204102772071426456'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5635587370432045273/posts/default/8204102772071426456'/><link rel='alternate' type='text/html' href='http://weblambdazero.blogspot.com/2011/09/human-factor.html' title='Human factor'/><author><name>Krzysztof Kliś</name><uri>http://www.blogger.com/profile/03518001329895236884</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://2.bp.blogspot.com/_CVm77bq8jjg/SNva5QYjDLI/AAAAAAAAABE/NKuv0JSEKuM/S220/calder.jpg'/></author><thr:total>7</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5635587370432045273.post-5073466319356358237</id><published>2011-09-02T21:41:00.007+02:00</published><updated>2011-09-03T13:12:36.669+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='erlang'/><category scheme='http://www.blogger.com/atom/ns#' term='c/c++'/><title type='text'>Another one bites the dust</title><content type='html'>A few days ago I found an interesting post on Ken Shirriff's blog, entitled &lt;a href="http://www.arcfn.com/2008/07/why-your-favorite-language-is-unpopular.html"&gt;Why your favourite language is unpopular&lt;/a&gt;. It summarizes a talk by &lt;a href="http://en.wikipedia.org/wiki/Erik_Meijer_%28computer_scientist%29"&gt;Erik Meijer&lt;/a&gt; who provided a simple, yet very accurate, explanation why some programming languages gain popularity, while some other (often better in many aspects) don't. I thought about this formula in context of Reia, a very promising language for Erlang platform I mentioned about back in 2008 in my post &lt;a href="http://weblambdazero.blogspot.com/2008/09/scripting-erlang.html"&gt;Scripting Erlang&lt;/a&gt;. The author of Reia has just announced that he &lt;a href="http://www.unlimitednovelty.com/2011/06/why-im-stopping-work-on-reia.html"&gt;drops development of Reia&lt;/a&gt; in favour of &lt;a href="http://github.com/josevalim/elixir"&gt;Elixir&lt;/a&gt;. It seems that with the amount of software existing today there is very little space for another programming language, even if it addresses problems hard to solve with mainstream languages. With existing &lt;a href="http://c2.com/cgi/wiki?ArmyOfProgrammers"&gt;army of programmers&lt;/a&gt; at its disposal, the IT industry can deal with most of its problems using existing tools, without the need of inventing &lt;a href="http://xkcd.com/927/"&gt;another language to rule them all&lt;/a&gt;. A good example of such philosophy is &lt;a href="http://software.intel.com/en-us/articles/intel-cilk-plus/"&gt;Cilk Plus&lt;/a&gt;, which originates from &lt;a href="http://supertech.csail.mit.edu/cilk/"&gt;Cilk&lt;/a&gt; and allows to &lt;a href="http://weblambdazero.blogspot.com/2008/09/cilk-c-that-scales.html"&gt;scale C/C++ code easily&lt;/a&gt; on multicore CPUs. With Cilk you can improve your existing software without rewriting it from scratch with a new computer language, which in the long run can create &lt;a href="http://www.joelonsoftware.com/articles/fog0000000069.html"&gt;more problems than it actually solves&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5635587370432045273-5073466319356358237?l=weblambdazero.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://weblambdazero.blogspot.com/feeds/5073466319356358237/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5635587370432045273&amp;postID=5073466319356358237' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5635587370432045273/posts/default/5073466319356358237'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5635587370432045273/posts/default/5073466319356358237'/><link rel='alternate' type='text/html' href='http://weblambdazero.blogspot.com/2011/09/few-days-ago-i-found-interesting-post.html' title='Another one bites the dust'/><author><name>Krzysztof Kliś</name><uri>http://www.blogger.com/profile/03518001329895236884</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://2.bp.blogspot.com/_CVm77bq8jjg/SNva5QYjDLI/AAAAAAAAABE/NKuv0JSEKuM/S220/calder.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5635587370432045273.post-1287820760865168468</id><published>2011-08-30T18:13:00.003+02:00</published><updated>2011-08-30T19:25:32.859+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java'/><title type='text'>Running Scala via Nailgun</title><content type='html'>Recently a friend of mine got me interested in &lt;a href="http://www.scala-lang.org/"&gt;Scala&lt;/a&gt;, a modern programming language for JVM. Scala reached a wide audience in 2009 when Twitter &lt;a href="http://www.theregister.co.uk/2009/04/01/twitter_on_scala/"&gt;announced&lt;/a&gt; that they use Scala in the most critical elements of their backend. It became popular for its efficiency and scalability, and for joining in a very pragmatic manner the concepts of functional and object oriented programming. It also implements some very powerful constructs, like &lt;span style="font-style:italic;"&gt;foldLeft&lt;/span&gt;, which allows you to compose your own reduction methods operating on lists (see &lt;a href="http://oldfashionedsoftware.com/2009/07/30/lots-and-lots-of-foldleft-examples/"&gt;this page&lt;/a&gt; for some very interesting examples).&lt;br /&gt;I decided to give it a try on my Acer Aspire One netbook, which I use often to do some daily tasks. Unfortunately, with 1.6 GHz Intel Atom and 1GB RAM running Fedora 14 it took Scala REPL almost 20 seconds to start. I was wondering if I could make it faster and found out that some people recommended &lt;a href="http://martiansoftware.com/nailgun/"&gt;Nailgun&lt;/a&gt; for this task. In short, Nailgun preloads the whole JVM into the memory and than uses its own bootstrap loader to connect your programs to it, so that they load much faster, without JVM startup overhead. However, besides some good advice I couldn't find any working example how to do it, so I decided to do it myself. Fortunately it turned out to be a quite easy task. First, I copied &lt;span style="font-style:italic;"&gt;nailgun-0.7.1.jar&lt;/span&gt; to Scala's &lt;span style="font-style:italic;"&gt;lib&lt;/span&gt; directory, then I took the original &lt;span style="font-style:italic;"&gt;bin/scala&lt;/span&gt; script and created a modified version. I changed line 161 from&lt;br /&gt;&lt;blockquote&gt;scala.tools.nsc.MainGenericRunner  "$@"&lt;/blockquote&gt;&lt;br /&gt;to&lt;br /&gt;&lt;blockquote&gt;com.martiansoftware.nailgun.NGServer  "$@"&lt;/blockquote&gt;&lt;br /&gt;and line 113 from&lt;br /&gt;&lt;blockquote&gt;CPSELECT="-Xbootclasspath/a:"&lt;/blockquote&gt;&lt;br /&gt;to&lt;br /&gt;&lt;blockquote&gt;CPSELECT="-cp "&lt;/blockquote&gt;&lt;br /&gt;The last change was necessary for Nailgun to load properly. Then I started regular Scala REPL through&lt;br /&gt;&lt;blockquote&gt;ng scala.tools.nsc.MainGenericRunner&lt;/blockquote&gt;&lt;br /&gt;just to learn that it still takes 20 seconds to start. Conclusion? Modern JVM loading overhead is so small that reducing it further makes little sense, even on slow machines. &lt;br /&gt;Lessons learned:&lt;br /&gt;1) Using Nailgun to speed up Scala won't get you anywhere.&lt;br /&gt;2) Don't listen to forum "experts" who recommend solutions which they have obviously never tried in practice.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5635587370432045273-1287820760865168468?l=weblambdazero.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://weblambdazero.blogspot.com/feeds/1287820760865168468/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5635587370432045273&amp;postID=1287820760865168468' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5635587370432045273/posts/default/1287820760865168468'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5635587370432045273/posts/default/1287820760865168468'/><link rel='alternate' type='text/html' href='http://weblambdazero.blogspot.com/2011/08/running-scala-via-nailgun.html' title='Running Scala via Nailgun'/><author><name>Krzysztof Kliś</name><uri>http://www.blogger.com/profile/03518001329895236884</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://2.bp.blogspot.com/_CVm77bq8jjg/SNva5QYjDLI/AAAAAAAAABE/NKuv0JSEKuM/S220/calder.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5635587370432045273.post-1695460683654770084</id><published>2011-03-26T21:53:00.009+01:00</published><updated>2011-03-27T18:56:32.431+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='c/c++'/><category scheme='http://www.blogger.com/atom/ns#' term='php'/><title type='text'>Need for speed</title><content type='html'>Working as a web developer maintaining a big web service can quickly make you understand that "everything counts in large amounts", and identifying and eliminating bottlenecks eventually becomes part of your daily routine. There are many ways to optimize your web application: from migrating to faster hardware platform, through reducing the number of network requests and extensive use of various caching layers, to refactoring of the code and optimizing your algorithms. Some very interesting performance tips can be found at &lt;a href="http://developer.yahoo.com/performance/rules.html"&gt;Yahoo Developer Network&lt;/a&gt; - but sometimes it's just not enough, and you have to reach deep into the core of your software engine.&lt;br /&gt;&lt;br /&gt;One way is to rewrite your application using either Java or C/C++. Another way, especially when your code base is so huge that it does not pay to rewrite it (even partially) is to try to compile the scripts to machine code. The best known engines implementing this technique are &lt;a href="http://codespeak.net/pypy/"&gt;PyPy&lt;/a&gt; for Python, developed as a followup to the &lt;a href="http://psyco.sourceforge.net/"&gt;Psyco&lt;/a&gt; project, and &lt;a href="https://github.com/facebook/hiphop-php/wiki"&gt;HipHop&lt;/a&gt; for PHP, developed at Facebook. What is especially interesting about the HipHop story is that it has been &lt;a href="http://developers.facebook.com/blog/post/358/"&gt;announced&lt;/a&gt; shortly after Koen Deforche &lt;a href="http://www.webtoolkit.eu/wt#/blog/2009/12/17/facebook__php__is_not_very_kopenhagen"&gt;stated on his blog&lt;/a&gt;, that Facebook could reduce the power consumption in their data centers by 75% only by using C++ instead of PHP. What is not surprising, &lt;a href="http://www.mybiodata.eu/team.html"&gt;Koen Deforche&lt;/a&gt; is an author of &lt;a href="http://www.webtoolkit.eu/wt"&gt;Wt&lt;/a&gt;, a C++ toolkit designed for building web applications.&lt;br /&gt;&lt;br /&gt;What makes Wt stand out among its alternatives is that it completely masks all underlying web technologies and makes Wt development look more like &lt;a href="http://doc.qt.nokia.com/4.7/qt-gui-concepts.html"&gt;Qt&lt;/a&gt; than web. However, developing regular web services with Wt is not easy. For a last few days I tried to create a fairly simple application with Wt and I simply gave up. For me it was just like playing with Lego Technic for Aliens. Maybe it's because Wt, as its author &lt;a href="http://discuss.joelonsoftware.com/default.asp?biz.5.599655.33"&gt;admits&lt;/a&gt;, is not a toolkit for porting an existing website to C++, but a toolkit for porting an existing desktop application to the web, and I'm primarily a web developer. Or maybe it's because there is too little useful real life examples out there and the community seems to be almost non existing. In my opinion Wt is rather a niche product, best suited for developing highly scalable intranet applications for big companies.&lt;br /&gt;&lt;br /&gt;At the opposite pole there is &lt;a href="http://koanlogic.com/klone/"&gt;KLone&lt;/a&gt;, a lightweight web framework that at first glance looks like &lt;a href="http://en.wikibooks.org/wiki/Java_Programming/JSP"&gt;JSP&lt;/a&gt;. KLone allows creating dynamic content by embedding C++ code into HTML, much like JSP does with Java. It also provides all necessary mechanisms to deal with sessions, requests, etc. The application is of course compiled to native code and can distributed as a standalone executable, since it includes its own embedded http server. At the moment it's definitely my choice if you want to write a web service based on C++, no matter if it's because your hardware is too poor for Java or you just don't want to hog your system resources with Tomcat.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5635587370432045273-1695460683654770084?l=weblambdazero.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://weblambdazero.blogspot.com/feeds/1695460683654770084/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5635587370432045273&amp;postID=1695460683654770084' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5635587370432045273/posts/default/1695460683654770084'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5635587370432045273/posts/default/1695460683654770084'/><link rel='alternate' type='text/html' href='http://weblambdazero.blogspot.com/2011/03/need-for-speed.html' title='Need for speed'/><author><name>Krzysztof Kliś</name><uri>http://www.blogger.com/profile/03518001329895236884</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://2.bp.blogspot.com/_CVm77bq8jjg/SNva5QYjDLI/AAAAAAAAABE/NKuv0JSEKuM/S220/calder.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5635587370432045273.post-3018826833500288025</id><published>2010-11-11T20:41:00.003+01:00</published><updated>2010-11-11T21:41:42.631+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='io'/><title type='text'>More fun with Io</title><content type='html'>One of Io's distinguishing features is an ability to extend its own syntax. Suppose that for some reason (for example to improve the readability of your code) you need &lt;span style="font-style:italic;"&gt;unless&lt;/span&gt; keyword, similar to the one &lt;a href="http://www.techotopia.com/index.php/Ruby_While_and_Until_Loops#unless_and_until"&gt;used in Ruby&lt;/a&gt;. You can define it as follows:&lt;br /&gt;&lt;code&gt;&lt;br /&gt;Object unless := method(if(call evalArgAt(0) not, call evalArgAt(1), call evalArgAt(2)))&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;That's it. You can now use a new keyword in your scripts:&lt;br /&gt;&lt;code&gt;&lt;br /&gt;Io&gt; x := 15; unless(x &lt; 10, "passed", "failed")&lt;br /&gt;==&gt; passed&lt;br /&gt;Io&gt; x := 5; unless(x &lt; 10, "passed", "failed")&lt;br /&gt;==&gt; failed&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;In Common Lisp a similar effect can be achieved by using a macro like this:&lt;br /&gt;&lt;code&gt;&lt;br /&gt;(defmacro unless (condition &amp;rest body) `(if (not ,condition) ,@body))&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;but in contrast to Common Lisp, Io does not use separate constructs to extend the language - what you can do in Lisp using macros, you can do in Io using only its own &lt;a href="http://www.iolanguage.com/scm/io/docs/IoGuide.html#Objects-Introspection"&gt;introspective features&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5635587370432045273-3018826833500288025?l=weblambdazero.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://weblambdazero.blogspot.com/feeds/3018826833500288025/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5635587370432045273&amp;postID=3018826833500288025' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5635587370432045273/posts/default/3018826833500288025'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5635587370432045273/posts/default/3018826833500288025'/><link rel='alternate' type='text/html' href='http://weblambdazero.blogspot.com/2010/11/more-fun-with-io.html' title='More fun with Io'/><author><name>Krzysztof Kliś</name><uri>http://www.blogger.com/profile/03518001329895236884</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://2.bp.blogspot.com/_CVm77bq8jjg/SNva5QYjDLI/AAAAAAAAABE/NKuv0JSEKuM/S220/calder.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5635587370432045273.post-2240943642949965656</id><published>2010-11-06T23:27:00.004+01:00</published><updated>2010-11-07T00:53:40.650+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='io'/><title type='text'>Language of the year 2011</title><content type='html'>Probably the biggest programming language hit of the last year was &lt;a href="http://golang.org/"&gt;Go&lt;/a&gt; - it was also (according to &lt;a href="http://www.tiobe.com/index.php/content/paperinfo/tpci/index.html"&gt;Tiobe&lt;/a&gt;) the fastest growing language in 2009. Year 2008 &lt;a href="http://weblog.hypotheticalabs.com/?p=293"&gt;belonged to Erlang&lt;/a&gt;: Amazon started their &lt;a href="http://www.satine.org/archives/2007/12/13/amazon-simpledb/"&gt;SimpleDB based on Erlang&lt;/a&gt;, and Facebook announced their &lt;a href="http://www.process-one.net/en/blogs/article/facebook_chat_is_developed_in_erlang"&gt;Erlang powered chat application&lt;/a&gt;.&lt;br /&gt;For some time I was wondering if the incoming year can bring another player entering the game, and I came to a conclusion that a good candidate is &lt;a href="http://www.iolanguage.com/"&gt;Io&lt;/a&gt;. It's  a &lt;a href="http://en.wikipedia.org/wiki/Prototype-based_programming"&gt;prototype-based&lt;/a&gt; programming language, which is amazing in many aspects: it combines &lt;a href="http://www.enemyofthestatement.com/io-where-i-think-i-want-to-be-today"&gt;very simple grammar&lt;/a&gt; with &lt;a href="http://www.enemyofthestatement.com/serving-simple-dynamic-content-with-io"&gt;incredible power&lt;/a&gt;, provides an interactive shell and a &lt;a href="http://www.iolanguage.com/scm/io/docs/reference/"&gt;rich set of libraries&lt;/a&gt; out of the box, it also allows hundreds of thousands of concurrent processes through &lt;a href="http://www.iolanguage.com/scm/io/docs/IoGuide.html#Concurrency"&gt;actor based model&lt;/a&gt;. Io is surprisingly mature as for a language with so &lt;a href="http://io-fans.jottit.com/"&gt;few Internet resources&lt;/a&gt; and is definitely worth trying - it has been recommended even by some renowned hackers like &lt;a href="http://web.archive.org/web/20080212010904/http://hackety.org/2008/01/05/ioHasAVeryCleanMirror.html"&gt;_why&lt;/a&gt; and &lt;a href="http://www.ruby-lang.org/"&gt;Ruby&lt;/a&gt;'s creator &lt;a href="http://ozone.wordpress.com/2006/02/09/io-small-is-beautiful/"&gt;Matsumoto Yukihiro&lt;/a&gt;. You can find a few Io example routines &lt;a href="http://www.iolanguage.com/about/samplecode/"&gt;here&lt;/a&gt;.&lt;br /&gt;Give Io a try if you have a minute, I can guarantee that you won't be sorry.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5635587370432045273-2240943642949965656?l=weblambdazero.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://weblambdazero.blogspot.com/feeds/2240943642949965656/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5635587370432045273&amp;postID=2240943642949965656' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5635587370432045273/posts/default/2240943642949965656'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5635587370432045273/posts/default/2240943642949965656'/><link rel='alternate' type='text/html' href='http://weblambdazero.blogspot.com/2010/11/language-of-year-2011.html' title='Language of the year 2011'/><author><name>Krzysztof Kliś</name><uri>http://www.blogger.com/profile/03518001329895236884</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://2.bp.blogspot.com/_CVm77bq8jjg/SNva5QYjDLI/AAAAAAAAABE/NKuv0JSEKuM/S220/calder.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5635587370432045273.post-3565957250014595327</id><published>2010-10-30T09:17:00.009+02:00</published><updated>2010-11-24T18:19:16.758+01:00</updated><title type='text'>Scale up your skills, not the hardware</title><content type='html'>It is not a big secret that good programmers keep &lt;a href="http://www.codinghorror.com/blog/2009/03/sharpening-the-saw.html"&gt;their saws sharp&lt;/a&gt; all the time. If you want to improve your mental skills a good place to start is &lt;a href="http://projecteuler.net/"&gt;Project Euler&lt;/a&gt;. I found it while browsing other programmers' blogs and immediately got hooked up. Project Euler is a place where you can challenge yourself (and others) in solving various mathematical and computer programming problems. The collection of problems is constantly growing and you can find them ranging from very easy to really difficult. When you provide the correct solution to a problem, a forum dedicated to it becomes revealed and you can see how other people managed to solve it. Sometimes you can also get a bonus in a form of paper explaining the problem and the best known solutions in details. You can learn a lot from these forums since people share there both their ideas and source code written in different programming languages; some of them don't even use a computer, all they need to find a solution is paper and pencil.&lt;br /&gt;What I particularly like about Project Euler is that most of the problems cannot be solved by brute force. They can make you check hundreds or thousands of possible combinations, but still require a more clever approach. A classic example are problems &lt;a href="http://projecteuler.net/index.php?section=problems&amp;id=18"&gt;18&lt;/a&gt; and &lt;a href="http://projecteuler.net/index.php?section=problems&amp;id=67"&gt;67&lt;/a&gt;, where you need to find a path from the top of the number pyramid to the bottom, so that the total sum of numbers on the path is the largest. While the pyramid in problem 18 is rather small and you can find the solution by trying every of 16384 possible paths, it is impossible to solve problem 67 the same way. To solve it you need to turn the problem upside down - literally, since you can easily get the correct solution if you start searching for the best path from the bottom of the pyramid to the top, reducing the number of combinations with every step.&lt;br /&gt;&lt;br /&gt;You may wonder how mathematics can help you in facing every day challenges as a programmer. Imagine you work for an on-line store with millions of CD records on stock, and you provide a browser with a dynamic list of products based on different criteria, such as genre, year and price. Now you want to show to your customers the most popular product within the range they choose. Getting all items satisfying the selected criteria from a database and finding the most popular one every time someone browses the list will quickly kill your back-end. On the other hand, it is impossible to generate such data in advance for every possible combination of search parameters. You can either expand your server farm (and possibly move to the &lt;a href="http://en.wikipedia.org/wiki/Cloud_computing"&gt;cloud&lt;/a&gt; to reduce costs) or you can use some statistical tools to help you do the job. The trick is to find a representative sample size for a given population of products. Assuming that &lt;span style="font-style:italic;"&gt;N&lt;/span&gt; is a total population, &lt;span style="font-style:italic;"&gt;z&lt;/span&gt; is a statistical factor for desired &lt;a href="http://en.wikipedia.org/wiki/Confidence_level"&gt;confidence level&lt;/a&gt;, &lt;span style="font-style:italic;"&gt;p&lt;/span&gt; is an estimated proportion of a given variable within the population, and &lt;span style="font-style:italic;"&gt;d&lt;/span&gt; is admissible error level, we can get sample size &lt;span style="font-style:italic;"&gt;n&lt;/span&gt; with the following formula:&lt;br /&gt;&lt;code&gt;&lt;br /&gt;x = z^2 * (p * (1 - p))&lt;br /&gt;n = N * x / ((N - 1) * d^2 + x)&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;The &lt;span style="font-style:italic;"&gt;z&lt;/span&gt; factor is constant and equals 1.96 for the 95% confidence level and 2.58 for the 99% confidence level. Assuming that a selected range of CD records contains one million &lt;a href="http://en.wikipedia.org/wiki/Uniform_distribution_%28continuous%29"&gt;uniformly distributed&lt;/a&gt; products and you can tolerate a 5% error, it turns out that in 95% cases you get the most popular one correctly by analysing only 385 randomly chosen items from the list, since:&lt;br /&gt;&lt;code&gt;&lt;br /&gt;x = 1.96^2 * (0.5 * (1 - 0.5)) = 0.9604&lt;br /&gt;n = 1000000 * 0.9604 / ((1000000 - 1) * 0.05^2 + 0.9604) =~ 384.013&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;To be 99% sure that no more than 1% results are incorrect, you'd need to analyse 16369 records.&lt;br /&gt;You can learn more about calculating sample sizes from &lt;a href="http://www.quirks.com/articles/a1999/19990603.aspx"&gt;this article at Quirks&lt;/a&gt; - I took the above formula from it. And remember: while it's true that machine cycles are cheap and people cycles are not, never forget that people cycles are worth billions of machine ones.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5635587370432045273-3565957250014595327?l=weblambdazero.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://weblambdazero.blogspot.com/feeds/3565957250014595327/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5635587370432045273&amp;postID=3565957250014595327' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5635587370432045273/posts/default/3565957250014595327'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5635587370432045273/posts/default/3565957250014595327'/><link rel='alternate' type='text/html' href='http://weblambdazero.blogspot.com/2010/10/scale-up-your-skills-not-hardware.html' title='Scale up your skills, not the hardware'/><author><name>Krzysztof Kliś</name><uri>http://www.blogger.com/profile/03518001329895236884</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://2.bp.blogspot.com/_CVm77bq8jjg/SNva5QYjDLI/AAAAAAAAABE/NKuv0JSEKuM/S220/calder.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5635587370432045273.post-1855518560585287249</id><published>2010-07-31T22:29:00.008+02:00</published><updated>2010-10-24T12:27:03.101+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='lisp'/><title type='text'>MapReduce with Gambit Scheme &amp; Termite</title><content type='html'>&lt;a href="http://code.google.com/p/termite/"&gt;Termite&lt;/a&gt; is a library that runs on top of &lt;a href="http://dynamo.iro.umontreal.ca/~gambit/"&gt;Gambit Scheme&lt;/a&gt; and implements concurrency model inspired by &lt;a href="http://www.erlang.org/"&gt;Erlang&lt;/a&gt; (there is also a Chicken Scheme &lt;a href="http://chicken.wiki.br/eggref/4/termite"&gt;port&lt;/a&gt;, but it's so far &lt;a href="http://pestilenz.org/~ckeen/blog/2009/09/19#termite"&gt;incomplete&lt;/a&gt;). Since I have &lt;a href="http://weblambdazero.blogspot.com/2008/08/scheme-termite-erlang-alternative.html"&gt;already posted&lt;/a&gt; about Termite some time ago, I will not go into details how to write distributed applications with it. Instead, I want to show you how to use Termite to implement a simple &lt;a href="http://labs.google.com/papers/mapreduce.html"&gt;MapReduce&lt;/a&gt; algorithm.&lt;br /&gt;&lt;br /&gt;A trivial implementation uses a simple &lt;span style="font-style:italic;"&gt;worker&lt;/span&gt; process that executes some code, and a &lt;span style="font-style:italic;"&gt;pmap&lt;/span&gt; function which spawns multiple workers and collects the results:&lt;br /&gt;&lt;blockquote&gt;&lt;pre&gt;&lt;br /&gt;(define (worker)&lt;br /&gt;  (let* ((msg (?)) (pid (car msg)) (fun (cadr msg)) (arg (caddr msg)))&lt;br /&gt;    (! pid (fun arg))))&lt;br /&gt;&lt;br /&gt;(define (pmap fun lst)&lt;br /&gt;  ; spawn workers&lt;br /&gt;  (for-each &lt;br /&gt;    (lambda (x) (let ((p (spawn worker))) (! p (list (self) fun x))))&lt;br /&gt;    lst)&lt;br /&gt;  ; collect results&lt;br /&gt;  (let loop ((i (length lst)) (result '()))&lt;br /&gt;    (if (= 0 i) (reverse result) (loop (- i 1) (cons (?) result)))))&lt;br /&gt;&lt;/pre&gt;&lt;/blockquote&gt;&lt;br /&gt;So far it works similar to its &lt;a href="http://weblambdazero.blogspot.com/2008/08/mapreduce-in-erlang.html"&gt;Erlang equivalent&lt;/a&gt;. However, this version does not guarantee (just like the Erlang one) that you get the results in the same order as the arguments passed to &lt;span style="font-style:italic;"&gt;pmap&lt;/span&gt;. Let's consider function &lt;span style="font-style:italic;"&gt;f&lt;/span&gt;, which holds execution of the current thread for a given number of seconds:&lt;br /&gt;&lt;blockquote&gt;&lt;pre&gt;&lt;br /&gt;(define (f x) (thread-sleep! x) x)&lt;br /&gt;&lt;/pre&gt;&lt;/blockquote&gt;&lt;br /&gt;If you run the following code:&lt;br /&gt;&lt;blockquote&gt;&lt;pre&gt;&lt;br /&gt;(pmap f (list 1 2 3 2 1))&lt;br /&gt;&lt;/pre&gt;&lt;/blockquote&gt;&lt;br /&gt;The result will be:&lt;br /&gt;&lt;blockquote&gt;&lt;pre&gt;&lt;br /&gt;(1 1 2 2 3)&lt;br /&gt;&lt;/pre&gt;&lt;/blockquote&gt;&lt;br /&gt;Since the first results on the list will come from the processes that finished first.&lt;br /&gt;&lt;br /&gt;A solution to this problem is to make a single worker process using a sequencer to mark spawned threads. Numbers generated by the sequencer are then used to sort the results to achieve the correct order of the result list:&lt;br /&gt;&lt;blockquote&gt;&lt;pre&gt;&lt;br /&gt;(define (worker)&lt;br /&gt;  ; init sequencer&lt;br /&gt;  (let loop ((n 0))&lt;br /&gt;    (let ((msg (?)))&lt;br /&gt;      ; terminate worker on request&lt;br /&gt;      (if (not (eqv? 'exit (car msg)))&lt;br /&gt;        (let ((pid (car msg)) (fun (cadr msg)) (arg (caddr msg)))&lt;br /&gt;          ; start a new thread&lt;br /&gt;          (spawn (lambda () (! pid (cons n (fun arg)))))&lt;br /&gt;          ; increase sequencer&lt;br /&gt;          (loop (+ n 1)))))))&lt;br /&gt;&lt;br /&gt;(define (pmap fun args)&lt;br /&gt;  ; start worker&lt;br /&gt;  (let ((p (spawn worker)) (result '()))&lt;br /&gt;    ; send data to the worker&lt;br /&gt;    (for-each (lambda (x) (! p (list (self) fun x))) args)&lt;br /&gt;    ; collect results&lt;br /&gt;    (let loop ((i (length args)) (lst '()))&lt;br /&gt;      (if (= 0 i)&lt;br /&gt;        (set! result lst)&lt;br /&gt;        (loop (- i 1) (cons (?) lst))))&lt;br /&gt;    ; terminate worker&lt;br /&gt;    (! p (list 'exit))&lt;br /&gt;    ; sort results&lt;br /&gt;    (let loop ((in (qsort result &lt;)) (out '()))&lt;br /&gt;      (if (null? in)&lt;br /&gt;        out&lt;br /&gt;        (loop (cdr in) (cons (cdar in) out))))))&lt;br /&gt;&lt;/pre&gt;&lt;/blockquote&gt;&lt;br /&gt;You can use any function you wish to sort the results. I used a modified version of &lt;a href="http://en.wikipedia.org/wiki/Quick_sort"&gt;quicksort&lt;/a&gt; found at &lt;a href="http://rosettacode.org/wiki/Sorting_algorithms/Quicksort#Scheme"&gt;Rosetta Code&lt;/a&gt;:&lt;br /&gt;&lt;blockquote&gt;&lt;pre&gt;&lt;br /&gt;(define (qsort l gt?)&lt;br /&gt;  (let q ((l l))&lt;br /&gt;    (if (null? l)&lt;br /&gt;      l&lt;br /&gt;      (let ((s (split-by (cdr l) (lambda (x) (gt? (car x) (caar l))))))&lt;br /&gt;        (append (q (car s)) (list (car l)) (q (cdr s)))))))&lt;br /&gt;&lt;br /&gt;(define (split-by l p)&lt;br /&gt;  (let loop ((low (list)) (high (list)) (l l))&lt;br /&gt;    (if (null? l)&lt;br /&gt;     (cons low high)&lt;br /&gt;     (if (p (car l))&lt;br /&gt;       (loop low (cons (car l) high) (cdr l))&lt;br /&gt;       (loop (cons (car l) low) high (cdr l))))))&lt;br /&gt;&lt;/pre&gt;&lt;/blockquote&gt;&lt;br /&gt;Now when you run the test again, you get the result list in the same order as the argument list, no matter what the execution time of single processes was:&lt;br /&gt;&lt;blockquote&gt;&lt;pre&gt;&lt;br /&gt;(pmap f (list 1 2 3 2 1))&lt;br /&gt;&lt;br /&gt;(1 2 3 2 1)&lt;br /&gt;&lt;/pre&gt;&lt;/blockquote&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5635587370432045273-1855518560585287249?l=weblambdazero.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://weblambdazero.blogspot.com/feeds/1855518560585287249/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5635587370432045273&amp;postID=1855518560585287249' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5635587370432045273/posts/default/1855518560585287249'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5635587370432045273/posts/default/1855518560585287249'/><link rel='alternate' type='text/html' href='http://weblambdazero.blogspot.com/2010/07/mapreduce-with-gambit-scheme-termite.html' title='MapReduce with Gambit Scheme &amp; Termite'/><author><name>Krzysztof Kliś</name><uri>http://www.blogger.com/profile/03518001329895236884</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://2.bp.blogspot.com/_CVm77bq8jjg/SNva5QYjDLI/AAAAAAAAABE/NKuv0JSEKuM/S220/calder.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5635587370432045273.post-2603813337958705484</id><published>2010-07-19T20:09:00.008+02:00</published><updated>2010-11-24T19:40:09.635+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='c/c++'/><title type='text'>Using trampolines in C</title><content type='html'>In my &lt;a href="http://weblambdazero.blogspot.com/2010/07/advanced-recursion-in-newlisp.html"&gt;previous post&lt;/a&gt; I presented my implementation of &lt;a href="http://en.wikipedia.org/wiki/Trampoline_%28computers%29"&gt;trampoline&lt;/a&gt; code in &lt;a href="http://www.newlisp.org/"&gt;newLISP&lt;/a&gt;. Since this technique is also used in non-functional programming languages, I prepared an example in &lt;a href="http://en.wikipedia.org/wiki/C_%28programming_language%29"&gt;C&lt;/a&gt;.&lt;br /&gt;Let's assume we have two &lt;a href="http://en.wikipedia.org/wiki/Mutual_recursion"&gt;mutually recursive&lt;/a&gt; functions &lt;span style="font-style:italic;"&gt;f1&lt;/span&gt; and &lt;span style="font-style:italic;"&gt;f2&lt;/span&gt;:&lt;br /&gt;&lt;blockquote&gt;&lt;pre&gt;&lt;br /&gt;#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;&lt;br /&gt;void f1(int n);&lt;br /&gt;void f2(int n);&lt;br /&gt;&lt;br /&gt;void f1(int n) {&lt;br /&gt;  printf("%d\n", n);&lt;br /&gt;  if (n == 0)&lt;br /&gt;    printf("Blastoff!\n");&lt;br /&gt;  else&lt;br /&gt;    f2(n);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;void f2(int n) {&lt;br /&gt;  f1(n-1);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;int main() {&lt;br /&gt;  f1(1000000);&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;/blockquote&gt;&lt;br /&gt;When you compile this code without any optimizations provided by a compiler and try to run it you will most probably quickly get a &lt;a href="http://en.wikipedia.org/wiki/Segmentation_fault"&gt;segmentation fault&lt;/a&gt; (or similar error, depending on your platform). What happens here is the application running out of stack for storing function callbacks.&lt;br /&gt;&lt;br /&gt;In Lisp you can solve this problem by rewriting functions to return &lt;a href="http://en.wikipedia.org/wiki/Continuation"&gt;continuations&lt;/a&gt; instead of values. In C you can simulate continuations by the following means:&lt;br /&gt;1. Making functions to operate on pointers to variables instead of actual variables, which allows the application to preserve their values between function calls.&lt;br /&gt;2. Returning a pointer to the next function to be called instead of calling it directly, which makes the use of application stack unnecessary.&lt;br /&gt;&lt;br /&gt;So rewritten &lt;span style="font-style:italic;"&gt;f1&lt;/span&gt; and &lt;span style="font-style:italic;"&gt;f2&lt;/span&gt; can be presented in the following form:&lt;br /&gt;&lt;blockquote&gt;&lt;pre&gt;&lt;br /&gt;#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;&lt;br /&gt;typedef void *(*Fun)(int *n);&lt;br /&gt;&lt;br /&gt;void *f1(int *n);&lt;br /&gt;void *f2(int *n);&lt;br /&gt;&lt;br /&gt;void *f1(int *n) {&lt;br /&gt;  printf("%d\n", *n);&lt;br /&gt;  if (*n == 0) {&lt;br /&gt;    printf("Blastoff!\n");&lt;br /&gt;    return NULL;&lt;br /&gt;  } else {&lt;br /&gt;    return f2;&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;void *f2(int *n) {&lt;br /&gt;  *n = *n - 1;&lt;br /&gt;  return f1;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;int main() {&lt;br /&gt;  int n = 1000000;&lt;br /&gt;  Fun f = f1;&lt;br /&gt;  while (f != NULL) {&lt;br /&gt;    f = (Fun)f(&amp;n);&lt;br /&gt;  }&lt;br /&gt;  return n;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;/blockquote&gt;&lt;br /&gt;Now the main function iteratively goes through subsequent function calls until the &lt;a href="http://en.wikipedia.org/wiki/Halting_problem"&gt;halting condition&lt;/a&gt; (NULL) is met. At the end of iteration variable &lt;span style="font-style:italic;"&gt;n&lt;/span&gt; holds 0.&lt;br /&gt;&lt;br /&gt;As a side note, &lt;a href="http://gcc.gnu.org/"&gt;gcc&lt;/a&gt; is able to optimize the code of mutually recursive functions quite effectively. If you compile the first example with &lt;span style="font-style:italic;"&gt;gcc -O2&lt;/span&gt; the resulting code will not crash, because the compiler replaces all &lt;span style="font-style:italic;"&gt;&lt;a href="http://en.wikibooks.org/wiki/X86_Assembly/Control_Flow#Function_Calls"&gt;call&lt;/a&gt;&lt;/span&gt; instructions with &lt;span style="font-style:italic;"&gt;&lt;a href="http://en.wikibooks.org/wiki/X86_Assembly/Control_Flow#Jump_Instructions"&gt;jmp&lt;/a&gt;&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;P.S. I would like to thank Johnny, my colleague and true programming expert, who inspired me to write this post. I was also inspired by Carlos Oliveira's &lt;a href="http://coliveira.net/software/recursion-using-trampoline-functions/"&gt;post on trampolines&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5635587370432045273-2603813337958705484?l=weblambdazero.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://weblambdazero.blogspot.com/feeds/2603813337958705484/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5635587370432045273&amp;postID=2603813337958705484' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5635587370432045273/posts/default/2603813337958705484'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5635587370432045273/posts/default/2603813337958705484'/><link rel='alternate' type='text/html' href='http://weblambdazero.blogspot.com/2010/07/using-trampolines-in-c.html' title='Using trampolines in C'/><author><name>Krzysztof Kliś</name><uri>http://www.blogger.com/profile/03518001329895236884</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://2.bp.blogspot.com/_CVm77bq8jjg/SNva5QYjDLI/AAAAAAAAABE/NKuv0JSEKuM/S220/calder.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5635587370432045273.post-1691486202039712827</id><published>2010-07-15T21:43:00.018+02:00</published><updated>2010-11-24T19:37:37.165+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='lisp'/><title type='text'>Advanced recursion in newLISP</title><content type='html'>In my &lt;a href="http://weblambdazero.blogspot.com/2010/06/newlisp-lisp-for-masses.html"&gt;recent post&lt;/a&gt; about newLISP I mentioned that it does not support &lt;a href="http://en.wikipedia.org/wiki/Tail_call"&gt;tail call optimization&lt;/a&gt;. In fact, many Lisps don't. As Bill Six &lt;a href="http://weblambdazero.blogspot.com/2010/06/newlisp-lisp-for-masses.html?showComment=1277086555305#c8185484923384487444"&gt;pointed out&lt;/a&gt; even the ANSI standard of Common Lisp standard does not mandate (&lt;a href="http://www.schemers.org/Documents/Standards/R5RS/HTML/r5rs-Z-H-6.html#%_sec_3.5"&gt;unlike Scheme&lt;/a&gt;) tail-call elimination provided by the language implementation, although it seems that all well-known ANSI Common Lisp compilers do it anyway.&lt;br /&gt;&lt;br /&gt;I was wondering if there is a way to circumvent this problem and the first solution I found was to use &lt;a href="http://www.newlisp.org/downloads/CodePatterns.html#toc-5"&gt;&lt;span style="font-style:italic;"&gt;memoize&lt;/span&gt;&lt;/a&gt; macro described in an excellent online documentation for newLISP, &lt;span style="font-style:italic;"&gt;Code Patterns in newLISP&lt;/span&gt;:&lt;br /&gt;&lt;blockquote&gt;&lt;pre&gt;&lt;br /&gt;(define-macro (memoize mem-func func)&lt;br /&gt;  (set (sym mem-func mem-func)&lt;br /&gt;    (letex (f func  c mem-func)&lt;br /&gt;      (lambda ()&lt;br /&gt;        (or (context c (string (args)))&lt;br /&gt;        (context c (string (args)) (apply f (args))))))))&lt;br /&gt;&lt;/pre&gt;&lt;/blockquote&gt;&lt;br /&gt;You can apply this macro to any function with any number of arguments. The trick here is that each time a function is called its result is cached in memory for another call. It can speed up your application tremendously, which can be observed by comparing the execution time of these example Fibonacci functions:&lt;br /&gt;&lt;blockquote&gt;&lt;pre&gt;&lt;br /&gt;(define (fibo n)&lt;br /&gt;  (if (&lt; n 2) 1&lt;br /&gt;    (+ (fibo (- n 1)) (fibo (- n 2)))))&lt;br /&gt;&lt;br /&gt;(memoize fibo-m&lt;br /&gt;  (lambda (n)&lt;br /&gt;    (if (&lt; n 2) 1&lt;br /&gt;      (+ (fibo-m (- n 1)) (fibo-m (- n 2))))))&lt;br /&gt;&lt;br /&gt;(time (fibo 35))&lt;br /&gt;(time (fibo-m 35))&lt;br /&gt;&lt;/pre&gt;&lt;/blockquote&gt;&lt;br /&gt;On my laptop &lt;span style="font-style:italic;"&gt;(fibo 35)&lt;/span&gt; took 12,98 seconds to execute, while &lt;span style="font-style:italic;"&gt;(fibo-m)&lt;/span&gt; executed in 0,016 miliseconds.&lt;br /&gt;&lt;br /&gt;Unfortunately the &lt;span style="font-style:italic;"&gt;memoize&lt;/span&gt; macro cannot help you to handle &lt;a href="http://en.wikipedia.org/wiki/Mutual_recursion"&gt;mutual recursion&lt;/a&gt;. A classic example of such recursion looks as follows:&lt;br /&gt;&lt;blockquote&gt;&lt;pre&gt;&lt;br /&gt;(define (f1 n)&lt;br /&gt;  (println n)&lt;br /&gt;    (if (= n 0)&lt;br /&gt;      (println "Blastoff!")&lt;br /&gt;      (f2 n)))&lt;br /&gt;&lt;br /&gt;(define (f2 n)&lt;br /&gt;  (f1 (- n 1)))&lt;br /&gt;&lt;/pre&gt;&lt;/blockquote&gt;&lt;br /&gt;You can easily make newLISP run out of stack by running &lt;span style="font-style:italic;"&gt;(f1 1000)&lt;/span&gt;, not to mention bigger numbers. What happens if we define a "memoized" version of &lt;span style="font-style:italic;"&gt;f1&lt;/span&gt; and &lt;span style="font-style:italic;"&gt;f2&lt;/span&gt;? Let's see:&lt;br /&gt;&lt;blockquote&gt;&lt;pre&gt;&lt;br /&gt;(memoize f1&lt;br /&gt;  (lambda (n)&lt;br /&gt;    (println n)&lt;br /&gt;    (if (= n 0)&lt;br /&gt;      (println "Blastoff!")&lt;br /&gt;      (f2 n))))&lt;br /&gt;&lt;br /&gt;(memoize f2&lt;br /&gt;  (lambda (n)&lt;br /&gt;    (f1 (- n 1))))&lt;br /&gt;&lt;/pre&gt;&lt;/blockquote&gt;&lt;br /&gt;Again, running &lt;span style="font-style:italic;"&gt;(f1 1000)&lt;/span&gt; immediately exhausts newLISP's stack.&lt;br /&gt;&lt;br /&gt;A solution to this problem is using a technique called &lt;a href="http://en.wikipedia.org/wiki/Trampoline_%28computers%29"&gt;trampolining&lt;/a&gt;. Bill Clementson on his &lt;a href="http://bc.tech.coop/blog/040613.html"&gt;blog&lt;/a&gt; not only explained in an excellent way the concept of using trampolines, but also provided a Common Lisp implementation, which became my inspiration to write a newLISP version:&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;&lt;blockquote&gt;&lt;pre&gt;&lt;br /&gt;(define (trampoline fun arg)&lt;br /&gt;  (catch&lt;br /&gt;    (while true&lt;br /&gt;      (let ((run (apply fun arg)))&lt;br /&gt;        (setf fun (first run) arg (rest run)))) 'result)&lt;br /&gt;  result)&lt;br /&gt;&lt;/pre&gt;&lt;/blockquote&gt;&lt;/span&gt;&lt;br /&gt;A trampoline iteratively executes code &lt;a href="http://en.wikipedia.org/wiki/Thunk"&gt;thunks&lt;/a&gt; returned by a function, and this way avoids blowing out application stack. However, in order to use trampoline, the function must return &lt;a href="http://en.wikipedia.org/wiki/Continuation"&gt;continuation&lt;/a&gt; (a pointer to the next step) instead of value. Below is a version of beforementioned functions modified to use the trampoline:&lt;br /&gt;&lt;blockquote&gt;&lt;pre&gt;&lt;br /&gt;(define (f1 n)&lt;br /&gt;  (println n)&lt;br /&gt;  (if (= n 0)&lt;br /&gt;    (throw "Blastoff!")&lt;br /&gt;    (list f2 n)))&lt;br /&gt;&lt;br /&gt;(define (f2 n)&lt;br /&gt;  (list f1 (- n 1)))&lt;br /&gt;&lt;/pre&gt;&lt;/blockquote&gt;&lt;br /&gt;Now you can test it with:&lt;br /&gt;&lt;blockquote&gt;&lt;pre&gt;&lt;br /&gt;(trampoline f1 '(1000))&lt;br /&gt;(trampoline f1 '(10000))&lt;br /&gt;(trampoline f1 '(100000))&lt;br /&gt;...&lt;br /&gt;&lt;/pre&gt;&lt;/blockquote&gt;&lt;br /&gt;Have fun!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5635587370432045273-1691486202039712827?l=weblambdazero.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://weblambdazero.blogspot.com/feeds/1691486202039712827/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5635587370432045273&amp;postID=1691486202039712827' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5635587370432045273/posts/default/1691486202039712827'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5635587370432045273/posts/default/1691486202039712827'/><link rel='alternate' type='text/html' href='http://weblambdazero.blogspot.com/2010/07/advanced-recursion-in-newlisp.html' title='Advanced recursion in newLISP'/><author><name>Krzysztof Kliś</name><uri>http://www.blogger.com/profile/03518001329895236884</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://2.bp.blogspot.com/_CVm77bq8jjg/SNva5QYjDLI/AAAAAAAAABE/NKuv0JSEKuM/S220/calder.jpg'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5635587370432045273.post-1270434198643522505</id><published>2010-06-03T18:03:00.007+02:00</published><updated>2010-07-15T23:31:44.827+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='lisp'/><title type='text'>newLISP - Lisp for the masses</title><content type='html'>There is a popular phrase among &lt;a href="http://en.wikipedia.org/wiki/Lisp"&gt;Lisp&lt;/a&gt; hackers: &lt;span style="font-style:italic;"&gt;Plant a tree, write a book, create your own dialect of lisp&lt;/span&gt;. Although there aren't many popular Lisps out there and even the mainstream &lt;a href="http://en.wikipedia.org/wiki/Common_lisp"&gt;Common Lisp&lt;/a&gt; has never been &lt;a href="http://www.tiobe.com/index.php/content/paperinfo/tpci/index.html"&gt;massively used&lt;/a&gt;, it seems that just like in case of &lt;a href="http://distrowatch.com/dwres.php?resource=major"&gt;various Linux distributions&lt;/a&gt;, often &lt;span style="font-weight:bold;"&gt;more&lt;/span&gt; means simply &lt;span style="font-weight:bold;"&gt;better&lt;/span&gt;. A good example of such success story is &lt;a href="http://weblambdazero.blogspot.com/2008/08/clojure-is-here.html"&gt;Clojure&lt;/a&gt;, and here comes another candidate to take the lead.&lt;br /&gt;&lt;a href="http://www.newlisp.org/"&gt;newLISP&lt;/a&gt; is a modern dialect of Lisp, designed by Lutz Mueller to be (as he &lt;a href="http://www.softwarebyrob.com/2007/04/19/interview-with-lutz-mueller-creator-of-newlisp/"&gt;says&lt;/a&gt; himself) &lt;span style="font-style:italic;"&gt;"quick to learn and to get the job done"&lt;/span&gt;. I must say that this sentence couldn't be more true - solving &lt;a href="http://projecteuler.net/index.php?section=problems&amp;id=10"&gt;Euler Problem 10&lt;/a&gt; (finding the sum of all primes below 2 million) after just two days of fiddling with newLISP took me less than 3 minutes, including designing, writing, testing and executing the following code:&lt;br /&gt;&lt;blockquote&gt;&lt;br /&gt;(println (apply + (filter (fn (n) (= 1 (length (factor n)))) (sequence 2 2000000))))&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;In spite of being an interpreted language, programs created with newLISP run amazingly fast. The code above is a purely brute force solution, yet it executes in less than 10 seconds on Core 2 Duo 1.66GHz.&lt;br /&gt;However, simplicity comes for a price. If you try to use a more sophisticated approach, like classic &lt;a href="http://en.wikipedia.org/wiki/Sieve_of_Eratosthenes"&gt;sieve of Eratosthenes&lt;/a&gt;, you might get a bit surprised:&lt;br /&gt;&lt;blockquote&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;(define (sieve seq out)&lt;br /&gt;  (let ((n (first seq)))&lt;br /&gt;    (setf seq (filter (fn (x) (!= 0 (mod x n))) seq))&lt;br /&gt;    (push n out)&lt;br /&gt;    (if (not seq) out (sieve seq out))))&lt;br /&gt;(print (apply + (sieve (sequence 2 2000000))))&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;In this code function &lt;span style="font-style:italic;"&gt;sieve&lt;/span&gt;, although properly &lt;a href="http://en.wikipedia.org/wiki/Tail_recursion"&gt;tail recursive&lt;/a&gt;, will make newLISP to quickly run out of stack or (if you provide enough space for the stack) of all available memory. It's because newLISP &lt;a href="http://newlispfanclub.alh.net/forum/viewtopic.php?f=3&amp;t=131&amp;start=0"&gt;does no tail recursion optimization&lt;/a&gt;. If for some reason you cannot live with it, you can still use Common Lisp for implementing such recursions:&lt;br /&gt;&lt;blockquote&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;(defun range (min max) (loop for i from min to max collect i))&lt;br /&gt;(defun sieve (seq &amp;optional out)&lt;br /&gt;  (let ((n (car seq)))&lt;br /&gt;    (setf seq (delete-if #'(lambda (x) (= 0 (mod x n))) seq))&lt;br /&gt;    (push n out)&lt;br /&gt;    (if (not seq) out (sieve seq out))))&lt;br /&gt;(print (apply #'+ (sieve (range 2 2000000))))&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;As you can see, the code of function &lt;span style="font-style:italic;"&gt;sieve&lt;/span&gt; is very similar, so it's fairly easy to switch to newLISP if you already have some Common Lisp background. Differences to other Lisp dialects are well &lt;a href="http://www.newlisp.org/index.cgi?page=Differences_to_Other_LISPs"&gt;documented&lt;/a&gt;, as well as the &lt;a href="http://www.newlisp.org/downloads/newlisp_manual.html"&gt;language itself&lt;/a&gt;. Documentation is another strength of newLISP: you can learn how to solve different real life problems using newLISP &lt;a href="http://www.newlisp.org/downloads/CodePatterns.html"&gt;code patterns&lt;/a&gt; or browse through many interesting &lt;a href="http://www.newlisp.org/index.cgi?page=Code_Snippets"&gt;code snippets&lt;/a&gt;.&lt;br /&gt;What I personally like about newLISP in comparison to other Lisps is its really tiny footprint. You can create a standalone executable containing an embedded newLISP engine which is 200kB small, using two simple steps:&lt;br /&gt;&lt;blockquote&gt;&lt;br /&gt;(load "/usr/share/newlisp/util/link.lsp")&lt;br /&gt;(link "/usr/bin/newlisp" "mycode.bin" "mycode.lsp")&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;Despite being so small, newLISP provides a surprising amount of functionalities out of the box: regular expressions, TCP/IP networking (including FTP and HTTP protocols), database access (through external &lt;a href="http://www.newlisp.org/index.cgi?Libraries"&gt;libraries&lt;/a&gt;), OpenGL, XML and XML-RPC handling, matrices, statistics (including Bayesian formulas), unicode support and a set of C/C++ &lt;a href="http://www.newlisp.org/code/modules/"&gt;modules&lt;/a&gt; that extend its abilities even more.&lt;br /&gt;newLISP also supports &lt;a href="http://www.newlisp.org/downloads/CodePatterns.html#toc-18"&gt;parallel processing&lt;/a&gt; through &lt;a href="http://weblambdazero.blogspot.com/2008/09/cilk-c-that-scales.html"&gt;Cilk&lt;/a&gt;-like API, and &lt;a href="http://www.newlisp.org/downloads/CodePatterns.html#toc-21"&gt;distributed computing&lt;/a&gt; through a built-in function &lt;span style="font-style:italic;"&gt;net-eval&lt;/span&gt;.&lt;br /&gt;newLISP is definitely not a New Common Lisp, and in some points (such as the beforementioned tail recursion) is still inferior. But newLISP is a perfect example that in the IT industry sometimes &lt;a href="http://en.wikipedia.org/wiki/Worse_is_Better"&gt;worse is better&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5635587370432045273-1270434198643522505?l=weblambdazero.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://weblambdazero.blogspot.com/feeds/1270434198643522505/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5635587370432045273&amp;postID=1270434198643522505' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5635587370432045273/posts/default/1270434198643522505'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5635587370432045273/posts/default/1270434198643522505'/><link rel='alternate' type='text/html' href='http://weblambdazero.blogspot.com/2010/06/newlisp-lisp-for-masses.html' title='newLISP - Lisp for the masses'/><author><name>Krzysztof Kliś</name><uri>http://www.blogger.com/profile/03518001329895236884</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://2.bp.blogspot.com/_CVm77bq8jjg/SNva5QYjDLI/AAAAAAAAABE/NKuv0JSEKuM/S220/calder.jpg'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5635587370432045273.post-1627713647412999109</id><published>2010-01-05T01:05:00.011+01:00</published><updated>2010-01-06T21:22:55.515+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='erlang'/><category scheme='http://www.blogger.com/atom/ns#' term='go'/><title type='text'>Web Sockets: a new era for the Web</title><content type='html'>&lt;a href="http://dev.w3.org/html5/websockets/"&gt;The Web Sockets API&lt;/a&gt; is a part of &lt;a href="http://www.w3.org/TR/html5/"&gt;HTML 5 specification&lt;/a&gt; and is to the Web what &lt;a href="http://en.wikipedia.org/wiki/Transmission_Control_Protocol"&gt;TCP&lt;/a&gt; is to the &lt;a href="http://en.wikipedia.org/wiki/Internet_Protocol"&gt;IP protocol&lt;/a&gt;. It allows full-duplex, bidirectional communication between the server and the client browser - no more polling, no more busy waiting, and no more &lt;a href="http://www.io.com/~maus/HttpKeepAlive.html"&gt;problems with keep-alive HTTP connections&lt;/a&gt;. Web Sockets allow to leverage Web applications to an absolutely new level, where they can finally operate like any other network software, without crippled overlays like &lt;a href="http://en.wikipedia.org/wiki/Ajax_%28programming%29"&gt;AJAX&lt;/a&gt; or &lt;a href="http://en.wikipedia.org/wiki/Comet_%28programming%29"&gt;Comet&lt;/a&gt;. With Web Sockets you can &lt;a href="http://en.wikipedia.org/wiki/Push_technology"&gt;push&lt;/a&gt; data to the client just as you &lt;a href="http://futuremacblog.blogspot.com/2008/01/matt-tucker-writes-on-jivesoftware.html"&gt;would do it with XMPP&lt;/a&gt;.&lt;br /&gt;One of the first browsers to support Web Sockets is &lt;a href="http://blog.chromium.org/2009/12/web-sockets-now-available-in-google.html"&gt;Google Chrome&lt;/a&gt;. And, of course, one of the first languages natively supporting Web Sockets is &lt;a href="http://golang.org/"&gt;Go&lt;/a&gt;. Here is a simple server application which sends time information to the browser in one second intervals:&lt;br /&gt;&lt;blockquote&gt;&lt;pre&gt;&lt;br /&gt;package main&lt;br /&gt;&lt;br /&gt;import (&lt;br /&gt;  "http"&lt;br /&gt;  "io"&lt;br /&gt;  "strconv"&lt;br /&gt;  "time"&lt;br /&gt;  "websocket"&lt;br /&gt;)&lt;br /&gt;&lt;br /&gt;func ClockServer(ws *websocket.Conn) {&lt;br /&gt;  ch := time.Tick(100000000)&lt;br /&gt;  t1 := &lt;- ch&lt;br /&gt;  t := t1 / 1000000000&lt;br /&gt;  for {&lt;br /&gt;    t2 := &lt;-ch&lt;br /&gt;    td := (t2 - t1) / 1000000000&lt;br /&gt;    if td != t {&lt;br /&gt;      io.WriteString(ws, strconv.Itoa64(td))&lt;br /&gt;      t = td&lt;br /&gt;    }&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;func main() {&lt;br /&gt;  http.Handle("/clock", websocket.Handler(ClockServer))&lt;br /&gt;  err := http.ListenAndServe(":12345", nil)&lt;br /&gt;  if err != nil {&lt;br /&gt;    panic("Error: ", err.String())&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;/blockquote&gt;&lt;br /&gt;When you compile and start the server, create a web page with the following content and save it to your disk:&lt;br /&gt;&lt;blockquote&gt;&lt;pre&gt;&lt;br /&gt;&amp;lt;html&amp;gt;&lt;br /&gt;&amp;lt;head&amp;gt;&lt;br /&gt;&amp;lt;title&amp;gt;WebSocket&amp;lt;/title&amp;gt;&lt;br /&gt;&amp;lt;script type=&amp;quot;text/javascript&amp;quot;&amp;gt;&lt;br /&gt;function init() {&lt;br /&gt;  var tick = document.getElementById(&amp;quot;tick&amp;quot;);&lt;br /&gt;  if (&amp;quot;WebSocket&amp;quot; in window) {&lt;br /&gt;    var ws = new WebSocket(&amp;quot;ws://localhost:12345/clock&amp;quot;);&lt;br /&gt;    ws.onmessage = function (evt) {&lt;br /&gt;      tick.innerHTML = evt.data;&lt;br /&gt;    };&lt;br /&gt;  } else {&lt;br /&gt;    tick.innerHTML = &amp;quot;The browser doesn't support WebSocket.&amp;quot;;&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&amp;lt;/script&amp;gt;&lt;br /&gt;&amp;lt;/head&amp;gt;&lt;br /&gt;&amp;lt;body onload=&amp;quot;init()&amp;quot;&amp;gt;&lt;br /&gt;&amp;lt;span&amp;gt;Seconds elapsed: &amp;lt;/span&amp;gt;&amp;lt;span id=&amp;quot;tick&amp;quot;&amp;gt;0&amp;lt;/span&amp;gt;&lt;br /&gt;&amp;lt;/body&amp;gt;&lt;br /&gt;&amp;lt;/html&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;/blockquote&gt;&lt;br /&gt;If you open the page in Google Chrome, you will see seconds ticking. There is no AJAX, no long-polling or any other fancy stuff - the server pushes data directly to the client. If you open more Chrome instances, you will see that each of them has its own connection with the server with its own clock (however, beware opening many connections in the same window, but in different tabs - this can occasionally crash your browser).&lt;br /&gt;You can also use Erlang to make use of Web Sockets technology. Joe Armstrong has recently &lt;a href="http://armstrongonsoftware.blogspot.com/2009/12/comet-is-dead-long-live-websockets.html"&gt;posted an article&lt;/a&gt; on his blog with full source code of both Web Sockets client and server.&lt;br /&gt;Have fun!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5635587370432045273-1627713647412999109?l=weblambdazero.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://weblambdazero.blogspot.com/feeds/1627713647412999109/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5635587370432045273&amp;postID=1627713647412999109' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5635587370432045273/posts/default/1627713647412999109'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5635587370432045273/posts/default/1627713647412999109'/><link rel='alternate' type='text/html' href='http://weblambdazero.blogspot.com/2010/01/web-sockets-new-era-for-web.html' title='Web Sockets: a new era for the Web'/><author><name>Krzysztof Kliś</name><uri>http://www.blogger.com/profile/03518001329895236884</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://2.bp.blogspot.com/_CVm77bq8jjg/SNva5QYjDLI/AAAAAAAAABE/NKuv0JSEKuM/S220/calder.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5635587370432045273.post-7580312104553093133</id><published>2009-12-30T22:06:00.010+01:00</published><updated>2010-01-07T23:43:50.213+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='go'/><title type='text'>Go memcache client package</title><content type='html'>Recently I needed to access &lt;a href="http://memcached.org/"&gt;Memcached&lt;/a&gt; from &lt;a href="http://golang.org"&gt;Go&lt;/a&gt;. I couldn't find a suitable package anywhere on the web, so I created one. &lt;span style="font-weight:bold;"&gt;Gomemcache&lt;/span&gt; provides basic operations to store, retrieve and delete data using &lt;a href="http://code.sixapart.com/svn/memcached/trunk/server/doc/protocol.txt"&gt;memcache text protocol&lt;/a&gt;. You can &lt;span style="font-weight:bold;"&gt;&lt;a href="http://github.com/kklis/gomemcache/"&gt;download the package&lt;/a&gt;&lt;/span&gt; from its Github repository.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt;Edit:&lt;/span&gt; Gomemcache is now distributed under the terms of &lt;a href="http://www.gnu.org/copyleft/lesser.html"&gt;LGPL license&lt;/a&gt; with static linking exception. It means that you can link it statically with independent modules to produce an executable, regardless of the license terms of these independent modules, and to copy and distribute the resulting executable under terms of your choice, provided that you meet the terms and conditions of LGPL for the package itself. Originally GNU Lesser General Public License does not allow unproblematic static linking with proprietary source code.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5635587370432045273-7580312104553093133?l=weblambdazero.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://weblambdazero.blogspot.com/feeds/7580312104553093133/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5635587370432045273&amp;postID=7580312104553093133' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5635587370432045273/posts/default/7580312104553093133'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5635587370432045273/posts/default/7580312104553093133'/><link rel='alternate' type='text/html' href='http://weblambdazero.blogspot.com/2009/12/go-memcache-client-package.html' title='Go memcache client package'/><author><name>Krzysztof Kliś</name><uri>http://www.blogger.com/profile/03518001329895236884</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://2.bp.blogspot.com/_CVm77bq8jjg/SNva5QYjDLI/AAAAAAAAABE/NKuv0JSEKuM/S220/calder.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5635587370432045273.post-127082020357278528</id><published>2009-12-27T14:21:00.002+01:00</published><updated>2009-12-27T14:36:32.530+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='go'/><title type='text'>Go Programming Language Resources</title><content type='html'>&lt;a href="http://golang.org/"&gt;Go&lt;/a&gt; is a fairly new programming language, so at the moment it is hard to find interesting projects associated with it. &lt;a href="http://go-lang.cat-v.org/"&gt;Go Programming Language Resources&lt;/a&gt; is a web site that tries to gather them in one place. It also contains links to mailing lists, discussion groups and IRC archives, as well as Go ports to different operating systems. You can also find there a few interesting development tools and syntax highlighting for the most popular programmer's editors. If you are interested in Go, this site is definitely worth adding to your bookmarks.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5635587370432045273-127082020357278528?l=weblambdazero.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://weblambdazero.blogspot.com/feeds/127082020357278528/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5635587370432045273&amp;postID=127082020357278528' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5635587370432045273/posts/default/127082020357278528'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5635587370432045273/posts/default/127082020357278528'/><link rel='alternate' type='text/html' href='http://weblambdazero.blogspot.com/2009/12/go-programming-language-resources.html' title='Go Programming Language Resources'/><author><name>Krzysztof Kliś</name><uri>http://www.blogger.com/profile/03518001329895236884</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://2.bp.blogspot.com/_CVm77bq8jjg/SNva5QYjDLI/AAAAAAAAABE/NKuv0JSEKuM/S220/calder.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5635587370432045273.post-4173411876301958717</id><published>2009-12-24T00:46:00.015+01:00</published><updated>2010-01-07T20:47:33.584+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='c/c++'/><category scheme='http://www.blogger.com/atom/ns#' term='go'/><title type='text'>Go - a new programming language from Google</title><content type='html'>&lt;a href="http://golang.org/"&gt;Go&lt;/a&gt; is a new programming language developed at Google, which according to its &lt;a href="http://golang.org/doc/go_lang_faq.html#creating_a_new_language"&gt;FAQ&lt;/a&gt; &lt;span style="font-style: italic;"&gt;"was born out of frustration with existing languages and environments for systems programming"&lt;/span&gt;. Some people ask if the world needs another programming language, but those who know that among Go authors are &lt;a href="http://en.wikipedia.org/wiki/Ken_Thompson"&gt;Ken Thompson&lt;/a&gt; and &lt;a href="http://en.wikipedia.org/wiki/Rob_Pike"&gt;Rob Pike&lt;/a&gt;, famous &lt;a href="http://www.faqs.org/docs/artu/ch01s06.html"&gt;Unix hackers&lt;/a&gt;, usually don't. If there is a language that has a chance to replace plain &lt;a href="http://en.wikipedia.org/wiki/C_%28programming_language%29"&gt;C&lt;/a&gt; in system programming, Go is a perfect candidate. It features a syntax derived from the C tree (which makes learning curve fairly easy for most of the programmers), fast compilation to native machine code, and fast execution of compiled binaries. Additionally, Go provides a built-in garbage collector and language constructs that simplify parallel programming, especially the concept of &lt;span style="font-style: italic;"&gt;&lt;a href="http://golang.org/doc/effective_go.html#goroutines"&gt;goroutines&lt;/a&gt;&lt;/span&gt;, which are regular program functions executed concurrently. Goroutines can communicate with each other and the main thread through &lt;span style="font-style: italic;"&gt;&lt;a href="http://golang.org/doc/effective_go.html#channels"&gt;channels&lt;/a&gt;&lt;/span&gt;, that can also be used for synchronization purposes.&lt;br /&gt;I have prepared a few simple programs to compare Go with C in terms of speed and to play with concurrent programming in Go. First, let's have a look at a typical recursive &lt;a href="http://en.wikipedia.org/wiki/Fibonacci_number"&gt;Fibonacci&lt;/a&gt; example. Below is a C version:&lt;br /&gt;&lt;blockquote&gt;&lt;pre&gt;&lt;br /&gt;#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;#include &amp;lt;stdlib.h&amp;gt;&lt;br /&gt;&lt;br /&gt;int fib(int n) {&lt;br /&gt;  if (n &amp;lt; 2) {&lt;br /&gt;    return(n);&lt;br /&gt;  }&lt;br /&gt;  return(fib(n-2) + fib(n-1));&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;int main(int argc, char *argv[]) {&lt;br /&gt;  int n = atoi(argv[1]);&lt;br /&gt;  printf(&amp;quot;%d\n&amp;quot;, fib(n));&lt;br /&gt;  return(0);&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;/blockquote&gt;&lt;br /&gt;and here is a Go version:&lt;br /&gt;&lt;blockquote&gt;&lt;pre&gt;&lt;br /&gt;package main&lt;br /&gt;&lt;br /&gt;import (&lt;br /&gt;  &amp;quot;flag&amp;quot;&lt;br /&gt;  &amp;quot;fmt&amp;quot;&lt;br /&gt;)&lt;br /&gt;&lt;br /&gt;var f = flag.Int(&amp;quot;f&amp;quot;, 1, &amp;quot;Fibonacci number&amp;quot;)&lt;br /&gt;&lt;br /&gt;func fib(n int) int {&lt;br /&gt;  if n &amp;lt; 2 {&lt;br /&gt;    return n&lt;br /&gt;  }&lt;br /&gt;  return fib(n-2) + fib(n-1)&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;func main() {&lt;br /&gt;  flag.Parse()&lt;br /&gt;  fmt.Println(fib(*f))&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;/blockquote&gt;&lt;br /&gt;A quick test shows that a single threaded Go program is actually &lt;span style="font-weight: bold;"&gt;faster&lt;/span&gt; than the C one:&lt;br /&gt;&lt;blockquote&gt;&lt;pre&gt;&lt;br /&gt;$ gcc -O2 -o fib fib.c&lt;br /&gt;$ time ./fib 40&lt;br /&gt;102334155&lt;br /&gt;&lt;br /&gt;real 0m1.987s&lt;br /&gt;user 0m1.980s&lt;br /&gt;sys 0m0.004s&lt;br /&gt;&lt;br /&gt;$ 8g fib.go; 8l fib.8&lt;br /&gt;$ time ./8.out -f=40&lt;br /&gt;102334155&lt;br /&gt;&lt;br /&gt;real 0m1.934s&lt;br /&gt;user 0m1.932s&lt;br /&gt;sys 0m0.004s&lt;br /&gt;&lt;/pre&gt;&lt;/blockquote&gt;&lt;br /&gt;I also prepared a program in Go to calculate a sum of subsequent Fibonacci sequences up to a given number in parallel. It uses &lt;span style="font-style: italic;"&gt;run&lt;/span&gt; function as a goroutine to calculate each sequence independently and a shared channel &lt;span style="font-style: italic;"&gt;ch&lt;/span&gt; to gather the results, that are finally summed up (so we don't care about the order in which they appear in the channel):&lt;br /&gt;&lt;blockquote&gt;&lt;pre&gt;&lt;br /&gt;package main&lt;br /&gt;&lt;br /&gt;import (&lt;br /&gt;  "flag"&lt;br /&gt;  "fmt"&lt;br /&gt;  "runtime"&lt;br /&gt;)&lt;br /&gt;&lt;br /&gt;var n = flag.Int("n", 1, "Number of CPUs to use")&lt;br /&gt;var f = flag.Int("f", 1, "Fibonacci number")&lt;br /&gt;&lt;br /&gt;func fib(n int) int {&lt;br /&gt;  if n &lt; 2 {&lt;br /&gt;    return n&lt;br /&gt;  }&lt;br /&gt;  return fib(n-2) + fib(n-1)&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;func run(n int, ch chan int) {&lt;br /&gt;  ch &lt;- fib(n)&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;func main() {&lt;br /&gt;  flag.Parse()&lt;br /&gt;  runtime.GOMAXPROCS(*n)&lt;br /&gt;  ch := make(chan int)&lt;br /&gt;  for i := 0; i &lt;= *f; i++ {&lt;br /&gt;    go run(i, ch)&lt;br /&gt;  }&lt;br /&gt;  sum := 0&lt;br /&gt;  for i := 0; i &lt;= *f; i++ {&lt;br /&gt;    sum += &lt;-ch&lt;br /&gt;  }&lt;br /&gt;  fmt.Println(sum)&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;/blockquote&gt;&lt;br /&gt;The program takes additional parameter &lt;span style="font-style: italic;"&gt;-n&lt;/span&gt; to indicate the number of CPUs to use. According to Go &lt;a href="http://golang.org/pkg/runtime/#GOMAXPROCS"&gt;runtime package documentation&lt;/a&gt; the call to GOMAXPROCS is temporary and will go away when the scheduler improves. Until then you have to remember to use this call, otherwise your application will use &lt;span style="font-weight: bold;"&gt;only one CPU&lt;/span&gt; by default.&lt;br /&gt;I ran the program for 40 Fibonacci sequences on dual Intel Xeon L5420 2.50GHz using from single up to all available CPU cores. The execution time improved most dramatically between &lt;span style="font-style: italic;"&gt;-n=1&lt;/span&gt; (5.073s) and &lt;span style="font-style: italic;"&gt;-n=2&lt;/span&gt; (3.141s), than it gradually slowed down from &lt;span style="font-style: italic;"&gt;-n=3&lt;/span&gt; (2.574s) to &lt;span style="font-style: italic;"&gt;-n=8&lt;/span&gt; (2.013s).&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_CVm77bq8jjg/SzLMFArk-xI/AAAAAAAAAGo/VOB5FeE4OAY/s1600-h/pfib.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 289px; height: 262px;" src="http://1.bp.blogspot.com/_CVm77bq8jjg/SzLMFArk-xI/AAAAAAAAAGo/VOB5FeE4OAY/s320/pfib.png" alt="" id="BLOGGER_PHOTO_ID_5418617688134318866" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;What I like about Go is that it gives a set of powerful tools into programmer's hands, but at the same time does not try to hide the complexity of parallel programming behind bloated libraries or awkward language constructs. It nicely follows the &lt;a href="http://en.wikipedia.org/wiki/Keep_it_simple_stupid"&gt;KISS&lt;/a&gt; principle and borrows some good ideas from Unix design (like channels, which work similar to &lt;a href="http://en.wikipedia.org/wiki/Pipeline_%28Unix%29"&gt;Unix pipelines&lt;/a&gt;). If you think seriously about future system programming, I think Go is definitely a language worth learning. Not only because it's Google ;-)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5635587370432045273-4173411876301958717?l=weblambdazero.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://weblambdazero.blogspot.com/feeds/4173411876301958717/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5635587370432045273&amp;postID=4173411876301958717' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5635587370432045273/posts/default/4173411876301958717'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5635587370432045273/posts/default/4173411876301958717'/><link rel='alternate' type='text/html' href='http://weblambdazero.blogspot.com/2009/12/go-new-programming-language-from-google.html' title='Go - a new programming language from Google'/><author><name>Krzysztof Kliś</name><uri>http://www.blogger.com/profile/03518001329895236884</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://2.bp.blogspot.com/_CVm77bq8jjg/SNva5QYjDLI/AAAAAAAAABE/NKuv0JSEKuM/S220/calder.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_CVm77bq8jjg/SzLMFArk-xI/AAAAAAAAAGo/VOB5FeE4OAY/s72-c/pfib.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5635587370432045273.post-2446425612715439827</id><published>2009-12-15T21:36:00.004+01:00</published><updated>2010-07-15T23:29:54.067+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='lisp'/><title type='text'>Funding Clojure 2010</title><content type='html'>There is no such thing as a free lunch - everybody knows that. But when it comes to software, we tend to think that it is (or should be) free. Free as in free beer, not as in speech, quite contrary to what &lt;a href="http://www.gnu.org/philosophy/free-sw.html"&gt;free software philosophy&lt;/a&gt; says. But software is not grown like crops in the field, it requires long hours of work from people who create it. Many people write software and release it under one of &lt;a href="http://www.opensource.org/licenses/alphabetical"&gt;open source licenses&lt;/a&gt; in hope that some day it becomes popular; but when it finally does, it turns out that its development takes so much time that you either have to drop it or start working on it full-time.&lt;br /&gt;This is what recently happened to &lt;a href="http://clojure.org/"&gt;Clojure&lt;/a&gt;. Rich Hickey, the creator and main developer of this fascinating programming language &lt;a href="http://groups.google.com/group/clojure/msg/5f40e7048e1f774e"&gt;announced&lt;/a&gt; his financial expectations towards individuals and businesses who benefit from it to fund its further development. I hope Rich gets enough financial funding to continue his work on Clojure. If you use Clojure in your development, maybe you should also think about &lt;a href="http://clojure.org/funding"&gt;donating&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5635587370432045273-2446425612715439827?l=weblambdazero.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://weblambdazero.blogspot.com/feeds/2446425612715439827/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5635587370432045273&amp;postID=2446425612715439827' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5635587370432045273/posts/default/2446425612715439827'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5635587370432045273/posts/default/2446425612715439827'/><link rel='alternate' type='text/html' href='http://weblambdazero.blogspot.com/2009/12/funding-clojure-2010.html' title='Funding Clojure 2010'/><author><name>Krzysztof Kliś</name><uri>http://www.blogger.com/profile/03518001329895236884</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://2.bp.blogspot.com/_CVm77bq8jjg/SNva5QYjDLI/AAAAAAAAABE/NKuv0JSEKuM/S220/calder.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5635587370432045273.post-8283145377817050305</id><published>2009-11-22T23:33:00.006+01:00</published><updated>2009-11-23T00:27:34.378+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='terracotta'/><title type='text'>MagLev public alpha</title><content type='html'>&lt;a href="http://www.gemstone.com/"&gt;Gemstone&lt;/a&gt; has just &lt;a href="http://groups.google.com/group/maglev-discussion/browse_thread/thread/1102993e9e21492a"&gt;announced&lt;/a&gt; an alpha version of their concurrent Ruby engine, &lt;a href="http://maglev.gemstone.com/"&gt;MagLev&lt;/a&gt;, available for &lt;a href="http://github.com/MagLev/maglev/blob/master/README.rdoc"&gt;download&lt;/a&gt;. MagLev is based on &lt;a href="http://www.gemstone.com/products/gemstone/"&gt;Gemstone's Smalltalk virtual machine&lt;/a&gt; and supports 64-bit Linux, Mac OS X and Solaris x86 operating systems. There are no plans for 32-bit version of MagLev.&lt;br /&gt;MagLev does not support Rails yet, but so does not Fabio Kung's &lt;a href="http://weblambdazero.blogspot.com/2008/11/jmaglev-terracotta-based-maglev-for.html"&gt;JMagLev&lt;/a&gt;. However, the advantage of MagLev over Fabio's machine is that Gemstone is determined to create an enterprise-class product, and JMagLev was just a demonstration of the power of &lt;a href="http://www.terracotta.org/"&gt;Terracotta&lt;/a&gt; and does not seem to be developed any further. It seems that the next step for Gemstone will be to implement Rails functionality and allow RoR applications to run in a clustered enviornment, just as Grails ones &lt;a href="http://grails.org/Terracotta+Plugin"&gt;can run on Terracotta&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5635587370432045273-8283145377817050305?l=weblambdazero.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://weblambdazero.blogspot.com/feeds/8283145377817050305/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5635587370432045273&amp;postID=8283145377817050305' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5635587370432045273/posts/default/8283145377817050305'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5635587370432045273/posts/default/8283145377817050305'/><link rel='alternate' type='text/html' href='http://weblambdazero.blogspot.com/2009/11/maglev-public-alpha.html' title='MagLev public alpha'/><author><name>Krzysztof Kliś</name><uri>http://www.blogger.com/profile/03518001329895236884</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://2.bp.blogspot.com/_CVm77bq8jjg/SNva5QYjDLI/AAAAAAAAABE/NKuv0JSEKuM/S220/calder.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5635587370432045273.post-7796897484030268451</id><published>2009-11-20T22:26:00.004+01:00</published><updated>2009-11-22T20:54:17.530+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='erlang'/><title type='text'>Erlang project crawler</title><content type='html'>Today I received an email from &lt;a href="http://www.erlang-consulting.com/"&gt;Erlang Training and Consulting Ltd.&lt;/a&gt; - the owner of popular Erlang Community Site &lt;a href="http://www.trapexit.org/"&gt;Trapexit&lt;/a&gt; - announcing its own Erlang open source project &lt;span style="font-weight:bold;"&gt;&lt;a href="http://projects.trapexit.org/"&gt;crawler&lt;/a&gt;&lt;/span&gt;. Crawler gathers information on open source Erlang projects from a number of code repositories such as &lt;a href="http://github.com/"&gt;GitHub&lt;/a&gt;, &lt;a href="http://bitbucket.org/"&gt;Bitbucket&lt;/a&gt;, &lt;a href="http://bitbucket.org/"&gt;SourceForge&lt;/a&gt; and &lt;a href="http://code.google.com/"&gt;Google Code&lt;/a&gt;. At the time when I am writing this post it includes information on 1228 projects. The number may not be impressive, but it is good to have information about the most interesting open source Erlang projects gathered in one place.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5635587370432045273-7796897484030268451?l=weblambdazero.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://weblambdazero.blogspot.com/feeds/7796897484030268451/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5635587370432045273&amp;postID=7796897484030268451' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5635587370432045273/posts/default/7796897484030268451'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5635587370432045273/posts/default/7796897484030268451'/><link rel='alternate' type='text/html' href='http://weblambdazero.blogspot.com/2009/11/erlang-project-crawler.html' title='Erlang project crawler'/><author><name>Krzysztof Kliś</name><uri>http://www.blogger.com/profile/03518001329895236884</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://2.bp.blogspot.com/_CVm77bq8jjg/SNva5QYjDLI/AAAAAAAAABE/NKuv0JSEKuM/S220/calder.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5635587370432045273.post-7137733931756569387</id><published>2009-09-06T14:29:00.009+02:00</published><updated>2010-07-15T23:31:17.958+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='c/c++'/><category scheme='http://www.blogger.com/atom/ns#' term='python'/><title type='text'>Top gear(man)</title><content type='html'>&lt;a href="http://gearman.org/"&gt;Gearman&lt;/a&gt; is an open source project providing a flexible and universal framework for writing distributed applications. It differs from similar projects in easiness of use and the number of bindings for programming languages it provides: C, C++, Java, Perl, PHP and Python. In fact, Gearman has a simple command line client, that allows you to start jobs using any language you want - all you need to do is to provide the client with input data and then fetch the client's output. Gearman API is very simple, consistent, and makes writing distributed applications really easy, quick and fun.&lt;br /&gt;&lt;br /&gt;Gearman architecture is equally simple: it consists of job servers, that accept task requests from clients and forward them to workers, and send results back to clients. Each worker can be connected to many job servers, and a client can choose which job server to use - this way there is no single point of failure that could break down the whole cluster. Job servers have their own queues and in case of worker failure they can reassign tasks to other workers. According to &lt;a href="http://highscalability.com/product-gearman-open-source-message-queuing-system"&gt;High Scalability&lt;/a&gt; Gearman has been successfully used by LiveJournal, Yahoo!, and Digg (which claims to run 300000 jobs a day through Gearman without any issues).&lt;br /&gt;&lt;br /&gt;I decided to try out Gearman at home, and I must say that it was a really pleasant experience. I wrote a simple C++ worker and even simpler Python client. The worker recursively finds Fibonacci number for given &lt;span style="font-style:italic;"&gt;n&lt;/span&gt;:&lt;br /&gt;&lt;blockquote&gt;&lt;pre&gt;&lt;br /&gt;#include &amp;lt;cstring&amp;gt;&lt;br /&gt;#include &amp;lt;cstdlib&amp;gt;&lt;br /&gt;#include &amp;lt;iostream&amp;gt;&lt;br /&gt;#include &amp;lt;sstream&amp;gt;&lt;br /&gt;#include &amp;lt;libgearman/gearman.h&amp;gt;&lt;br /&gt;#include &amp;lt;libgearman/worker.h&amp;gt;&lt;br /&gt;&lt;br /&gt;using namespace std;&lt;br /&gt;&lt;br /&gt;void *fib_worker(gearman_job_st *job, void *cb_arg, size_t *result_size, gearman_return_t *ret_ptr);&lt;br /&gt;long fib(long n);&lt;br /&gt;static void usage(char *name);&lt;br /&gt;&lt;br /&gt;int main(int argc, char *argv[])&lt;br /&gt;{&lt;br /&gt;  int c;&lt;br /&gt;  char *host = &amp;quot;127.0.0.1&amp;quot;;&lt;br /&gt;  in_port_t port = 0;&lt;br /&gt;  gearman_worker_st worker;&lt;br /&gt;&lt;br /&gt;  while ((c = getopt(argc, argv, &amp;quot;h:p:&amp;quot;)) != -1) {&lt;br /&gt;    switch(c) {&lt;br /&gt;      case 'h':&lt;br /&gt;        host = optarg;&lt;br /&gt;        break;&lt;br /&gt;      case 'p':&lt;br /&gt;        port = (in_port_t) atoi(optarg);&lt;br /&gt;        break;&lt;br /&gt;      default:&lt;br /&gt;        usage(argv[0]);&lt;br /&gt;        exit(1);&lt;br /&gt;    }&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  if (argc != optind) {&lt;br /&gt;    usage(argv[0]);&lt;br /&gt;    exit(1);&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  gearman_worker_create(&amp;amp;worker);&lt;br /&gt;  gearman_worker_add_server(&amp;amp;worker, host, port);&lt;br /&gt;  gearman_worker_add_function(&amp;amp;worker, &amp;quot;fib&amp;quot;, 10, fib_worker, NULL);&lt;br /&gt;  while (1) {&lt;br /&gt;    gearman_worker_work(&amp;amp;worker);&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  return 0;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;void *fib_worker(gearman_job_st *job, void *cb_arg, size_t *result_size, gearman_return_t *ret_ptr) {&lt;br /&gt;  char ch[256];&lt;br /&gt;  ostringstream os;&lt;br /&gt;  int size = gearman_job_workload_size(job);&lt;br /&gt;  strncpy(ch, (char *) gearman_job_workload(job), size);&lt;br /&gt;  ch[size] = 0;&lt;br /&gt;  long n = atol(ch);&lt;br /&gt;  os &amp;lt;&amp;lt; fib(n);&lt;br /&gt;  string s = os.str();&lt;br /&gt;  *result_size = s.size();&lt;br /&gt;  *ret_ptr = GEARMAN_SUCCESS;&lt;br /&gt;  return strdup(s.c_str());&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;long fib(long n) {&lt;br /&gt;  if (n &amp;lt; 2) {&lt;br /&gt;    return 1;&lt;br /&gt;  } else {&lt;br /&gt;    return fib(n - 2) + fib(n - 1);&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;static void usage(char *name) {&lt;br /&gt;  cout &amp;lt;&amp;lt; &amp;quot;Usage: &amp;quot; &amp;lt;&amp;lt; name &amp;lt;&amp;lt; &amp;quot; [-h &amp;lt;host&amp;gt;] [-p &amp;lt;port&amp;gt;] &amp;lt;string&amp;gt;&amp;quot; &amp;lt;&amp;lt; endl;&lt;br /&gt;  cout &amp;lt;&amp;lt; &amp;quot;\t-h &amp;lt;host&amp;gt; - job server host&amp;quot; &amp;lt;&amp;lt; endl;&lt;br /&gt;  cout &amp;lt;&amp;lt; &amp;quot;\t-p &amp;lt;port&amp;gt; - job server port&amp;quot; &amp;lt;&amp;lt; endl;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;/blockquote&gt;&lt;br /&gt;Python client prepares a set of jobs for a sequence of &lt;span style="font-style:italic;"&gt;n&lt;/span&gt; numbers, runs them simultaneously through a job server and sums up the result:&lt;br /&gt;&lt;blockquote&gt;&lt;pre&gt;&lt;br /&gt;import optparse&lt;br /&gt;from gearman import *&lt;br /&gt;&lt;br /&gt;parser = optparse.OptionParser()&lt;br /&gt;parser.add_option('--host', help = &amp;quot;Specifies gearman job server&amp;quot;)&lt;br /&gt;parser.add_option('-n', '--num', help = &amp;quot;Amount of Fibonacci numbers to compute&amp;quot;)&lt;br /&gt;(opts, args) = parser.parse_args()&lt;br /&gt;&lt;br /&gt;client = GearmanClient([opts.host])&lt;br /&gt;&lt;br /&gt;ts = Taskset()&lt;br /&gt;for i in range(1, int(opts.num)):&lt;br /&gt;  t = Task(func = &amp;quot;fib&amp;quot;, arg = i)&lt;br /&gt;  ts.add(t)&lt;br /&gt;&lt;br /&gt;client.do_taskset(ts)&lt;br /&gt;&lt;br /&gt;sum = 0&lt;br /&gt;for task in ts.values():&lt;br /&gt;  sum += int(task.result)&lt;br /&gt;&lt;br /&gt;print sum&lt;br /&gt;&lt;/pre&gt;&lt;/blockquote&gt;&lt;br /&gt;You can download the source code of both worker and client &lt;span style="font-weight:bold;"&gt;&lt;a href="http://www.caldersoft.net/files/gearman/"&gt;here&lt;/a&gt;&lt;/span&gt;. After you compile and install Gearman with traditional:&lt;br /&gt;&lt;blockquote&gt;&lt;br /&gt;./configure&lt;br /&gt;make&lt;br /&gt;sudo make install&lt;br /&gt;sudo ldconfig&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;Install Python extension with:&lt;br /&gt;&lt;blockquote&gt;easy_install gearman&lt;/blockquote&gt;&lt;br /&gt;And compile the C++ example with:&lt;br /&gt;&lt;blockquote&gt;make&lt;/blockquote&gt;&lt;br /&gt;Then you can run a job server as a daemon:&lt;br /&gt;&lt;blockquote&gt;gearmand -d -L 127.0.0.1&lt;/blockquote&gt;&lt;br /&gt;or in debug mode:&lt;br /&gt;&lt;blockquote&gt;gearmand -vv -L 127.0.0.1&lt;/blockquote&gt;&lt;br /&gt;Next, run a couple of Gearman workers:&lt;br /&gt;&lt;blockquote&gt;./GearmanWorker -h 127.0.0.1&lt;/blockquote&gt;&lt;br /&gt;And the Python client:&lt;br /&gt;&lt;blockquote&gt;python GearmanClient.py --host 127.0.0.1 -n 45&lt;/blockquote&gt;&lt;br /&gt;For a single machine, it makes sense to run at most as many workers as there are CPUs (or CPU cores) available. For a network cluster, you can run more job servers and workers (and clients) respectively.&lt;br /&gt;&lt;br /&gt;I've made some tests with the client and worker above. using my home laptop and an Intel Atom based net-top running together in a local network. For only one laptop worker, computing the sum of 45 Fibonacci numbers took 66.955 seconds, for two laptop workers it took 35.702 seconds, and adding a remote worker reduced the total time to 25.593 seconds. Adding more workers didn't reduce computation time, it even slightly slowed the cluster down - which is quite understandable, as the number of workers exceeded the number of free CPUs (Intel Atom in fact has only one physical core, although applications see it as dual-core CPU).&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5635587370432045273-7137733931756569387?l=weblambdazero.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://weblambdazero.blogspot.com/feeds/7137733931756569387/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5635587370432045273&amp;postID=7137733931756569387' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5635587370432045273/posts/default/7137733931756569387'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5635587370432045273/posts/default/7137733931756569387'/><link rel='alternate' type='text/html' href='http://weblambdazero.blogspot.com/2009/09/top-gearman.html' title='Top gear(man)'/><author><name>Krzysztof Kliś</name><uri>http://www.blogger.com/profile/03518001329895236884</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://2.bp.blogspot.com/_CVm77bq8jjg/SNva5QYjDLI/AAAAAAAAABE/NKuv0JSEKuM/S220/calder.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5635587370432045273.post-5189017491225649423</id><published>2009-07-05T20:53:00.009+02:00</published><updated>2009-07-05T22:03:18.747+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java'/><category scheme='http://www.blogger.com/atom/ns#' term='erlang'/><title type='text'>Jabase: Jabber cluster on HBase</title><content type='html'>Java has often been compared with Erlang by Erlang advocates, who emphasize its advantage over Java in &lt;a href="http://www.sics.se/~joe/ericsson/du98024.html"&gt;thread creating&lt;/a&gt; and &lt;a href="http://www.vijaykandy.com/archives/59"&gt;message passing&lt;/a&gt;. Some even claim that Erlang can be Java &lt;a href="http://www.cincomsmalltalk.com/userblogs/ralph/blogView?entry=3364027251"&gt;successor&lt;/a&gt; in concurrent programming. Of course such comparisons and benchmarks have some value, but the truth is that Erlang has never been, and never will be, Java competitor. The reason for this is simple, and was perfectly explained by Dennis Byrne in his article &lt;a href="http://www.theserverside.com/tt/articles/article.tss?l=IntegratingJavaandErlang"&gt;"Integrating Java and Erlang"&lt;/a&gt;:&lt;br /&gt;&lt;blockquote&gt;Java and Erlang are not mutually exclusive, they complement each other. I personally have learned to embrace both because very few complex business problems can be modeled exclusively from an object oriented or functional paradigm.&lt;/blockquote&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Integration&lt;/span&gt; and &lt;span style="font-weight:bold;"&gt;interoperability&lt;/span&gt; are now the key words that make modern IT business go round. It is also understood very well by the Erlang team, who created &lt;a href="http://erlang.org/doc/apps/jinterface/"&gt;Jinterface&lt;/a&gt; - a set of Java classes for communicating with Erlang.&lt;br /&gt;&lt;br /&gt;Jinterface is also the key element that allowed me to build a highly scalable Jabber cluster based on &lt;a href="http://www.ejabberd.im/"&gt;ejabberd&lt;/a&gt; as XMPP server and &lt;a href="http://wiki.apache.org/hadoop/Hbase"&gt;HBase&lt;/a&gt; distributed database as a storage. Ejabberd is a distributed Jabber server written in Erlang, but unfortunately Erlang native storage, &lt;a href="http://www.erlang.org/doc/apps/mnesia/"&gt;Mnesia&lt;/a&gt;, &lt;a href="http://article.gmane.org/gmane.comp.lang.erlang.general/27651"&gt;can't handle large amount of data&lt;/a&gt;. To overcome this limitation, ejabberd provides &lt;a href="http://en.wikipedia.org/wiki/Odbc"&gt;ODBC&lt;/a&gt; drivers for &lt;a href="http://www.mysql.com/"&gt;MySQL&lt;/a&gt;, &lt;a href="http://www.microsoft.com/sql/"&gt;MS SQL&lt;/a&gt; and &lt;a href="http://www.postgresql.org/"&gt;PostgreSQL&lt;/a&gt;, but it's only a partial solution to the scalability problem. First, the whole ejabberd cluster still uses a single database instance as data storage, and second, user sessions are still kept in Mnesia.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.division-by-zero.com/jabase.html"&gt;&lt;span style="font-weight:bold;"&gt;Jabase&lt;/span&gt;&lt;/a&gt; is a middleware set of components written in Erlang and Java providing communication layer between ejabberd XMPP server and HBase distributed database. While ejabberd ensures communication between users and server instances, HBase provides highly scalable, distributed database to store large amount of data and serve them efficiently. Additionally, Java instances are responsible for caching user sessions and providing efficient methods of serving and searching for session data, while Erlang code ensures session data integrity among Jabber server instances. Jabase architecture looks like this:&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_CVm77bq8jjg/SlD_gfgih2I/AAAAAAAAAE4/WSkkFcjH7TE/s1600-h/jabase_architecture.gif"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 298px;" src="http://2.bp.blogspot.com/_CVm77bq8jjg/SlD_gfgih2I/AAAAAAAAAE4/WSkkFcjH7TE/s400/jabase_architecture.gif" border="0" alt=""id="BLOGGER_PHOTO_ID_5355060890622396258" /&gt;&lt;/a&gt;&lt;br /&gt;The source code of Jabase has been released under &lt;a href="http://www.gnu.org/licenses/#GPL"&gt;GPL&lt;/a&gt; and the project &lt;a href="http://www.division-by-zero.com/jabase.html"&gt;website&lt;/a&gt; contains a manual how to compile and set up a simple Jabber cluster based on Jabase. However, technical support is served exclusively by &lt;a href="http://www.division-by-zero.com/"&gt;Division-by-Zero&lt;/a&gt;, for which I built this software. If you have any questions or are interested in using Jabase in your company, please &lt;a href="http://www.division-by-zero.com/contact.html"&gt;contact Division-by-Zero&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5635587370432045273-5189017491225649423?l=weblambdazero.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://weblambdazero.blogspot.com/feeds/5189017491225649423/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5635587370432045273&amp;postID=5189017491225649423' title='5 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5635587370432045273/posts/default/5189017491225649423'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5635587370432045273/posts/default/5189017491225649423'/><link rel='alternate' type='text/html' href='http://weblambdazero.blogspot.com/2009/07/jabase-jabber-on-hbase.html' title='Jabase: Jabber cluster on HBase'/><author><name>Krzysztof Kliś</name><uri>http://www.blogger.com/profile/03518001329895236884</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://2.bp.blogspot.com/_CVm77bq8jjg/SNva5QYjDLI/AAAAAAAAABE/NKuv0JSEKuM/S220/calder.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_CVm77bq8jjg/SlD_gfgih2I/AAAAAAAAAE4/WSkkFcjH7TE/s72-c/jabase_architecture.gif' height='72' width='72'/><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5635587370432045273.post-7663150418519550716</id><published>2009-03-04T11:16:00.007+01:00</published><updated>2010-07-15T23:30:13.286+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='lisp'/><category scheme='http://www.blogger.com/atom/ns#' term='java'/><category scheme='http://www.blogger.com/atom/ns#' term='terracotta'/><title type='text'>Incoming Revolution: Clojure + Terracotta</title><content type='html'>For some time I have been working quite extensively with Java and Java-related technologies in addition to all that Erlang and functional stuff I do every day, and I must say that I am really impressed with what is going on in the area where both worlds overlap. A few months ago I was experimenting with &lt;a href="http://weblambdazero.blogspot.com/2008/11/distributed-processing-with-jscheme-and.html"&gt;JScheme running on Terracotta&lt;/a&gt;, but as &lt;a href="https://www.blogger.com/comment.g?blogID=5635587370432045273&amp;postID=7246634709087475316"&gt;I told&lt;/a&gt; Ari from Terracotta Inc., who became interested in the project, much more interesting would be combining their product with &lt;a href="http://weblambdazero.blogspot.com/2008/08/clojure-is-here.html"&gt;Clojure&lt;/a&gt;. I knew that some people had already been &lt;a href="http://groups.google.com/group/clojure/browse_thread/thread/afdfe8dfb5cb099b"&gt;thinking about it&lt;/a&gt;.&lt;br /&gt;Not much time has passed since then, and guess what. Paul Stadig &lt;a href="http://paul.stadig.name/2009/02/clojure-terracotta-yeah-baby.html"&gt;announced on his blog&lt;/a&gt; that he managed to run Clojure code on Terracotta. Today the same guy just made me looking for my jaw on the floor: he made &lt;span style="font-weight:bold;"&gt;the whole Clojure environment&lt;/span&gt; (together with REPL) &lt;a href="http://paul.stadig.name/2009/03/clojure-terracotta-next-steps.html"&gt;work on Terracotta&lt;/a&gt;! Now imagine Clojure concurrent applications, using Software Transactional Memory distributed across computer network through Terracotta: you can build massive software clusters that can work with incredible performance; you can add &lt;a href="http://hadoop.apache.org/"&gt;Hadoop&lt;/a&gt; (distributed file system) and &lt;a href="http://hadoop.apache.org/hbase"&gt;Hbase&lt;/a&gt; (distributed database) and be able to build a system that can handle hundreds of thousands of parallel operations and store petabytes of data; you can scale your system up and and down just by adding or removing machines from the cluster. And with modern cloud computing services, like &lt;a href="http://aws.amazon.com/"&gt;AWS&lt;/a&gt;, you can build a large computation cluster or a social networking website with a relatively small budget.&lt;br /&gt;Basically, you don't need much money to start another Facebook. Your imagination and programming skills are your only limit. Good luck!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5635587370432045273-7663150418519550716?l=weblambdazero.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://weblambdazero.blogspot.com/feeds/7663150418519550716/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5635587370432045273&amp;postID=7663150418519550716' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5635587370432045273/posts/default/7663150418519550716'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5635587370432045273/posts/default/7663150418519550716'/><link rel='alternate' type='text/html' href='http://weblambdazero.blogspot.com/2009/03/incoming-revolution-clojure-terracotta.html' title='Incoming Revolution: Clojure + Terracotta'/><author><name>Krzysztof Kliś</name><uri>http://www.blogger.com/profile/03518001329895236884</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://2.bp.blogspot.com/_CVm77bq8jjg/SNva5QYjDLI/AAAAAAAAABE/NKuv0JSEKuM/S220/calder.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5635587370432045273.post-9011744430363388930</id><published>2008-11-13T20:45:00.005+01:00</published><updated>2009-11-22T23:44:46.587+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='java'/><category scheme='http://www.blogger.com/atom/ns#' term='terracotta'/><title type='text'>JMagLev: Terracotta based MagLev for Ruby</title><content type='html'>In &lt;a href="http://weblambdazero.blogspot.com/2008/09/living-in-concurrent-world.html"&gt;one of my previous posts&lt;/a&gt; I wrote about clustering solutions for Ruby. One of them was &lt;a href="http://ruby.gemstone.com/"&gt;MagLev&lt;/a&gt;, based on &lt;a href="http://www.gemstone.com/products/gemstone/"&gt;Gemstone's Smalltalk virtual machine&lt;/a&gt;, the second one was &lt;a href="http://jonasboner.com/2007/02/05/clustering-jruby-with-open-terracotta/"&gt;based on Terracotta&lt;/a&gt;. The latter solution seems more appealing, since Terracotta is open source, and lets you do some own experiments (like &lt;a href="http://weblambdazero.blogspot.com/2008/10/clustering-jscheme-with-terracotta.html"&gt;this&lt;/a&gt;, or &lt;a href="http://weblambdazero.blogspot.com/2008/10/clustering-kawa-with-terracotta.html"&gt;this&lt;/a&gt;, or even &lt;a href="http://weblambdazero.blogspot.com/2008/11/distributed-processing-with-jscheme-and.html"&gt;this&lt;/a&gt;). Unfortunately, all solutions I have seen so far (including my own) for JVM based languages other than Java depended on a special library that interfaced Terracotta through &lt;span style="font-style:italic;"&gt;com.tc.object.bytecode.ManagerUtil&lt;/span&gt; class instances, and were not transparent to the programmer. Until now.&lt;br /&gt;Recently, Fabio Kung took a step further and &lt;a href="http://fabiokung.com/2008/10/08/jruby-sharing-objects-across-multiple-runtimes-jmaglev/"&gt;patched JRuby to behave like MagLev&lt;/a&gt;, transparently sharing objects across multiple JRuby runtimes. It seems that MagLev got a strong competitor before it even managed to hit the market. Have a look at the &lt;a href="http://blog.caelum.com.br/video/jruby/fabiokung-jmaglev.swf"&gt;demo&lt;/a&gt;, it looks equally impressive to what Avi Bryant from Gemstone showed at RailsConf 2008.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5635587370432045273-9011744430363388930?l=weblambdazero.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://weblambdazero.blogspot.com/feeds/9011744430363388930/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5635587370432045273&amp;postID=9011744430363388930' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5635587370432045273/posts/default/9011744430363388930'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5635587370432045273/posts/default/9011744430363388930'/><link rel='alternate' type='text/html' href='http://weblambdazero.blogspot.com/2008/11/jmaglev-terracotta-based-maglev-for.html' title='JMagLev: Terracotta based MagLev for Ruby'/><author><name>Krzysztof Kliś</name><uri>http://www.blogger.com/profile/03518001329895236884</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://2.bp.blogspot.com/_CVm77bq8jjg/SNva5QYjDLI/AAAAAAAAABE/NKuv0JSEKuM/S220/calder.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5635587370432045273.post-7246634709087475316</id><published>2008-11-06T22:25:00.015+01:00</published><updated>2010-10-24T12:27:30.773+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='lisp'/><category scheme='http://www.blogger.com/atom/ns#' term='java'/><category scheme='http://www.blogger.com/atom/ns#' term='terracotta'/><title type='text'>Distributed processing with JScheme and Terracotta</title><content type='html'>In my post about &lt;a href="http://weblambdazero.blogspot.com/2008/10/clustering-jscheme-with-terracotta.html"&gt;clustering JScheme with Terracotta&lt;/a&gt; I presented how to share Java objects through &lt;a href="http://www.terracotta.org/"&gt;Terracotta&lt;/a&gt; using &lt;a href="http://jscheme.sourceforge.net/"&gt;JScheme&lt;/a&gt;. But clustering is not only about sharing data. It is also about parallel (and possibly distributed) task processing.&lt;br /&gt;&lt;br /&gt;One of the fundamental assumptions of Scheme (and other Lisps) is that &lt;span style="font-weight:bold;"&gt;code is data&lt;/span&gt;. Programs are just collections of evaluable expressions and thus you can represent data as code, and vice versa. This is exactly what you need when you want to distribute code over a system designed primarily to share data.&lt;br /&gt;&lt;br /&gt;I prepared a simple system based on JScheme that allows distributed, concurrent code processing over a Terracotta cluster. It uses a concept of independent nodes (borrowed from Erlang). Each node polls a shared list to find a new expression to evaluate. Once it finds a job to be done, it evaluates the expression using a JScheme evaluator (instance of &lt;span style="font-style:italic;"&gt;jscheme.JScheme&lt;/span&gt; class) and writes a result back on the list. The client process which initiated the task, reads back the result and returns it.&lt;br /&gt;Since all nodes are independent entities, you can start as many of them as you need and use them concurrently. But in most cases the optimal number of nodes is equivalent to the number of CPUs (or CPU cores) to be used on each machine connected to Terracotta. So if you have 2 computers with a quad core CPU and want to use only half of their power, you can start 2 nodes on each of them. If you want to use them to the full, you should use 8 nodes, 4 per each machine, and so on. You can start the nodes on single machine using a single or multiple JScheme shells, it's up to you. For me, a single Scheme &lt;a href="http://en.wikipedia.org/wiki/REPL"&gt;REPL&lt;/a&gt; seems to be the most convenient option.&lt;br /&gt;Client jobs are started through &lt;span style="font-style:italic;"&gt;tc-map&lt;/span&gt;. It's a function that is similar to the standard &lt;span style="font-style:italic;"&gt;map&lt;/span&gt;, but it takes an additional argument - a list of nodes to use for the job. Unfortunately, the system is not fault tolerant, so if one of the nodes dies during doing the job, the whole processing task hangs up. The only way out then is either to restart the dead node or evaluate the whole &lt;span style="font-style:italic;"&gt;tc-map&lt;/span&gt; expression again.&lt;br /&gt;&lt;br /&gt;OK, enough for the theory, let's do some real work. First you need to &lt;span style="font-weight:bold;"&gt;&lt;a href="http://www.caldersoft.net/files/jstc/"&gt;download the library&lt;/a&gt;&lt;/span&gt;. The online folder contains the library itself (&lt;span style="font-style:italic;"&gt;jstc.scm&lt;/span&gt;), sample Terracotta configuration (&lt;span style="font-style:italic;"&gt;tc-config.xml&lt;/span&gt;) and some tests. After you get the library and the configuration file, you should start the Terracotta server (I described the whole procedure in detail &lt;a href="http://weblambdazero.blogspot.com/2008/10/clustering-jscheme-with-terracotta.html"&gt;previously&lt;/a&gt;). If you run the Terracotta server on a remote machine, you should also edit the &lt;span style="font-style:italic;"&gt;tc-config.xml&lt;/span&gt; file and change server host to the IP of the Terracotta host. Now you can start JScheme through the Terracotta bootstrap:&lt;br /&gt;&lt;blockquote&gt;&lt;br /&gt;java -Xbootclasspath/p:[terracotta boot jar] -Dtc.config=tc-config.xml -Dtc.install-root=[terracotta install dir] -jar jscheme.jar&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;You can to find the boot jar in &lt;span style="font-style:italic;"&gt;lib/dso-boot&lt;/span&gt; folder of your Terracotta installation directory. If it isn't there, you can generate it with Terracotta &lt;span style="font-style:italic;"&gt;make-boot-jar.sh&lt;/span&gt; script.&lt;br /&gt;Now you can load the library with:&lt;br /&gt;&lt;blockquote&gt;&lt;br /&gt;(load "jstc.scm")&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;and start playing with it. For starters, let's run two nodes:&lt;br /&gt;&lt;blockquote&gt;&lt;br /&gt;(start-node "test1")&lt;br /&gt;(start-node "test2")&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;and define a helper function to generate a list of integers from a specified range:&lt;br /&gt;&lt;blockquote&gt;&lt;br /&gt;(define (range min max) (let loop ((x max) (l '())) (if (&lt; x min) l (loop (- x 1) (cons x l)))))&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;Now we need to "teach" running evaluators the Fibonacci function:&lt;br /&gt;&lt;blockquote&gt;&lt;br /&gt;(tc-load (list "test1" "test2") "(define (fib n) (cond ((= n 0) 0) ((= n 1) 1) (else (+ (fib (- n 1)) (fib (- n 2))))))" )&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;and we are ready to spread a test job across the nodes:&lt;br /&gt;&lt;blockquote&gt;&lt;br /&gt;(tc-map (list "test1" "test2") "fib" (range 1 20))&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;After a few seconds you should receive the following list:&lt;br /&gt;&lt;blockquote&gt;&lt;br /&gt;(1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 1597 2584 4181 6765)&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;You can use &lt;span style="font-style:italic;"&gt;time&lt;/span&gt; function to compare computation times with results received by using a single node or a regular, sequential &lt;span style="font-style:italic;"&gt;map&lt;/span&gt;:&lt;br /&gt;&lt;blockquote&gt;&lt;br /&gt;(time (tc-map (list "test1" "test2") "fib" (range 1 20)))&lt;br /&gt;(time (tc-map (list "test1") "fib" (range 1 20)))&lt;br /&gt;(define (fib n) (cond ((= n 0) 0) ((= n 1) 1) (else (+ (fib (- n 1)) (fib (- n 2))))))&lt;br /&gt;(time (map fib (range 1 20)))&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;Take note that a function passed to &lt;span style="font-style:italic;"&gt;map&lt;/span&gt; is a regular Scheme expression, while with &lt;span style="font-style:italic;"&gt;tc-map&lt;/span&gt; it must be a string.&lt;br /&gt;&lt;br /&gt;It is quite possible that you get no gain over sequential processing using less than 3 nodes running on 3 cores with this library. The main reason is that Terracotta introduces some overhead itself. The second one is that nodes poll Terracotta for job lists in 20ms intervals. Those intervals are necessary if you don't want to consume the whole CPU power just for loops and leave none for jobs. You can adjust them by changing the value of &lt;span style="font-style:italic;"&gt;JSTC_EVAL_DELAY&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;I did some tests and I must say that the results surprised me. On my home laptop (Core2 Duo T5450 1.66 Ghz, 2 cores, 2GB RAM) the results looked like this:&lt;br /&gt;&lt;blockquote&gt;&lt;br /&gt;(time (map fib (range 1 25))) - 17234 msec&lt;br /&gt;(time (tc-map (list "test1") "fib" (range 1 25))) - 29020 msec&lt;br /&gt;(time (tc-map (list "test1" "test2") "fib" (range 1 25))) - 19620 msec&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;while on three servers (dual Xeon E5430 2.66 Ghz, 8 cores, 8GB RAM each):&lt;br /&gt;&lt;blockquote&gt;&lt;br /&gt;(time (map fib (range 1 25))) - 12687 msec&lt;br /&gt;(time (tc-map (list "test1") "fib" (range 1 25))) - 22502 msec&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;but:&lt;br /&gt;&lt;blockquote&gt;&lt;br /&gt;(time (tc-map (list "test1" "test2") "fib" (range 1 25))) - 25256 msec&lt;br /&gt;(time (tc-map (list "test1" "test2" "test3") "fib" (range 1 20))) - 22355 msec&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;when I ran the tests on a single machine, and:&lt;br /&gt;&lt;blockquote&gt;&lt;br /&gt;(time (tc-map (list "test1" "test2") "fib" (range 1 25))) - 14216 msec&lt;br /&gt;(time (tc-map (list "test1" "test2" "test3") "fib" (range 1 20))) - 11538 msec&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;when each node was on a different machine.&lt;br /&gt;On my laptop I got almost 150% speedup by using two Terracotta nodes instead of one, but on a server machine two nodes actually slowed the tasks down. I could get faster job processing only by spreading nodes across different machines. Adding new nodes to the machines seemed to have no impact on the results, so I couldn't get past 250% speedup factor.&lt;br /&gt;Weird, isn't it?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5635587370432045273-7246634709087475316?l=weblambdazero.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://weblambdazero.blogspot.com/feeds/7246634709087475316/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5635587370432045273&amp;postID=7246634709087475316' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5635587370432045273/posts/default/7246634709087475316'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5635587370432045273/posts/default/7246634709087475316'/><link rel='alternate' type='text/html' href='http://weblambdazero.blogspot.com/2008/11/distributed-processing-with-jscheme-and.html' title='Distributed processing with JScheme and Terracotta'/><author><name>Krzysztof Kliś</name><uri>http://www.blogger.com/profile/03518001329895236884</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://2.bp.blogspot.com/_CVm77bq8jjg/SNva5QYjDLI/AAAAAAAAABE/NKuv0JSEKuM/S220/calder.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5635587370432045273.post-7667439629646142359</id><published>2008-10-27T19:30:00.013+01:00</published><updated>2010-10-24T12:28:22.894+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='lisp'/><category scheme='http://www.blogger.com/atom/ns#' term='java'/><category scheme='http://www.blogger.com/atom/ns#' term='terracotta'/><title type='text'>Clustering Kawa with Terracotta</title><content type='html'>In my &lt;a href="http://weblambdazero.blogspot.com/2008/10/clustering-jscheme-with-terracotta.html"&gt;recent post&lt;/a&gt; I described a method of building a cluster of &lt;a href="http://jscheme.sourceforge.net/"&gt;JScheme&lt;/a&gt; instances using &lt;a href="http://www.terracotta.org/"&gt;Terracotta&lt;/a&gt; object management system. I also prepared a small library for JScheme that makes using Terracotta in JScheme easy - it is &lt;a href="http://www.gnu.org/licenses/lgpl.html"&gt;LGPL&lt;/a&gt; licensed and free for &lt;a href="http://www.caldersoft.net/files/jstc/"&gt;download&lt;/a&gt;. Today I tried the same trick with &lt;a href="http://www.gnu.org/software/kawa/"&gt;Kawa&lt;/a&gt;, which is not only a full-featured Scheme implementation in Java, but also a complete framework for implementing other programming languages to run on Java platform. Knowing how to cluster JScheme, making Kawa work with Terracotta was a piece of cake.&lt;br /&gt;First you start a Terracotta server. Then you run a Kawa shell through the following command:&lt;br /&gt;&lt;blockquote&gt;&lt;br /&gt;java -Xbootclasspath/p:[terracotta boot jar] -Dtc.config=tc-config.xml -Dtc.install-root=[terracotta install dir] -jar kawa.jar&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;Just as with JScheme, &lt;span style="font-style:italic;"&gt;boot jar&lt;/span&gt; is is a stub jar file that starts a Terracotta client before the main application and &lt;span style="font-style:italic;"&gt;tc-config&lt;/span&gt; is a Terracotta configuration file (see the &lt;a href="http://weblambdazero.blogspot.com/2008/10/clustering-jscheme-with-terracotta.html"&gt;post about JScheme&lt;/a&gt; for details).&lt;br /&gt;Next, you load the Terracotta library:&lt;br /&gt;&lt;blockquote&gt;&lt;br /&gt;(load "kwtc.scm")&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;and define an object (for example an ArrayList) to share across the cluster:&lt;br /&gt;&lt;blockquote&gt;&lt;br /&gt;(define ob (create-root "list" (make &amp;lt;java.util.ArrayList&amp;gt;)))&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;Now you can put values on the list:&lt;br /&gt;&lt;blockquote&gt;&lt;br /&gt;(sync-write (lambda () (ob:add 1)) ob)&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;and read them back synchronously:&lt;br /&gt;&lt;blockquote&gt;&lt;br /&gt;(sync-read (lambda () (ob:get 0)) ob))&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;or simply with:&lt;br /&gt;&lt;blockquote&gt;&lt;br /&gt;(ob:get 0)&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;The library for Kawa can be downloaded from &lt;a href="http://www.caldersoft.net/files/kwtc/"&gt;&lt;span style="font-weight:bold;"&gt;here&lt;/span&gt;&lt;/a&gt;.&lt;br /&gt;Happy coding!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5635587370432045273-7667439629646142359?l=weblambdazero.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://weblambdazero.blogspot.com/feeds/7667439629646142359/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5635587370432045273&amp;postID=7667439629646142359' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5635587370432045273/posts/default/7667439629646142359'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5635587370432045273/posts/default/7667439629646142359'/><link rel='alternate' type='text/html' href='http://weblambdazero.blogspot.com/2008/10/clustering-kawa-with-terracotta.html' title='Clustering Kawa with Terracotta'/><author><name>Krzysztof Kliś</name><uri>http://www.blogger.com/profile/03518001329895236884</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://2.bp.blogspot.com/_CVm77bq8jjg/SNva5QYjDLI/AAAAAAAAABE/NKuv0JSEKuM/S220/calder.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5635587370432045273.post-1049182435193984359</id><published>2008-10-26T15:06:00.013+01:00</published><updated>2010-10-24T12:28:39.015+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='lisp'/><category scheme='http://www.blogger.com/atom/ns#' term='java'/><category scheme='http://www.blogger.com/atom/ns#' term='terracotta'/><title type='text'>Clustering JScheme with Terracotta</title><content type='html'>In &lt;a href="http://weblambdazero.blogspot.com/2008/09/living-in-concurrent-world.html"&gt;one of my previous posts&lt;/a&gt; I mentioned &lt;a href="http://www.terracotta.org/"&gt;Terracotta&lt;/a&gt;, an open source clustering solution for Java. Its main advantage over traditional Java solutions in use (like &lt;a href="http://java.sun.com/docs/books/tutorial/rmi/index.html"&gt;RMI&lt;/a&gt;) is that it works as middleware between a JVM and an application, enabling transparent sharing of Java objects across the network. The only requirement for a programmer is to execute operations on shared objects in &lt;a href="http://java.sun.com/docs/books/tutorial/essential/concurrency/locksync.html"&gt;synchornized context&lt;/a&gt;, which allows you to build distributed applications or refactor already existing ones quickly.&lt;br /&gt;Inspired by&lt;a href="http://jonasboner.com/2007/02/05/clustering-jruby-with-open-terracotta/"&gt; Jonas Bonér's experiments with JRuby&lt;/a&gt; I decided to give it a try with &lt;a href="http://jscheme.sourceforge.net/"&gt;JScheme&lt;/a&gt;, an open source &lt;a href="http://en.wikipedia.org/wiki/Scheme_(programming_language)"&gt;Scheme&lt;/a&gt; implementation running on JVM. I chose JScheme over other Scheme implementations (like &lt;a href="http://www.gnu.org/software/kawa/"&gt;Kawa&lt;/a&gt; or &lt;a href="http://sisc-scheme.org/"&gt;SISC&lt;/a&gt;) because of its very simple, clear and elegant &lt;a href="http://jscheme.sourceforge.net/jscheme/doc/javaprimitives.html"&gt;interface to Java objects&lt;/a&gt;. In fact, since Terracotta operates on the JVM level, you can use it to cluster any application written in any language, as long as it compiles to Java bytecode and provides an interface to communicate with Java objects and classes.&lt;br /&gt;First, you need to &lt;a href="http://terracotta.org/web/display/orgsite/DownloadCatalog"&gt;download&lt;/a&gt; and install Terracotta (current stable version is 2.7.0). Then, you have to start a server with &lt;span style="font-style:italic;"&gt;start-tc-server.sh&lt;/span&gt; script. In Linux, if you encounter any strange errors running any of the scripts in the &lt;span style="font-style:italic;"&gt;bin&lt;/span&gt; directory of your Terracotta installation, change the header of a problematic script from &lt;span style="font-style:italic;"&gt;#!/bin/sh&lt;/span&gt; to &lt;span style="font-style:italic;"&gt;#!/bin/bash&lt;/span&gt; - this should help to solve the problem. The server manages all the shared objects in Terracotta cluster and needs to be started before any client applications are run.&lt;br /&gt;Next, you need to prepare a client configuration in the form of an XML file. I used a configuration provided by Jonas and stored it in &lt;span style="font-style:italic;"&gt;tc-config.xml&lt;/span&gt;:&lt;br /&gt;&lt;blockquote&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&amp;lt;?xml version="1.0" encoding="UTF-8"?&amp;gt;&lt;br /&gt;&amp;lt;tc:tc-config xmlns:tc="http://www.terracotta.org/config"&amp;gt;&lt;br /&gt;  &amp;lt;servers&amp;gt;&lt;br /&gt;    &amp;lt;server name="localhost"/&amp;gt;&lt;br /&gt;  &amp;lt;/servers&amp;gt;&lt;br /&gt;  &amp;lt;clients&amp;gt;&lt;br /&gt;    &amp;lt;logs&amp;gt;%(user.home)/terracotta/jtable/client-logs&amp;lt;/logs&amp;gt;&lt;br /&gt;    &amp;lt;statistics&amp;gt;%(user.home)/terracotta/jtable/client-logs&amp;lt;/statistics&amp;gt;&lt;br /&gt;  &amp;lt;/clients&amp;gt;&lt;br /&gt;  &amp;lt;application&amp;gt;&lt;br /&gt;    &amp;lt;dso&amp;gt;&lt;br /&gt;      &amp;lt;instrumented-classes&amp;gt;&lt;br /&gt;        &amp;lt;include&amp;gt;&lt;br /&gt;          &amp;lt;class-expression&amp;gt;*..*&amp;lt;/class-expression&amp;gt;&lt;br /&gt;        &amp;lt;/include&amp;gt;&lt;br /&gt;      &amp;lt;/instrumented-classes&amp;gt;&lt;br /&gt;    &amp;lt;/dso&amp;gt;&lt;br /&gt;  &amp;lt;/application&amp;gt;&lt;br /&gt;&amp;lt;/tc:tc-config&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;Now you can start JScheme interpreter hosted by Terracotta:&lt;br /&gt;&lt;blockquote&gt;&lt;br /&gt;java -Xbootclasspath/p:[terracotta boot jar] -Dtc.config=tc-config.xml -Dtc.install-root=[terracotta install dir] -jar jscheme.jar&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;Boot jar is a stub jar file that starts a Terracotta client and connects to the server before the main application is started. You should be able to find it in &lt;span style="font-style:italic;"&gt;lib/dso-boot&lt;/span&gt; folder of your Terracotta installation directory. If it isn't there, you can generate it with &lt;span style="font-style:italic;"&gt;make-boot-jar.sh&lt;/span&gt; script found in Terracotta &lt;span style="font-style:italic;"&gt;bin&lt;/span&gt; folder.&lt;br /&gt;Now when the whole working environment has been set up, you can use &lt;span style="font-style:italic;"&gt;com.tc.object.bytecode.ManagerUtil&lt;/span&gt; class to create a shared root object. Unfortunately Jonas's method which uses LOCK_TYPE_WRITE static field of &lt;span style="font-style:italic;"&gt;com.tc.object.bytecode.Manager&lt;/span&gt; class to perform a write lock during this operation fails to work. It causes some strange error about missing &lt;span style="font-style:italic;"&gt;com.tc.object.event.DmiManager&lt;/span&gt; class, which seems to be a problem &lt;a href="http://lists.terracotta.org/pipermail/tc-users/2008-September/000814.html"&gt;even with Jonas's JRuby example&lt;/a&gt; itself. A quick solution to this problem is to define locks in a way they are defined in &lt;span style="font-style:italic;"&gt;com.tc.object.lockmanager.api.LockLevel&lt;/span&gt; class:&lt;br /&gt;&lt;blockquote&gt;&lt;br /&gt;(define TC_READ_LOCK 1)&lt;br /&gt;(define TC_WRITE_LOCK 2)&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;Now let's define a sample object to share. It can be, for example, an ArrayList:&lt;br /&gt;&lt;blockquote&gt;&lt;br /&gt;(define l (ArrayList.))&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;Next you need to create a shared root object named "list" that will hold the &lt;span style="font-style:italic;"&gt;l&lt;/span&gt; object:&lt;br /&gt;&lt;blockquote&gt;&lt;br /&gt;(import "com.tc.object.bytecode.ManagerUtil")&lt;br /&gt;(ManagerUtil.beginLock "list" TC_WRITE_LOCK)&lt;br /&gt;(define ob (ManagerUtil.lookupOrCreateRoot "list" l))&lt;br /&gt;(ManagerUtil.commitLock "list")&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;Terracotta provides a great debugging tool called Terracotta Administrator Console to analyze the objects held by the server. Start the console by running &lt;span style="font-style:italic;"&gt;admin.sh&lt;/span&gt; script found in &lt;span style="font-style:italic;"&gt;bin&lt;/span&gt; folder of the Terracotta installation directory, then connect to &lt;span style="font-style:italic;"&gt;localhost&lt;/span&gt; and go to &lt;span style="font-style:italic;"&gt;Cluster object browser&lt;/span&gt;. You should see an empty ArrayList on the object list.&lt;br /&gt;Now let's add a new value to the shared object:&lt;br /&gt;&lt;blockquote&gt;&lt;br /&gt;(ManagerUtil.monitorEnter ob TC_WRITE_LOCK)&lt;br /&gt;(.add ob 1)&lt;br /&gt;(ManagerUtil.monitorExit ob)&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;Go back to Terracotta Administrator Console, select the shared ArrayList and press F5 to refresh the view. You should see that now it holds a single value: 1.&lt;br /&gt;Now start another scheme shell instance and try to read the first list value on the shared list:&lt;br /&gt;&lt;blockquote&gt;&lt;br /&gt;(define TC_READ_LOCK 1)&lt;br /&gt;(define TC_WRITE_LOCK 2)&lt;br /&gt;(import "com.tc.object.bytecode.ManagerUtil")&lt;br /&gt;(ManagerUtil.beginLock "list" TC_WRITE_LOCK)&lt;br /&gt;(define ob (ManagerUtil.lookupOrCreateRoot "list" (ArrayList.)))&lt;br /&gt;(ManagerUtil.commitLock "list")&lt;br /&gt;(.get ob 0)&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;The return value is 1. Sweet!&lt;br /&gt;I wrote a small library for JScheme that allows you to perform the basic operations of creating shared root objects in Terracotta and modifying them with read and write locks. You can download it from &lt;a href="http://www.caldersoft.net/files/jstc/"&gt;&lt;span style="font-weight:bold;"&gt;this location&lt;/span&gt;&lt;/a&gt;.&lt;br /&gt;To do the list operations described above you can simply do:&lt;br /&gt;&lt;blockquote&gt;&lt;br /&gt;(load "jstc.scm")&lt;br /&gt;(define ob (create-root "list" (ArrayList.)))&lt;br /&gt;(sync-write (lambda () (.add ob 1)) ob)&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;in one shell and then read the list value in another shell:&lt;br /&gt;&lt;blockquote&gt;&lt;br /&gt;(load "jstc.scm")&lt;br /&gt;(define ob (create-root "list" (ArrayList.)))&lt;br /&gt;(.get ob 0)&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;Have fun!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5635587370432045273-1049182435193984359?l=weblambdazero.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://weblambdazero.blogspot.com/feeds/1049182435193984359/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5635587370432045273&amp;postID=1049182435193984359' title='5 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5635587370432045273/posts/default/1049182435193984359'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5635587370432045273/posts/default/1049182435193984359'/><link rel='alternate' type='text/html' href='http://weblambdazero.blogspot.com/2008/10/clustering-jscheme-with-terracotta.html' title='Clustering JScheme with Terracotta'/><author><name>Krzysztof Kliś</name><uri>http://www.blogger.com/profile/03518001329895236884</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://2.bp.blogspot.com/_CVm77bq8jjg/SNva5QYjDLI/AAAAAAAAABE/NKuv0JSEKuM/S220/calder.jpg'/></author><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5635587370432045273.post-8327921381754968796</id><published>2008-10-23T23:30:00.004+02:00</published><updated>2008-10-24T12:26:16.397+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='erlang'/><title type='text'>Erlang tips and tricks: records</title><content type='html'>The most awkward thing I ran into while programming in Erlang are things called records. I call them "things" since they are neither Erlang primitives nor data structures. In fact, records are not even understood by Erlang VM itslef (try to define a record in interactive shell). They are some kind of macros (they remind me the ones used in &lt;a href="http://en.wikipedia.org/wiki/C_preprocessor#Macro_definition_and_expansion"&gt;ANSI C&lt;/a&gt;) that are translated by the compiler into Erlang native data structures.&lt;br /&gt;The biggest problem with records is that you cannot dynamically modify them. For example, suppose you want to create a table in Mnesia, but you don't know at the moment how many columns your table will have. With records, you have to provide all record declarations for all tables you plan to generate on compilation time, which sometimes is simply impossible.&lt;br /&gt;I did some research on the topic while writing &lt;a href="http://weblambdazero.blogspot.com/search/label/mnapi"&gt;Mnapi&lt;/a&gt;, and I must say it wasn't that easy if you don't know where to start. Finally, I managed to decipher Erlang records secrets mostly by analyzing Mnesia source code. One more reason for using open source software, by the way :-)&lt;br /&gt;It turns out that records are in fact wrappers for &lt;a href="http://www.erlang.org/course/sequential_programming.html#tuples"&gt;tuples&lt;/a&gt;. So a record defined as:&lt;br /&gt;&lt;blockquote&gt;-record(book, {isbn, author, title}).&lt;/blockquote&gt;&lt;br /&gt;gets translated internally into:&lt;br /&gt;&lt;blockquote&gt;{book, isbn, author, title}.&lt;/blockquote&gt;&lt;br /&gt;Thus, an equivalent of:&lt;br /&gt;&lt;blockquote&gt;mnesia:write(#book{isbn = I, author = A, title = T}).&lt;/blockquote&gt;&lt;br /&gt;is:&lt;br /&gt;&lt;blockquote&gt;mnesia:write({book, I, A, T}).&lt;/blockquote&gt;&lt;br /&gt;The only advantage of such crippled structure is that the compiler knows the positions of all elements in the record, so it can always put them in a valid tuple in correct order and find possible errors instantly at the compilation stage. No matter if you write:&lt;br /&gt;&lt;blockquote&gt;&lt;br /&gt;#book{isbn = I, author = A, title = T}.&lt;br /&gt;#book{author = A, isbn = I, title = T}.&lt;br /&gt;#book{title = T, author = A, isbn = I}.&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;the &lt;span style="font-style:italic;"&gt;#book&lt;/span&gt; record will eventually end up in Erlang as:&lt;br /&gt;&lt;blockquote&gt;{book, I, A, T}.&lt;/blockquote&gt;&lt;br /&gt;Records try to make accessing data easier. To get an author from the tuple above you would have to use &lt;span style="font-style:italic;"&gt;element&lt;/span&gt; function:&lt;br /&gt;&lt;blockquote&gt;X = element(3, {book, I, A, T}).&lt;/blockquote&gt;&lt;br /&gt;which can become problematic if you shift fields in the tuple. With record you can do the same simply with:&lt;br /&gt;&lt;blockquote&gt;X = #book.author.&lt;/blockquote&gt;&lt;br /&gt;no matter what the order of the record is. But it's still cumbersome and static.&lt;br /&gt;Fortunately, Erlang allows you to build &lt;a href="http://www.erlang.org/doc/man/dict.html"&gt;dictionaries&lt;/a&gt;, which can be used to store Key - Value pairs dynamically. For example:&lt;br /&gt;&lt;blockquote&gt;&lt;br /&gt;D = dict:new(),&lt;br /&gt;D1 = dict:store(isbn, 1234, D),&lt;br /&gt;D2 = dict:store(author, myAuthor, D1),&lt;br /&gt;D3 = dict:store(title, myTitle, D2),&lt;br /&gt;Book = dict:store(book, D3, D3),&lt;br /&gt;dict:find(author, Book).&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;Personally, I don't use records, unless I really have to. I use dictionaries instead, they are much more powerful and elegant. And you can evaluate them on runtime.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5635587370432045273-8327921381754968796?l=weblambdazero.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://weblambdazero.blogspot.com/feeds/8327921381754968796/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5635587370432045273&amp;postID=8327921381754968796' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5635587370432045273/posts/default/8327921381754968796'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5635587370432045273/posts/default/8327921381754968796'/><link rel='alternate' type='text/html' href='http://weblambdazero.blogspot.com/2008/10/erlang-tips-and-tricks-records.html' title='Erlang tips and tricks: records'/><author><name>Krzysztof Kliś</name><uri>http://www.blogger.com/profile/03518001329895236884</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://2.bp.blogspot.com/_CVm77bq8jjg/SNva5QYjDLI/AAAAAAAAABE/NKuv0JSEKuM/S220/calder.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5635587370432045273.post-3602130053503588989</id><published>2008-10-23T20:19:00.012+02:00</published><updated>2009-12-29T21:35:34.385+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java'/><category scheme='http://www.blogger.com/atom/ns#' term='erlang'/><category scheme='http://www.blogger.com/atom/ns#' term='mnesia'/><category scheme='http://www.blogger.com/atom/ns#' term='php'/><category scheme='http://www.blogger.com/atom/ns#' term='mnapi'/><title type='text'>Mnapi 1.2</title><content type='html'>I tweaked a bit my &lt;a href="http://weblambdazero.blogspot.com/search/label/mnapi"&gt;Java/PHP API for Mnesia&lt;/a&gt; by adding memory caching for auxiliary table structures used by the API. My tests have shown that it speeds up fetching single rows for tables where data are kept in &lt;span style="font-style:italic;"&gt;disc_only_copies&lt;/span&gt; by about 2%. Much less than I expected, I must say. But since the changes are really little and work seamlessly with data created with Mnapi 1.1 and earlier, I decided to leave them in the code. If anyone is interested in the new version, &lt;a href="http://www.caldersoft.net/files/mnapi/"&gt;&lt;span style="font-weight:bold;"&gt;here it is&lt;/span&gt;&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5635587370432045273-3602130053503588989?l=weblambdazero.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://weblambdazero.blogspot.com/feeds/3602130053503588989/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5635587370432045273&amp;postID=3602130053503588989' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5635587370432045273/posts/default/3602130053503588989'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5635587370432045273/posts/default/3602130053503588989'/><link rel='alternate' type='text/html' href='http://weblambdazero.blogspot.com/2008/10/mnapi-12.html' title='Mnapi 1.2'/><author><name>Krzysztof Kliś</name><uri>http://www.blogger.com/profile/03518001329895236884</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://2.bp.blogspot.com/_CVm77bq8jjg/SNva5QYjDLI/AAAAAAAAABE/NKuv0JSEKuM/S220/calder.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5635587370432045273.post-4913452297840316380</id><published>2008-10-05T16:30:00.014+02:00</published><updated>2009-12-29T21:35:15.786+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java'/><category scheme='http://www.blogger.com/atom/ns#' term='erlang'/><category scheme='http://www.blogger.com/atom/ns#' term='mnesia'/><category scheme='http://www.blogger.com/atom/ns#' term='php'/><category scheme='http://www.blogger.com/atom/ns#' term='mnapi'/><title type='text'>Mnapi 1.1</title><content type='html'>Today I released a new version of my &lt;a href="http://weblambdazero.blogspot.com/2008/08/mnapi-mnesia-api-for-java-and-php.html"&gt;Mnesia API for Java and PHP&lt;/a&gt;. The main change is merging main code trunk with the &lt;a href="http://weblambdazero.blogspot.com/2008/09/mnapi-for-tokyocabinet.html"&gt;Tokyo Cabinet branch&lt;/a&gt; and adding the ability to select storage type when creating a table. You can now choose one of the following:&lt;br /&gt;* &lt;span style="font-style:italic;"&gt;ram&lt;/span&gt; - for RAM only based storage,&lt;br /&gt;* &lt;span style="font-style:italic;"&gt;disc&lt;/span&gt; - for disc based storage with RAM copy of the table for improved performance (this is the default),&lt;br /&gt;*  &lt;span style="font-style:italic;"&gt;disc_only&lt;/span&gt; - for disc only based storage (much slower, but uses a lot less memory),&lt;br /&gt;* &lt;span style="font-style:italic;"&gt;tokyo&lt;/span&gt; - for use with Tokyo Cabinet storage engine.&lt;br /&gt;The API does not support table fragmentation and as for now I don't plan to introduce this feature (you can always use &lt;span style="font-style:italic;"&gt;tokyo&lt;/span&gt; as a storage for data exceeding &lt;a href="http://article.gmane.org/gmane.comp.lang.erlang.general/27651"&gt;2GB limit&lt;/a&gt;). But, since the library code is licensed under &lt;a href="http://www.gnu.org/licenses/lgpl.html"&gt;LGPL&lt;/a&gt;, you are &lt;a href="http://www.gnu.org/philosophy/free-sw.html"&gt;free&lt;/a&gt; to extend it or modify it if you lack any feature.&lt;br /&gt;You can get Mnapi 1.1 &lt;a href="http://www.caldersoft.net/files/mnapi/"&gt;&lt;span style="font-weight:bold;"&gt;here&lt;/span&gt;&lt;/a&gt;.&lt;br /&gt;Happy coding!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5635587370432045273-4913452297840316380?l=weblambdazero.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://weblambdazero.blogspot.com/feeds/4913452297840316380/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5635587370432045273&amp;postID=4913452297840316380' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5635587370432045273/posts/default/4913452297840316380'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5635587370432045273/posts/default/4913452297840316380'/><link rel='alternate' type='text/html' href='http://weblambdazero.blogspot.com/2008/10/mnapi-11.html' title='Mnapi 1.1'/><author><name>Krzysztof Kliś</name><uri>http://www.blogger.com/profile/03518001329895236884</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://2.bp.blogspot.com/_CVm77bq8jjg/SNva5QYjDLI/AAAAAAAAABE/NKuv0JSEKuM/S220/calder.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5635587370432045273.post-1048364781857713908</id><published>2008-09-29T02:08:00.006+02:00</published><updated>2010-06-03T18:03:34.462+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='lisp'/><category scheme='http://www.blogger.com/atom/ns#' term='erlang'/><title type='text'>LFE: Lisp Flavoured Erlang</title><content type='html'>Today Robert Virding &lt;a href="http://forum.trapexit.org/viewtopic.php?p=43887"&gt;released&lt;/a&gt; a new version of his Lisp syntax front-end to the Erlang compiler, which he called LFE (Lisp Flavoured Erlang). I saw the previous versions of his work, and I must say that it is the first version that looks really mature to me now.&lt;br /&gt;&lt;br /&gt;LFE is not an implementation of &lt;a href="http://en.wikipedia.org/wiki/Lisp"&gt;Lisp&lt;/a&gt; or even &lt;a href="http://en.wikipedia.org/wiki/Scheme_(programming_language)"&gt;Scheme&lt;/a&gt;. Its syntax reflects some specific constructs and limitations of Erlang, since it compiles programs to Erlang bytecode and runs them directly on Erlang VM.&lt;br /&gt;&lt;br /&gt;Is a &lt;a href="http://weblambdazero.blogspot.com/2008/09/scripting-erlang.html"&gt;new trend for Erlang&lt;/a&gt; coming on?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5635587370432045273-1048364781857713908?l=weblambdazero.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://weblambdazero.blogspot.com/feeds/1048364781857713908/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5635587370432045273&amp;postID=1048364781857713908' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5635587370432045273/posts/default/1048364781857713908'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5635587370432045273/posts/default/1048364781857713908'/><link rel='alternate' type='text/html' href='http://weblambdazero.blogspot.com/2008/09/lfe-lisp-flavoured-erlang.html' title='LFE: Lisp Flavoured Erlang'/><author><name>Krzysztof Kliś</name><uri>http://www.blogger.com/profile/03518001329895236884</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://2.bp.blogspot.com/_CVm77bq8jjg/SNva5QYjDLI/AAAAAAAAABE/NKuv0JSEKuM/S220/calder.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5635587370432045273.post-6242641814108508408</id><published>2008-09-27T22:32:00.008+02:00</published><updated>2010-07-15T23:32:09.297+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='c/c++'/><title type='text'>Cilk: C that scales</title><content type='html'>Do you like &lt;a href="http://en.wikipedia.org/wiki/C_(programming_language)"&gt;C&lt;/a&gt;? I do. I used to write software for embedded devices, where resources are priceless and each CPU cycle and every byte of RAM counts. I enjoyed it a lot, mostly because it was a real challenge and it reminded me of good old 8-bit computer times, when if your program was not fast enough you had to optimize its code or find a smarter solution instead of buying a better CPU, expanding memory, or building a home data center. Even today few people question using C to speed up the most critical parts of software, not to mention some obvious examples like Linux kernel, written almost entirely in ANSI C. Two years ago &lt;a href="http://www.nvidia.com/"&gt;NVidia&lt;/a&gt; announced its &lt;a href="http://www.nvidia.com/object/cuda_what_is.html"&gt;CUDA platform&lt;/a&gt;, which allows developers to write software in C that can run concurrently on many &lt;a href="http://www.nvidia.com/object/cuda_learn_products.html"&gt;GPUs&lt;/a&gt;, outperforming applications using standard CPUs.&lt;br /&gt;&lt;br /&gt;For those who don't own NVidia hardware, there is an alternative called &lt;a href="http://supertech.csail.mit.edu/cilk/"&gt;Cilk&lt;/a&gt;. Cilk is a language for multithreaded parallel programming based on ANSI C. It extends standard C with new keywords like &lt;span style="font-style:italic;"&gt;cilk&lt;/span&gt; (identifying parallel function), &lt;span style="font-style:italic;"&gt;spawn&lt;/span&gt; (which spawns a new computation thread) and &lt;span style="font-style:italic;"&gt;sync&lt;/span&gt; (which gathers job results from all threads started with &lt;span style="font-style:italic;"&gt;spawn&lt;/span&gt;).&lt;br /&gt;&lt;br /&gt;I ran an example Cilk application that finds &lt;a href="http://mathworld.wolfram.com/FibonacciNumber.html"&gt;Fibonacci numbers&lt;/a&gt; of a given value:&lt;br /&gt;&lt;blockquote&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;#include &amp;lt;cilk-lib.cilkh&amp;gt;&lt;br /&gt;#include &amp;lt;stdlib.h&amp;gt;&lt;br /&gt;#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;&lt;br /&gt;cilk int fib(int n)&lt;br /&gt;{&lt;br /&gt;     if (n &amp;lt; 2)&lt;br /&gt;          return (n);&lt;br /&gt;     else {&lt;br /&gt;          int x, y;&lt;br /&gt;          x = spawn fib(n - 1);&lt;br /&gt;          y = spawn fib(n - 2);&lt;br /&gt;          sync;&lt;br /&gt;          return (x + y);&lt;br /&gt;     }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;cilk int main(int argc, char *argv[])&lt;br /&gt;{&lt;br /&gt;     int n, result;&lt;br /&gt;&lt;br /&gt;     if (argc != 2) {&lt;br /&gt;          fprintf(stderr, "Usage: fib [&lt;cilk options&gt;] &amp;lt;n&amp;gt;\n");&lt;br /&gt;          Cilk_exit(1);&lt;br /&gt;     }&lt;br /&gt;     n = atoi(argv[1]);&lt;br /&gt;     result = spawn fib(n);&lt;br /&gt;     sync;&lt;br /&gt;&lt;br /&gt;     printf("Result: %d\n", result);&lt;br /&gt;     return 0;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;As you can see it looks almost like an ordinary C program. You can run it with &lt;span style="font-style:italic;"&gt;--nproc&lt;/span&gt; argument to determine the number of CPUs (or CPU cores) that are supposed to be used by the application.&lt;br /&gt;&lt;br /&gt;As I expected, the Cilk program turned out to be faster than its &lt;a href="http://weblambdazero.blogspot.com/2008/08/mapreduce-in-erlang.html"&gt;Erlang equivalent&lt;/a&gt;. The speedup was from 5.110972 to 0.689607 seconds on dual Xeon E5430 2.66 Ghz (8 cores total), comparing to 25.635218 and 10.017358 seconds of Erlang version respectively. But what struck me the most about the results was that the &lt;span style="font-weight:bold;"&gt;Cilk code scaled in almost linear manner&lt;/span&gt;:&lt;br /&gt;&lt;blockquote&gt;&lt;br /&gt;Wall-clock running time on 1 processor: 5.110972 s&lt;br /&gt;Wall-clock running time on 2 processors: 2.696646 s&lt;br /&gt;Wall-clock running time on 4 processors: 1.355353 s&lt;br /&gt;Wall-clock running time on 8 processors: 689.607000 ms&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;Cilk code performance boost was approximately 740%, comparing to Erlang 250%. On 8 cores Cilk code outperformed Erlang code by more than an order of magnitude. This is something that should make Erlang developers feel respect for.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5635587370432045273-6242641814108508408?l=weblambdazero.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://weblambdazero.blogspot.com/feeds/6242641814108508408/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5635587370432045273&amp;postID=6242641814108508408' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5635587370432045273/posts/default/6242641814108508408'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5635587370432045273/posts/default/6242641814108508408'/><link rel='alternate' type='text/html' href='http://weblambdazero.blogspot.com/2008/09/cilk-c-that-scales.html' title='Cilk: C that scales'/><author><name>Krzysztof Kliś</name><uri>http://www.blogger.com/profile/03518001329895236884</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://2.bp.blogspot.com/_CVm77bq8jjg/SNva5QYjDLI/AAAAAAAAABE/NKuv0JSEKuM/S220/calder.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5635587370432045273.post-5060864166638996132</id><published>2008-09-26T22:38:00.008+02:00</published><updated>2009-02-17T01:08:38.742+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='java'/><category scheme='http://www.blogger.com/atom/ns#' term='terracotta'/><category scheme='http://www.blogger.com/atom/ns#' term='python'/><category scheme='http://www.blogger.com/atom/ns#' term='php'/><title type='text'>Living in a concurrent world</title><content type='html'>&lt;a href="http://www.erlang.org/"&gt;Erlang&lt;/a&gt; is a great platform for writing concurrent, distributed, fault-tolerant applications. But it's not the only one. Some of the &lt;a href="http://www.langpop.com/"&gt;popular programming languages&lt;/a&gt; also have tools that help developers build concurrent, highly scalable web services.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Java&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;One of the main sources of Java power is that it has libraries to do almost anything you can imagine. And there are of course libraries that offer various solutions to the scaling out problem, like &lt;a href="http://soa.sys-con.com/node/39400"&gt;JMS with JCache&lt;/a&gt; or &lt;a href="http://www.scala-lang.org/node/242"&gt;Scala Actors&lt;/a&gt; library.&lt;br /&gt;But the real killer application in my opinion is &lt;a href="http://www.terracotta.org/"&gt;Terracotta&lt;/a&gt;. It's an open source clustering solution for Java that works &lt;span style="font-weight:bold;"&gt;beneath the application level&lt;/span&gt;. It uses &lt;a href="http://en.wikipedia.org/wiki/Software_transactional_memory"&gt;transactional memory&lt;/a&gt; to share objects between applications running on different JVM instances, most notably on different physical machines. Object pool is stored on a master server, which can have multiple &lt;a href="http://www.terracotta.org/confluence/display/docs1/Creating+a+Terracotta+Server+Cluster"&gt;passive backups&lt;/a&gt;. As a result you receive a clustering solution transparent for the applications you write (you only need to define objects you want to share in Terracotta configuration files). What's more, you can use Terracotta to cluster applications created in languages other than Java, but running on JVM - like &lt;a href="http://jonasboner.com/2007/02/05/clustering-jruby-with-open-terracotta/"&gt;JRuby&lt;/a&gt; or &lt;a href="http://jonasboner.com/2008/01/25/clustering-scala-actors-with-terracotta/"&gt;Scala&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Python&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Python programmers can use &lt;a href="http://discoproject.org/"&gt;Disco&lt;/a&gt;. It's an open source &lt;a href="http://en.wikipedia.org/wiki/MapReduce"&gt;map-reduce&lt;/a&gt; framework written in Erlang that allows you to scale your application easily. Unfortunately, it does not allow neither sharing any data between different application instances (like Terracotta), nor passing messages (like Erlang itself).&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Ruby&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Ruby looks much better than Python in this aspect. First, there is &lt;a href="http://jruby.codehaus.org/"&gt;JRuby&lt;/a&gt;, which you can cluster with Terracotta. Second, there is soon-to-come &lt;a href="http://ruby.gemstone.com/"&gt;MagLev&lt;/a&gt; by &lt;a href="http://www.gemstone.com/"&gt;Gemstone&lt;/a&gt;. It's a Ruby implementation running on a &lt;a href="http://www.gemstone.com/products/smalltalk/"&gt;Smalltalk virtual machine&lt;/a&gt;, and the first public &lt;a href="http://www.vimeo.com/1147409"&gt;presentation&lt;/a&gt; of MagLev at RailsConf 2008 was quite impressive.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;PHP&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Not much to say here... You cannot expect much from a language created to produce dynamic HTML pages. You can only rely on external libraries like &lt;a href="http://www.danga.com/memcached/"&gt;memcached&lt;/a&gt; to store and retrieve objects, but it's by no means an extension to the language itself.&lt;br /&gt;&lt;br /&gt;If you know of any other interesting projects providing transparent (or almost transparent) concurrency and distribution to already existing programming languages, you are welcome to tell me about it!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5635587370432045273-5060864166638996132?l=weblambdazero.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://weblambdazero.blogspot.com/feeds/5060864166638996132/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5635587370432045273&amp;postID=5060864166638996132' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5635587370432045273/posts/default/5060864166638996132'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5635587370432045273/posts/default/5060864166638996132'/><link rel='alternate' type='text/html' href='http://weblambdazero.blogspot.com/2008/09/living-in-concurrent-world.html' title='Living in a concurrent world'/><author><name>Krzysztof Kliś</name><uri>http://www.blogger.com/profile/03518001329895236884</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://2.bp.blogspot.com/_CVm77bq8jjg/SNva5QYjDLI/AAAAAAAAABE/NKuv0JSEKuM/S220/calder.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5635587370432045273.post-8622379270928014900</id><published>2008-09-26T15:48:00.005+02:00</published><updated>2009-12-29T21:40:36.280+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='erlang'/><title type='text'>Scripting Erlang</title><content type='html'>Today I came across an interesting &lt;a href="http://debasishg.blogspot.com/2008/06/targeting-beam-for-extreme-reliability.html"&gt;post&lt;/a&gt; about new scripting language &lt;a href="http://reia-lang.org/"&gt;Reia&lt;/a&gt; for Erlang virtual machine. It seems that some people within the Erlang community started to realize what .NET developers always knew and Java programmers understood a few years ago: that you have to distinguish &lt;span style="font-weight:bold;"&gt;between the language and the runtime&lt;/span&gt;. People who were tired with Java limitations or just wanted to introduce their own ideas started to develop things like &lt;a href="http://jruby.codehaus.org/"&gt;JRuby&lt;/a&gt;, &lt;a href="http://www.jython.org/"&gt;Jython&lt;/a&gt;, &lt;a href="http://groovy.codehaus.org/"&gt;Groovy&lt;/a&gt;, &lt;a href="http://www.scala-lang.org/"&gt;Scala&lt;/a&gt; or &lt;a href="http://clojure.org/"&gt;Clojure&lt;/a&gt;, just to name a few. Erlang has already developed a strong &lt;a href="http://debasishg.blogspot.com/2008/08/erlang-as-middleware.html"&gt;position as middleware&lt;/a&gt;. Now it's time to make it scriptable.&lt;br /&gt;&lt;br /&gt;You can read more about Reia on &lt;a href="http://tonyarcieri.org/"&gt;this blog&lt;/a&gt;. It discusses Reia design principles and goals, as well as some controversial ideas, like introducing &lt;a href="http://tonyarcieri.org/articles/2008/09/24/reia-classes-and-objects"&gt;classes and objects&lt;/a&gt; or &lt;a href="http://tonyarcieri.org/articles/2008/07/26/the-single-assignment-cargo-cult"&gt;multiple variable assignment&lt;/a&gt;. It is true that it goes up the stream against &lt;a href="http://www.sics.se/~joe/thesis/armstrong_thesis_2003.pdf"&gt;Erlang philosophy&lt;/a&gt;, but I think that there is nothing inherently stupid about any idea until you can prove it wrong. This is why I don't agree with Joe Armstrong's thesis that &lt;a href="http://www.sics.se/~joe/bluetail/vol1/v1_oo.html"&gt;Object Oriented programming sucks&lt;/a&gt;. There are programming languages that succesfully combine OO and functional paradigms (&lt;a href="http://caml.inria.fr/ocaml/"&gt;OCaml&lt;/a&gt;, &lt;a href="http://www.scala-lang.org/"&gt;Scala&lt;/a&gt;, &lt;a href="http://en.wikipedia.org/wiki/Common_Lisp_Object_System"&gt;CLOS&lt;/a&gt;), which prove just the opposite. It would be nice to see a modern object system in Erlang, and &lt;a href="http://en.wikipedia.org/wiki/ALGOL"&gt;ALGOL&lt;/a&gt; based syntax could convince more people to use this excellent platform. Or, at least, possibly alleviate some already exising &lt;a href="http://damienkatz.net/2008/03/what_sucks_abou.html"&gt;Erlang pains&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5635587370432045273-8622379270928014900?l=weblambdazero.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://weblambdazero.blogspot.com/feeds/8622379270928014900/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5635587370432045273&amp;postID=8622379270928014900' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5635587370432045273/posts/default/8622379270928014900'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5635587370432045273/posts/default/8622379270928014900'/><link rel='alternate' type='text/html' href='http://weblambdazero.blogspot.com/2008/09/scripting-erlang.html' title='Scripting Erlang'/><author><name>Krzysztof Kliś</name><uri>http://www.blogger.com/profile/03518001329895236884</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://2.bp.blogspot.com/_CVm77bq8jjg/SNva5QYjDLI/AAAAAAAAABE/NKuv0JSEKuM/S220/calder.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5635587370432045273.post-2603711297093895818</id><published>2008-09-26T02:36:00.013+02:00</published><updated>2009-12-29T21:34:13.137+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java'/><category scheme='http://www.blogger.com/atom/ns#' term='erlang'/><category scheme='http://www.blogger.com/atom/ns#' term='mnesia'/><category scheme='http://www.blogger.com/atom/ns#' term='php'/><category scheme='http://www.blogger.com/atom/ns#' term='mnapi'/><title type='text'>Mnapi for Tokyocabinet</title><content type='html'>Finally, I found some time to patch &lt;a href="http://weblambdazero.blogspot.com/2008/08/mnapi-mnesia-api-for-java-and-php.html"&gt;Mnapi&lt;/a&gt; to work with &lt;a href="http://code.google.com/p/tcerl/"&gt;tcerl&lt;/a&gt;. Now you can use it to build your web service with this &lt;a href="http://weblambdazero.blogspot.com/2008/09/sky-is-limit.html"&gt;highly promising&lt;/a&gt; Mnesia storage backend.&lt;br /&gt;&lt;br /&gt;You can download the new Mnapi &lt;a href="http://www.caldersoft.net/files/mnapi/"&gt;&lt;span style="font-weight:bold;"&gt;here&lt;/span&gt;&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Due to the nature of Tokyocabinet, remember to always stop Mnapi via &lt;blockquote&gt;mnapi:stop().&lt;/blockquote&gt; before closing or shooting Erlang shell, so it could gracefully flush all RAM buffered data to disk before stopping Mnesia. Yeah, I know I could use &lt;span style="font-style:italic;"&gt;gen_server&lt;/span&gt; behaviour to handle it, but I just cannot convince myself to Erlang &lt;span style="font-style:italic;"&gt;behaviourism&lt;/span&gt; ;-)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5635587370432045273-2603711297093895818?l=weblambdazero.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://weblambdazero.blogspot.com/feeds/2603711297093895818/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5635587370432045273&amp;postID=2603711297093895818' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5635587370432045273/posts/default/2603711297093895818'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5635587370432045273/posts/default/2603711297093895818'/><link rel='alternate' type='text/html' href='http://weblambdazero.blogspot.com/2008/09/mnapi-for-tokyocabinet.html' title='Mnapi for Tokyocabinet'/><author><name>Krzysztof Kliś</name><uri>http://www.blogger.com/profile/03518001329895236884</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://2.bp.blogspot.com/_CVm77bq8jjg/SNva5QYjDLI/AAAAAAAAABE/NKuv0JSEKuM/S220/calder.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5635587370432045273.post-6979420121522769830</id><published>2008-09-21T17:45:00.002+02:00</published><updated>2008-09-29T13:14:00.720+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='erlang'/><category scheme='http://www.blogger.com/atom/ns#' term='mnesia'/><title type='text'>Sky is the limit for Mnesia</title><content type='html'>Until recently the biggest &lt;a href="http://www.erlang.org/doc/apps/mnesia/"&gt;Mnesia&lt;/a&gt; flaw was its &lt;a href="http://article.gmane.org/gmane.comp.lang.erlang.general/27651"&gt;storage limit&lt;/a&gt;. It is not the fault of the database system, since Mnesia itself can handle data of virtually infinite size. The main problem lays in an outdated Erlang term storage engine called &lt;a href="http://www.erlang.org/doc/man/dets.html"&gt;DETS&lt;/a&gt;, which is slow and uses 32-bit offsets (it limits single file size to 2GB). DETS could be a perfect fit for the famous &lt;a href="http://www.ericsson.com/ericsson/corpinfo/publications/review/2000_03/files/2000031.pdf"&gt;AXD301 ATM switch&lt;/a&gt;, but is certainly not for modern web development. A few times I had to drop Mnesia in favour of &lt;a href="http://hadoop.apache.org/hbase/"&gt;Hbase&lt;/a&gt; to serve data and use &lt;a href="http://www.erlang.org/doc/apps/jinterface/"&gt;Jinterface&lt;/a&gt; to make it communicate with Erlang code, which served application logic.&lt;br /&gt;&lt;br /&gt;But those times are finally over. Thanks to &lt;a href="http://www.wagerlabs.com/blog/2008/06/mnesia-unlimited.html"&gt;Joel Reymont&lt;/a&gt; and the &lt;a href="http://dukesoferl.blogspot.com/2008/06/tokyocabinet-and-mnesia.html"&gt;Dukes of Erl&lt;/a&gt; you can now use &lt;a href="http://tokyocabinet.sourceforge.net/index.html"&gt;Tokyocabinet&lt;/a&gt; engine as a storage for Mnesia. What is the most exciting about this solution is that it is completely transparent to your application - only creating a table looks a bit different:&lt;br /&gt;&lt;blockquote&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;Table = testtab,&lt;br /&gt;mnesia:create_table(Table, [{type, {external, ordered_set, tcbdbtab}},&lt;br /&gt;                            {external_copies, [node()]},&lt;br /&gt;                            {user_properties, [{deflate, true},&lt;br /&gt;                                               {bucket_array_size,&lt;br /&gt;                                               10000}]}]).&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;You also need to start &lt;a href="http://code.google.com/p/tcerl/"&gt;tcerl&lt;/a&gt; before running Mnesia:&lt;br /&gt;&lt;blockquote&gt;&lt;br /&gt;tcerl:start().&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;and synchronize table data with disk before closing Erlang, if you don't want to loose some of your data:&lt;br /&gt;&lt;blockquote&gt;&lt;br /&gt;Port = mnesia_lib:val({Table, tcbdb_port}),&lt;br /&gt;tcbdbets:sync(Port).&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;To sync all existing Mnesia tables you can use the following function:&lt;br /&gt;&lt;blockquote&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;F = fun(T) -&gt;&lt;br /&gt;            case catch mnesia_lib:val({T, tcbdb_port}) of&lt;br /&gt;                {'EXIT', _} -&gt;&lt;br /&gt;                    skip;&lt;br /&gt;                Port -&gt;&lt;br /&gt;                    tcbdbets:sync(Port)&lt;br /&gt;            end&lt;br /&gt;    end,&lt;br /&gt;Tabs = mnesia_lib:val({schema, tables}),&lt;br /&gt;lists:foreach(F, Tabs).&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;All other common operations, like reading and writing data, transactions, etc., don't need to be changed. You can learn more by looking at &lt;a href="http://code.google.com/p/tcerl/wiki/Example"&gt;example&lt;/a&gt; provided with the library.&lt;br /&gt;&lt;br /&gt;I managed to make &lt;a href="http://www.ejabberd.im/"&gt;ejabberd&lt;/a&gt; (one of the best Jabber/XMPP servers around) to run on Tokyocabinet, only with changing a few lines of its code. Now I'm on my way to make &lt;a href="http://weblambdazero.blogspot.com/2008/08/mnapi-mnesia-api-for-java-and-php.htmlhttp://weblambdazero.blogspot.com/2008/08/mnapi-mnesia-api-for-java-and-php.html"&gt;Mnapi&lt;/a&gt; work with it. Thank you guys!!!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5635587370432045273-6979420121522769830?l=weblambdazero.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://weblambdazero.blogspot.com/feeds/6979420121522769830/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5635587370432045273&amp;postID=6979420121522769830' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5635587370432045273/posts/default/6979420121522769830'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5635587370432045273/posts/default/6979420121522769830'/><link rel='alternate' type='text/html' href='http://weblambdazero.blogspot.com/2008/09/sky-is-limit.html' title='Sky is the limit for Mnesia'/><author><name>Krzysztof Kliś</name><uri>http://www.blogger.com/profile/03518001329895236884</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://2.bp.blogspot.com/_CVm77bq8jjg/SNva5QYjDLI/AAAAAAAAABE/NKuv0JSEKuM/S220/calder.jpg'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5635587370432045273.post-1641143373491400837</id><published>2008-08-21T18:30:00.007+02:00</published><updated>2010-07-15T23:30:44.767+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='lisp'/><title type='text'>Clojure is here</title><content type='html'>&lt;a href="http://clojure.org/"&gt;Clojure&lt;/a&gt; is a &lt;a href="http://en.wikipedia.org/wiki/Lisp_(programming_language)"&gt;Lisp&lt;/a&gt; family, dynamic, functional programming language targeting the Java Virtual Machine, with excellent support for concurrent programming. Rich Hickey, Clojure author, prepared a few impressive &lt;a href="http://clojure.blip.tv/"&gt;presentations&lt;/a&gt; about the language, which are definitely worth watching. They are not only about Clojure itself, but also give a deep insight into computer language design and concurrent programming in general.&lt;br /&gt;&lt;br /&gt;There have been some attempts to &lt;a href="http://groups.google.com/group/clojure/browse_thread/thread/2a2b24ffef5d1631/"&gt;compare Clojure with Erlang&lt;/a&gt;, although both of the languages address different problem classes. Erlang has strong &lt;a href="http://www.erlang.org/faq/introduction.html#1.5"&gt;telecommunication background&lt;/a&gt; - starting with the language &lt;a href="http://dictionary.reference.com/browse/agner%20krarup%20erlang"&gt;name&lt;/a&gt; itself. It features its own, highly efficient virtual machine, which allows spawning hundreds of thousands of processes and soft real-time performance. Most of its syntax comes from &lt;a href="http://en.wikipedia.org/wiki/Prolog"&gt;Prolog&lt;/a&gt;, since initially Erlang &lt;a href="http://cgibin.erols.com/ziring/cgi-bin/cep/cep.pl?_key=Erlang"&gt;emerged as its dialect&lt;/a&gt; - everyone who programmed in Prolog before (like me) will feel at home with Erlang. Finally, Erlang supports programming model based on transparent distribution, which means that you can spawn processes throughout one or several machines without making any changes to the software. Processes (also called actors) share no common memory or data and communicate purely through message passing.&lt;br /&gt;&lt;br /&gt;Clojure does not provide its own virtual machine with ability to handle millions of soft realtime processes. Instead, it compiles directly to JVM bytecode, which immediately gives you access to all Java classes and to thousands of libraries written for the Java platform. Clojure is based on Lisp, which is much more popular for programming real-life applications than Prolog. Therefore, despite of its &lt;span style="font-style:italic;"&gt;(&lt;span style="font-weight:bold;"&gt;L&lt;/span&gt;ots (of &lt;span style="font-weight:bold;"&gt;I&lt;/span&gt;rritating (and &lt;span style="font-weight:bold;"&gt;S&lt;/span&gt;uperfluous (&lt;span style="font-weight:bold;"&gt;P&lt;/span&gt;arentheses))))&lt;/span&gt; syntax, Clojure may be faster to learn and adapt by regular software developers than Erlang. As regards concurrency, Clojure does not support distributed programming. Instead, it uses &lt;a href="http://en.wikipedia.org/wiki/Software_transactional_memory"&gt;Software Transactional Memory&lt;/a&gt; model. Clojure agents, unlike Erlang actors, use actions instead of message passing to change their state. Actions can be committed inside transactions, which allows for example to read the state of all agents within one transaction, and this way obtain a consistent snapshot of a whole system (pretty tough to achieve in distributed enviornment).&lt;br /&gt;&lt;br /&gt;Erlang has a 20-year success story in telecommunication industry and is especially suitable for building highly scalable, fault tolerant, distributed application clusters that are expected to work under very heavy load. It is also ready to work on multiprocessor machines out of the box. However, when finally multi-core CPUs became standard in home computers, Erlang did not sweep away other anachronic programming languages, despite its obvious &lt;a href="http://www.ericsson.com/technology/opensource/erlang/news/archive/erlang_goes_multi_core.shtml"&gt;advantages&lt;/a&gt;. I think it is because most home applications don't need many of the features Erlang has to offer. Users don't need 99,98% uptime, as they usually turn off their machines overnight. They don't need soft real-time processing, since they can easily tolerate a few second delay in data processing. Finally, they don't need high scalability, as very few of them are geeks who connect their machines in clusters (who needs it anyway, if you have more and more cores in one box?). As Rich Hickey, Clojure author, said in his &lt;a href="http://groups.google.com/group/clojure/browse_thread/thread/5c7a962cc72c1fe7"&gt;discussion&lt;/a&gt; on STM:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt;"Scalability is not a universal problem - some systems need to handle thousands of simultaneous connections - most don't, some need to leverage hundreds of CPUs in a single application - most don't."&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Clojure seems to meet the needs of desktop programmers slightly better than Erlang. It provides easy concurrency and all qualities of functional programming, allows you to take advantage of vast set of Java libraries, and lets you to run your software without modification on every platform for which the Java runtime exists. Erlang is unbeatable on server platform, but leaves a lot of space for its desktop counterparts. Clojure is just the first of them. I am sure there will be more.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5635587370432045273-1641143373491400837?l=weblambdazero.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://weblambdazero.blogspot.com/feeds/1641143373491400837/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5635587370432045273&amp;postID=1641143373491400837' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5635587370432045273/posts/default/1641143373491400837'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5635587370432045273/posts/default/1641143373491400837'/><link rel='alternate' type='text/html' href='http://weblambdazero.blogspot.com/2008/08/clojure-is-here.html' title='Clojure is here'/><author><name>Krzysztof Kliś</name><uri>http://www.blogger.com/profile/03518001329895236884</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://2.bp.blogspot.com/_CVm77bq8jjg/SNva5QYjDLI/AAAAAAAAABE/NKuv0JSEKuM/S220/calder.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5635587370432045273.post-8505271470267001269</id><published>2008-08-14T19:15:00.001+02:00</published><updated>2008-09-29T13:14:25.315+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='erlang'/><title type='text'>MapReduce in Erlang</title><content type='html'>&lt;a href="http://labs.google.com/papers/mapreduce.html"&gt;MapReduce&lt;/a&gt; is a Java framework for parallel computations, designed and developed by Google. It is often referred to not only as a platform, but also more general as an algorithm (or a "programming model", as Google calls it itself). The main idea behind MapReduce is to spawn computations on a set of data to many single processes (map), and then gather their results (reduce).&lt;br /&gt;&lt;br /&gt;Implementing MapReduce in &lt;a href="http://www.erlang.org/"&gt;Erlang&lt;/a&gt; is unbelievably trivial. &lt;a href="http://www.sics.se/~joe/"&gt;Joe Armstrong&lt;/a&gt;, Erlang inventor and main architect, &lt;a href="http://www.erlang.org/ml-archive/erlang-questions/200606/msg00187.html"&gt;published&lt;/a&gt; a sample &lt;span style="font-style:italic;"&gt;pmap/2&lt;/span&gt; function, which can be used as a parallel equivalent of standard Erlang &lt;span style="font-style:italic;"&gt;lists:map/2&lt;/span&gt;:&lt;br /&gt;&lt;blockquote&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;pmap(F, L) -&gt;&lt;br /&gt;    S = self(),&lt;br /&gt;    Pids = lists:map(fun(I) -&gt;&lt;br /&gt;                         spawn(fun() -&gt; do_f(S, F, I) end)&lt;br /&gt;                     end, L),&lt;br /&gt;    gather(Pids).&lt;br /&gt;&lt;br /&gt;gather([H|T]) -&gt;&lt;br /&gt;    receive&lt;br /&gt;        {H, Ret} -&gt; [Ret|gather(T)]&lt;br /&gt;    end;&lt;br /&gt;gather([]) -&gt;&lt;br /&gt;    [].&lt;br /&gt;&lt;br /&gt;do_f(Parent, F, I) -&gt;&lt;br /&gt;    Parent ! {self(), (catch F(I))}.&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;Joe didn't provide any particular examples of using &lt;span style="font-style:italic;"&gt;pmap&lt;/span&gt;, so I wrote a test function that makes a sequence of &lt;a href="http://mathworld.wolfram.com/FibonacciNumber.html"&gt;Fibonacci numbers&lt;/a&gt;. First, let's start an Erlang shell with &lt;span style="font-style:italic;"&gt;-smp&lt;/span&gt; flag, that enables it to use many CPUs and many CPU cores:&lt;br /&gt;&lt;blockquote&gt;erl -smp&lt;/blockquote&gt;&lt;br /&gt;Now define a Fibonacci function:&lt;br /&gt;&lt;blockquote&gt;&lt;br /&gt;fib(0) -&gt; 0;&lt;br /&gt;fib(1) -&gt; 1;&lt;br /&gt;fib(N) when N &gt; 0 -&gt; fib(N-1) + fib(N-2).&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;and generate a test list as a sequence of numbers (for example from 0 to 40):&lt;br /&gt;&lt;blockquote&gt;L = lists:seq(0,40).&lt;/blockquote&gt;&lt;br /&gt;To make every element of the list &lt;span style="font-style:italic;"&gt;L&lt;/span&gt; to be processed by &lt;span style="font-style:italic;"&gt;fib/1&lt;/span&gt; function we use &lt;span style="font-style:italic;"&gt;lists:map/2&lt;/span&gt;:&lt;br /&gt;&lt;blockquote&gt;lists:map(fun(X) -&gt; fib(X) end, L).&lt;/blockquote&gt;&lt;br /&gt;To do a parallel computation we need to use &lt;span style="font-style:italic;"&gt;pmap/2&lt;/span&gt; instead of &lt;span style="font-style:italic;"&gt;lists:map/2&lt;/span&gt;:&lt;br /&gt;&lt;blockquote&gt;pmap(fun(X) -&gt; fib(X) end, L).&lt;/blockquote&gt;&lt;br /&gt;On my laptop with Core2 Duo T5450 1.66 Ghz running the parallel version of &lt;span style="font-style:italic;"&gt;fib/1&lt;/span&gt; function reduced execution time from 53.405534 to 31.354125 seconds (as measured by &lt;span style="font-style:italic;"&gt;timer:tc/3&lt;/span&gt;). On dual Xeon E5430 2.66 Ghz (8 cores total) the speedup was from 25.635218 seconds to 10.017358. It is less than Joe Armstrong managed to achieve (he probably used more sophisticated test functions and different hardware than a regular PC), but it clearly shows how easy it is to parallelize an Erlang program - &lt;span style="font-weight:bold;"&gt;just replace every instance of &lt;span style="font-style:italic;"&gt;map/2&lt;/span&gt; with &lt;span style="font-style:italic;"&gt;pmap/2&lt;/span&gt;&lt;/span&gt; and you're done.&lt;br /&gt;&lt;br /&gt;I prepared a modified version of &lt;span style="font-style:italic;"&gt;pmap/2&lt;/span&gt;, which spawns processes not only on local machine, but also on all nodes in a cluster:&lt;br /&gt;&lt;blockquote&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;pmap(F, L) -&gt;&lt;br /&gt;    S = self(),&lt;br /&gt;    Nod = [node()|nodes()],&lt;br /&gt;    {Pids, _} = lists:mapfoldl(&lt;br /&gt;        fun(I, {N1, N2}) -&gt;&lt;br /&gt;            case N1 == [] of&lt;br /&gt;                true -&gt; N = N2;&lt;br /&gt;                false -&gt; N = N1&lt;br /&gt;            end,&lt;br /&gt;            [H|T] = N,&lt;br /&gt;            {spawn(H, fun() -&gt; do_f(S, F, I) end), {T, N2}}&lt;br /&gt;        end, {Nod, Nod}, L),&lt;br /&gt;    gather(Pids).&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;Using the modified &lt;span style="font-style:italic;"&gt;pmap/2&lt;/span&gt;, I got similar results with a cluster of two Erlang shells running on a single Core2 Duo machine as with Joe's function on a single shell started in smp mode. This version of pmap/2 also allows you to rebalance computations by starting as many Erlang shells as there are CPUs (or CPU cores) on multiple machines, and &lt;a href="http://weblambdazero.blogspot.com/2008/08/erlang-tips-and-tricks-part-1.html"&gt;joining them in one cluster&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5635587370432045273-8505271470267001269?l=weblambdazero.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://weblambdazero.blogspot.com/feeds/8505271470267001269/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5635587370432045273&amp;postID=8505271470267001269' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5635587370432045273/posts/default/8505271470267001269'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5635587370432045273/posts/default/8505271470267001269'/><link rel='alternate' type='text/html' href='http://weblambdazero.blogspot.com/2008/08/mapreduce-in-erlang.html' title='MapReduce in Erlang'/><author><name>Krzysztof Kliś</name><uri>http://www.blogger.com/profile/03518001329895236884</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://2.bp.blogspot.com/_CVm77bq8jjg/SNva5QYjDLI/AAAAAAAAABE/NKuv0JSEKuM/S220/calder.jpg'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5635587370432045273.post-9006576349591075278</id><published>2008-08-11T19:17:00.003+02:00</published><updated>2010-10-24T12:27:54.839+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='lisp'/><title type='text'>Scheme &amp; Termite: Erlang alternative?</title><content type='html'>&lt;a href="http://dynamo.iro.umontreal.ca/~gambit/"&gt;Gambit-C&lt;/a&gt; is a renowned Scheme interpreter and compiler, which can generate fast and portable C code. It features &lt;a href="http://code.google.com/p/termite/"&gt;Termite&lt;/a&gt; library written in Scheme, which implements Erlang-like concurrency model for distributed programming. Let's see how it works.&lt;br /&gt;&lt;br /&gt;First, create two nodes on two separate machines. Suppose machine one IP address is 192.168.1.101 while machine two is 192.168.1.102. Start a Scheme &lt;a href="http://en.wikipedia.org/wiki/REPL"&gt;REPL&lt;/a&gt; on the first machine through &lt;span style="font-style:italic;"&gt;tsi&lt;/span&gt; script shipped with Termite (it enhances standard Gambit &lt;span style="font-style:italic;"&gt;gsi&lt;/span&gt; shell with Termite functions) and init it as &lt;span style="font-style:italic;"&gt;node1&lt;/span&gt;:&lt;br /&gt;&lt;blockquote&gt;(node-init (make-node "192.168.1.101" 4321))&lt;/blockquote&gt;&lt;br /&gt;Now start &lt;span style="font-style:italic;"&gt;tsi&lt;/span&gt; on the second machine and init it as &lt;span style="font-style:italic;"&gt;node2&lt;/span&gt;:&lt;br /&gt;&lt;blockquote&gt;(node-init (make-node "192.168.1.102" 4321))&lt;/blockquote&gt;&lt;br /&gt;Stay at &lt;span style="font-style:italic;"&gt;node2&lt;/span&gt; shell and define an expression to identify &lt;span style="font-style:italic;"&gt;node1&lt;/span&gt;:&lt;br /&gt;&lt;blockquote&gt;(define node1 (make-node "192.168.1.101" 4321))&lt;/blockquote&gt;&lt;br /&gt;Now you can remotely spawn a process on &lt;span style="font-style:italic;"&gt;node1&lt;/span&gt;:&lt;br /&gt;&lt;blockquote&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;(define p (remote-spawn node1&lt;br /&gt;  (lambda ()&lt;br /&gt;    (let loop ()&lt;br /&gt;      (let ((x (?)))&lt;br /&gt;        (! (car x) ((cdr x)))&lt;br /&gt;        (loop))))))&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;The code above remotely spawns procedure &lt;span style="font-style:italic;"&gt;p&lt;/span&gt; on &lt;span style="font-style:italic;"&gt;node1&lt;/span&gt;, which waits for a signal in an infinite loop. When it receives signal &lt;span style="font-style:italic;"&gt;x&lt;/span&gt; as a pair of sender and expression to evaluate, it evaluates the expression, sends its result back to the sender, and loops back. To see it in action evaluate the following expression in &lt;span style="font-style:italic;"&gt;node1&lt;/span&gt; REPL:&lt;br /&gt;&lt;blockquote&gt;(! p (cons (self) host-name))&lt;/blockquote&gt;&lt;br /&gt;It causes command &lt;span style="font-style:italic;"&gt;host-name&lt;/span&gt; to be sent to process &lt;span style="font-style:italic;"&gt;p&lt;/span&gt; on &lt;span style="font-style:italic;"&gt;node1&lt;/span&gt;. Now you can display received result with:&lt;br /&gt;&lt;blockquote&gt;(?)&lt;/blockquote&gt;&lt;br /&gt;Erlang equivalent would look like this:&lt;br /&gt;&lt;blockquote&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;-module(p).&lt;br /&gt;&lt;br /&gt;-export([start/0,loop/0]).&lt;br /&gt;&lt;br /&gt;start() -&gt;&lt;br /&gt;    register(p, spawn(node1, p, loop, [])).&lt;br /&gt;&lt;br /&gt;loop() -&gt;&lt;br /&gt;    receive&lt;br /&gt;        {Pid, F} -&gt;&lt;br /&gt;            Pid ! (catch F()),&lt;br /&gt;            loop()&lt;br /&gt;    end.&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;You would call it with:&lt;br /&gt;&lt;blockquote&gt;{p, node1} ! {self(), fun() -&gt; N = node(), N end}.&lt;/blockquote&gt;&lt;br /&gt;and read its result with:&lt;br /&gt;&lt;blockquote&gt;receive X -&gt; X end.&lt;/blockquote&gt;&lt;br /&gt;So far so good. Now let's halt the Termite shell on &lt;span style="font-style:italic;"&gt;node1&lt;/span&gt;:&lt;br /&gt;&lt;blockquote&gt;,q&lt;/blockquote&gt;&lt;br /&gt;And try to invoke procedure &lt;span style="font-style:italic;"&gt;p&lt;/span&gt; from &lt;span style="font-style:italic;"&gt;node2&lt;/span&gt; again:&lt;br /&gt;&lt;blockquote&gt;(! p (cons (self) host-name))&lt;/blockquote&gt;&lt;br /&gt;The shell will segfault. Oops...&lt;br /&gt;&lt;br /&gt;This is not the only problem with Termite. Gambit-C comes with &lt;span style="font-style:italic;"&gt;gsc&lt;/span&gt;, a Scheme to C compiler, which I used to compile the sample script above. First, I had to go to &lt;span style="font-style:italic;"&gt;/usr/local/gambc/current/lib/termite&lt;/span&gt; and compile Termite itself:&lt;br /&gt;&lt;blockquote&gt;gsc termite&lt;/blockquote&gt;&lt;br /&gt;Then I prepared a sample file &lt;span style="font-style:italic;"&gt;remote.scm&lt;/span&gt;:&lt;br /&gt;&lt;blockquote&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;(##include "~~/lib/gambit#.scm")&lt;br /&gt;(##include "~~/lib/termite/termite#.scm")&lt;br /&gt;&lt;br /&gt;(node-init (make-node "192.168.1.102" 4321))&lt;br /&gt;(define node1 (make-node "192.168.1.101" 4322))&lt;br /&gt;&lt;br /&gt;(define p (remote-spawn node1&lt;br /&gt;  (lambda ()&lt;br /&gt;    (let loop ()&lt;br /&gt;      (let ((x (?)))&lt;br /&gt;        (print (cdr x))&lt;br /&gt;        (! (car x) ((cdr x)))&lt;br /&gt;        (loop))))))&lt;br /&gt;&lt;br /&gt;(! p (cons (self) host-name))&lt;br /&gt;(print (?))&lt;br /&gt;(newline)&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;And compiled it to executable binary code:&lt;br /&gt;&lt;blockquote&gt;&lt;br /&gt;gsc -c remote.scm&lt;br /&gt;&lt;br /&gt;gsc -link /usr/local/gambc/current/lib/termite/termite.c remote.c&lt;br /&gt;&lt;br /&gt;gcc -o remote /usr/local/gambc/current/lib/termite/termite.c remote.c remote_.c -lgambc -lm -ldl -lutil -I/usr/local/gambc/current/include -L/usr/local/gambc/current/lib&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;Now I started &lt;span style="font-style:italic;"&gt;node1&lt;/span&gt; on 192.168.1.101 again:&lt;br /&gt;&lt;blockquote&gt;(node-init (make-node "192.168.1.101" 4321))&lt;/blockquote&gt;&lt;br /&gt;and tried to run &lt;span style="font-style:italic;"&gt;remote&lt;/span&gt; binary code from 192.168.1.102:&lt;br /&gt;&lt;blockquote&gt;./remote&lt;/blockquote&gt;&lt;br /&gt;Kaboom! Another segfault... Seems like compiled binary cannot handle message passing correctly, although it works in &lt;span style="font-style:italic;"&gt;tsi&lt;/span&gt; interpreter.&lt;br /&gt;&lt;br /&gt;I tried to create a bit more sophisticated Gambit-C/Termite application, but unfortunately I failed to find more useful documentation on Termite than its &lt;a href="http://termite.googlecode.com/files/termite.pdf"&gt;initial paper&lt;/a&gt;. There are also very few examples on Termite, and the most interesting I found come from &lt;a href="http://theschemeway.blogspot.com/2007/04/introduction-to-termite.html"&gt;Dominique Boucher's blog&lt;/a&gt; (my test script is based on those examples).&lt;br /&gt;&lt;br /&gt;On the other hand, a great advantage of Gambit-C over Erlang is that it can translate Scheme applications to plain C, which than can be compiled to standalone executables using &lt;span style="font-style:italic;"&gt;gcc&lt;/span&gt;. Thanks to this feature I managed to compile a few Gambit examples with &lt;a href="http://downloads.openwrt.org/whiterussian/0.9/"&gt;OpenWRT-SDK&lt;/a&gt; and ran it on my home Linksys WRT54GL router with OpenWRT firmware - the only thing I had to do was to replace &lt;span style="font-style:italic;"&gt;gcc&lt;/span&gt; command with &lt;span style="font-style:italic;"&gt;mipsel-linux-gcc&lt;/span&gt; while compiling &lt;span style="font-style:italic;"&gt;gsc&lt;/span&gt; output files.&lt;br /&gt;&lt;br /&gt;To sum up, Termite is a very interesting and ambitious project, and its authors deserve applause for their job. Unfortunatelly, it seems that it is still in its experimental stage, and is not ready for production use yet. However, when finally done, it can be very useful Erlang alternative (thanks to the Gambit-C compiler) for programming embedded devices and systems, where Erlang VM does not exist. I think &lt;a href="http://theschemeway.blogspot.com/2007/03/erlang-or-gambit-ctermite-practitioners.html"&gt;this post&lt;/a&gt; is also a good comment on Erlang and Termite.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5635587370432045273-9006576349591075278?l=weblambdazero.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://weblambdazero.blogspot.com/feeds/9006576349591075278/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5635587370432045273&amp;postID=9006576349591075278' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5635587370432045273/posts/default/9006576349591075278'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5635587370432045273/posts/default/9006576349591075278'/><link rel='alternate' type='text/html' href='http://weblambdazero.blogspot.com/2008/08/scheme-termite-erlang-alternative.html' title='Scheme &amp; Termite: Erlang alternative?'/><author><name>Krzysztof Kliś</name><uri>http://www.blogger.com/profile/03518001329895236884</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://2.bp.blogspot.com/_CVm77bq8jjg/SNva5QYjDLI/AAAAAAAAABE/NKuv0JSEKuM/S220/calder.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5635587370432045273.post-4706042305954463400</id><published>2008-08-07T19:19:00.007+02:00</published><updated>2009-12-29T21:32:21.138+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='erlang'/><title type='text'>Web services need balance</title><content type='html'>So we already have a nice and fast web service based on &lt;a href="http://weblambdazero.blogspot.com/2008/08/php-zend-framework-on-yaws.html"&gt;PHP and Yaws&lt;/a&gt; or not so fast, but still nice, service powered by Java and Tomcat. We also have a powerful &lt;a href="http://www.erlang.org/doc/apps/mnesia/"&gt;Mnesia&lt;/a&gt; storage back-end we can communicate with through a &lt;a href="http://weblambdazero.blogspot.com/2008/08/mnapi-mnesia-api-for-java-and-php.html"&gt;dedicated api&lt;/a&gt;. Now we are ready to scale.&lt;br /&gt;&lt;br /&gt;There's a lot of ways for balancing a web cluster. You can use one of many software load balancers, configure a front-end web server as a &lt;a href="http://en.wikipedia.org/wiki/Reverse_proxy"&gt;reverse proxy&lt;/a&gt; or even use a dedicated hardware load balancer. But hey, we have Erlang, so why bother with complicated software or spend money for expensive hardware? Writing a simple load balancer in Erlang took me about an hour, including testing, and I am not a very experienced Erlang programmer. This can give you some picture of how functional programming can improve your performance as a developer.&lt;br /&gt;&lt;br /&gt;What the balancer actually does is checking the system load on all nodes in a cluster and returning a name of the least loaded one. The software is &lt;a href="http://www.gnu.org/licenses/gpl.html"&gt;GPL&lt;/a&gt; licensed and can be downloaded from &lt;a href="http://www.caldersoft.net/files/erlang/balancer.erl"&gt;&lt;span style="font-weight:bold;"&gt;here&lt;/span&gt;&lt;/a&gt;. You should compile it with:&lt;br /&gt;&lt;blockquote&gt;erlc balancer.erl&lt;/blockquote&gt;&lt;br /&gt;and deploy it to all machines you want to monitor. Now you can check the system load of the current node:&lt;br /&gt;&lt;blockquote&gt;balancer:load().&lt;/blockquote&gt;&lt;br /&gt;all of the nodes you are connected to:&lt;br /&gt;&lt;blockquote&gt;balancer:show(nodes()).&lt;/blockquote&gt;&lt;br /&gt;all of the nodes including current node:&lt;br /&gt;&lt;blockquote&gt;balancer:show([node()|nodes()]).&lt;/blockquote&gt;&lt;br /&gt;pick the least loaded one with:&lt;br /&gt;&lt;blockquote&gt;balancer:pick(nodes()).&lt;/blockquote&gt;&lt;br /&gt;or with:&lt;br /&gt;&lt;blockquote&gt;balancer:pick([node()|nodes()]).&lt;/blockquote&gt;&lt;br /&gt;Due to Erlang nature, dead nodes are instantly removed from the nodes() list, so they are not queried. Additionally, the balancer filters out all nodes that returned an error, so you always get valid results, with no timeouts, deadlocks, etc. However, the result only says that a machine is up, so if a web server dies for some reason, and the machine itself did not crash, the node will still appear on the list (which is quite obvious).&lt;br /&gt;&lt;br /&gt;Since the balancer is written in Erlang, it seems natural to deploy Yaws as a front-end web server and use it to redirect users to the servers that are least loaded at the moment. Suppose we have each web server running on different sub-domain (&lt;span style="font-style:italic;"&gt;s1.host.domain&lt;/span&gt;, &lt;span style="font-style:italic;"&gt;s2.host.domain&lt;/span&gt;, etc.), and each of them runs a single Erlang node. In this case our &lt;span style="font-style:italic;"&gt;index.yaws&lt;/span&gt; on &lt;span style="font-style:italic;"&gt;http://host.domain/&lt;/span&gt; can look like this:&lt;br /&gt;&lt;blockquote&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&amp;lt;html&amp;gt;&lt;br /&gt;&amp;lt;erl&amp;gt;&lt;br /&gt;out(Arg) -&gt;&lt;br /&gt;    {Node, _} = balancer:pick(nodes()),&lt;br /&gt;    [_|[Host|_]] = string:tokens(atom_to_list(Node), "@"),&lt;br /&gt;    Url = string:concat("http://", Host),&lt;br /&gt;    {redirect, Url}.&lt;br /&gt;&amp;lt;/erl&amp;gt;&lt;br /&gt;&amp;lt;/html&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;Connecting to &lt;span style="font-style:italic;"&gt;http://host.domain/&lt;/span&gt; will now automatically redirect you to the fastest server. It is your choice if you want to keep users bound to the back-end server or refactor links on your web site to make them go through the redirector each time they click on a link. In the latter case, if you provide dynamic content, you can use Mnesia to store user sessions so they would not get logged out if they suddenly switch from one back-end server to another.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5635587370432045273-4706042305954463400?l=weblambdazero.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://weblambdazero.blogspot.com/feeds/4706042305954463400/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5635587370432045273&amp;postID=4706042305954463400' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5635587370432045273/posts/default/4706042305954463400'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5635587370432045273/posts/default/4706042305954463400'/><link rel='alternate' type='text/html' href='http://weblambdazero.blogspot.com/2008/08/web-services-need-balance.html' title='Web services need balance'/><author><name>Krzysztof Kliś</name><uri>http://www.blogger.com/profile/03518001329895236884</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://2.bp.blogspot.com/_CVm77bq8jjg/SNva5QYjDLI/AAAAAAAAABE/NKuv0JSEKuM/S220/calder.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5635587370432045273.post-7137424377146275781</id><published>2008-08-07T16:21:00.009+02:00</published><updated>2009-12-29T21:31:45.368+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java'/><category scheme='http://www.blogger.com/atom/ns#' term='erlang'/><category scheme='http://www.blogger.com/atom/ns#' term='mnesia'/><category scheme='http://www.blogger.com/atom/ns#' term='php'/><category scheme='http://www.blogger.com/atom/ns#' term='mnapi'/><title type='text'>Mnapi: Mnesia API for Java and PHP</title><content type='html'>&lt;a href="http://www.erlang.org/doc/apps/mnesia/"&gt;Mnesia&lt;/a&gt; is a scalable database system designed to work as a storage system for large, distributed applications. In &lt;a href="http://weblambdazero.blogspot.com/2008/08/erlang-tips-and-tricks-mnesia.html"&gt;my previous post&lt;/a&gt; I showed you how to set up a Mnesia cluster using &lt;a href="http://www.erlang.org"&gt;Erlang&lt;/a&gt; shell. Unfortunately, Mnesia cannot be easily accessed from languages other than Erlang. If you are a web developer, there is even an &lt;a href="http://en.wikipedia.org/wiki/Model-view-controller"&gt;MVC&lt;/a&gt; framework for you - &lt;a href="http://erlyweb.org/"&gt;Erlyweb&lt;/a&gt;. But what if you are a mainstream programmer who would like to use the power of Mnesia, but is not willing to learn another language and change the whole way of thinking in order to understand the functional programming philosophy?&lt;br /&gt;&lt;br /&gt;This is why I created Mnapi - API for Java and PHP, which provides basic methods to create, fetch, update and delete records in Mnesia. It is licensed under &lt;a href="http://www.gnu.org/copyleft/lesser.html"&gt;LGPL&lt;/a&gt;, which means that you can get it and use it in any commercial or non-commercial applications, and you are only obliged to publish only the source code of Mnapi if you extend it or modify it (the license does not affect an application which makes a use of it). You can download Mnapi &lt;a href="http://www.caldersoft.net/files/mnapi/"&gt;&lt;span style="font-weight:bold;"&gt;here&lt;/span&gt;&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Please bear in mind that Mnesia does not support creating multiple databases or schemas within one instance, joining tables, etc. - and the API reflects those restrictions. You can learn more about it reading documentation attached to the source code and running example applications, so I will not be describing it here in detail. What you need to start using Mnapi is to compile Erlang driver for Mnesia:&lt;br /&gt;&lt;blockquote&gt;erlc mnapi.erl&lt;/blockquote&gt;&lt;br /&gt;then start an Erlang shell:&lt;br /&gt;&lt;blockquote&gt;erl -sname erl -setcookie mysecretcookie&lt;/blockquote&gt;&lt;br /&gt;and run Mnapi server from the shell:&lt;br /&gt;&lt;blockquote&gt;mnapi:start().&lt;/blockquote&gt;&lt;br /&gt;Now you can use Java or PHP to talk to Mnesia through Mnapi libraries.&lt;br /&gt;&lt;br /&gt;Note that to use Mnapi from PHP you first need to install and configure &lt;a href="http://www.math-hat.com/~zukerman/projects/php-erlang/"&gt;Erlang extension for PHP&lt;/a&gt;. Read instructions provided with the extension to learn how to configure you PHP installation.&lt;br /&gt;&lt;br /&gt;To compile Java api you need &lt;a href="http://www.erlang.org/doc/apps/jinterface/"&gt;Jinterface&lt;/a&gt;. If you cannot find Jinterface in &lt;span style="font-style:italic;"&gt;lib&lt;/span&gt; folder of your standard Erlang installation, you can either download Erlang source code distribution or install it as a package from &lt;a href="http://cean.process-one.net/"&gt;CEAN&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Have fun!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5635587370432045273-7137424377146275781?l=weblambdazero.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://weblambdazero.blogspot.com/feeds/7137424377146275781/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5635587370432045273&amp;postID=7137424377146275781' title='9 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5635587370432045273/posts/default/7137424377146275781'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5635587370432045273/posts/default/7137424377146275781'/><link rel='alternate' type='text/html' href='http://weblambdazero.blogspot.com/2008/08/mnapi-mnesia-api-for-java-and-php.html' title='Mnapi: Mnesia API for Java and PHP'/><author><name>Krzysztof Kliś</name><uri>http://www.blogger.com/profile/03518001329895236884</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://2.bp.blogspot.com/_CVm77bq8jjg/SNva5QYjDLI/AAAAAAAAABE/NKuv0JSEKuM/S220/calder.jpg'/></author><thr:total>9</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5635587370432045273.post-4453821921419641270</id><published>2008-08-07T09:51:00.000+02:00</published><updated>2008-08-14T12:13:39.685+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='erlang'/><category scheme='http://www.blogger.com/atom/ns#' term='mnesia'/><title type='text'>Erlang tips and tricks: Mnesia</title><content type='html'>&lt;a href="http://www.erlang.org/doc/apps/mnesia/"&gt;Mnesia&lt;/a&gt; is one of Erlang killer applications. It's a distributed, fault tolerant, scalable, soft real-time database system which makes building data clusters really easy. It is not designed as a fully blown relational database, and it should not be treated as its replacement. Although Mnesia supports transactions (in a much more powerful way than traditional databases, as any Erlang function can be a transaction), it does not support SQL or any of its subsets. Mnesia is best suitable for a distributed, easily scalable data storage, which can be shared by a large cluster of servers. One of the most notably known examples are &lt;a href="http://www.ejabberd.im"&gt;ejabberd&lt;/a&gt; - a famous distributed jabber/xmpp server - and &lt;a href="http://code.google.com/p/cacherl/"&gt;cacherl&lt;/a&gt; - a distributed data caching system compatible with &lt;a href="http://www.danga.com/memcached/"&gt;memcached&lt;/a&gt; interface.&lt;br /&gt;&lt;br /&gt;Setting up a cluster of Mnesia nodes is easy. First you need to set up a cluster of Erlang nodes as I described in my post &lt;a href="http://weblambdazero.blogspot.com/2008/08/erlang-tips-and-tricks-part-1.html"&gt;Erlang tips and tricks: nodes&lt;/a&gt;. Start Mnesia instances on all of them:&lt;br /&gt;&lt;blockquote&gt;mnesia:start().&lt;/blockquote&gt;&lt;br /&gt;Now choose one of the nodes as initial Mnesia server node. It can be any node, as Mnesia works in peer-to-peer model and does not use any central management point. Go to a chosen Erlang shell and move the database schema to disc to make it persistent:&lt;br /&gt;&lt;blockquote&gt;mnesia:change_table_copy_type(schema, node(), disc_copies).&lt;/blockquote&gt;&lt;br /&gt;You can now create a new table, for example:&lt;br /&gt;&lt;blockquote&gt;mnesia:create_table(test, [{attributes, [key, value]}, {disc_copies, [node()]}]).&lt;/blockquote&gt;&lt;br /&gt;which creates table &lt;span style="font-style:italic;"&gt;test&lt;/span&gt; with two columns: &lt;span style="font-style:italic;"&gt;key&lt;/span&gt; and &lt;span style="font-style:italic;"&gt;value&lt;/span&gt;. Attribute &lt;span style="font-style:italic;"&gt;disc_copies&lt;/span&gt; means that a table will be held in RAM, but its copy will be also stored on disc. If you don't store any persistent data in your table, you can use &lt;span style="font-style:italic;"&gt;ram_copies&lt;/span&gt; attribute for better performance. On the other hand, if you want to spare some of your system memory, you can use &lt;span style="font-style:italic;"&gt;disc_only_copies&lt;/span&gt; attribute, but at the cost of reduced performance.&lt;br /&gt;Now let's add a second node to Mnesia:&lt;br /&gt;&lt;blockquote&gt;mnesia:change_config(extra_db_nodes, [node2@host.domain]).&lt;/blockquote&gt;&lt;br /&gt;Of course replace &lt;span style="font-style:italic;"&gt;node2@host.domain&lt;/span&gt; with the name of a node you want to add (or a list of nodes: &lt;span style="font-style:italic;"&gt;[node2@host.domain, node3@host.domain, ...]&lt;/span&gt;).&lt;br /&gt;Now switch to Erlang shell at the node you have just added and move its schema to disc, so Mnesia remembers it's a part of the cluster:&lt;br /&gt;&lt;blockquote&gt;mnesia:change_table_copy_type(schema, node(), disc_copies).&lt;/blockquote&gt;&lt;br /&gt;You can now create a copy of table &lt;span style="font-style:italic;"&gt;test&lt;/span&gt; on this node:&lt;br /&gt;&lt;blockquote&gt;mnesia:add_table_copy(test, node(), disc_copies).&lt;/blockquote&gt;&lt;br /&gt;Now you can add a third node, a fourth node, etc. in the same way as you added the second one. When you have many nodes in the cluster you can keep tables as &lt;span style="font-style:italic;"&gt;disc_copies&lt;/span&gt; only on some nodes as backup, and use &lt;span style="font-style:italic;"&gt;ram__copies&lt;/span&gt; on other nodes to improve their performance. It generally makes sense to keep tables on disc only on one of the nodes per single machine.&lt;br /&gt;&lt;br /&gt;To remove &lt;span style="font-style:italic;"&gt;node@host.domain&lt;/span&gt; from the cluster stop Mnesia on that node:&lt;br /&gt;&lt;blockquote&gt;mnesia:stop().&lt;/blockquote&gt;&lt;br /&gt;Now switch to any other node in the cluster and do:&lt;br /&gt;&lt;blockquote&gt;mnesia:del_table_copy(schema, node@host.domain).&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;Mnesia is strongly fault-tolerant, which means that generally you don't need to worry when one of your nodes crashes. Just restart it and &lt;a href="http://weblambdazero.blogspot.com/2008/08/erlang-tips-and-tricks-part-1.html"&gt;reconnect it to the cluster&lt;/a&gt; - Mnesia node will synchronize itself and fix all broken and out-of-date tables. I really like to imagine Mnesia as a database equivalent of &lt;a href="http://en.wikipedia.org/wiki/T-1000"&gt;T-1000&lt;/a&gt;, which even heavily damaged or broken into pieces, every time reassembles itself to its original form.&lt;br /&gt;&lt;br /&gt;Unfortunately Mnesia has &lt;a href="http://article.gmane.org/gmane.comp.lang.erlang.general/27651"&gt;its limits&lt;/a&gt;. A &lt;a href="http://web.telia.com/~u83304791/erlang_faq/faq.html#AEN1447"&gt;storage limit&lt;/a&gt; seems to be the most troublesome of them.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5635587370432045273-4453821921419641270?l=weblambdazero.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://weblambdazero.blogspot.com/feeds/4453821921419641270/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5635587370432045273&amp;postID=4453821921419641270' title='5 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5635587370432045273/posts/default/4453821921419641270'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5635587370432045273/posts/default/4453821921419641270'/><link rel='alternate' type='text/html' href='http://weblambdazero.blogspot.com/2008/08/erlang-tips-and-tricks-mnesia.html' title='Erlang tips and tricks: Mnesia'/><author><name>Krzysztof Kliś</name><uri>http://www.blogger.com/profile/03518001329895236884</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://2.bp.blogspot.com/_CVm77bq8jjg/SNva5QYjDLI/AAAAAAAAABE/NKuv0JSEKuM/S220/calder.jpg'/></author><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5635587370432045273.post-5138121651099578131</id><published>2008-08-05T00:30:00.001+02:00</published><updated>2008-09-29T13:16:03.485+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='erlang'/><title type='text'>Erlang tips and tricks: interactive shell</title><content type='html'>In my &lt;a href="http://weblambdazero.blogspot.com/2008/08/erlang-tips-and-tricks-part-1.html"&gt;previous post&lt;/a&gt; I described issues you can run into when configuring an &lt;a href="http://erlang.org/"&gt;Erlang&lt;/a&gt; cluster. Now let's move a step further.&lt;br /&gt;&lt;br /&gt;One of the most impressive Erlang features is its unique ability to do a hot code swapping. It means you can exchange the code of a running system without stopping it! Pretty neat, huh? Let's have a look at a very simple server, that just loops and displays its status when asked:&lt;br /&gt;&lt;blockquote&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;-module(test).&lt;br /&gt;-export([start/0, loop/0]).&lt;br /&gt;start() -&gt;&lt;br /&gt;    register(test, spawn(test, loop, [])).&lt;br /&gt;loop() -&gt;&lt;br /&gt;    receive&lt;br /&gt;        status -&gt;&lt;br /&gt;            io:format("~n Status OK ~n"),&lt;br /&gt;            loop();&lt;br /&gt;        reload -&gt;&lt;br /&gt;            test:loop();&lt;br /&gt;        quit -&gt;&lt;br /&gt;            ok;&lt;br /&gt;        _ -&gt;&lt;br /&gt;            loop()&lt;br /&gt;    end.&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;The main loop waits for signals from clients and according to the signal does one of the following:&lt;br /&gt;1) On &lt;span style="font-style:italic;"&gt;status&lt;/span&gt; it displays a text "Status OK" and continues to loop.&lt;br /&gt;2) On &lt;span style="font-style:italic;"&gt;reload&lt;/span&gt; it hot swaps the server code.&lt;br /&gt;3) On &lt;span style="font-style:italic;"&gt;quit&lt;/span&gt; it quits with finishes with &lt;span style="font-style:italic;"&gt;ok&lt;/span&gt;.&lt;br /&gt;4) On any other signal it just loops.&lt;br /&gt;After saving this code as &lt;span style="font-style:italic;"&gt;test.erl&lt;/span&gt; and compiling with:&lt;br /&gt;&lt;blockquote&gt;erlc test.erl&lt;/blockquote&gt;&lt;br /&gt;you can start a &lt;a href="http://en.wikipedia.org/wiki/REPL"&gt;REPL&lt;/a&gt; shell and run the server with:&lt;br /&gt;&lt;blockquote&gt;test:start().&lt;/blockquote&gt;&lt;br /&gt;The start() function spawns a new Erlang process and registers it on the currently running node, so you can call it through a name instead of through its process ID like this:&lt;br /&gt;&lt;blockquote&gt;test ! status.&lt;/blockquote&gt;&lt;br /&gt;If you play around with Erlang you already know that. But how about calling &lt;span style="font-style:italic;"&gt;test&lt;/span&gt; from another node? When you connect another node to the cluster and try to call it you will get an error saying that &lt;span style="font-style:italic;"&gt;test&lt;/span&gt; is not a registered name. The answer is simple, but unfortunately not so easy to find in Erlang documentation. You need to call it with a tuple (pair) containing  both node name and process name:&lt;br /&gt;&lt;blockquote&gt;{test, test1@host.domain} ! status.&lt;/blockquote&gt;&lt;br /&gt;So now comes the time for hot swapping. You can edit the source file, change "Status OK" to any other text of your choice and recompile - of course without leaving the interactive shell, since our server is supposed to have 100% uptime :-)&lt;br /&gt;Afterwards you switch back to REPL, do&lt;br /&gt;&lt;blockquote&gt;test ! reload.&lt;/blockquote&gt;&lt;br /&gt;than&lt;br /&gt;&lt;blockquote&gt;test ! status.&lt;/blockquote&gt;&lt;br /&gt;and you see... no change whatsoever. Why? Because &lt;span style="font-weight:bold;"&gt;Erlang shell caches executable code&lt;/span&gt;. If you want to load the modified version of the code you just compiled into REPL, you need to tell it to do so with:&lt;br /&gt;&lt;blockquote&gt;l(test).&lt;/blockquote&gt;&lt;br /&gt;Suppose you have more nodes in your cluster where the code exists and you want to refresh Erlang cache on all of them, you should use:&lt;br /&gt;&lt;blockquote&gt;nl(test).&lt;/blockquote&gt;&lt;br /&gt;You can also use the latter command to distribute your code across the cluster, without the need of sending the compiled binary &lt;span style="font-style:italic;"&gt;test.beam&lt;/span&gt; to all of them through FTP or SCP.&lt;br /&gt;Sweet, isn't it?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5635587370432045273-5138121651099578131?l=weblambdazero.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://weblambdazero.blogspot.com/feeds/5138121651099578131/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5635587370432045273&amp;postID=5138121651099578131' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5635587370432045273/posts/default/5138121651099578131'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5635587370432045273/posts/default/5138121651099578131'/><link rel='alternate' type='text/html' href='http://weblambdazero.blogspot.com/2008/08/erlang-tips-and-tricks-interactive.html' title='Erlang tips and tricks: interactive shell'/><author><name>Krzysztof Kliś</name><uri>http://www.blogger.com/profile/03518001329895236884</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://2.bp.blogspot.com/_CVm77bq8jjg/SNva5QYjDLI/AAAAAAAAABE/NKuv0JSEKuM/S220/calder.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5635587370432045273.post-1473642714031564215</id><published>2008-08-04T19:51:00.004+02:00</published><updated>2008-12-01T13:28:34.107+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='erlang'/><title type='text'>Erlang tips and tricks: nodes</title><content type='html'>The title might be a bit exaggerated, but if you have just started your adventure with &lt;a href="http://erlang.org"&gt;Erlang&lt;/a&gt; I would like to provide you with a couple of hints that can spare you a serious headache.&lt;br /&gt;&lt;br /&gt;The basic tool to work with Erlang is its REPL shell, started in terminal mode with &lt;span style="font-style:italic;font-weight:bold;"&gt;erl&lt;/span&gt; command. The name &lt;a href="http://en.wikipedia.org/wiki/REPL"&gt;REPL&lt;/a&gt; comes from &lt;span style="font-style:italic;"&gt;read, eval, print, loop&lt;/span&gt; cycle and among functional languages is a commonly used term for interactive shell. Since Erlang has been developed with distributed programming in mind, you can start as many shells as you like and make them communicate with each other. The basic rule you have to remember about is that you can interface only shells that &lt;span style="font-weight:bold;"&gt;share the same cookie&lt;/span&gt;. A cookie is simply a string that acts as a shared password to all nodes in a cluster, whether they run on the same computer or different machines across the network. You can set it either from the command line when starting REPL using &lt;span style="font-style:italic;"&gt;-setcookie&lt;/span&gt; parameter or from the Erlang shell itself:&lt;br /&gt;&lt;blockquote&gt;erlang:set_cookie(node(),mysecretcookie).&lt;/blockquote&gt;&lt;br /&gt;You can also edit &lt;span style="font-style:italic;"&gt;.erlang.cookie&lt;/span&gt; file in your home directory so you don't have to set it up every time you start the shell. However, this method has some nasty side effects and that's why it is not recommended. The first one is that all Erlang applications you start from your user account, including all REPLs, will share the same cookie, which not always is a desired behaviour. Secondly, it is very likely that you forget to edit this file on another machine where you move your Erlang application to (or will not have enough permissions to do it), and your application will not work in environment other than yours.&lt;br /&gt;&lt;br /&gt;So now when you have started your shells and set up a shared cookie you may want to check the connectivity between them. But first you need to know how to call them - now here's where the real fun begins. Erlang allows you to call a node (shell instance) with either a short or a long name ("-sname" and "-name" command line parameters respectively). A short name is a common name like "test" while a long name is a fully qualified domain name like "test@host.domain". Short names are shared across machines in the same domain, while FQDN names can be used (theoretically) across the whole Internet. So you start a short name REPL with:&lt;br /&gt;&lt;blockquote&gt;/usr/bin/erl -sname test1 -setcookie mysecretcookie&lt;/blockquote&gt;&lt;br /&gt;So far so good. Now try another one within the same domain:&lt;br /&gt;&lt;blockquote&gt;/usr/bin/erl -sname test2 -setcookie mysecretcookie&lt;/blockquote&gt;&lt;br /&gt;And now you want to ping test2 from test1 to check if everything is OK. So you input the following command in test1 REPL:&lt;br /&gt;&lt;blockquote&gt;net_adm:ping(test2).&lt;/blockquote&gt;&lt;br /&gt;And you see "pang", which means that something went wrong. So you start to tear your hair out until you realize that test1 &lt;span style="font-weight:bold;"&gt;is not a node name&lt;/span&gt; in Erlang! Now go back to your REPL again and look carefully at the prompt. You will probably see something like:&lt;br /&gt;&lt;blockquote&gt;(test1@localhost)1&gt;&lt;/blockquote&gt;&lt;br /&gt;Now try to ping &lt;span style="font-style:italic;"&gt;test2&lt;/span&gt; again, but this time use a full name as displayed in REPL prompt:&lt;br /&gt;&lt;blockquote&gt;net_adm:ping(test2@localhost).&lt;/blockquote&gt;&lt;br /&gt;And what you should now see is "pong", which means that the nodes can now see each other. Note that test2@localhost, although doesn't seem so is still a short name, not a fully qualified domain name (it lacks a domain part).&lt;br /&gt;&lt;br /&gt;You can always see a list of all other hosts in the cluster after issuing command:&lt;br /&gt;&lt;blockquote&gt;nodes().&lt;/blockquote&gt;&lt;br /&gt;in REPL. But remember about one important thing: &lt;span style="font-weight:bold;"&gt;new hosts are not seen by Erlang automatically&lt;/span&gt;. If you start a new Erlang instance and want it to show on the nodes() list, you have to ping one of the hosts already existing in the cluster. Information about a new node will be automatically propagated among all other nodes. To avoid it, you can use &lt;span style="font-style:italic;"&gt;.hosts.erlang&lt;/span&gt; file in your home directory, which role is similar to the role of &lt;span style="font-style:italic;"&gt;.erlang.cookie&lt;/span&gt; (including side effects) - it holds the list of all nodes which will be automatically informed about every new Erlang instance started on your user account, for example:&lt;br /&gt;&lt;blockquote&gt;&lt;br /&gt;'test1@localhost'.&lt;br /&gt;'test2@localhost'.&lt;br /&gt;&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;You need to have one empty line at the file end (look &lt;a href="http://www.erlang.org/doc/man/net_adm.html"&gt;here&lt;/a&gt; for more information about the syntax).&lt;br /&gt;&lt;br /&gt;So here are the basic things you should remember about when building an Erlang cluster:&lt;br /&gt;1) Choose carefully between short and fully qualified domain names, since the first cannot communicate with the latter ones (to make it simple: &lt;span style="font-weight:bold;"&gt;you cannot mix short and long named nodes across one Erlang cluster)&lt;/span&gt;.&lt;br /&gt;2) When using more than one machine in your cluster, make sure all DNS records on all machines are set up properly to avoid communication problems.&lt;br /&gt;3) Use the same cookie for all Erlang instances you want to put in a cluster.&lt;br /&gt;4) When you start a new node always inform the cluster about it by pinging one of the running nodes.&lt;br /&gt;5) Open port 4369 TCP/UDP on your firewall for all clustered machines - it is used by &lt;span style="font-style:italic;"&gt;epmd&lt;/span&gt; daemon, which handles inter-nodes Erlang communication.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5635587370432045273-1473642714031564215?l=weblambdazero.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://weblambdazero.blogspot.com/feeds/1473642714031564215/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5635587370432045273&amp;postID=1473642714031564215' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5635587370432045273/posts/default/1473642714031564215'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5635587370432045273/posts/default/1473642714031564215'/><link rel='alternate' type='text/html' href='http://weblambdazero.blogspot.com/2008/08/erlang-tips-and-tricks-part-1.html' title='Erlang tips and tricks: nodes'/><author><name>Krzysztof Kliś</name><uri>http://www.blogger.com/profile/03518001329895236884</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://2.bp.blogspot.com/_CVm77bq8jjg/SNva5QYjDLI/AAAAAAAAABE/NKuv0JSEKuM/S220/calder.jpg'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5635587370432045273.post-5303644652108114065</id><published>2008-08-04T16:02:00.008+02:00</published><updated>2009-12-29T21:32:48.150+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='erlang'/><category scheme='http://www.blogger.com/atom/ns#' term='php'/><title type='text'>PHP Zend Framework on Yaws</title><content type='html'>Web developers looking for an efficient web server should definitely give a chance to &lt;a href="http://yaws.hyber.org/"&gt;Yaws&lt;/a&gt;, a lightweight and very fast open source web server developed in &lt;a href="http://erlang.org/"&gt;Erlang&lt;/a&gt;. For those who do some work in Erlang, this should be enough for a recommendation, since Erlang has been designed with high performance and scalability in mind. Those who haven't heard of Yaws and Erlang should have a look at this &lt;a href="http://www.sics.se/%7Ejoe/apachevsyaws.html"&gt;Yaws vs Apache comparison&lt;/a&gt; to get the idea.&lt;br /&gt;&lt;br /&gt;Unfortunately, Yaws is not as mature as Apache in terms of available functionality. The one thing I missed particularly about it was the lack of easily definable &lt;a href="http://en.wikipedia.org/wiki/Rewrite_engine"&gt;rewrite&lt;/a&gt; rules, which would allow me to set up my favourite PHP framework (namely &lt;a href="http://framework.zend.com/"&gt;Zend Framework&lt;/a&gt;) to work under control of Yaws. Browsing through Yaws &lt;a href="http://yaws.hyber.org/wiki/"&gt;Wiki&lt;/a&gt; I found a &lt;a href="http://yaws.hyber.org/wiki/showPage.yaws?node=RewriteModule"&gt;post&lt;/a&gt; explaining how to use rewrite feature in Yaws. I used it as a starting point for my own rewriting module, which allowed me to run ZF on Yaws. I published it on &lt;a href="http://forum.trapexit.org/viewtopic.php?t=14964"&gt;Trapexit&lt;/a&gt; as a free code under no particular licence, beacuse - as I said - I didn't write it from scratch, but used a public domain work. Here's how it works (I assume you already have Erlang and Yaws installed in your system):&lt;br /&gt;&lt;br /&gt;First you need to configure your MVC enviornment. I suggest following a manual at &lt;a href="http://akrabat.com/zend-framework-tutorial/"&gt;Akra’s DevNotes&lt;/a&gt; to create the basic directory structure. Suppose your Yaws document directory is &lt;span style="font-style: italic;"&gt;/opt/yaws&lt;/span&gt;, you'll have to create folders &lt;span style="font-style: italic;"&gt;/opt/yaws/application&lt;/span&gt;, &lt;span style="font-style: italic;"&gt;/opt/yaws/library&lt;/span&gt; and &lt;span style="font-style: italic;"&gt;/opt/yaws/public&lt;/span&gt;. Also create &lt;span style="font-style: italic;"&gt;/opt/yaws/log&lt;/span&gt; folder for web server logs. Then create &lt;span style="font-style: italic;"&gt;/opt/yaws/ebin&lt;/span&gt; and put there &lt;a href="http://www.caldersoft.net/files/erlang/rewriter.erl"&gt;&lt;span style="font-weight:bold;"&gt;rewriter.erl&lt;/span&gt;&lt;/a&gt;. Compile the rewriter module from the command line with&lt;br /&gt;&lt;blockquote&gt;erlc rewriter.erl&lt;/blockquote&gt;&lt;br /&gt;Create yaws configuration file &lt;span style="font-style: italic;"&gt;yaws.conf&lt;/span&gt; and inform the web server to use php scripts and the rewrite module&lt;br /&gt;&lt;blockquote&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;php_exe_path = /usr/bin/php-cgi&lt;br /&gt;ebin_dir = /opt/yaws/ebin&lt;br /&gt;logdir = /opt/yaws/log&lt;br /&gt;&lt;br /&gt;&amp;lt;server localhost&amp;gt;&lt;br /&gt;    port = 8080&lt;br /&gt;    listen = 0.0.0.0&lt;br /&gt;    docroot = /opt/yaws/public&lt;br /&gt;    allowed_scripts = yaws php&lt;br /&gt;    arg_rewrite_mod = rewriter&lt;br /&gt;&amp;lt;/server&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;Finally, run your web server&lt;br /&gt;&lt;blockquote&gt;yaws --conf yaws.conf&lt;/blockquote&gt;&lt;br /&gt;and go to &lt;a href="http://localhost:8080/"&gt;http://localhost:8080&lt;/a&gt; to see if it works.&lt;br /&gt;&lt;br /&gt;From now on, all client requests to localhost will be redirected through a bootstrap file /opt/yaws/public/index.php. Make sure all paths in your PHP scripts lead to correct locations.&lt;br /&gt;&lt;br /&gt;Tested on Erlang R11B with yaws 1.68 on Linux Mint 4.0 32-bit and yaws 1.73 on Ubuntu Server 8.04 64-bit with Zend Framework 1.5.&lt;br /&gt;&lt;br /&gt;Good luck!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5635587370432045273-5303644652108114065?l=weblambdazero.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://weblambdazero.blogspot.com/feeds/5303644652108114065/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5635587370432045273&amp;postID=5303644652108114065' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5635587370432045273/posts/default/5303644652108114065'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5635587370432045273/posts/default/5303644652108114065'/><link rel='alternate' type='text/html' href='http://weblambdazero.blogspot.com/2008/08/php-zend-framework-on-yaws.html' title='PHP Zend Framework on Yaws'/><author><name>Krzysztof Kliś</name><uri>http://www.blogger.com/profile/03518001329895236884</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://2.bp.blogspot.com/_CVm77bq8jjg/SNva5QYjDLI/AAAAAAAAABE/NKuv0JSEKuM/S220/calder.jpg'/></author><thr:total>1</thr:total></entry></feed>
