<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/css" href="/stylesheets/rss.css"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/">
  <channel>
    <title>lighty's life: Threaded stat()</title>
    <link>http://blog.lighttpd.net/articles/2007/01/31/threaded-stat</link>
    <language>en-us</language>
    <ttl>40</ttl>
    <description></description>
    <item>
      <title>Threaded stat()</title>
      <description>&lt;p&gt;Just as a proof of concept I implemented a threaded stat() call. It is a bit of a hack currently, but it looks promising when I look at the performance data:&lt;/p&gt;


&lt;pre&gt;
avg-cpu:  %user   %nice %system %iowait  %steal   %idle
           5.00    0.00   26.60   68.40    0.00    0.00

Device:    rrqm/s wrqm/s   r/s   w/s  rsec/s  wsec/s    rMB/s    wMB/s avgrq-sz avgqu-sz   await  svctm  %util
sda          0.00   0.60 66.90  1.60 13019.20   22.40     6.36     0.01   190.39     6.10   88.20  14.49  99.28
sdb          0.00   0.60 66.60  1.60 13061.60   22.40     6.38     0.01   191.85    14.09  208.82  14.67 100.04
&lt;/pre&gt;

	&lt;p&gt;In &lt;a href="http://blog.lighttpd.net/articles/2007/01/27/accelerating-small-file-transfers"&gt;http://blog.lighttpd.net/articles/2007/01/27/accelerating-small-file-transfers&lt;/a&gt; we tried the same without a async stat() and with fcgi-stat-accel. With the threaded stat() I moved the code into lighttpd itself which reduces the external communicating and manages everything in lighttpd itself.&lt;/p&gt;


&lt;pre&gt;
name              Throughput  util% iowait%
----------------- ------------ ----- ------------
no stat-accel     12.07MByte/s 81%  
stat-accel (tcp)  13.64MByte/s 99% 45.00%
stat-accel (unix) 13.86MByte/s 99% 53.25%
threaded-stat     14.32MByte/s 99% 68.40%
&lt;/pre&gt;

	&lt;p&gt;(larger is better)&lt;/p&gt;
&lt;h3&gt;Implementation&lt;/h3&gt;

	&lt;p&gt;in stat_cache.c I started a separate thread for handling the stat() call, 4 threads to be exact.&lt;/p&gt;


	&lt;p&gt;stat_cache_get_entry() checks its cache, if this file is already known. If not, it pushes the filename into the stat_cache_queue and returns &lt;span class="caps"&gt;HANDLER&lt;/span&gt;_WAIT_FOR_EVENT. On the other end of the stat_cache_queue is one of the 4 stat()-threads which runs the stat() and pushs the connection back into the joblist_queue. On the mainloop, just where the poll() call is started is now the handler for this queue which just actives all connections which are in this queue.&lt;/p&gt;


	&lt;p&gt;This way we made the stat() call itself async and can leave the rest of the code as is. Up to now we only get the inode into the fs-buffers as in the other examples, we are not handling the full stat-cache updates in the thread.&lt;/p&gt;


&lt;pre&gt;
gpointer *stat_cache_thread(gpointer *_srv) {
        server *srv = (server *)_srv;
        stat_job *sj = NULL;

        /* take the stat-job-queue */
        GAsyncQueue * inq = g_async_queue_ref(srv-&amp;gt;stat_queue);
        GAsyncQueue * outq = g_async_queue_ref(srv-&amp;gt;joblist_queue);

        /* get the jobs from the queue */
        while ((sj = g_async_queue_pop(inq))) {
                /* let's see what we have to stat */
                struct stat st;

                /* don't care about the return code for now */
                stat(sj-&amp;gt;name-&amp;gt;ptr, &amp;#38;st);

                stat_job_free(sj);

                g_async_queue_push(outq, sj-&amp;gt;con);
        }

        return NULL;
}
&lt;/pre&gt;</description>
      <pubDate>Wed, 31 Jan 2007 12:00:00 +0000</pubDate>
      <guid isPermaLink="false">urn:uuid:fe092b84-6c41-40c0-b7b3-2b244318e220</guid>
      <author>jan</author>
      <link>http://blog.lighttpd.net/articles/2007/01/31/threaded-stat</link>
      <category>lighttpd</category>
      <category>aio</category>
      <trackback:ping>http://blog.lighttpd.net/articles/trackback/3254</trackback:ping>
    </item>
    <item>
      <title>"Threaded stat()" by Andre Bogus</title>
      <description>Roze: If you develop with Lighty, you usually have a test environment, which might restart rather often...</description>
      <pubDate>Mon, 05 Feb 2007 14:29:28 +0000</pubDate>
      <guid isPermaLink="false">urn:uuid:0ca82d3b-a8e0-4ce5-b49a-f56d1017ac13</guid>
      <link>http://blog.lighttpd.net/articles/2007/01/31/threaded-stat#comment-3276</link>
    </item>
    <item>
      <title>"Threaded stat()" by Roze</title>
      <description>Scott: how often do you need to restart your lighttpd? :) Once a year? </description>
      <pubDate>Sun, 04 Feb 2007 08:28:58 +0000</pubDate>
      <guid isPermaLink="false">urn:uuid:7ac76eee-4e59-4ca9-9bd9-ff6cef50ba4a</guid>
      <link>http://blog.lighttpd.net/articles/2007/01/31/threaded-stat#comment-3271</link>
    </item>
    <item>
      <title>"Threaded stat()" by Scott</title>
      <description>I kind of like externally spawning fcgi processes.  It means that making any changes to the lighttpd config and restarting doesn't also mean the overhead of killing and restarting fcgi handlers each time.</description>
      <pubDate>Wed, 31 Jan 2007 18:27:24 +0000</pubDate>
      <guid isPermaLink="false">urn:uuid:8527e551-33e4-4af4-b1f2-970de94f9fbe</guid>
      <link>http://blog.lighttpd.net/articles/2007/01/31/threaded-stat#comment-3257</link>
    </item>
    <item>
      <title>"Threaded stat()" by FreeDude</title>
      <description>Great! This is IMHO a _much_ better solution that hacking it through the fastcgi interface. Now everybody benefits, without needing to complicate their site setup.
Now all I have left to wish for in 1.5 is to automatically spawn the php fastgi processes :)</description>
      <pubDate>Wed, 31 Jan 2007 14:37:32 +0000</pubDate>
      <guid isPermaLink="false">urn:uuid:ab4b3ba0-c0c1-4f31-9743-878da30ab32f</guid>
      <link>http://blog.lighttpd.net/articles/2007/01/31/threaded-stat#comment-3256</link>
    </item>
  </channel>
</rss>
