<?xml version="1.0" encoding="utf-8"?><?xml-stylesheet title="XSL formatting" type="text/xsl" href="http://blog.pwkf.org/feed/rss2/xslt" ?><rss version="2.0"
  xmlns:dc="http://purl.org/dc/elements/1.1/"
  xmlns:wfw="http://wellformedweb.org/CommentAPI/"
  xmlns:content="http://purl.org/rss/1.0/modules/content/"
  xmlns:atom="http://www.w3.org/2005/Atom">
<channel>
  <title>Personal Workflow Blog</title>
  <link>http://blog.pwkf.org/</link>
  <atom:link href="http://blog.pwkf.org:82/feed/rss2" rel="self" type="application/rss+xml"/>
  <description>Some thoughts I encounter during my working day in the J2EE land. Originally a blog about PWKF, an easy-to-use workflow solution, but I have less time to work on PWKF that what I had before as real life kicked in !</description>
  <language>en</language>
  <pubDate>Sat, 14 Jan 2012 10:39:55 +0100</pubDate>
  <copyright>(c) 2006-2011 - Steve Schnepp</copyright>
  <docs>http://blogs.law.harvard.edu/tech/rss</docs>
  <generator>Dotclear</generator>
  
    
  <item>
    <title>Enhance RRD I/O performance in Munin 1.4 and Scale</title>
    <link>http://blog.pwkf.org/post/2011/06/Enhance-RRD-I/O-performance-in-Munin-1.4-and-Scale</link>
    <guid isPermaLink="false">urn:md5:e375b97e3b545a1b4e856d09553193e4</guid>
    <pubDate>Mon, 20 Jun 2011 09:42:00 +0200</pubDate>
    <dc:creator>Steve Schnepp</dc:creator>
        <category>munin</category>
        <category>munin</category><category>performance</category><category>rrd</category>    
    <description>    &lt;p&gt;As with most of the RRD-based monitoring software (Cacti, Ganglia, ...), it
is quite difficult to scale.&lt;/p&gt;
&lt;p&gt;The bad part is that &lt;strong&gt;updating&lt;/strong&gt; &lt;strong&gt;lots&lt;/strong&gt; of
small RRD files seems like &lt;strong&gt;pure random I/O to&lt;/strong&gt; the OS as stated
in there documentation.&lt;/p&gt;
&lt;p&gt;The &lt;strong&gt;good part&lt;/strong&gt; is that we are not alone, and therefore the
&lt;strong&gt;RRD developers did tackle the issue&lt;/strong&gt; with &lt;a href=&quot;http://oss.oetiker.ch/rrdtool/doc/rrdcached.en.html&quot; hreflang=&quot;en&quot;&gt;rrdcached&lt;/a&gt;. It spools the updates, and flushs them to disk in a batched
manner, or when needed by a rrd read command such as graphing. That's why it is
&lt;strong&gt;scales&lt;/strong&gt; well when using &lt;strong&gt;CGI graphing&lt;/strong&gt;.
Otherwise, munin-graph will read every rrd, and therefore force a flush on all
the cache.&lt;/p&gt;
&lt;p&gt;And the icing on the cake is that, although it is only fully integrated to
munin 2.0, &lt;strong&gt;you can use it right away in the 1.4.x series&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;You only need to define the environment variable
&lt;code&gt;RRDCACHED_ADDRESS&lt;/code&gt; while running the scripts accessing the
RRDs.&lt;/p&gt;
&lt;p&gt;Then, you have to remove the &lt;code&gt;munin-graph&lt;/code&gt; part of the
&lt;code&gt;munin-cron&lt;/code&gt; and run it on its own line. Usually only every hour or
so, to be able to accumulate data in &lt;code&gt;rrdcached&lt;/code&gt; before flushing it
all to disk when graphing.&lt;/p&gt;
&lt;p&gt;Updating to 2.0 is also an option to have a real CGI support. (CGI on 1.4 is
existing but has nowhere decent performance).&lt;/p&gt;</description>
    
    
    
          <comments>http://blog.pwkf.org/post/2011/06/Enhance-RRD-I/O-performance-in-Munin-1.4-and-Scale#comment-form</comments>
      <wfw:comment>http://blog.pwkf.org/post/2011/06/Enhance-RRD-I/O-performance-in-Munin-1.4-and-Scale#comment-form</wfw:comment>
      <wfw:commentRss>http://blog.pwkf.org/feed/atom/comments/614814</wfw:commentRss>
      </item>
    
  <item>
    <title>Autovivification in Perl : Great Idea but also Huge Trap - Another Leaking Abstraction...</title>
    <link>http://blog.pwkf.org/post/2011/06/Autovivification-in-Perl-Great-Idea-Huge-Trap-Leaking-Abstraction</link>
    <guid isPermaLink="false">urn:md5:a3f3a669f2a289052af57b868d238497</guid>
    <pubDate>Thu, 16 Jun 2011 20:20:00 +0200</pubDate>
    <dc:creator>Steve Schnepp</dc:creator>
        <category>perl</category>
        <category>fail</category><category>perl</category>    
    <description>    &lt;p&gt;&lt;a href=&quot;http://en.wikipedia.org/wiki/Autovivification&quot; hreflang=&quot;en&quot;&gt;Autovivification&lt;/a&gt; is one of Perl's really great design success.&lt;/p&gt;
&lt;p&gt;It all comes to &lt;em&gt;you don't need to worry about existence before
dereferencing something&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;That means, for setting a nested hash, you only need to write :&lt;/p&gt;
&lt;pre&gt;
$h-&amp;gt;{foo}{bar} = &amp;quot;value&amp;quot;;
&lt;/pre&gt;
&lt;p&gt;And that will work out of the box. Perl will happily create all the
data-structure for you.&lt;/p&gt;
&lt;p&gt;So, now a little coding test, what does the following code output ?&lt;/p&gt;
&lt;pre&gt;
my $a;

if ($a-&amp;gt;{foo}{bar}) {
   print &amp;quot;Found foo/bar\n&amp;quot;;
}

