<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Trac on bramp.net</title>
    <link>https://blog.bramp.net/</link>
    <description>Recent content in Trac on bramp.net</description>
    <generator>Hugo -- gohugo.io</generator>
    <language>en-GB</language>
    <lastBuildDate>Tue, 11 May 2010 00:00:00 +0000</lastBuildDate>
    <atom:link href="https://blog.bramp.net/tags/trac/" rel="self" type="application/rss+xml" />
    
    <item>
      <title>Python close_fds issue</title>
      <link>https://blog.bramp.net/post/2010/05/11/python-close_fds-issue/</link>
      <pubDate>Tue, 11 May 2010 00:00:00 +0000</pubDate>
      
      <guid>https://blog.bramp.net/post/2010/05/11/python-close_fds-issue/</guid>
      <description><p>So I spent the better part of my evening trying to track down a bug, which turns out to be a “feature” of python.</p>
<p>I had just installed the <a href="http://trac-hacks.org/wiki/GitPlugin">GitPlugin</a> for <a href="http://trac.edgewall.org/">trac</a> but I started to experience problems. When browsing the source inside trac it was taking over 30seconds to load the page and sometimes it would fail completely. A lot of searching didn’t help much, so I attempted to debug the problem myself. The first thing I noticed was Apache was taking 100% of the processor for a good 30seconds. I attached <a href="http://en.wikipedia.org/wiki/Strace">strace</a> to it and saw something like this:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">[pid 22682] close(43029)                = -1 EBADF (Bad file descriptor)
</span></span><span class="line"><span class="cl">[pid 22682] close(43030)                = -1 EBADF (Bad file descriptor)
</span></span><span class="line"><span class="cl">[pid 22682] close(43031)                = -1 EBADF (Bad file descriptor)
</span></span><span class="line"><span class="cl">[pid 22682] close(43032)                = -1 EBADF (Bad file descriptor)
</span></span><span class="line"><span class="cl">[pid 22682] close(43033)                = -1 EBADF (Bad file descriptor)
</span></span><span class="line"><span class="cl">[pid 22682] close(43034)                = -1 EBADF (Bad file descriptor)
</span></span><span class="line"><span class="cl">[pid 22682] close(43035)                = -1 EBADF (Bad file descriptor)
</span></span><span class="line"><span class="cl">[pid 22682] close(43036)                = -1 EBADF (Bad file descriptor)
</span></span></code></pre></div><p>This obviously didn’t look good! After some tinkering I found the problem went away when I ran trac <a href="http://trac.edgewall.org/wiki/TracStandalone">standalone</a>, instead of using <a href="http://www.modpython.org/">mod_python</a> or <a href="http://en.wikipedia.org/wiki/FastCGI">fcgi</a>. This turned out to be a bit of a red herring because I spent my time trying to figure out what was different between a standalone executable and one being run inside Apache.</p>
<p>After playing around with environment variables, I gave up and attempted to printf debug the trac git plugin. I found that the actual call to git was taking on the order of seconds, whereas calling it myself from the command took milliseconds. The line of code (in PyGIT.py) looked a bit like this:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="n">p</span> <span class="o">=</span> <span class="n">Popen</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">__build_git_cmd</span><span class="p">(</span><span class="n">git_cmd</span><span class="p">,</span> <span class="o">*</span><span class="n">cmd_args</span><span class="p">),</span> <span class="n">stdin</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> <span class="n">stdout</span><span class="o">=</span><span class="n">PIPE</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">			                                        <span class="n">stderr</span><span class="o">=</span><span class="n">PIPE</span><span class="p">,</span> <span class="n">close_fds</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
</span></span></code></pre></div><p>Now, when I removed the close_fds argument the problems went away! After some more digging I found this <a href="http://bugs.python.org/issue8052">bug report</a> which describes the behaviour of close_fds. Python will spin in a tight loop calling close for all possible valid fd number just incase it was previously used. WTF! You can see the python <a href="http://svn.python.org/projects/python/tags/r311/Lib/subprocess.py">code here</a>:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">_close_fds</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">but</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">    <span class="n">os</span><span class="o">.</span><span class="n">closerange</span><span class="p">(</span><span class="mi">3</span><span class="p">,</span> <span class="n">but</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">os</span><span class="o">.</span><span class="n">closerange</span><span class="p">(</span><span class="n">but</span> <span class="o">+</span> <span class="mi">1</span><span class="p">,</span> <span class="n">MAXFD</span><span class="p">)</span>
</span></span></code></pre></div><p>So the simple fix to this was to remove the close_fds, so that Python doesn’t stupidly spin calling close(). I suspect the reason I only noticed this when running inside Apache, is because Apache must have a larger MAXFD. Hopefully in the future Python will change this behaviour and find a more sensible way to close all file descriptors, especially when I read this <a href="http://bugs.python.org/issue7213">bug report</a> which advises changing close_fds default to true.</p>
</description>
    </item>
    
  </channel>
</rss>