if ($a-&amp;gt;{foo}) {
   print &amp;quot;Found foo\n&amp;quot;;
}
&lt;/pre&gt;
&lt;p&gt;Naively, it shouldn’t output anything, right ?&lt;/p&gt;
&lt;p&gt;Not so fast. Upon a careful read of &lt;q&gt;Perl will happily create all the
data-structure for you&lt;/q&gt;, we can put some emphasis on one word : &lt;q&gt;Perl will
happily &lt;strong&gt;create&lt;/strong&gt; all the data-structure for you&lt;/q&gt;.&lt;/p&gt;
&lt;p&gt;That might be just perfect, except that Perl creates it whenever it needs
it, even if it is only for &lt;strong&gt;reading&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;And now you understand the catch : a &lt;strong&gt;read&lt;/strong&gt; operation can
result in a &lt;strong&gt;write&lt;/strong&gt; one.&lt;/p&gt;
&lt;p&gt;As Uncle Ben (from SpiderMan) said&lt;sup&gt;[&lt;a href=&quot;http://blog.pwkf.org/post/2011/06/#pnote-614219-1&quot; id=&quot;rev-pnote-614219-1&quot; name=&quot;rev-pnote-614219-1&quot;&gt;1&lt;/a&gt;]&lt;/sup&gt; : &lt;q&gt;With Great
Power Comes Great Responsibility&lt;/q&gt;.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://search.cpan.org/~ilmari/&quot; hreflang=&quot;en&quot;&gt;Dagfinn Ilmari
Mannsåker&lt;/a&gt; showed me a nice &lt;a href=&quot;http://search.cpan.org/perldoc?autovivification&quot; hreflang=&quot;en&quot;&gt;autovivification&lt;/a&gt; module on CPAN that fixes this behavior, and enables
a fine tuning of this process.&lt;/p&gt;
&lt;p&gt;I really think the fact that creation also happen when querying the value is
a real bug in Perl itself, or at least a bug in the design of the feature.&lt;/p&gt;
&lt;div class=&quot;footnotes&quot;&gt;
&lt;h4&gt;Notes&lt;/h4&gt;
&lt;p&gt;[&lt;a href=&quot;http://blog.pwkf.org/post/2011/06/#rev-pnote-614219-1&quot; id=&quot;pnote-614219-1&quot; name=&quot;pnote-614219-1&quot;&gt;1&lt;/a&gt;] Voltaire, Franklin D. Roosevelt and other said
something very similar, but they are not as geeky.&lt;/p&gt;
&lt;/div&gt;</description>
    
    
    
          <comments>http://blog.pwkf.org/post/2011/06/Autovivification-in-Perl-Great-Idea-Huge-Trap-Leaking-Abstraction#comment-form</comments>
      <wfw:comment>http://blog.pwkf.org/post/2011/06/Autovivification-in-Perl-Great-Idea-Huge-Trap-Leaking-Abstraction#comment-form</wfw:comment>
      <wfw:commentRss>http://blog.pwkf.org/feed/atom/comments/614219</wfw:commentRss>
      </item>
    
  <item>
    <title>Waiting for Munin 2.0 - Keep more data with custom data retention plans</title>
    <link>http://blog.pwkf.org/post/2010/08/Waiting-for-Munin-2.0-Keep-more-data-with-custom-data-retention-plans</link>
    <guid isPermaLink="false">urn:md5:b528a73802a31e6004307ae6cb82e4d7</guid>
    <pubDate>Mon, 23 Aug 2010 18:47:00 +0200</pubDate>
    <dc:creator>Steve Schnepp</dc:creator>
        <category>munin</category>
        <category>munin</category><category>munin20</category><category>sysadmin</category>    
    <description>    &lt;h2&gt;RRD is Munin's backbone.&lt;/h2&gt;
&lt;p&gt;Munin keeps its data in an &lt;a href=&quot;http://oss.oetiker.ch/rrdtool/&quot;&gt;RRD
database&lt;/a&gt;. It's a wonderful piece of software, designed for this very
purpose : keep an history of numeric data.&lt;/p&gt;
&lt;p&gt;All you need is to tell RRD for how long and the precision you want to keep
your data. RRD manages then all the underlying work : pruning old data,
averaging to decrease precision if needed, ...&lt;/p&gt;
&lt;p&gt;Munin automatically creates the RRD databases it needs.&lt;/p&gt;
&lt;h2&gt;1.2 - Only one set&lt;/h2&gt;
&lt;p&gt;In 1.2, every database creation was done with the same temporal &amp;amp;
precision parameters. Since the output parameters were constant (day, week,
month, year graphs), there were little need to have a different set of
parameters.&lt;/p&gt;
&lt;h2&gt;1.4 - 2 sets : normal &amp;amp; huge&lt;/h2&gt;
&lt;p&gt;In 1.4, various users showed their need to have different graphing outputs,
and began to hack around Munin's fixed graphing. It became rapidly obvious that
the 1.2 preset wasn't a fit for everyone.&lt;/p&gt;
&lt;p&gt;Therefore a &lt;code&gt;huge&lt;/code&gt; dataset was available to be able to extend the
finest precision (5min) to the whole Munin timeframe. This comes at a price
though : more space is required, and the graph generation is slower, specially
when generating the yearly one, since more data has to be read and
analysed.&lt;/p&gt;
&lt;p&gt;The switch is done for the whole munin installation by changing the
system-wide &lt;code&gt;graph_data_size&lt;/code&gt;, although already created rrd
databases aren't changed. It is then even possible for a user to pre-customize
the rrd file. Munin will then happily uses them transparently thanks to the RRD
layer.&lt;/p&gt;
&lt;h3&gt;Manual overriding&lt;/h3&gt;
&lt;p&gt;Altering the RRD files after it is created is possible, but not as simple.
Standard export &amp;amp; import from RRD take the structure with it. So data has
to be moved around with special tools. &lt;a href=&quot;http://code.google.com/p/pmptools/source/browse/trunk/rrd/rrdmove&quot;&gt;rrdmove&lt;/a&gt;
is my attempt to create such a tool. It copies data between 2 already existing
RRD files, even asking RRD to interpolate the data when needed.&lt;/p&gt;
&lt;h2&gt;2.0 - Full control&lt;/h2&gt;
&lt;p&gt;Starting with 2.0, the parameter &lt;code&gt;graph_data_size&lt;/code&gt; is per
service. It also has a special mode : &lt;code&gt;custom&lt;/code&gt;. &lt;a href=&quot;http://munin-monitoring.org/wiki/format-graph_data_size&quot;&gt;Its format&lt;/a&gt; is
very simple :&lt;/p&gt;
&lt;pre&gt;
 
graph_data_size custom FULL_NB, MULTIPLIER_1 MULTIPLIER_1_NB, ... MULTIPLIER_NMULTIPLIER_N_NB
graph_data_size custom 300, 15 1600, 30 3000
&lt;/pre&gt;
&lt;p&gt;The first number is the number of data at full resolution. Then usually it
comes gradually decreasing resolution.&lt;/p&gt;
&lt;p&gt;A decreasing resolution has 2 usages :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Limit the space consumption : keeping full resolution for the whole period
(default : 5min for 2 years) is sometime too precise.&lt;/li&gt;
&lt;li&gt;Increase performance : RRD will choose the best fitting resolution to
generate its graphs. Already aggregated data is faster to compute.&lt;/li&gt;
&lt;/ul&gt;</description>
    
    
    
          <comments>http://blog.pwkf.org/post/2010/08/Waiting-for-Munin-2.0-Keep-more-data-with-custom-data-retention-plans#comment-form</comments>
      <wfw:comment>http://blog.pwkf.org/post/2010/08/Waiting-for-Munin-2.0-Keep-more-data-with-custom-data-retention-plans#comment-form</wfw:comment>
      <wfw:commentRss>http://blog.pwkf.org/feed/atom/comments/540984</wfw:commentRss>
      </item>
    
  <item>
    <title>Waiting for Munin 2.0 - Native SSH transport</title>
    <link>http://blog.pwkf.org/post/2010/07/Waiting-for-Munin-2.0-Native-SSH-transport</link>
    <guid isPermaLink="false">urn:md5:909601af6402cb869f7d9e2e3b0515ee</guid>
    <pubDate>Mon, 12 Jul 2010 14:11:00 +0200</pubDate>
    <dc:creator>Steve Schnepp</dc:creator>
        <category>munin</category>
        <category>http</category><category>munin</category><category>munin20</category><category>ssh</category><category>sysadmin</category>    
    <description>    &lt;p&gt;In the munin architecture, the munin-master has to connect to the munin-node
via a very simple protocol and plain TCP.&lt;/p&gt;
&lt;p&gt;This has several advantages :&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Very&lt;/strong&gt; simple to manage &amp;amp; install&lt;/li&gt;
&lt;li&gt;Optional SSL since 1.4 enabling secure communications&lt;/li&gt;
&lt;li&gt;Quite simple firewall rules.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;It has also some disadvantages :&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;A new listening service means a wider exposure&lt;/li&gt;
&lt;li&gt;The SSL option might add some administrative overhead (certificates
management, ...)&lt;/li&gt;
&lt;li&gt;A native protocol isn't always covered by all firewall solutions&lt;/li&gt;
&lt;li&gt;Some organisations only authorize a few protocols to simplify audits (ex:
only SSH &amp;amp; HTTPS)&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;Native SSH&lt;/h2&gt;
&lt;p&gt;Theses down points may be solved by &lt;a href=&quot;http://munin-monitoring.org/wiki/MuninSSHTunneling&quot; hreflang=&quot;en&quot;&gt;encapsulation over SSH&lt;/a&gt;, but it can be a tedious task to maintain if
the number of hosts increases.&lt;/p&gt;
&lt;p&gt;Therefore 2.0 introduces the concept of a &lt;strong&gt;native SSH&lt;/strong&gt;
transport. Its usage is dead simple : replace the address with an
&lt;code&gt;ssh://&lt;/code&gt; URL-like one.&lt;/p&gt;
&lt;p&gt;The node still has to be modified to communicate with
&lt;code&gt;stdin&lt;/code&gt;/&lt;code&gt;stdout&lt;/code&gt; instead of a network socket. For now,
only &lt;a href=&quot;http://blog.pwkf.org/post/2008/11/04/A-Poor-Man-s-Munin-Node-to-Monitor-Hostile-UNIX-Servers&quot;&gt;pmmn&lt;/a&gt;
and &lt;a href=&quot;http://blog.pwkf.org/post/2010/06/Waiting-for-Munin-2.0-Performance-Asynchronous-updates&quot;&gt;munin-async&lt;/a&gt;
are able to provide such a node.&lt;/p&gt;
&lt;h3&gt;Configuration&lt;/h3&gt;
&lt;p&gt;The URL is quite self-explanatory as shown in the example below :&lt;/p&gt;
&lt;pre&gt;
[old-style-host]
    address host.example.com

[new-style-host]
    address ssh://munin-node-user@host.example.com/path/to/stdio-enabled-node --params
&lt;/pre&gt;
&lt;h3&gt;Installation notes&lt;/h3&gt;
&lt;p&gt;Authentication should be done without password but via SSH keys. The
connection is from &lt;code&gt;munin-user@host-munin&lt;/code&gt; to
&lt;code&gt;munin-node-user@remote-node&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;If you use &lt;code&gt;munin-async&lt;/code&gt;, the user on the remote node might only
be a readonly one, since it only needs to read spooled data. This implies that
you use &lt;code&gt;--spoolfetch&lt;/code&gt; and not &lt;code&gt;--vectorfetch&lt;/code&gt; that
updates the spool repository.&lt;/p&gt;
&lt;h2&gt;Upcoming HTTP(S) transport in 3.0&lt;/h2&gt;
&lt;p&gt;And the sweetest part is that since all the work has been done for adding
another transport, adding a CGI-based HTTP transport one is possible (and
therefore done) for 3.0.&lt;/p&gt;</description>
    
    
    
          <comments>http://blog.pwkf.org/post/2010/07/Waiting-for-Munin-2.0-Native-SSH-transport#comment-form</comments>
      <wfw:comment>http://blog.pwkf.org/post/2010/07/Waiting-for-Munin-2.0-Native-SSH-transport#comment-form</wfw:comment>
      <wfw:commentRss>http://blog.pwkf.org/feed/atom/comments/532312</wfw:commentRss>
      </item>
    
  <item>
    <title>Waiting for Munin 2.0 - Performance - Asynchronous updates</title>
    <link>http://blog.pwkf.org/post/2010/06/Waiting-for-Munin-2.0-Performance-Asynchronous-updates</link>
    <guid isPermaLink="false">urn:md5:e1957d01162a0736f5534140c4cbdd4e</guid>
    <pubDate>Sat, 26 Jun 2010 16:07:00 +0200</pubDate>
    <dc:creator>Steve Schnepp</dc:creator>
        <category>munin</category>
        <category>munin</category><category>munin20</category><category>performance</category>    
    <description>    &lt;p&gt;&lt;code&gt;munin-update&lt;/code&gt; is &lt;strong&gt;the&lt;/strong&gt; fragile link in the munin
architecture. A &lt;strong&gt;missed execution&lt;/strong&gt; means that some &lt;strong&gt;data
is lost&lt;/strong&gt;.&lt;/p&gt;
&lt;h2&gt;The problem : updates are synchronous&lt;/h2&gt;
&lt;p&gt;In Munin 1.x, updates are synchronous : the value of each
service&lt;sup&gt;[&lt;a href=&quot;http://blog.pwkf.org/post/2010/06/#pnote-526512-1&quot; id=&quot;rev-pnote-526512-1&quot; name=&quot;rev-pnote-526512-1&quot;&gt;1&lt;/a&gt;]&lt;/sup&gt; is the one that &lt;code&gt;munin-update&lt;/code&gt;
retrieves each scheduled run.&lt;/p&gt;
&lt;p&gt;The issue is that &lt;code&gt;munin-update&lt;/code&gt; has to ask every service on
every node for their values. Since the values are only computed when asked,
&lt;code&gt;munin-update&lt;/code&gt; has to wait quite some time for every value.&lt;/p&gt;
&lt;p&gt;This &lt;strong&gt;very simple design&lt;/strong&gt; enables munin to have the
&lt;strong&gt;simplest plugins&lt;/strong&gt; : they are completely
&lt;strong&gt;stateless&lt;/strong&gt;. While being one great strength of munin, it puts a
severe blow on scalability : more plugins/node means obviously a slower
retrieval.&lt;/p&gt;
&lt;h2&gt;Evolving Solutions&lt;/h2&gt;
&lt;h3&gt;1.4 : Parallel Fetching&lt;/h3&gt;
&lt;p&gt;1.4 addresses some of these scalability issues by implementing parallel
fetching. It takes into account that the &lt;strong&gt;most of the execution
time&lt;/strong&gt; of &lt;code&gt;munin-update&lt;/code&gt; is spent &lt;strong&gt;waiting for
replies&lt;/strong&gt;. In 1.4 &lt;code&gt;munin-update&lt;/code&gt; can ask
&lt;code&gt;max_processes&lt;/code&gt; nodes in parallel.&lt;/p&gt;
&lt;p&gt;Now, the I/O part is becoming the next limiting factor, since updating many
RRDs in &lt;strong&gt;parallel&lt;/strong&gt; is the same as &lt;strong&gt;random I/O&lt;/strong&gt;
access for the underlying munin-master OS. Serializing &amp;amp; grouping the
updates will be possible with the new RRDp interface from rrdtool version 1.4
and on-demand graphing. Tomas Zvala even offered &lt;a href=&quot;http://sourceforge.net/mailarchive/message.php?msg_name=4BEDB877.9050004%40zvala.cz&quot; hreflang=&quot;en&quot;&gt;a patch for 1.4 RRDp&lt;/a&gt; on the ML. It is very promising, but
doesn't address the root defect in this design : a hard dependence of regular
&lt;code&gt;munin-update&lt;/code&gt; runs.&lt;/p&gt;
&lt;h3&gt;2.0 : Stateful plugins&lt;/h3&gt;
&lt;p&gt;2.0 provides a way for plugins to be stateful. They might schedule their
polling themselves, and then when &lt;code&gt;munin-update&lt;/code&gt; runs, only emit
collect already computed values. This way, a &lt;strong&gt;missed run&lt;/strong&gt; isn't
as dramatic as it is in the 1.x series, since &lt;strong&gt;data isn't lost&lt;/strong&gt;.
The data collection is also &lt;strong&gt;much faster&lt;/strong&gt; because the real
computing is done &lt;strong&gt;ahead of time&lt;/strong&gt;.&lt;/p&gt;
&lt;h3&gt;2.0 : Asynchronous proxy node&lt;/h3&gt;
&lt;p&gt;But &lt;strong&gt;changing plugins&lt;/strong&gt; to be &lt;strong&gt;stateful&lt;/strong&gt; and
self-polled is &lt;strong&gt;difficult&lt;/strong&gt; and tedious. &lt;strong&gt;It even works
against of one of the real strength of munin&lt;/strong&gt; : having simple &amp;amp;
stateless plugins.&lt;/p&gt;
&lt;p&gt;To address this concern, an experimental proxy node is created. For 2.0 it
takes the form of a couple of processes : &lt;code&gt;munin-async-server&lt;/code&gt; and
&lt;code&gt;munin-sync-client&lt;/code&gt;.&lt;/p&gt;
&lt;h2&gt;The proxy node in detail (&lt;code&gt;munin-async&lt;/code&gt;)&lt;/h2&gt;
&lt;h3&gt;Overview&lt;/h3&gt;
&lt;p&gt;These 2 processes form an asynchronous proxy between
&lt;code&gt;munin-update&lt;/code&gt; and &lt;code&gt;munin-node&lt;/code&gt;. This avoids the need to
change the plugins or upgrade &lt;code&gt;munin-node&lt;/code&gt; on all nodes.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;munin-async-server&lt;/code&gt; should be installed on the same host than
the proxied &lt;code&gt;munin-node&lt;/code&gt; in order to avoid any network issue. It is
the process that will poll regularly &lt;code&gt;munin-node&lt;/code&gt;. The I/O issue of
&lt;code&gt;munin-update&lt;/code&gt; is here non-existent, since &lt;code&gt;munin-async&lt;/code&gt;
stores all the values by simply appending them in a text file without any
further processing. This file is later read by the client's
&lt;code&gt;munin-update&lt;/code&gt;, and it will be processed there.&lt;/p&gt;
&lt;h3&gt;Specific update rates&lt;/h3&gt;
&lt;p&gt;Having one proxy per node enables a polling of all the services there with a
specific update rate.&lt;/p&gt;
&lt;p&gt;To achieve this, &lt;code&gt;munin-async-server&lt;/code&gt; forks into multiple
processes, one for each proxied service. This way each service is completely
isolated from the other, and therefore is able to have its own update rate, is
safe from other plugins slowdowns, and it does even completely parallelize the
information gathering.&lt;/p&gt;
&lt;h3&gt;SSH transport&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;munin-async-client&lt;/code&gt; uses the new SSH native transport of 2.0. It
permits a very simple install of the async proxy.&lt;/p&gt;
&lt;div class=&quot;footnotes&quot;&gt;
&lt;h4&gt;Notes&lt;/h4&gt;
&lt;p&gt;[&lt;a href=&quot;http://blog.pwkf.org/post/2010/06/#rev-pnote-526512-1&quot; id=&quot;pnote-526512-1&quot; name=&quot;pnote-526512-1&quot;&gt;1&lt;/a&gt;] in 1.2 it's the same as plugin, but since 1.4 and the
introduction of &lt;ins&gt;multigraph&lt;/ins&gt;, one plugin can provide multiple
&lt;ins&gt;services&lt;/ins&gt;.&lt;/p&gt;
&lt;/div&gt;</description>
    
    
    
          <comments>http://blog.pwkf.org/post/2010/06/Waiting-for-Munin-2.0-Performance-Asynchronous-updates#comment-form</comments>
      <wfw:comment>http://blog.pwkf.org/post/2010/06/Waiting-for-Munin-2.0-Performance-Asynchronous-updates#comment-form</wfw:comment>
      <wfw:commentRss>http://blog.pwkf.org/feed/atom/comments/526512</wfw:commentRss>
      </item>
    
  <item>
    <title>CGI on steroids with FastCGI, but on a CGI-only server - The FastCGI wrapper</title>
    <link>http://blog.pwkf.org/post/2010/06/CGI-on-steroids-with-FastCGI%2C-but-on-a-CGI-only-server-The-FastCGI-wrapper</link>
    <guid isPermaLink="false">urn:md5:ba5366e894e1d3032bccad18415143b6</guid>
    <pubDate>Mon, 21 Jun 2010 22:22:00 +0200</pubDate>
    <dc:creator>Steve Schnepp</dc:creator>
        <category>sysadmin</category>
        <category>design</category><category>performance</category><category>perl</category>    
    <description>    &lt;h2&gt;FastCGI is really &lt;em&gt;CGI on steroids&lt;/em&gt;&lt;/h2&gt;
&lt;p&gt;FastCGI is very common way to increase performance of a CGI installation. It
is based on the fact that usually the startup of CGI scripts is slow, whereas
the response is quite fast.&lt;/p&gt;
&lt;p&gt;So if you have a persistent process, you only have to take care of the
startup once, and you then experience a real speedup.&lt;/p&gt;
&lt;h3&gt;FastCGI vs mod_perl (or mod_python, ...)&lt;/h3&gt;
&lt;p&gt;Once a big fan of &lt;code&gt;mod_perl&lt;/code&gt;, I'm converted to FastCGI since.
&lt;code&gt;mod_perl&lt;/code&gt; was for a long time &lt;strong&gt;the&lt;/strong&gt; answer for
speeding up Perl CGI scripts. It has a very good track record of stability and
has real hooks deep in the Apache processing requests.&lt;/p&gt;
&lt;p&gt;FastCGI focuses on a different feature set that is more actual than
&lt;code&gt;mod_perl&lt;/code&gt;&lt;sup&gt;[&lt;a href=&quot;http://blog.pwkf.org/post/2010/06/#pnote-527747-1&quot; id=&quot;rev-pnote-527747-1&quot; name=&quot;rev-pnote-527747-1&quot;&gt;1&lt;/a&gt;]&lt;/sup&gt; :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;It is much simpler to install and configure, especially when having
multiple applications.&lt;/li&gt;
&lt;li&gt;Able to connect to a distant server (running as a different UID, chrooted
or even on a remote host)&lt;/li&gt;
&lt;li&gt;Able to mix scripting languages without any need to compile some other
apache modules.&lt;/li&gt;
&lt;li&gt;Able to be used with several webservers, even closed-source ones : FastCGI
is a protocol, not an API.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;But steroids do have some side effects&lt;/h2&gt;
&lt;h3&gt;CGI issues&lt;/h3&gt;
&lt;p&gt;One downside is that your CGI script should be adapted to FastCGI and the
fact that the script doesn't end with the end of the request.&lt;/p&gt;
&lt;p&gt;In the real world that's quite easy. Every language that is commonly used
for CGI offers &lt;a href=&quot;http://www.fastcgi.com/drupal/node/5&quot; hreflang=&quot;en&quot;&gt;CGI-wrapper libraries&lt;/a&gt; that works in a FastCGI context as well as a
plain CGI one.&lt;/p&gt;
&lt;h3&gt;Webserver issues&lt;/h3&gt;
&lt;p&gt;Another issue can also come from the webserver. Since CGI is dead simple to
implement even the micro-webserver &lt;a href=&quot;http://www.acme.com/software/thttpd/&quot; hreflang=&quot;en&quot;&gt;thttpd&lt;/a&gt; implements
it.&lt;/p&gt;
&lt;p&gt;FastCGI on the other hand is a little more difficult to implement, since the
webserver needs to create a container that monitors and calls the
FastCGI-enabled script.&lt;/p&gt;
&lt;h3&gt;A standalone FastCGI container&lt;/h3&gt;
&lt;p&gt;Fortunately, the FastCGI team provided us with a ready-to-use container and
a very simple client that acts a plain CGI script, but proxies it to a
full-blown container.&lt;/p&gt;
&lt;p&gt;Since the plain CGI part is a very small native executable its overhead is
negligible compared to the reply time, even without comparison with the startup
time of the whole script.&lt;/p&gt;
&lt;p&gt;Its installation is also quite straightforward. I just installed the
&lt;code&gt;libfcgi&lt;/code&gt; package on Debian : it provides
&lt;code&gt;/usr/bin/cgi-fcgi&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;I created a simple CGI wrapper for my previous &lt;a href=&quot;http://blog.pwkf.org/post/2010/06/Waiting-for-Munin-2.0-Performance-FastCGI&quot;&gt;munin
benchmarking&lt;/a&gt; needs :&lt;/p&gt;
&lt;pre&gt;
#! /bin/sh

exec /usr/bin/cgi-fcgi -connect /tmp/munin-cgi.sock \
     /usr/lib/cgi-bin/munin-cgi-graph
&lt;/pre&gt;
&lt;div class=&quot;footnotes&quot;&gt;
&lt;h4&gt;Notes&lt;/h4&gt;
&lt;p&gt;[&lt;a href=&quot;http://blog.pwkf.org/post/2010/06/#rev-pnote-527747-1&quot; id=&quot;pnote-527747-1&quot; name=&quot;pnote-527747-1&quot;&gt;1&lt;/a&gt;] who really need deep apache hooks ?&lt;/p&gt;
&lt;/div&gt;</description>
    
    
    
          <comments>http://blog.pwkf.org/post/2010/06/CGI-on-steroids-with-FastCGI%2C-but-on-a-CGI-only-server-The-FastCGI-wrapper#comment-form</comments>
      <wfw:comment>http://blog.pwkf.org/post/2010/06/CGI-on-steroids-with-FastCGI%2C-but-on-a-CGI-only-server-The-FastCGI-wrapper#comment-form</wfw:comment>
      <wfw:commentRss>http://blog.pwkf.org/feed/atom/comments/527747</wfw:commentRss>
      </item>
    
  <item>
    <title>Waiting for Munin 2.0 - Performance - FastCGI</title>
    <link>http://blog.pwkf.org/post/2010/06/Waiting-for-Munin-2.0-Performance-FastCGI</link>
    <guid isPermaLink="false">urn:md5:68c4f27314364d8247cef0bd2bb372fc</guid>
    <pubDate>Wed, 16 Jun 2010 23:25:00 +0200</pubDate>
    <dc:creator>Steve Schnepp</dc:creator>
        <category>munin</category>
        <category>munin</category><category>munin20</category>    
    <description>    &lt;p&gt;1.2 has CGI, it is slow, unsupported, but &lt;a href=&quot;http://munin-monitoring.org/wiki/CgiHowto&quot; hreflang=&quot;en&quot;&gt;it does
exist&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;1.4 has even an &lt;a href=&quot;http://munin-monitoring.org/wiki/CgiHowto#FastCGI&quot; hreflang=&quot;en&quot;&gt;experimental FastCGI&lt;/a&gt; install mode.&lt;/p&gt;
&lt;p&gt;Quoting from this page :&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;This is more a proof of concept than a recommended - it's slow. Also we do
not test it before every release&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;In 2.0 lots of work has been done to take this experimental CGI mode into a
supported one. It might even be the primary way of using munin since, when an
install has a certain size, CGI becomes mandatory.&lt;/p&gt;
&lt;p&gt;That's because &lt;code&gt;munin-graph&lt;/code&gt; doesn't have time to finish its job
when the next one is launched, and the new one doesn't run. It is not as
dramatic as a missed &lt;code&gt;munin-update&lt;/code&gt; execution, since the graphs will
still be generated on the later round, but there will be random graph lags and
it will put quite some stress on the CPU &amp;amp; I/O subsystem. This will slow
&lt;code&gt;munin-update&lt;/code&gt; down since it also uses the I/O subsystem much, and
that's to be avoided at all costs.&lt;/p&gt;
&lt;p&gt;Mainstream CGI has some consequences :&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Only the FastCGI wrapper remained : the plain CGI one is dropped.
&lt;ul&gt;
&lt;li&gt;The CPAN module &lt;code&gt;CGI::Fast&lt;/code&gt; is compatible when launched as a
normal CGI.&lt;/li&gt;
&lt;li&gt;Almost all HTTP servers support plain CGI, and with the &lt;a href=&quot;http://www.fastcgi.com/devkit/doc/cgi-fcgi.1&quot; hreflang=&quot;en&quot;&gt;cgi-fcgi&lt;/a&gt;
wrapper from the FastCGI devkit (Debian package &lt;code&gt;libfcgi&lt;/code&gt;), you can
have the best of both worlds (a custom HTTP server &amp;amp; FastCGI). I even
posted on how to have a working &lt;a href=&quot;http://blog.pwkf.org/post/2010/06/CGI-on-steroids-with-FastCGI%2C-but-on-a-CGI-only-server-The-FastCGI-wrapper&quot;&gt;
thttpd with FastCGI&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;The old process limit mechanism is dropped also. The FastCGI server
configuration is a much better way to control it. The old code was based on
System V semaphores and was not 100% reliable.&lt;/li&gt;
&lt;li&gt;A caching system has to be implemented, in order for each graph to be
generated only once for its lifetime.&lt;/li&gt;
&lt;li&gt;The CGI process is launched with the HTTP server user. Since it doesn't
only read now, but also writes log files and images files, there is an extra
step when installing it. But it's already described in the &lt;a href=&quot;http://munin-monitoring.org/wiki/CgiHowto&quot; hreflang=&quot;en&quot;&gt;Munin CGI&lt;/a&gt; page
given previously.&lt;/li&gt;
&lt;li&gt;Since the process is launched only once, for now it read only once the
config. So if some part of the config change, the FastCGI container MUST be
restarted.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;Some benchmarks&lt;/h2&gt;
&lt;p&gt;Now, the sweet part : I'm putting up some micro-benchmarks.&lt;/p&gt;
&lt;p&gt;They should be taken with caution as every benchmark should be, but I think
the general idea is conveyed. For the sake of simplicity I'm only doing 1
request in parallel and disabled IMS caching.&lt;/p&gt;
&lt;h3&gt;Basic 1.2 CGI&lt;/h3&gt;
&lt;pre&gt;
$ httperf --num-conns 10  --add-header='Cache-Control: no-cache\n' \
    --uri  /cgi-bin/munin-cgi-graph/localdomain/localhost.localdomain/cpu-day.png

Total: connections 10 requests 10 replies 10 test-duration 27.939 s

Connection rate: 0.4 conn/s (2793.9 ms/conn, &amp;lt;=1 concurrent connections)
Connection time [ms]: min 1653.9 avg 2793.9 max 5217.0 median 1912.5 stddev 1487.8
Connection time [ms]: connect 0.0
Connection length [replies/conn]: 1.000

Request rate: 0.4 req/s (2793.9 ms/req)
Request size [B]: 131.0
&lt;/pre&gt;
&lt;h3&gt;1.4 FastCGI&lt;/h3&gt;
&lt;p&gt;The munin-fastcgi-graph is only loaded once, but the munin-graph is reloaded
each time.&lt;/p&gt;
&lt;pre&gt;
$ httperf --num-conns 10  --add-header='Cache-Control: no-cache\n' \
    --uri  /cgi-bin/munin-fastcgi-graph/localdomain/localhost.localdomain/cpu-day.png

Total: connections 10 requests 10 replies 10 test-duration 13.807 s

Connection rate: 0.7 conn/s (1380.7 ms/conn, &amp;lt;=1 concurrent connections)
Connection time [ms]: min 1141.3 avg 1380.7 max 1636.1 median 1381.5 stddev 173.7
Connection time [ms]: connect 0.0
Connection length [replies/conn]: 1.000

Request rate: 0.7 req/s (1380.7 ms/req)
&lt;/pre&gt;
&lt;p&gt;The response time is cut almost in half. That's expected, since only the top
half of the processing isn't reloaded.&lt;/p&gt;
&lt;h3&gt;2.0 FastCGI&lt;/h3&gt;
&lt;p&gt;Here everything is loaded once.&lt;/p&gt;
&lt;pre&gt;
$ httperf --num-conns 10  --add-header='Cache-Control: no-cache\n' \
    --uri  /cgi-bin/munin-cgi-graph-2.0/localdomain/localhost.localdomain/cpu-day.png

Total: connections 10 requests 10 replies 10 test-duration 1.668 s

Connection rate: 6.0 conn/s (166.8 ms/conn, &amp;lt;=1 concurrent connections)
Connection time [ms]: min 123.0 avg 166.8 max 513.4 median 127.5 stddev 121.9
Connection time [ms]: connect 0.0
Connection length [replies/conn]: 1.000

Request rate: 6.0 req/s (166.8 ms/req)
&lt;/pre&gt;
&lt;p&gt;Now response time is cut almost by a ten factor ! That's quite good news,
since it goes 20 times faster that the original CGI.&lt;/p&gt;</description>
    
    
    
          <comments>http://blog.pwkf.org/post/2010/06/Waiting-for-Munin-2.0-Performance-FastCGI#comment-form</comments>
      <wfw:comment>http://blog.pwkf.org/post/2010/06/Waiting-for-Munin-2.0-Performance-FastCGI#comment-form</wfw:comment>
      <wfw:commentRss>http://blog.pwkf.org/feed/atom/comments/525792</wfw:commentRss>
      </item>
    
  <item>
    <title>Waiting for Munin 2.0 - Performance - Architecture</title>
    <link>http://blog.pwkf.org/post/2010/06/Waiting-for-Munin-2.0-Performance-Introduction-Architecture</link>
    <guid isPermaLink="false">urn:md5:08010319781f7bf88a099f0de8c8960e</guid>
    <pubDate>Thu, 10 Jun 2010 03:48:00 +0200</pubDate>
    <dc:creator>Steve Schnepp</dc:creator>
        <category>munin</category>
        <category>munin</category><category>munin20</category>    
    <description>    &lt;h2&gt;A little intro/refresh on munin's architecture on the master&lt;/h2&gt;
&lt;p&gt;Munin has a very simple architecture on the master : &lt;code&gt;munin-cron&lt;/code&gt;
is launched via cron every 5 minutes. Its only job is to launch in order
&lt;code&gt;munin-update&lt;/code&gt;, &lt;code&gt;munin-graph&lt;/code&gt;, &lt;code&gt;munin-html&lt;/code&gt;
&amp;amp; &lt;code&gt;munin-limits&lt;/code&gt;.&lt;/p&gt;
&lt;h2&gt;The various processes&lt;/h2&gt;
&lt;h3&gt;munin-update&lt;/h3&gt;
&lt;p&gt;This process retrieves the values from the various nodes and to update the
rrd files. This one should never take more than 5 minutes to run, otherwise
there will be gaps since the next update will not be launched
(lockfile-protected runs).&lt;/p&gt;
&lt;p&gt;This process stresses the I/O on the master, and depends on the plugins
execution time on the various nodes. On 1.4 the retrieval is
multi-threaded&lt;sup&gt;[&lt;a href=&quot;http://blog.pwkf.org/post/2010/06/#pnote-525782-1&quot; id=&quot;rev-pnote-525782-1&quot; name=&quot;rev-pnote-525782-1&quot;&gt;1&lt;/a&gt;]&lt;/sup&gt;, so an slow node doesn't impact too much the
whole process.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;2.0 proposes asynchronous updates and vectorized
updates.&lt;/strong&gt;&lt;/p&gt;
&lt;h3&gt;munin-graph&lt;/h3&gt;
&lt;p&gt;This process generates all the image files from the rrd files.&lt;/p&gt;
&lt;p&gt;It is usually a process that is quite CPU-bound, it generates also a fair
load of I/O. Since 1.4 there might also be a parallel graphing generation in
order to take advantage of multiple CPU / multiple I/O paths.&lt;/p&gt;
&lt;p&gt;A simple optimization is to generate only needed graphs instead of all of
them each time. This leads to CGI-generation of graphs. 1.2 &amp;amp; 1.4 took a
first step in this direction, but it's quite a hack since it's only a very
basic script that calls &lt;code&gt;munin-update&lt;/code&gt; with the correct
parameters.&lt;/p&gt;
&lt;p&gt;A FastCGI port of the wrapper (&lt;code&gt;munin-cgi-graph&lt;/code&gt;) removes the
overhead of starting the wrapper for each call, but in 1.4 the code is quite
experimental and has some serious bugs that would need extensive patching to be
fixed.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;2.0 completes the integration of CGI graphing with removing the
overhead of calling &lt;code&gt;munin-graph&lt;/code&gt; and does this extensive patching
for bugs fixing&lt;/strong&gt;&lt;/p&gt;
&lt;h3&gt;munin-html&lt;/h3&gt;
&lt;p&gt;This process generates all the html files from the rrd files. This one is
quite fast for now.&lt;/p&gt;
&lt;h3&gt;munin-limits&lt;/h3&gt;
&lt;p&gt;This process checks the limits to see if there is a warning/alert to send
via mail or nagios. This one is also quite fast for now.&lt;/p&gt;
&lt;div class=&quot;footnotes&quot;&gt;
&lt;h4&gt;Notes&lt;/h4&gt;
&lt;p&gt;[&lt;a href=&quot;http://blog.pwkf.org/post/2010/06/#rev-pnote-525782-1&quot; id=&quot;pnote-525782-1&quot; name=&quot;pnote-525782-1&quot;&gt;1&lt;/a&gt;] more multi-process actually&lt;/p&gt;
&lt;/div&gt;</description>
    
    
    
          <comments>http://blog.pwkf.org/post/2010/06/Waiting-for-Munin-2.0-Performance-Introduction-Architecture#comment-form</comments>
      <wfw:comment>http://blog.pwkf.org/post/2010/06/Waiting-for-Munin-2.0-Performance-Introduction-Architecture#comment-form</wfw:comment>
      <wfw:commentRss>http://blog.pwkf.org/feed/atom/comments/525782</wfw:commentRss>
      </item>
    
  <item>
    <title>Waiting for Munin 2.0 - Introduction</title>
    <link>http://blog.pwkf.org/post/2010/06/Waiting-for-Munin-2.0-Introduction</link>
    <guid isPermaLink="false">urn:md5:bb2170b02e8c57e4f5118071419e8e6a</guid>
    <pubDate>Tue, 08 Jun 2010 22:30:00 +0200</pubDate>
    <dc:creator>Steve Schnepp</dc:creator>
        <category>munin</category>
        <category>munin</category><category>munin20</category>    
    <description>    &lt;p&gt;This is the first article of a series about the coming version 2.0 of
&lt;a href=&quot;http://munin-monitoring.org/&quot; hreflang=&quot;en&quot;&gt;Munin&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The idea came from the series &lt;a href=&quot;http://www.depesz.com/index.php/2009/07/03/waiting-for-8-5-lets-start/&quot; hreflang=&quot;en&quot;&gt;Waiting from 8.5&lt;/a&gt; about PostgreSQL.&lt;/p&gt;
&lt;p&gt;The ironic part is that their 8.5 release has become a 9.0, just like our
1.5 will be a 2.0.&lt;/p&gt;
&lt;p&gt;I'll post several small articles about new or enhanced-enough features. They
will all be tagged &lt;a href=&quot;http://blog.pwkf.org/tag/munin20&quot;&gt;munin20&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Planned summary :&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href=&quot;http://blog.pwkf.org/post/2010/06/Waiting-for-Munin-2.0-Performance-Introduction-Architecture&quot;&gt;Performance
- Architecture context&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://blog.pwkf.org/post/2010/06/Using-FastCGI-with-a-CGI-only-server-The-FastCGI-wrapper&quot;&gt;Performance
- FastCGI&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://blog.pwkf.org/post/2010/06/Waiting-for-Munin-2.0-Performance-Asynchronous-updates&quot;&gt;Performance
- Asynchronous updates&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Performance - Misc&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://blog.pwkf.org/post/2010/07/Waiting-for-Munin-2.0-Native-SSH-transport&quot;&gt;Native
SSH transport&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://blog.pwkf.org/post/2010/08/Waiting-for-Munin-2.0-Keep-more-data-with-custom-data-retention-plans&quot;&gt;
Custom data retention plans (keep more data)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Dynamic zooming&lt;/li&gt;
&lt;/ol&gt;</description>
    
    
    
          <comments>http://blog.pwkf.org/post/2010/06/Waiting-for-Munin-2.0-Introduction#comment-form</comments>
      <wfw:comment>http://blog.pwkf.org/post/2010/06/Waiting-for-Munin-2.0-Introduction#comment-form</wfw:comment>
      <wfw:commentRss>http://blog.pwkf.org/feed/atom/comments/525488</wfw:commentRss>
      </item>
    
  <item>
    <title>Don't use Excerpt... At least with DotClear.</title>
    <link>http://blog.pwkf.org/post/2010/04/Do-not-use-Excerpt-At-least-with-DotClear</link>
    <guid isPermaLink="false">urn:md5:5e310276dfa3d044fb0f767f3527a814</guid>
    <pubDate>Thu, 01 Apr 2010 08:00:00 +0200</pubDate>
    <dc:creator>Steve Schnepp</dc:creator>
        <category>general</category>
            
    <description>    &lt;p&gt;DotClear automatically generates a &lt;code&gt;meta description&lt;/code&gt; tag from
the blog entry, but it doesn't take the excerpt into account.&lt;/p&gt;
&lt;p&gt;It just takes the beginning of the article &lt;strong&gt;content&lt;/strong&gt;. Since
the excerpt is also shown at the beginning of the article, I cannot just write
2 times the same content.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;meta description&lt;/code&gt; is quite interesting since it is usually used
for the little snipped under a search result in usual search engines, so having
the beginning of the post in here is very nice.&lt;/p&gt;
&lt;p&gt;This fact annihilates the &lt;a href=&quot;http://blog.pwkf.org/post/2009/05/Are-Excerpts-a-Good-Thing&quot;&gt;good point of having
excerpts&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I'm now falling back to removing progressively all the excerpts on my
posts...&lt;/p&gt;</description>
    
    
    
          <comments>http://blog.pwkf.org/post/2010/04/Do-not-use-Excerpt-At-least-with-DotClear#comment-form</comments>
      <wfw:comment>http://blog.pwkf.org/post/2010/04/Do-not-use-Excerpt-At-least-with-DotClear#comment-form</wfw:comment>
      <wfw:commentRss>http://blog.pwkf.org/feed/atom/comments/504880</wfw:commentRss>
      </item>
    
  <item>
    <title>API Design: Avoid hidden costs of simple features</title>
    <link>http://blog.pwkf.org/post/2010/03/API-Design%3A-Hidden-costs-of-simple-features</link>
    <guid isPermaLink="false">urn:md5:8ea72e6386e7410474ce3ece000deda1</guid>
    <pubDate>Wed, 31 Mar 2010 21:00:00 +0200</pubDate>
    <dc:creator>Steve Schnepp</dc:creator>
        <category>programming</category>
        <category>api</category><category>design</category><category>performance</category>    
    <description>    &lt;p&gt;&lt;strong&gt;Programmers&lt;/strong&gt; are usually like water : they &lt;strong&gt;always
use&lt;/strong&gt; the &lt;strong&gt;path of least resistance&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Let's see how to use this fact to predict the usage of an API when you
design it.&lt;/p&gt;
&lt;h2&gt;Initial API&lt;/h2&gt;
&lt;p&gt;Consider the very simple DB API that consumes a connected ResultSet and
presents a disconnected version of it.&lt;/p&gt;
&lt;pre&gt;
class DisconnectedResultSet{
        public DisconnectedResultSet (ResultSet rs);
        public boolean next();
        public Object getObject(int col_idx);
}
&lt;/pre&gt;
&lt;p&gt;It's usage is quite easy :&lt;/p&gt;
&lt;pre&gt;
while (drs.next()) {
        int col_idx = 1;
        drs.getObject(col_idx++); // Do something w/ 1st col
        drs.getObject(col_idx++); // Do something w/ 2st col
        //...
}
&lt;/pre&gt;
&lt;h2&gt;Just a &lt;em&gt;little&lt;/em&gt; evolution...&lt;/h2&gt;
&lt;p&gt;Since the &lt;code&gt;DisconnectedResultSet&lt;/code&gt; is &lt;em&gt;disconnected&lt;/em&gt;, we
can imagine that it should implement a &lt;code&gt;rewind()&lt;/code&gt; method in order to
use it several times without running the initial query again. We now have an
updated class :&lt;/p&gt;
&lt;pre&gt;
class DisconnectedResultSet{
        public DisconnectedResultSet (ResultSet rs);
        public boolean next();
        public Object getObject(int col_idx);   
        public void rewind(); // Be able to rewind it
}
&lt;/pre&gt;
&lt;p&gt;And its classical usage :&lt;/p&gt;
&lt;pre&gt;
while (drs.next()) {
        // do stuff...
}
// ...
drs.rewind();
while (drs.next()) {
        // do something else with the same data...
}
// ...
drs.rewind();
while (drs.next()) {
        // do something else with the same data...
}
// ...
&lt;/pre&gt;
&lt;h2&gt;A new need comes&lt;/h2&gt;
&lt;p&gt;A new need comes : see if the &lt;code&gt;DisconnectedResultSet&lt;/code&gt; is empty or
not in order to avoid sending header.&lt;/p&gt;
&lt;p&gt;The usual way is to send them once when iterating like :&lt;/p&gt;
&lt;pre&gt;
boolean is_headers_sent = false;
while (drs.next()) {
        if (! is_headers_sent) { 
                send_headers(); 
                is_headers_sent = true;
        }
        // do something else with the same data...
}
&lt;/pre&gt;
&lt;p&gt;But since there is a nice &lt;code&gt;rewind()&lt;/code&gt;method, just waiting to be
used, the code might become :&lt;/p&gt;
&lt;pre&gt;
if (drs.next()) {
        send_headers(); 
}
drs.rewind();
while (drs.next()) {
        // do something else with the same data...
}
&lt;/pre&gt;
&lt;p&gt;Now, this code isn't generic anymore to accommodate a connected
ResultSet.&lt;/p&gt;
&lt;p&gt;So, as John Carmack said :&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The cost of adding a feature isn't just the time it takes to code it. The
cost also includes the addition of an obstacle to future expansion.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;That's really true when you design &lt;strong&gt;APIs&lt;/strong&gt; since their purpose
is to &lt;strong&gt;last long&lt;/strong&gt; and to &lt;strong&gt;be extended&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;So, &lt;strong&gt;think twice when you propose an extension &amp;quot;just in
case&amp;quot;&lt;/strong&gt;.&lt;/p&gt;
&lt;h2&gt;The &lt;em&gt;little&lt;/em&gt; evolution, revisited...&lt;/h2&gt;
&lt;p&gt;To solve this case, don't propose a &lt;code&gt;rewind()&lt;/code&gt; method, but offer
a &lt;code&gt;duplicate()&lt;/code&gt; one. It offers the same functionality, just in a new
object.&lt;/p&gt;
&lt;p&gt;The usage will be almost the same as shown below, but since it feels more
performance-sensitive, it won't be used as lightly : the &lt;code&gt;boolean
is_headers_sent&lt;/code&gt; pattern has now more chances to be used.&lt;/p&gt;
&lt;pre&gt;
while (drs.next()) {
        // do stuff...
}
// ...
drs = drs.duplicate();
while (drs.next()) {
        // do something else with the same data...
}
// ...
drs = drs.duplicate();
while (drs.next()) {
        // do something else with the same data...
}
// ...
&lt;/pre&gt;
&lt;p&gt;It's an other example that &lt;a href=&quot;http://blog.pwkf.org/post/2007/12/03/Use-immutable-objects-to-avoid-synchronisation&quot;&gt;immutable
objects are the way to go&lt;/a&gt;, but for a different reason this time.&lt;/p&gt;
&lt;p&gt;Note: Just finished my March 2010 article, even &lt;strong&gt;on time&lt;/strong&gt;...
I'm still trying to keep at least a one article per month blogging rate. So far
so good for 2010, still 9 months to go !&lt;/p&gt;</description>
    
    
    
          <comments>http://blog.pwkf.org/post/2010/03/API-Design%3A-Hidden-costs-of-simple-features#comment-form</comments>
      <wfw:comment>http://blog.pwkf.org/post/2010/03/API-Design%3A-Hidden-costs-of-simple-features#comment-form</wfw:comment>
      <wfw:commentRss>http://blog.pwkf.org/feed/atom/comments/475523</wfw:commentRss>
      </item>
    
  <item>
    <title>Free Exception lunch : Use unchecked exceptions, but still announce which ones you might throw.</title>
    <link>http://blog.pwkf.org/post/2010/02/You-Shall-Declare-The-Unchecked-Exceptions-You-Might-Throw</link>
    <guid isPermaLink="false">urn:md5:03e06c61165fcdfa2d6e0d529dfbeb36</guid>
    <pubDate>Sat, 20 Feb 2010 16:01:00 +0100</pubDate>
    <dc:creator>Steve Schnepp</dc:creator>
        <category>java</category>
            
    <description>    &lt;p&gt;In a previous article I choosed my side : &lt;a href=&quot;http://blog.pwkf.org/post/2009/07/Checked-or-Unchecked-Exceptions-for-Legacy-Code&quot;&gt;Unchecked
Exceptions are much simpler to use&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;But, on the other side of this great division, there is a very valid point :
&lt;strong&gt;You usually declare checked exceptions&lt;/strong&gt;. Sure it's possible to
only declare to throw &lt;code&gt;Exception&lt;/code&gt;, but that would defeat the whole
purpose of using checked exceptions.&lt;/p&gt;
&lt;p&gt;The nicest thing is that you can also have a custom exception hierarchy, but
based on &lt;code&gt;RuntimeException&lt;/code&gt; instead of a plain
&lt;code&gt;Exception&lt;/code&gt;. This way it's like in C++. Everything might be thrown,
and you don't &lt;strong&gt;need&lt;/strong&gt; to handle them.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Declaring them&lt;/strong&gt;, on the other side, is very interesting
because you are &lt;strong&gt;documenting your interface&lt;/strong&gt; for almost
&lt;strong&gt;free&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;So, use unchecked exceptions to free yourself of the checked catch-slavery,
but still declare the custom ones you might throw.&lt;/p&gt;</description>
    
    
    
          <comments>http://blog.pwkf.org/post/2010/02/You-Shall-Declare-The-Unchecked-Exceptions-You-Might-Throw#comment-form</comments>
      <wfw:comment>http://blog.pwkf.org/post/2010/02/You-Shall-Declare-The-Unchecked-Exceptions-You-Might-Throw#comment-form</wfw:comment>
      <wfw:commentRss>http://blog.pwkf.org/feed/atom/comments/436982</wfw:commentRss>
      </item>
    
  <item>
    <title>Immutability of an URL</title>
    <link>http://blog.pwkf.org/post/2010/02/Immutability-of-an-URL</link>
    <guid isPermaLink="false">urn:md5:d309c7c0d59a5f7e7cbcd5c896b3f2cd</guid>
    <pubDate>Sat, 20 Feb 2010 15:18:00 +0100</pubDate>
    <dc:creator>Steve Schnepp</dc:creator>
        <category>general</category>
            
    <description>    &lt;p&gt;In the pure spirit of &lt;a href=&quot;http://www.javapractices.com/topic/TopicAction.do?Id=211&quot; hreflang=&quot;en&quot;&gt;Data
is King&lt;/a&gt; I think that URL should &lt;strong&gt;never&lt;/strong&gt; change. Even the W3C
agrees with their &lt;a href=&quot;http://www.w3.org/Provider/Style/URI.html&quot; hreflang=&quot;en&quot;&gt;Cool URIs don't change&lt;/a&gt; article.&lt;/p&gt;
&lt;p&gt;But we all know that in IT &lt;em&gt;never&lt;/em&gt; is only &lt;em&gt;not in the foreseen
future&lt;/em&gt;. So URL &lt;strong&gt;do&lt;/strong&gt; change, at least after a while, and
usually for technical reasons&lt;sup&gt;[&lt;a href=&quot;http://blog.pwkf.org/post/2010/02/#pnote-397657-1&quot; id=&quot;rev-pnote-397657-1&quot; name=&quot;rev-pnote-397657-1&quot;&gt;1&lt;/a&gt;]&lt;/sup&gt;.&lt;/p&gt;
&lt;p&gt;Since you can update your website to update the URLs, but the inbound link
cannot be easily updated. To handle this need, the HTTP protocol has specified
the 301 response code.&lt;/p&gt;
&lt;p&gt;The solution is that the site should remember all the urls that it generated
and redirects accordingly. This way you'll never loose a potential reader to
the infamous 404 (this page does not exist).&lt;/p&gt;
&lt;p&gt;Some sites even try to approximate the page on a custom 404 page. That's
another reason to have user-friendly urls : to be able to hint your reader to
appropriate pages in case you don't find his initial destination.&lt;/p&gt;
&lt;p&gt;Sadly, this redirect behavior isn't supported by my blog engine
(dotclear)... That's for the &lt;a href=&quot;http://en.wikipedia.org/wiki/Eating_one%27s_own_dog_food&quot; hreflang=&quot;en&quot;&gt;eat
your own dog's food&lt;/a&gt;, but I'm looking forward to do it on my current
blogging platform.&lt;/p&gt;
&lt;div class=&quot;footnotes&quot;&gt;
&lt;h4&gt;Notes&lt;/h4&gt;
&lt;p&gt;[&lt;a href=&quot;http://blog.pwkf.org/post/2010/02/#rev-pnote-397657-1&quot; id=&quot;pnote-397657-1&quot; name=&quot;pnote-397657-1&quot;&gt;1&lt;/a&gt;] upgrade to another blog engine...&lt;/p&gt;
&lt;/div&gt;</description>
    
    
    
          <comments>http://blog.pwkf.org/post/2010/02/Immutability-of-an-URL#comment-form</comments>
      <wfw:comment>http://blog.pwkf.org/post/2010/02/Immutability-of-an-URL#comment-form</wfw:comment>
      <wfw:commentRss>http://blog.pwkf.org/feed/atom/comments/397657</wfw:commentRss>
      </item>
    
  <item>
    <title>Avoid the Preprocessor : Use ''Compile-Time Polymorphism'' for Cross-platform Development</title>
    <link>http://blog.pwkf.org/post/2009/12/Avoid-the-Preprocessor-Use-Compile-Time-Polymorphism-for-Cross-platform-Development</link>
    <guid isPermaLink="false">urn:md5:ac68468a97cc5a2146661e506b24a7c2</guid>
    <pubDate>Fri, 11 Dec 2009 23:00:00 +0100</pubDate>
    <dc:creator>Steve Schnepp</dc:creator>
        <category>c++</category>
            
    <description>&lt;p&gt;When writing portable cross-platform code, don't litter your code with
preprocessor macros, use &lt;em&gt;compile-time polymorphism&lt;/em&gt; instead.&lt;/p&gt;
&lt;p&gt;A flexible build system will enable you to use advanced OOP-like
compile-time polymorphism. That way you can hide all the specifics of the
different platform behind an interface firewall. It is the usual way that most
cross-platform toolkits and frameworks (such as QT, GTK or wxWidgets) are
designed.&lt;/p&gt;    &lt;p&gt;We'll take a very simple file I/O subsystem here as an example
(&lt;code&gt;open&lt;/code&gt;, &lt;code&gt;close&lt;/code&gt;). We'll also only take Linux and
Windows, since that's usually the 2 most common platforms people want to
develop for&lt;sup&gt;[&lt;a href=&quot;http://blog.pwkf.org/post/2009/12/#pnote-467153-1&quot; id=&quot;rev-pnote-467153-1&quot; name=&quot;rev-pnote-467153-1&quot;&gt;1&lt;/a&gt;]&lt;/sup&gt;.&lt;/p&gt;
&lt;h2&gt;The usual abstraction with the preprocessor&lt;/h2&gt;
&lt;p&gt;Usually preprocessor &lt;code&gt;#ifdef&lt;/code&gt;s are used to compile specific parts
for the underlying OS.&lt;/p&gt;
&lt;p&gt;The file &lt;code&gt;fileiosys.cpp&lt;/code&gt; looks&lt;sup&gt;[&lt;a href=&quot;http://blog.pwkf.org/post/2009/12/#pnote-467153-2&quot; id=&quot;rev-pnote-467153-2&quot; name=&quot;rev-pnote-467153-2&quot;&gt;2&lt;/a&gt;]&lt;/sup&gt; like the one below
:&lt;/p&gt;
&lt;pre&gt;
fileiosys_filedesc open(char* filename) {
#ifdefine __WIN32__
    return OpenFile(
        filename, 
        GENERIC_READ | GENERIC_WRITE, 
        FILE_SHARE_READ | FILE_SHARE_WRITE, 
        NULL,
    );  
#else // UNIX
    return open(filename, O_READ | O_WRITE, 0666);
#endif
}

int close (fileiosys_filedesc fd) {
#ifdefine __WIN32__
    return CloseHandle(fd) ? 0 : -1;
#else // UNIX
    return close(fd);
#endif
}
&lt;/pre&gt;
&lt;p&gt;The header &lt;code&gt;fileiosys.h&lt;/code&gt; looks then like :&lt;/p&gt;
&lt;pre&gt;
// Define a custom file descriptor
#ifdefine __WIN32__
    #define fileiosys_filedesc HANDLE
#else // UNIX
    #define fileiosys_filedesc int
#endif

fileiosys_filedesc open(char* filename); 
int close(fileiosys_filedesc fd); 
&lt;/pre&gt;
&lt;h2&gt;Avoid the preprocessor Compile-time polymorphism&lt;/h2&gt;
&lt;p&gt;As the previous little example, the code isn't really easy to read. You have
to always think which environnement you are in. All the specifics are
multiplexed in the same file, and the programmer has to always demultiplex it
in real time each time he reads the code.&lt;/p&gt;
&lt;p&gt;The last part of the interface file is quite simple to read since it's
already abstracted away. Now let's completely demultiplex the implementation in
several implementation files.&lt;/p&gt;
&lt;h3&gt;The header file is the common interface&lt;/h3&gt;
&lt;p&gt;The interface is the most important part of the design. It should be
high-level enough to mask the differences between the plateforms you want to
support, but not too high-level, otherwise you'll end up duplicating to much
code.&lt;/p&gt;
&lt;p&gt;So, for our file I/O subsystem, we'll just abstract the usual syscalls
&lt;code&gt;open&lt;/code&gt;, &lt;code&gt;close&lt;/code&gt; in the same way as before.&lt;/p&gt;
&lt;p&gt;The parameters that are passed through the interface are also very
important. You cannot usually leak a platform-specific structure. So here all
the file descriptors are just an opaque handle, represented by a pointer to a
structure defined only as a forward declaration in the header. This pattern,
sometimes called the &lt;a href=&quot;http://en.wikipedia.org/wiki/Opaque_pointer&quot; hreflang=&quot;en&quot;&gt;pimpl idiom&lt;/a&gt;, enables use to really share the representation
while implementing it differently.&lt;/p&gt;
&lt;p&gt;The header file is preserved as &lt;code&gt;fileiosys.h&lt;/code&gt;, whereas the
implementation is in the files &lt;code&gt;linux/fileiosys.cpp&lt;/code&gt; and
&lt;code&gt;win32/fileiosys.cpp&lt;/code&gt;&lt;/p&gt;
&lt;h4&gt;&lt;code&gt;fileiosys.h&lt;/code&gt;&lt;/h4&gt;
&lt;pre&gt;
// Define the forward declaration
struct fis_filedesc;
fis_filedesc* open(char* filename); 
int close(fileiosys_filedesc* fd); 
&lt;/pre&gt;
&lt;h4&gt;&lt;code&gt;win32/fileiosys.cpp&lt;/code&gt;&lt;/h4&gt;
&lt;pre&gt;
struct fis_filedesc {
    HANDLE handle;
};

fis_filedesc* open(char* filename) {
    fis_filedesc* fd = new fis_filedesc();
    fd-&amp;gt;handle = OpenFile(
        filename, 
        GENERIC_READ | GENERIC_WRITE, 
        FILE_SHARE_READ | FILE_SHARE_WRITE, 
        NULL,
    );  

    return fd;
}

int close (fis_filedesc* fd) {
    int retval = CloseHandle(fd-&amp;gt;handle) ? 0 : -1;
    delete(fd);
    return retval;
}
&lt;/pre&gt;
&lt;h4&gt;&lt;code&gt;linux/fileiosys.cpp&lt;/code&gt;&lt;/h4&gt;
&lt;pre&gt;
struct fis_filedesc {
    int file_descriptor;
};

static fis_filedesc[32];

fis_filedesc* open(char* filename) {
    fis_filedesc* fd = new fis_filedesc();
    fd-&amp;gt;file_descriptor = open(filename, O_READ | O_WRITE, 0666);
    return fd;
}

int close (fis_filedesc* fd) {
    int retval = close(fd);
    delete(fd);
    return retval;
}
&lt;/pre&gt;
&lt;h4&gt;The build system : &lt;code&gt;Makefile&lt;/code&gt;&lt;/h4&gt;
&lt;p&gt;The makefile should take into account the different platforms, and only
compile the needed implementation file. All the gluing magic will then be done
at linking time instead of preprocessor time.&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;The interest of have multiple implementation files is obvious. It is
&lt;strong&gt;much&lt;/strong&gt; more straightforward to read and only marginally harder
to write. But since most of the time code is read and not written, the choose
is quite a no-brainer.&lt;/p&gt;
&lt;p&gt;The nicest part is that all this is possible even without the expensive
run-time polymorphism and RTTI, since the choose is done at compile-time.&lt;/p&gt;
&lt;div class=&quot;footnotes&quot;&gt;
&lt;h4&gt;Notes&lt;/h4&gt;
&lt;p&gt;[&lt;a href=&quot;http://blog.pwkf.org/post/2009/12/#rev-pnote-467153-1&quot; id=&quot;pnote-467153-1&quot; name=&quot;pnote-467153-1&quot;&gt;1&lt;/a&gt;] actually when targeting Linux, you usually target all
Unix-like systems since they already have POSIX as a common abstraction&lt;/p&gt;
&lt;p&gt;[&lt;a href=&quot;http://blog.pwkf.org/post/2009/12/#rev-pnote-467153-2&quot; id=&quot;pnote-467153-2&quot; name=&quot;pnote-467153-2&quot;&gt;2&lt;/a&gt;] The code is not real, it has been sweetened&lt;/p&gt;
&lt;/div&gt;</description>
    
    
    
          <comments>http://blog.pwkf.org/post/2009/12/Avoid-the-Preprocessor-Use-Compile-Time-Polymorphism-for-Cross-platform-Development#comment-form</comments>
      <wfw:comment>http://blog.pwkf.org/post/2009/12/Avoid-the-Preprocessor-Use-Compile-Time-Polymorphism-for-Cross-platform-Development#comment-form</wfw:comment>
      <wfw:commentRss>http://blog.pwkf.org/feed/atom/comments/467153</wfw:commentRss>
      </item>
    
  <item>
    <title>Native SSH transport for Munin</title>
    <link>http://blog.pwkf.org/post/2009/11/Native-SSH-transport-for-Munin</link>
    <guid isPermaLink="false">urn:md5:9850ae8f77d67536a24ea8c5e21b723e</guid>
    <pubDate>Thu, 26 Nov 2009 22:00:00 +0100</pubDate>
    <dc:creator>Steve Schnepp</dc:creator>
        <category>munin</category>
        <category>munin</category><category>ssh</category>    
    <description>&lt;p style=&quot;color:red&quot;&gt;&lt;b&gt;Update&lt;/b&gt;: This page is obsolete, since it has been
merged in the &lt;a&gt;2.0 version of Munin&lt;/a&gt;. The syntax is a little bit
different, but the idea is the same.&lt;/p&gt;
&lt;p&gt;I &lt;a href=&quot;http://blog.pwkf.org/post/2008/11/04/A-Poor-Man-s-Munin-Node-to-Monitor-Hostile-UNIX-Servers&quot;&gt;blogged&lt;/a&gt;
about the &lt;a href=&quot;http://munin.projects.linpro.no/&quot; hreflang=&quot;en&quot;&gt;munin
monitoring system&lt;/a&gt; a while ago.&lt;/p&gt;
&lt;p&gt;The fact the Munin team did quite a remarkable job in cleaning up the 1.2
code for the 1.4 release enabled me to add a native SSH transport for Munin,
and made be able to get rid of all SSH tunnels.&lt;/p&gt;    &lt;p&gt;Actually the tunnel won't disappear, but they will be launched only when
needed and, most importantly configured in &lt;code&gt;munin.conf&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The &lt;a href=&quot;http://blog.pwkf.org/public/direct_ssh_transport.diff&quot; hreflang=&quot;en&quot;&gt;native ssh for
munin patch&lt;/a&gt; should applies quite cleanly on revision 3101 of the svn
trunk.&lt;/p&gt;
&lt;p&gt;Its use is quite straightforward : in &lt;code&gt;/etc/munin/munin.conf&lt;/code&gt;,
you just migrate address to the new configuration directive
&lt;code&gt;remote_connection_cmd&lt;/code&gt; that take the whole &lt;code&gt;ssh&lt;/code&gt; command
to launch a stdio munin-node such as pmmn.&lt;/p&gt;
&lt;p&gt;If we take the examples from the previous post, it becomes clear it's
&lt;strong&gt;much&lt;/strong&gt; easier to configure.&lt;/p&gt;
&lt;h3&gt;munin.conf snippet - Inetd version&lt;/h3&gt;
&lt;pre&gt;
[server1]
    address localhost
    port 7001
[server2]
    address localhost
    port 7002
&lt;/pre&gt;
&lt;h3&gt;munin.conf snippet - Native SSH transport version&lt;/h3&gt;
&lt;p&gt;Right now, the &lt;code&gt;address&lt;/code&gt; directive is still mandatory, but
ignored when connecting.&lt;/p&gt;
&lt;pre&gt;
[server1]
    address dummy
    remote_connection_cmd /usr/bin/ssh -- supusr@server1 /home/suprusr/pmmn/pmmn.pl
[server2]
    address dummy
    remote_connection_cmd /usr/bin/ssh -- supusr@server2 /home/suprusr/pmmn/pmmn.pl
&lt;/pre&gt;
&lt;h3&gt;Warning&lt;/h3&gt;
&lt;p&gt;Beware that the &lt;code&gt;ssh&lt;/code&gt; process will now be launched by the
&lt;code&gt;munin&lt;/code&gt; user, so you have to update the key-based SSH authentication
accordingly.&lt;/p&gt;</description>
    
    
    
          <comments>http://blog.pwkf.org/post/2009/11/Native-SSH-transport-for-Munin#comment-form</comments>
      <wfw:comment>http://blog.pwkf.org/post/2009/11/Native-SSH-transport-for-Munin#comment-form</wfw:comment>
      <wfw:commentRss>http://blog.pwkf.org/feed/atom/comments/462735</wfw:commentRss>
      </item>
    
  <item>
    <title>Sed is much slower than Perl, or not...</title>
    <link>http://blog.pwkf.org/post/2009/11/Sed-is-much-slower-than-Perl-or-not...</link>
    <guid isPermaLink="false">urn:md5:97ad55cfcb78666f554d7bfbd3f3915e</guid>
    <pubDate>Sat, 14 Nov 2009 12:18:00 +0100</pubDate>
    <dc:creator>Steve Schnepp</dc:creator>
        <category>sysadmin</category>
        <category>locales</category><category>perl</category><category>sql</category>    
    <description>    &lt;p&gt;I wanted to do some text replacement with a &lt;strong&gt;huge&lt;/strong&gt; file
(think ~18GiB), filled with &lt;strong&gt;huge&lt;/strong&gt; lines (think ~2MiB per
ligne)&lt;sup&gt;[&lt;a href=&quot;http://blog.pwkf.org/post/2009/11/#pnote-459477-1&quot; id=&quot;rev-pnote-459477-1&quot; name=&quot;rev-pnote-459477-1&quot;&gt;1&lt;/a&gt;]&lt;/sup&gt;.&lt;/p&gt;
&lt;p&gt;I naïvely piped it through &lt;code&gt;sed&lt;/code&gt; and I was quite shocked that it
was CPU bound, and not I/O bound. The average rate was about 5 MiB/s (measured
with &lt;a href=&quot;http://www.ivarch.com/programs/pv.shtml&quot; hreflang=&quot;en&quot;&gt;pv&lt;/a&gt;,
and the CPU was at almost 100%.The text file was gzipped on the filesystem, but
with a 1/100 ratio, so the gzip process just took less than 2% CPU. I replaced
then the &lt;code&gt;sed -e&lt;/code&gt; with the Perl one-liner &lt;code&gt;perl -lnpe&lt;/code&gt;,
and .... &lt;em&gt;tadaa&lt;/em&gt;, it was flying at a rate of 50MiB/s !&lt;/p&gt;
&lt;p&gt;While I'm a big fan of Perl, and know its effectiveness to handle text
streams, I'm was still astonished : being 10x faster than sed was
something.&lt;/p&gt;
&lt;p&gt;But in the good old saying &lt;q&gt;Too good to be true means suspect&lt;/q&gt;, I
remembered something about the character encoding of the regular expression.
Since the system is entirely configured in UTF8, I suspected the
&lt;em&gt;infamous&lt;/em&gt; UTF8 overhead over plain ASCII.&lt;/p&gt;
&lt;p&gt;I was right : a little &lt;code&gt;LANG=C&lt;/code&gt; in front of the sed command line
restored the rate to 50MiB/s.&lt;/p&gt;
&lt;p&gt;So, &lt;strong&gt;beware&lt;/strong&gt; of the &lt;strong&gt;performance impact&lt;/strong&gt; of
&lt;strong&gt;UTF8&lt;/strong&gt; strings, and try to avoid it if you can.&lt;/p&gt;
&lt;div class=&quot;footnotes&quot;&gt;
&lt;h4&gt;Notes&lt;/h4&gt;
&lt;p&gt;[&lt;a href=&quot;http://blog.pwkf.org/post/2009/11/#rev-pnote-459477-1&quot; id=&quot;pnote-459477-1&quot; name=&quot;pnote-459477-1&quot;&gt;1&lt;/a&gt;] For the record, it was a MySQL dump&lt;/p&gt;
&lt;/div&gt;</description>
    
    
    
          <comments>http://blog.pwkf.org/post/2009/11/Sed-is-much-slower-than-Perl-or-not...#comment-form</comments>
      <wfw:comment>http://blog.pwkf.org/post/2009/11/Sed-is-much-slower-than-Perl-or-not...#comment-form</wfw:comment>
      <wfw:commentRss>http://blog.pwkf.org/feed/atom/comments/459477</wfw:commentRss>
      </item>
    
  <item>
    <title>Sychronize clock between hosts with SSH</title>
    <link>http://blog.pwkf.org/post/2009/09/Sychronize-clock-between-hosts-with-SSH</link>
    <guid isPermaLink="false">urn:md5:11e72e879c3d3f63b031ab72bb65db9f</guid>
    <pubDate>Fri, 11 Sep 2009 08:00:00 +0200</pubDate>
    <dc:creator>Steve Schnepp</dc:creator>
        <category>sysadmin</category>
        <category>ssh</category>    
    <description>    &lt;p&gt;&lt;a href=&quot;http://en.wikipedia.org/wiki/Network_Time_Protocol&quot; hreflang=&quot;en&quot;&gt;NTP&lt;/a&gt; is very handy for server clock synchronisation, but it can be
cumbersome to deploy.&lt;/p&gt;
&lt;p&gt;Sometimes you just need to do a one-shot clock synchronisation, so you use
the standard &lt;code&gt;date&lt;/code&gt; command. But there isn't a flag to easily copy a
setting to another.&lt;/p&gt;
&lt;h2&gt;From a remote host&lt;/h2&gt;
&lt;p&gt;Quite easy :&lt;/p&gt;
&lt;pre&gt;
# date `ssh remoteuser@remotehost date +%m%d%H%M%Y.%S`
&lt;/pre&gt;
&lt;h2&gt;To a remote host&lt;/h2&gt;
&lt;p&gt;It's also very easy&lt;sup&gt;[&lt;a href=&quot;http://blog.pwkf.org/post/2009/09/#pnote-440747-1&quot; id=&quot;rev-pnote-440747-1&quot; name=&quot;rev-pnote-440747-1&quot;&gt;1&lt;/a&gt;]&lt;/sup&gt; :&lt;/p&gt;
&lt;pre&gt;
# ssh root@remotehost date `date +%m%d%H%M%Y.%S`
&lt;/pre&gt;
&lt;div class=&quot;footnotes&quot;&gt;
&lt;h4&gt;Notes&lt;/h4&gt;
&lt;p&gt;[&lt;a href=&quot;http://blog.pwkf.org/post/2009/09/#rev-pnote-440747-1&quot; id=&quot;pnote-440747-1&quot; name=&quot;pnote-440747-1&quot;&gt;1&lt;/a&gt;] Yes, I &lt;strong&gt;do&lt;/strong&gt; know that logging remotely
as root is a security pitfall...&lt;/p&gt;
&lt;/div&gt;</description>
    
    
    
          <comments>http://blog.pwkf.org/post/2009/09/Sychronize-clock-between-hosts-with-SSH#comment-form</comments>
      <wfw:comment>http://blog.pwkf.org/post/2009/09/Sychronize-clock-between-hosts-with-SSH#comment-form</wfw:comment>
      <wfw:commentRss>http://blog.pwkf.org/feed/atom/comments/440747</wfw:commentRss>
      </item>
    
  <item>
    <title>Databases: Efficient Case-insensitive searches with Function-based Indexing</title>
    <link>http://blog.pwkf.org/post/2009/09/Databases%3A-Efficient-Case-insensitive-searches-with-Function-based-Indexing</link>
    <guid isPermaLink="false">urn:md5:0672e1835437418b84886618aa2e1440</guid>
    <pubDate>Tue, 08 Sep 2009 22:00:00 +0200</pubDate>
    <dc:creator>Steve Schnepp</dc:creator>
        <category>database</category>
            
    <description>&lt;p&gt;Doing a &lt;strong&gt;case insensitive search&lt;/strong&gt; is a very &lt;strong&gt;common
task&lt;/strong&gt;, but is quite &lt;strong&gt;hard to optimize correctly&lt;/strong&gt;. But
since it's done via a &lt;code&gt;UPPER(MY_COLUMN) = UPPER('MY_DATA')&lt;/code&gt;, it
doesn't use the index that could be on &lt;code&gt;MY_COLUMN&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Different RDMS means different approaches.&lt;/p&gt;    &lt;h2&gt;Special case of case-insensitive search&lt;/h2&gt;
&lt;p&gt;In Oracle10g, you might use the new case-insensitive search with a
&lt;code&gt;&lt;a href=&quot;http://www.dba-oracle.com/t_oracle10g_release_2_case_insensitive_searches.htm&quot; hreflang=&quot;en&quot;&gt;NLS_SORT=BINARY_CI&lt;/a&gt;&lt;/code&gt; command.&lt;/p&gt;
&lt;h3&gt;Pro&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Designed for this purpose, so it's very straightforward to use&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Con&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Limited to case-insensitive searching by design&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Native functional indexes&lt;/h2&gt;
&lt;p&gt;Some databases provides native functional indexes.&lt;/p&gt;
&lt;p&gt;On these databases optimization is done simply by creating an index on
&lt;code&gt;UPPER(MY_COLUMN)&lt;/code&gt; and letting the query optimizer
transparently&lt;sup&gt;[&lt;a href=&quot;http://blog.pwkf.org/post/2009/09/#pnote-426279-1&quot; id=&quot;rev-pnote-426279-1&quot; name=&quot;rev-pnote-426279-1&quot;&gt;1&lt;/a&gt;]&lt;/sup&gt; use the newly created index.&lt;/p&gt;
&lt;p&gt;It usually work by applies a function to the data just before handing it to
the index, so the function output doesn't exist in the database.&lt;/p&gt;
&lt;h3&gt;Pro&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Very&lt;/strong&gt; easy to use : it just feels right (you can naïvely
create an index on the WHERE clause)&lt;/li&gt;
&lt;li&gt;Doesn't take any extra space in the database (only the index).&lt;/li&gt;
&lt;li&gt;Generic, can be used for something else than just case-insensitive
searches.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Con&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Since the data isn't stored in the database, a call to the function has to
be made when&lt;/li&gt;
&lt;li&gt;Functions have to be from the immutable category in the &lt;a href=&quot;http://www.postgresql.org/docs/8.3/static/xfunc-volatility.html&quot; hreflang=&quot;en&quot;&gt;function volatility categories&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Generated columns&lt;/h2&gt;
&lt;p&gt;DB2 provides something called &lt;a href=&quot;http://publib.boulder.ibm.com/infocenter/db2luw/v8/topic/com.ibm.db2.udb.doc/ad/c0007004.htm&quot; hreflang=&quot;en&quot;&gt;generated columns&lt;/a&gt;. It's almost the same than the native
indexes, except that the functional column is explicit.&lt;/p&gt;
&lt;h3&gt;Pro&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Quite easy to use, since the column is updated and used transparently.&lt;/li&gt;
&lt;li&gt;Generic, can be used for something else than just case-insensitive
searches. Just make sure the optimizer uses the extra column. You might have to
rewrite the request a little.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Con&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Requires extra space in the table.&lt;/li&gt;
&lt;li&gt;Removing a column can be cumbersome (in DB2 you have to recreate the whole
table for example), whereas removing a simple index is much easier.&lt;/li&gt;
&lt;li&gt;The extra column is returned when doing a &lt;code&gt;SELECT * FROM
...&lt;/code&gt;&lt;sup&gt;[&lt;a href=&quot;http://blog.pwkf.org/post/2009/09/#pnote-426279-2&quot; id=&quot;rev-pnote-426279-2&quot; name=&quot;rev-pnote-426279-2&quot;&gt;2&lt;/a&gt;]&lt;/sup&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Trigger-based &lt;em&gt;Generated columns&lt;/em&gt; Emulation&lt;/h2&gt;
&lt;p&gt;If nothing else is provided, you always have the option to emulate. The
solution will be trigger-based since it's one of the few perfect match for
them.&lt;/p&gt;
&lt;p&gt;So, the base idea is derived from the &lt;em&gt;Generated columns&lt;/em&gt; : have a
special extra column that represents the output of the function. An index will
be created on this column and used via a &lt;em&gt;manual&lt;/em&gt; update of the involved
requests (Adding an extra &lt;code&gt;WHERE&lt;/code&gt; clause should be more than enough,
this way you might even benefit from a partial match).&lt;/p&gt;
&lt;h3&gt;Pro&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Universal. Useful if portability is paramount.&lt;/li&gt;
&lt;li&gt;Very simple : there is no need to understand advanced database
features.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Con&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Only a poor man's solution : everything is manual&lt;/li&gt;
&lt;li&gt;The same than &lt;em&gt;Generated columns&lt;/em&gt; since it's the same idea, just
manually implemented.&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&quot;footnotes&quot;&gt;
&lt;h4&gt;Notes&lt;/h4&gt;
&lt;p&gt;[&lt;a href=&quot;http://blog.pwkf.org/post/2009/09/#rev-pnote-426279-1&quot; id=&quot;pnote-426279-1&quot; name=&quot;pnote-426279-1&quot;&gt;1&lt;/a&gt;] You might have to update some kind of statistics for
the new index&lt;/p&gt;
&lt;p&gt;[&lt;a href=&quot;http://blog.pwkf.org/post/2009/09/#rev-pnote-426279-2&quot; id=&quot;pnote-426279-2&quot; name=&quot;pnote-426279-2&quot;&gt;2&lt;/a&gt;] But you don't do that anyway, do you ?&lt;/p&gt;
&lt;/div&gt;</description>
    
    
    
          <comments>http://blog.pwkf.org/post/2009/09/Databases%3A-Efficient-Case-insensitive-searches-with-Function-based-Indexing#comment-form</comments>
      <wfw:comment>http://blog.pwkf.org/post/2009/09/Databases%3A-Efficient-Case-insensitive-searches-with-Function-based-Indexing#comment-form</wfw:comment>
      <wfw:commentRss>http://blog.pwkf.org/feed/atom/comments/426279</wfw:commentRss>
      </item>
    
  <item>
    <title>Overloading a method is hard : a common pitfall</title>
    <link>http://blog.pwkf.org/post/2009/09/Overloading-method-is-hard-%3A-a-common-pitfall</link>
    <guid isPermaLink="false">urn:md5:b89efe0436b185be77c2bd6856338b51</guid>
    <pubDate>Mon, 07 Sep 2009 22:00:00 +0200</pubDate>
    <dc:creator>Steve Schnepp</dc:creator>
        <category>java</category>
            
    <description>    &lt;p&gt;As I said in my &lt;a href=&quot;http://blog.pwkf.org/post/2009/06/Equality-in-Java-is-a-Hot-Topic-but-a-Hazardous-one&quot;&gt;equality
article&lt;/a&gt;, overloading in Java&lt;sup&gt;[&lt;a href=&quot;http://blog.pwkf.org/post/2009/09/#pnote-439371-1&quot; id=&quot;rev-pnote-439371-1&quot; name=&quot;rev-pnote-439371-1&quot;&gt;1&lt;/a&gt;]&lt;/sup&gt; is resolved by the
&lt;strong&gt;static&lt;/strong&gt; type of the argument, not the &lt;strong&gt;run-time&lt;/strong&gt;
type.&lt;/p&gt;
&lt;p&gt;It's a &lt;strong&gt;generic&lt;/strong&gt; problem of most compiled OO languages since
usually &lt;strong&gt;overloading resolution happens at compile-time and not at
runtime&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Now, &lt;em&gt;that&lt;/em&gt; militates for the well known idiom :&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Never overload a method with one that has the same number of parameters.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Actually, it should be enough to overload a method with one that accept
parameters that are not inheritance-related : &lt;code&gt;String&lt;/code&gt; and
&lt;code&gt;Number&lt;/code&gt; would be OK, but &lt;code&gt;MyClass&lt;/code&gt; and
&lt;code&gt;Object&lt;/code&gt; would not.&lt;/p&gt;
&lt;div class=&quot;footnotes&quot;&gt;
&lt;h4&gt;Notes&lt;/h4&gt;
&lt;p&gt;[&lt;a href=&quot;http://blog.pwkf.org/post/2009/09/#rev-pnote-439371-1&quot; id=&quot;pnote-439371-1&quot; name=&quot;pnote-439371-1&quot;&gt;1&lt;/a&gt;] It's not really a &lt;em&gt;Java&lt;/em&gt;-ism, it's the same in
other languages, such as C++ .&lt;/p&gt;
&lt;/div&gt;</description>
    
    
    
          <comments>http://blog.pwkf.org/post/2009/09/Overloading-method-is-hard-%3A-a-common-pitfall#comment-form</comments>
      <wfw:comment>http://blog.pwkf.org/post/2009/09/Overloading-method-is-hard-%3A-a-common-pitfall#comment-form</wfw:comment>
      <wfw:commentRss>http://blog.pwkf.org/feed/atom/comments/439371</wfw:commentRss>
      </item>
    
  <item>
    <title>A Simple Dns Server for a SOHO Network</title>
    <link>http://blog.pwkf.org/post/2009/08/A-Simple-Dns-Server-for-a-SOHO-Network</link>
    <guid isPermaLink="false">urn:md5:980ba57dcf712852978b5c8496cfeca0</guid>
    <pubDate>Mon, 10 Aug 2009 20:00:00 +0200</pubDate>
    <dc:creator>Steve Schnepp</dc:creator>
        <category>sysadmin</category>
        <category>sql</category>    
    <description>    &lt;p&gt;I'm in search of a very simple DNS Server for a small network. It should be
:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;recursive &amp;amp; caching (can be used as a proxy)&lt;/li&gt;
&lt;li&gt;very simple administration (parsing /etc/hosts would be perfect, raw DNS
zones like BIND would be a little bit overkill)&lt;/li&gt;
&lt;li&gt;quite lightweight (aka no dependency on an SQL engine like MySQL, such as
MyDNS)&lt;/li&gt;
&lt;li&gt;Seamless integration to Windows lookups (nmblookup) via proxying functions
(DNS to/from NMB)&lt;/li&gt;
&lt;/ul&gt;</description>
    
    
    
          <comments>http://blog.pwkf.org/post/2009/08/A-Simple-Dns-Server-for-a-SOHO-Network#comment-form</comments>
      <wfw:comment>http://blog.pwkf.org/post/2009/08/A-Simple-Dns-Server-for-a-SOHO-Network#comment-form</wfw:comment>
      <wfw:commentRss>http://blog.pwkf.org/feed/atom/comments/340907</wfw:commentRss>
      </item>
    
</channel>
</rss>
