<?xml version="1.0"?>
<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
         xmlns:dc="http://purl.org/dc/elements/1.1/"
         xmlns:syn="http://purl.org/rss/1.0/modules/syndication/"
         xmlns="http://purl.org/rss/1.0/">




    



<channel rdf:about="http://www.jarn.com/blog/blog-feed/RSS">
  <title>Jarn Blog</title>
  <link>http://www.jarn.com</link>
  
  <description>
    
       News, happenings and rants from the Jarn team.  
       
  </description>



  
  
            <syn:updatePeriod>daily</syn:updatePeriod>
            <syn:updateFrequency>1</syn:updateFrequency>
            <syn:updateBase>2007-08-20T10:53:11Z</syn:updateBase>
        
  
  <image rdf:resource="http://www.jarn.com/logo.jpg"/>

  <items>
    <rdf:Seq>
        
            <rdf:li rdf:resource="http://www.jarn.com/blog/plone-performance-sprint-bristol-2008"/>
        
        
            <rdf:li rdf:resource="http://www.jarn.com/blog/saving-the-day-recovering-lost-objects"/>
        
        
            <rdf:li rdf:resource="http://www.jarn.com/blog/listening-for-signals-from-dead-zopes"/>
        
        
            <rdf:li rdf:resource="http://www.jarn.com/blog/catalog-query-plan"/>
        
        
            <rdf:li rdf:resource="http://www.jarn.com/blog/plone-indexing-performance"/>
        
        
            <rdf:li rdf:resource="http://www.jarn.com/blog/explore-portlet"/>
        
        
            <rdf:li rdf:resource="http://www.jarn.com/blog/getting-rid-of-redundant-reindexing"/>
        
        
            <rdf:li rdf:resource="http://www.jarn.com/blog/membrane-performance"/>
        
        
            <rdf:li rdf:resource="http://www.jarn.com/blog/plone-2-5-performance"/>
        
        
            <rdf:li rdf:resource="http://www.jarn.com/blog/announcing-plone-enterprise-forum"/>
        
        
            <rdf:li rdf:resource="http://www.jarn.com/blog/zope-town-liberia"/>
        
        
            <rdf:li rdf:resource="http://www.jarn.com/blog/the-classic-portlet-a-first-class-plone-3-citizen"/>
        
        
            <rdf:li rdf:resource="http://www.jarn.com/blog/one-cookie-please"/>
        
        
            <rdf:li rdf:resource="http://www.jarn.com/blog/feedmixer"/>
        
        
            <rdf:li rdf:resource="http://www.jarn.com/blog/small-change-big-effect"/>
        
    </rdf:Seq>
  </items>

</channel>

    <item rdf:about="http://www.jarn.com/blog/plone-performance-sprint-bristol-2008">        <title>Plone performance sprint bristol 2008</title>        <link>http://www.jarn.com/blog/plone-performance-sprint-bristol-2008</link>        

<description>            

 A summary of the performance sprint in Bristol, 2008 
 
&lt;p&gt;It's been some time since the performance sprint in Bristol now, but it certainly deserves a summary.&lt;/p&gt;
&lt;h3&gt;&lt;img class="image-right" src="../images/castle-park-bristol/image_mini" alt="Castle Park, Bristol" /&gt;Location&lt;/h3&gt;
&lt;p&gt;Turns out Bristol is a great city with a wonderful atmosphere. There is plenty of history and old buildings (unlike in Norway). Netsight also picked a great location for the sprint, and provided plenty of refreshments to keep the geeks doing long days.&lt;/p&gt;
&lt;h2&gt;&lt;a class="external-link" href="http://www.openplans.org/projects/plone-performance-sprint-2008/topics"&gt;Sprint topics&lt;/a&gt;&lt;/h2&gt;
&lt;h3&gt;Automated performance tests&lt;/h3&gt;
&lt;p&gt;The most important result from the performance sprint is probably the &lt;a class="external-link" href="http://www.openplans.org/projects/plone-performance-sprint-2008/standard-performance-scalability-test-suite-buildout"&gt;automated funkload tests&lt;/a&gt;. In Copenhagen in 2007 we looked into using JMeter, but it was too much hassle to work with, and we didn't get beyond creating some &lt;a class="external-link" href="http://dev.plone.org/collective/browser/JMeterTestPlans/trunk"&gt;test plan templates&lt;/a&gt; for Plone.&lt;/p&gt;
&lt;p&gt;With &lt;a class="external-link" href="http://dev.plone.org/collective/browser/collective.loadtesting"&gt;collective.loadtesting&lt;/a&gt; we have something that is a lot easier to set up and use in a buildout, and we can have daily performance runs and keep track of the general performance of Plone (although it doesn't seem to be set up yet). This means we can easily and immediately spot changes that affect performance in a negative way, and make informed decisions whether the advantages of functionality or code changes is worth the performance loss.&lt;/p&gt;
&lt;h3&gt;Instrumentation&lt;/h3&gt;
&lt;p&gt;&lt;a class="external-link" href="http://www.openplans.org/projects/plone-performance-sprint-2008/instrumentation-zodb-transactions-and-catalogging"&gt;Instrumentation&lt;/a&gt; was the other important topic at the sprint. We always need more performance data, more accurate information, and better ways of presenting that data to enable us to understand and improve the system we're profiling.&lt;/p&gt;
&lt;p&gt;Enter &lt;a class="external-link" href="http://pypi.python.org/pypi/mr.bent/"&gt;mr.bent&lt;/a&gt;. Mr. Bent &lt;a class="external-link" href="http://wiki.lspace.org/wiki/Mavolio_Bent"&gt;knows his numbers&lt;/a&gt;, and is a framework for allowing profile data to be collected in a Python
application and viewed at different logical levels.&lt;/p&gt;
&lt;p&gt;One example of usage is &lt;a class="external-link" href="http://dev.plone.org/collective/browser/collective.performancecolouriser"&gt;collective.performancecolouriser&lt;/a&gt; which enables the developer to visually see timing info for different page components by color.&lt;/p&gt;
&lt;h3&gt;ExtendedPathIndex refactoring&lt;/h3&gt;
&lt;p&gt;While the ExtendedPathIndex has worked quite well for a long time, the implementation was rather obtuse, or obfuscated if you like.&lt;/p&gt;
&lt;p&gt;Martijn Pieters has been planning a rewrite for quite some time, and at the sprint he finally had the opportunity to do so. He found several bugs in the old implementation, added tests and implemented all features for all scenarios, while also improving performance by being smarter about set operation ordering.&lt;/p&gt;
&lt;p&gt;The improvements were released as version &lt;a class="external-link" href="http://pypi.python.org/pypi/Products.ExtendedPathIndex/"&gt;2.5&lt;/a&gt;, and will be included in Plone at the earliest convenience.&lt;/p&gt;
&lt;h3&gt;Catalog&lt;/h3&gt;
&lt;p&gt;&lt;a class="external-link" href="http://pypi.python.org/pypi/experimental.catalogqueryplan"&gt;experimental.catalogqueryplan&lt;/a&gt; saw two improvements. The first one is faster set operations when intersecting a large and a small set. In Plone, especially with Membrane, there are some cases where you have a rather small result set from one index (like user or group ids) and a large result set from another (implemented interfaces or permissions). In those cases it is more efficient to check if the large set has a certain key by direct lookup than to scan all keys for a match. The size check is implemented in Python as a temporary monkeypatch used for the catalogqueryplan indexes, and gives a noticeable improvement. The exact improvement depends on whether all values in the small set are found at the beginning ('Low values' in graph) or end ('high values' in graph) of the large set. It might be as much as 20x faster to check for a key.&lt;/p&gt;
&lt;p&gt;&lt;img class="image-right" src="../images/intersection-performance/image_preview" alt="Intersection performance" /&gt;The graph shows the timing of an intersection between a set of 10000 items and a subset of 10 items, repeated 100 times. The green bar is the regular C implementation from IIBTree, the yellow bar is our python implementation using has_key with fallback to the C implementation, and the blue bar is using the builtin Python set (instead of the IISet from Zope).&lt;/p&gt;
&lt;p&gt;Inside the indexes, we now sort the sets on length when doing intersection operations, to use the smallest sets first. When doing OR operations, we use multiunion instead of several unions. This should be noticeable for the permissions index (allowedRolesAndUsers) for example.&lt;/p&gt;
&lt;p&gt;The improvements are released as version &lt;a class="external-link" href="http://pypi.python.org/pypi/experimental.catalogqueryplan/"&gt;1.1&lt;/a&gt;, and can easily be tested by including experimental.catalogqueryplan in your buildout.&lt;/p&gt;
&lt;p&gt;The second improvement is the inclusion of a new index. &lt;a class="external-link" href="http://dev.plone.org/collective/browser/Products.BooleanIndex/trunk"&gt;BooleanIndex&lt;/a&gt; is a simplified FieldIndex which only stores True values and ignores everything else. This will lower the object count slightly for indexes like default page and folderish and will enable the use of the intersection improvements for smaller sets. This only works as long as there are fewer True than False values indexed.&lt;/p&gt;
&lt;p&gt;-- Helge Tesdal&lt;/p&gt;

     
</description>

        <dc:publisher>No publisher</dc:publisher>        

  <dc:creator> 
      Helge Tesdal
      - Jarn 
  </dc:creator>
  
  
      
     
          <dc:rights></dc:rights>                <dc:date>2009-01-05T18:12:07Z</dc:date>        <dc:type>Blog Posting</dc:type>    </item>
    <item rdf:about="http://www.jarn.com/blog/saving-the-day-recovering-lost-objects">        <title>Saving the day: recovering lost objects</title>        <link>http://www.jarn.com/blog/saving-the-day-recovering-lost-objects</link>        

<description>            

 When a customer discovers over a week later that an important object was accidentially deleted, what do you do? 
 &lt;h3&gt;Oh noes!&lt;/h3&gt;
&lt;p&gt;A customer discovered that an important entire section of his site was missing and asked us to bring it back. This was in a heavily edited site, with loads of writes each day, but we quickly located the offending transaction: someone had deleted the object in question 9 days earlier.&lt;/p&gt;
&lt;p&gt;Undo was no longer an option, though: too many things had changed, not least the catalog. Truncating the Data.fs (removing all transactions since, including the offending one) was not only undesirable, but impossible as the site stores the data in Oracle through &lt;a href="http://wiki.zope.org/ZODB/RelStorage"&gt;RelStorage&lt;/a&gt;.&lt;/p&gt;
&lt;img class="image-right" src="resolveuid/9bad330fe62bf3ce4053922ab7ce61ca" alt="Antique timepiece" /&gt;&lt;h3&gt;Time travel&lt;/h3&gt;
&lt;p&gt;So, instead of permanently removing transactions, we used a handy little package to do some time traveling: &lt;a href="http://pypi.python.org/pypi/zc.beforestorage"&gt;zc.beforestorage&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;zc.beforestorage&lt;/code&gt; does require a ZODB version 3.8 or 3.9; the customer installation is on Plone 3.0, so a newer ZODB3 egg was necessary for this operation. A small additional buildout configuration file (saved as beforestorage.cfg) helps out:&lt;/p&gt;
&lt;pre&gt;[buildout]&lt;br /&gt;extends =&lt;br /&gt;    buildout.cfg&lt;br /&gt;eggs +=&lt;br /&gt;    zc.beforestorage&lt;br /&gt;    ZODB3&lt;br /&gt;    zope.proxy&lt;br /&gt;&lt;br /&gt;[versions]&lt;br /&gt;ZODB3 = 3.8.1&lt;br /&gt;zope.proxy = 3.4.2&lt;br /&gt;&lt;br /&gt;[relstorage-patch]&lt;br /&gt;recipe = plone.recipe.command&lt;br /&gt;command = &lt;br /&gt;    cd ${buildout:eggs-directory}/ZODB3-3.8.1-py2.4-linux-i686.egg/ZODB&lt;br /&gt;    curl -s http://svn.zope.de/zope.org/relstorage/tags/1.1c1/poll-invalidation-1-zodb-3-8-0.patch | patch -N -p0&lt;br /&gt;    cd ${buildout:directory}&lt;br /&gt;update-command = ${relstorage-patch:command}&lt;br /&gt;&lt;br /&gt;[instance]&lt;br /&gt;zope-conf-additional +=&lt;br /&gt;    enable-product-installation False&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;relstorage-patch&lt;/code&gt; section in the above code ensures that our ZODB3 egg is patched with the RelStorage additions, and the zope.proxy egg is needed because ZODB 3.8 requires a newer version. The &lt;code&gt;enable-product-installation&lt;/code&gt; line is required because &lt;code&gt;zc.beforestorage&lt;/code&gt; puts your ZODB in read-only mode (understandibly); the option tells Zope not to try and write product information to the ZODB.&lt;/p&gt;
&lt;p&gt;Once buildout has been run with this configuration (with the &lt;code&gt;-c&lt;/code&gt; switch), you'll still need to edit the zope.conf file for your instance, usually in parts/instance/etc/zope.conf. You need to edit the &amp;lt;zodb_db main&amp;gt; section to wrap the storage in the beforestorage. Ours looked something like this:&lt;/p&gt;
&lt;pre&gt;&amp;lt;zodb_db main&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; # Main database&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; cache-size 650000&lt;br /&gt;%import zc.beforestorage&lt;br /&gt;%import relstorage&lt;br /&gt;    &amp;lt;before&amp;gt;&lt;br /&gt;    before 2008-12-08T10:29:03&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;relstorage&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;oracle&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; dsn RELSTORAGE_DSN&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; password xxxxxxxxx&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; user xxxxxxxx&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;/oracle&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;/relstorage&amp;gt;&lt;br /&gt;    &amp;lt;/before&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; mount-point /&lt;br /&gt;&amp;lt;/zodb_db&amp;gt;&lt;/pre&gt;
&lt;p&gt;Any line with the word 'before' in it is new. The timestamp we learned from the undo log, simply converted to UTC. Now, when you start the instance, you are in the past. You can't alter this past (no killing of grandfathers), but you &lt;em&gt;can&lt;/em&gt; read it. And lo and behold, the deleted object is back.&lt;/p&gt;
&lt;h3&gt;Recovery&lt;/h3&gt;
&lt;p&gt;Now that we have found the lost object, we can recover it. We simply exported it; in the ZMI, choose the Export/Import button, and save the export on the server. Remove the zc.beforestorage configuration (just run buildout with your regular buildout file), restart, import the .zexp file, done!&lt;/p&gt;
&lt;p&gt;Note that you'll need to reindex the imported content and that any related data that lives outside of the object itself is gone. For example, its intid are gone and all relationships to it will have to be recreated etc. But you just saved your customers bacon, I'm sure they won't mind a little manual work!&lt;/p&gt;
&lt;p&gt;--&lt;br /&gt;Martijn Pieters&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
     
</description>

        <dc:publisher>No publisher</dc:publisher>        

  <dc:creator> 
      Martijn Pieters
      - Jarn 
  </dc:creator>
  
  
      
     
          <dc:rights></dc:rights>                <dc:date>2008-12-18T09:47:43Z</dc:date>        <dc:type>Blog Posting</dc:type>    </item>
    <item rdf:about="http://www.jarn.com/blog/listening-for-signals-from-dead-zopes">        <title>Listening for signals from dead Zopes</title>        <link>http://www.jarn.com/blog/listening-for-signals-from-dead-zopes</link>        

<description>            

 Occasionally the impossible, or at least very unlikely, happens: your Zope instance hangs. You can see in the process listing that it is working very hard on something but it is refusing to show you what that is. 
 &lt;p&gt;This phenomenon is commonly known as a &lt;em&gt;deadlocked Zope&lt;/em&gt;. This is a bit of a misnomer since you might be dealing with infinite loops instead of a deadlock.&lt;/p&gt;
&lt;p&gt;There are two popular tools to help you debug your Zope: &lt;a class="generated" href="http://www.zope.org/Members/nuxeo/Products/DeadlockDebugger"&gt;DeadlockDebugger&lt;/a&gt; and &lt;a class="generated" href="http://pypi.python.org/pypi/z3c.deadlockdebugger"&gt;z3c.deadlockdebugger&lt;/a&gt;. Both provide a magic URL you can visit and which will return an overview of all stackframes for all threads. This will show you exactly what Zope is hiding from you.&lt;/p&gt;
&lt;p&gt;&lt;img class="image-right" src="resolveuid/65bd836bd3c6ced0934fd81baabe8f49/image_mini" alt="internet heartbeat" /&gt;Both these tools have an achilles heel: If all your Zope threads are stuck there is nothing available to process your magic URL. We ran into exactly that situation for a customer project and had to find a solution. Luckily this turned out to be simple: instead of requesting and returning the stackframe data through the webserver why not do it directly on the console? UNIX already provides us with a very useful signalling system available for: signals. Signals also have the benefit of being more secure: they can only be sent by someone who has access to the server and the account used to run the Zope instance. And thus was born a new product: &lt;a class="generated" href="http://pypi.python.org/pypi/Products.signalstack"&gt;Products.signalstack&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Once you have installed signalstack in your Zope instance all your need to do is send a USR1 signal to the Zope process and it dumps the stackframes of all threads to its standard output.&lt;/p&gt;
&lt;h3&gt;Installing&lt;/h3&gt;
&lt;p&gt;Installing signalstack is simple: you only need to install the Products.signalstack package in your site. If you are using &lt;a class="generated" href="http://pypi.python.org/pypi/zc.buildout"&gt;zc.buildout&lt;/a&gt; just add it to the eggs-line for your instance and run buildout.&amp;nbsp;&lt;/p&gt;
&lt;pre&gt;[instance]&lt;br /&gt;recipe = plone.recipe.zope2instance&lt;br /&gt;zope2-location = ${zope2:location}&lt;br /&gt;eggs =&lt;br /&gt;    Plone&lt;br /&gt;    PIL&lt;br /&gt;    Products.signalstack&lt;/pre&gt;
&lt;p&gt;If you are not using buildout you can use easy_install to install it either globally or inside your Zope instance.&lt;/p&gt;
&lt;h3&gt;Using&lt;/h3&gt;
First you need to figure out the pid (process id) of your Zope instance. You can find this in the &lt;em&gt;var/instance.pid&lt;/em&gt; file in your buildout. If you can not find that file look for a zope process in your process listing. Once you have found the pid you can send a signal to it:
&lt;pre&gt;$ kill -USR1 4361&lt;/pre&gt;
&lt;p&gt;Zope will respond in kind by throwing a lot of data at you:&lt;/p&gt;
&lt;pre&gt;Threads traceback dump at 2008-10-21 11:34:47&lt;br /&gt;&lt;br /&gt;Thread -1340051456:&lt;br /&gt;  File "/Users/wichert/Library/Zope/Zope-2.10.6-final-py2.4/lib/python/ZServer/PubCore/ZServerPublisher.py", line 19, in __init__&lt;br /&gt;    name, a, b=accept()&lt;br /&gt;  File "/Users/wichert/Library/Zope/Zope-2.10.6-final-py2.4/lib/python/ZServer/PubCore/ZRendezvous.py", line 73, in accept&lt;br /&gt;    l.acquire()&lt;br /&gt;&lt;br /&gt;Thread -1340583936 (GET /Plone):&lt;br /&gt;  File "/Users/wichert/Library/Zope/Zope-2.10.6-final-py2.4/lib/python/ZServer/PubCore/ZServerPublisher.py", line 25, in __init__&lt;br /&gt;    response=b)&lt;br /&gt;  File "/Users/wichert/Library/Zope/Zope-2.10.6-final-py2.4/lib/python/ZPublisher/Publish.py", line 401, in publish_module&lt;br /&gt;    environ, debug, request, response)&lt;br /&gt;  File "/Users/wichert/Library/Zope/Zope-2.10.6-final-py2.4/lib/python/ZPublisher/Publish.py", line 202, in publish_module_standard&lt;br /&gt;    response = publish(request, module_name, after_list, debug=debug)&lt;br /&gt;&lt;br /&gt;[ .. removed a lot of uninteresting frames here ..]&lt;br /&gt;&lt;br /&gt;  File "/Users/wichert/Library/Zope/Zope-2.10.6-final-py2.4/lib/python/Products/PageTemplates/Expressions.py", line 123, in render&lt;br /&gt;    ob = ob()&lt;br /&gt;  File "/Users/wichert/Development/plone/plone3.2/src/Plone/Products/CMFPlone/browser/ploneview.py", line 287, in showEditableBorder&lt;br /&gt;    request = self.request&lt;br /&gt;  File "/opt/local/Library/Frameworks/Python.framework/Versions/2.4/lib/python2.4/bdb.py", line 48, in trace_dispatch&lt;br /&gt;    return self.dispatch_line(frame)&lt;br /&gt;  File "/opt/local/Library/Frameworks/Python.framework/Versions/2.4/lib/python2.4/bdb.py", line 66, in dispatch_line&lt;br /&gt;    self.user_line(frame)&lt;br /&gt;  File "/opt/local/Library/Frameworks/Python.framework/Versions/2.4/lib/python2.4/pdb.py", line 135, in user_line&lt;br /&gt;    self.interaction(frame, None)&lt;br /&gt;  File "/opt/local/Library/Frameworks/Python.framework/Versions/2.4/lib/python2.4/pdb.py", line 158, in interaction&lt;br /&gt;    self.cmdloop()&lt;br /&gt;  File "/opt/local/Library/Frameworks/Python.framework/Versions/2.4/lib/python2.4/cmd.py", line 130, in cmdloop&lt;br /&gt;    line = raw_input(self.prompt)&lt;br /&gt;&lt;br /&gt;Thread -1341648896:&lt;br /&gt;  File "/Users/wichert/Library/Zope/Zope-2.10.6-final-py2.4/lib/python/ZServer/PubCore/ZServerPublisher.py", line 19, in __init__&lt;br /&gt;    name, a, b=accept()&lt;br /&gt;  File "/Users/wichert/Library/Zope/Zope-2.10.6-final-py2.4/lib/python/ZServer/PubCore/ZRendezvous.py", line 73, in accept&lt;br /&gt;    l.acquire()&lt;br /&gt;&lt;br /&gt;Thread -1341116416:&lt;br /&gt;  File "/Users/wichert/Library/Zope/Zope-2.10.6-final-py2.4/lib/python/ZServer/PubCore/ZServerPublisher.py", line 19, in __init__&lt;br /&gt;    name, a, b=accept()&lt;br /&gt;  File "/Users/wichert/Library/Zope/Zope-2.10.6-final-py2.4/lib/python/ZServer/PubCore/ZRendezvous.py", line 73, in accept&lt;br /&gt;    l.acquire()&lt;br /&gt;&lt;br /&gt;End of dump&lt;/pre&gt;
&lt;p&gt;It is immediately obvious that this Zope has a problem: someone forgot to remove a pdb.set_trace() statement at line 287 of ploneview.py.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;--&lt;br /&gt;Wichert Akkerman&lt;/p&gt;&lt;p&gt;&lt;/p&gt;
     
</description>

        <dc:publisher>No publisher</dc:publisher>        

  <dc:creator> 
      Wichert Akkerman
      - Jarn 
  </dc:creator>
  
  
      
     
          <dc:rights></dc:rights>                <dc:date>2008-10-22T09:54:08Z</dc:date>        <dc:type>Blog Posting</dc:type>    </item>
    <item rdf:about="http://www.jarn.com/blog/catalog-query-plan">        <title>Catalog query plan</title>        <link>http://www.jarn.com/blog/catalog-query-plan</link>        

<description>            

 Making the catalog faster 
 
&lt;p&gt;While the catalog tool in Zope is immensely useful, we have seen some slowdowns in large Plone sites with a combination of additional indexes and lots of content.&lt;/p&gt;
&lt;h2&gt;Analyzing Catalog implementation&lt;/h2&gt;
&lt;p&gt;The catalog implementation is using BTree set operations like union, multiunion and intersection. Those operations are fairly fast, especially when everything is in memory. However, the catalog implementation is rather naïve which leads to lots of set operations on rather big sets.&lt;/p&gt;
&lt;h3&gt;Example&lt;/h3&gt;
&lt;p&gt;A typical simple scenario is an intranet with 150000 content items, most of them published, and local roles used to handle access to most of the content.&lt;/p&gt;
&lt;p&gt;We want to look for pending Documents in a section of the site. In addition to the specified requirements, the catalog tool in Plone would add a search for allowedRolesAndUsers and effectiveRange to only return results the user is allowed to see.&lt;/p&gt;
&lt;p&gt;There is no explicit ordering of the indexes, so in our first example our ordering is &lt;em&gt;portal_type,&amp;nbsp;&lt;/em&gt;&lt;em&gt;allowedRolesAndUsers&lt;/em&gt;, &lt;em&gt;review_state&lt;/em&gt;, &lt;em&gt;effectiveRange&lt;/em&gt;, &lt;em&gt;path&lt;/em&gt;. The first index, &lt;em&gt;portal_type&lt;/em&gt; returns 90000 items.&amp;nbsp; Then we continue on to &lt;em&gt;allowedRolesAndUsers&lt;/em&gt;, which returns 40000 items. This is intersected with the the previous set, yielding a set of 20000.  As all the content in this section is published, there are no items in the &lt;em&gt;review_state=pending&lt;/em&gt;, which gives an empty set when intersected with the previous set.&lt;em&gt; effectiveRange&lt;/em&gt; returns 140000 items, which is intersected with empty set. &lt;em&gt;path&lt;/em&gt; returns 400 items which is once again intersected with the empty result set. The end result is an empty set and the query typically takes 0.15 seconds on my laptop.&lt;/p&gt;
&lt;p&gt;As a basic first improvement, it would help to immediately return after getting an empty result set from an index, but we can go even further.&lt;/p&gt;
&lt;h2&gt;Query plan&lt;/h2&gt;
&lt;p&gt;Search engines and databases uses &lt;a href="http://en.wikipedia.org/wiki/Query_optimizer"&gt;query optimizers&lt;/a&gt; to select &lt;a href="http://en.wikipedia.org/wiki/Query_plan"&gt;query plans&lt;/a&gt; that will minimize the result set as early as possible, because working with large amounts of data is time consuming.&lt;/p&gt;
&lt;p&gt;What we want to do is to search against the indexes giving the smallest result set first. However, for that to be useful, we need to pass that result along into the indexes to allow the indexes to limit the result set as soon as possible internally. When calculating a path search, there is no need to look in all 150000 results if the portal type index has already limited the possible result to 10000. If we have already limited the result to 10000 results, all set operations are going to be significantly faster.&lt;/p&gt;
&lt;h2&gt;Solution&lt;/h2&gt;
&lt;p&gt;We identify different searches by the list of indexes that are searched. If there are no query plans for a set of indexes, the query is run like normal while storing the number of results for each index. When all indexes have been checked, the list is sorted on number of results and stored as a query plan. Next time a search on the same indexes comes in, the query plan is looked up.&lt;/p&gt;
&lt;p&gt;To get different query plans for similar queries, you can provide additional bogus index names. They will be ignored by the catalog, but will become part of the key. This means that if you search for Documents in &lt;em&gt;draft&lt;/em&gt; state for a worklist, you can have a different ordering than when searching for &lt;em&gt;published&lt;/em&gt; Documents, as there are likely to be very few items in draft state, but many in published state.&lt;/p&gt;
&lt;h2&gt;Results&lt;/h2&gt;
&lt;p&gt;&lt;img class="image-right" src="resolveuid/725ef1a64e34a3e72f552bd09714afcd" alt="Catalog query plan" /&gt;I tested this in an example site locally with a 15GB Data.fs, 150000 content items, and running a JMeter test plan that logged in, viewed a couple of pages and logged out again.&lt;/p&gt;
&lt;p&gt;When measuring in the regular catalog, there were 1220 queries taking 81 seconds with the regular catalog, which is 66ms per query. When using the query plan, the queries took 14.1 seconds, which is 11ms per query. The catalog implementation is also used for membrane and reference catalog to look up users and objects, but those have significantly fewer indexes than the regular catalog tool, so we also measure on the Catalog Tool.&lt;/p&gt;
&lt;p&gt;When measuring only the catalog tool, there were 510 queries taking 80.9 seconds with the regular catalog, which is 159ms per query. With the query plan it took 14.3 seconds, which is 28ms per query. We consider 14.3 vs 14.1 to be within normal variations when measuring, and the numbers indicate that the time spent in membrane and reference catalog can be ignored compared to the time spent in the catalog tool.&lt;/p&gt;
&lt;p&gt;Going from 159ms to 28ms for typical queries is a noticeable improvement. If you are mildly abusing the catalog, this might add up to a second or more on a single page view.&lt;/p&gt;
&lt;h2&gt;Interested?&lt;/h2&gt;
&lt;p&gt;You can try these performance improvements by installing the &lt;a href="http://pypi.python.org/pypi/experimental.catalogqueryplan"&gt;experimental.catalogqueryplan&lt;/a&gt; package in your Plone site. Just add it to the eggs list in your buildout configuration and either import experimental.catalogqueryplan from your code, or load its zcml.&lt;/p&gt;
&lt;h2&gt;Sponsored by&lt;/h2&gt;
&lt;p&gt;&lt;a href="http://www.elkjop.no/"&gt;&lt;img class="image-inline" src="resolveuid/4e61c35d8a124ab01cbf776feffb5ae6" alt="Elkjøp logo" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;--&lt;br /&gt;
Helge Tesdal&lt;/p&gt;

     
</description>

        <dc:publisher>No publisher</dc:publisher>        

  <dc:creator> 
      Helge Tesdal
      - Jarn 
  </dc:creator>
  
  
      
     
          <dc:rights></dc:rights>                <dc:date>2008-07-29T10:15:45Z</dc:date>        <dc:type>Blog Posting</dc:type>    </item>
    <item rdf:about="http://www.jarn.com/blog/plone-indexing-performance">        <title>Clean and fast indexing in Plone</title>        <link>http://www.jarn.com/blog/plone-indexing-performance</link>        

<description>            

 Getting rid of redundant reindexing the right way. 
 &lt;h2&gt;Background and motivation&lt;/h2&gt;
&lt;p&gt;We have already established the fact that indexing can be improved in Plone in a &lt;a title="Getting rid of redundant reindexing" href="resolveuid/36e1ea51b7421a9435fdf93a40d3483d"&gt;previous blog posting&lt;/a&gt;, where we investigated the potential for improvement by applying an insane/inspired monkeypatch.&lt;/p&gt;
&lt;p&gt;The monkeypatch made the Plone site temporarily ignore any indexing requests, and it had side effects. Like the fact that
any additional indexing triggered by content creation in factory method
or initializeArchetype would be ignored.&lt;/p&gt;
&lt;h2&gt;Moving forward&lt;/h2&gt;
&lt;p&gt;The fundamental problem with indexing from a performance point of view, is that indexing is performed instantly instead of at transaction boundary. By postponing indexing until the transaction commits, we are able to filter the indexing events. This enables us to&lt;/p&gt;
&lt;ul&gt;&lt;li&gt;Ignore unnecessary indexing (add followed by delete)&lt;/li&gt;&lt;li&gt;Only do one (re)indexing instead of many on the same object&lt;/li&gt;&lt;/ul&gt;
&lt;h2&gt;Technical details&lt;/h2&gt;
&lt;p&gt;We added an indexing queue, which was in turn controlled by a transaction manager. The transaction manager pattern was reused from &lt;em&gt;enfold.solr&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;On modified event, or when (re)indexObject is called, the indexing requests are
put in the queue. When the transaction commits, the queue is processed. There is a default reducer which filters duplicates (which can be overridden by registering a new adapter). Then the requests are dispatched to any queue processors registered. The default queue processor is for adding content in portal_catalog, and dispatches to CatalogAware and CatalogMultiplex. You can easily add queue processors for asynchronous queue processing, or for external indexing.&lt;/p&gt;
&lt;h2&gt;Results&lt;/h2&gt;
&lt;p&gt;&lt;img class="image-right" src="resolveuid/f28ad2f2114b99ff3d0fa6ad11757fd3" alt="collective.indexing performance improvement" /&gt;When measuring improvements, we created 100 news articles using the &lt;a href="http://dev.plone.org/collective/browser/JMeterTestPlans/trunk"&gt;JMeter Test Plan&lt;/a&gt; from the collective. Unmodified is plain Plone. Indexing refers to a site with the &lt;a href="http://plone.org/products/collective.indexing/"&gt;collective.indexing&lt;/a&gt; extension profile applied. Experimental refers to &lt;a href="http://dev.plone.org/collective/browser/experimental.contentcreation/trunk"&gt;experimental.contentcreation&lt;/a&gt; (without redundant reindex hack), and E+I is &lt;a href="http://dev.plone.org/collective/browser/experimental.contentcreation/trunk"&gt;experimental.contentcreation&lt;/a&gt; and &lt;a href="http://plone.org/products/collective.indexing/"&gt;collective.indexing&lt;/a&gt; together.&lt;/p&gt;
&lt;p&gt;Note that the test results are not useful as a measure of absolute performance or to be compared with other tests. We can see that the performance improves when avoiding redundant reindexing, and now it is done in a clean and efficient way.&lt;/p&gt;
&lt;p&gt;In a real life deployment with more indexes and metadata, and possibly file conversion as well, the improvement will be bigger.&lt;/p&gt;
&lt;h2&gt;Try it out for yourself&lt;/h2&gt;
&lt;p&gt;You can use the buildout for testing this yourself.&lt;/p&gt;
&lt;pre&gt;svn co http://svn.plone.org/svn/collective/collective.indexing/buildout indexing&lt;br /&gt;cd indexing&lt;br /&gt;python bootstrap.py&lt;br /&gt;bin/buildout&lt;br /&gt;bin/instance start&lt;/pre&gt;
&lt;p&gt;Create a new Plone site, using the &lt;a href="http://plone.org/products/collective.indexing/"&gt;collective.indexing&lt;/a&gt; extension profile.&lt;/p&gt;
&lt;h2&gt;Future plans&lt;/h2&gt;
&lt;p&gt;While this component is fully usable, it is also about exploring indexing in Zope in general. During the Sorrento Sprint, Malthe Borch and Sylvain Viollon were looking into Xapian integration, and found the time to start splitting &lt;a href="http://plone.org/products/collective.indexing/"&gt;collective.indexing&lt;/a&gt; into &lt;em&gt;z3c.indexing.dispatcher&lt;/em&gt;, which will in turn dispatch to components like &lt;em&gt;z3c.indexing.zcatalog&lt;/em&gt;, external indexers or asynchronous queues similar to the one in &lt;em&gt;ore.xapian&lt;/em&gt;. For extracting data from content in Plone, there will be a &lt;em&gt;plone&lt;/em&gt; namespace packages with adapters for data extraction.&lt;/p&gt;

&lt;p&gt;Because &lt;a href="http://plone.org/products/collective.indexing/"&gt;collective.indexing&lt;/a&gt; is about adapters and utilities and not data structures, it is simple to switch parts of it as it becomes available in &lt;em&gt;z3c&lt;/em&gt; packages, and when that's done, move it into the &lt;em&gt;plone&lt;/em&gt; namespace and hopefully also towards inclusion in Plone core...&lt;/p&gt;
&lt;h2&gt;Sponsored by&lt;/h2&gt;
&lt;p&gt;&lt;a href="http://www.elkjop.no/"&gt;&lt;img class="image-inline" src="resolveuid/4e61c35d8a124ab01cbf776feffb5ae6" alt="Elkjøp logo" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;--&lt;br /&gt;Andreas Zeidler and Helge Tesdal&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;

     
</description>

        <dc:publisher>No publisher</dc:publisher>        

  <dc:creator> 
      Helge Tesdal
      - Jarn 
  </dc:creator>
  
  
      
     
          <dc:rights></dc:rights>                <dc:date>2008-04-01T07:33:33Z</dc:date>        <dc:type>Blog Posting</dc:type>    </item>
    <item rdf:about="http://www.jarn.com/blog/explore-portlet">        <title>Explore portlet</title>        <link>http://www.jarn.com/blog/explore-portlet</link>        

<description>            

  
 &lt;img class="image-right" src="resolveuid/a495a27a76fcfab7da90bd858b8b33bd/image_mini" alt="" /&gt;
&lt;h2&gt;Navigating the seas of Plone&lt;/h2&gt;
&lt;p&gt;One of the most important things you need to do when using a content management system such as Plone is to find your way to your data. Typically this involves navigating through a site using the navigation portlet: for every step your browser needs to load another page so you can find the next step on your path. This can be a slow procedure since you need a full page load at each step.&lt;/p&gt;
&lt;h2&gt;A faster way to travel&lt;/h2&gt;
&lt;p&gt;To help you get to your destination faster we wrote the &lt;a href="http://plone.org/products/collective.portlet.explore"&gt;Explore portlet&lt;/a&gt;. This is an alternative to the standard Plone 3 navigation portlet which features AJAX-based navigation: simply click on the triangle next to a folder in the navigation tree and its contents will be loaded into the tree. Click again and the tree collapses again. This gives you a very fast and intuitive method to explore the contents of your site.&lt;/p&gt;
&lt;h2&gt;Sponsored by&lt;/h2&gt;
&lt;p&gt;&lt;a href="http://www.elkjop.no/"&gt;&lt;img class="image-inline" src="resolveuid/4e61c35d8a124ab01cbf776feffb5ae6" alt="Elkjøp logo" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;--&lt;br /&gt;Wichert Akkerman&lt;/p&gt;

     
</description>

        <dc:publisher>No publisher</dc:publisher>        

  <dc:creator> 
      Wichert Akkerman
      - Jarn 
  </dc:creator>
  
  
      
     
          <dc:rights></dc:rights>                <dc:date>2008-03-07T10:51:15Z</dc:date>        <dc:type>Blog Posting</dc:type>    </item>
    <item rdf:about="http://www.jarn.com/blog/getting-rid-of-redundant-reindexing">        <title>Getting rid of redundant reindexing</title>        <link>http://www.jarn.com/blog/getting-rid-of-redundant-reindexing</link>        

<description>            

 experimental.contentcreation cuts amount of reindexing. 
 
&lt;h3&gt;Redundant reindexing&lt;/h3&gt;
&lt;p&gt;While creating a new object using the factory tool, the new object would be reindexed four times.&lt;/p&gt;
&lt;ol&gt;&lt;li&gt;ObjectAddedEvent event handler&lt;/li&gt;&lt;li&gt;Finish construction in factory method&lt;/li&gt;&lt;li&gt;processForm in Archetypes.BaseObject&lt;/li&gt;&lt;li&gt;Rename after creation&lt;/li&gt;&lt;/ol&gt;
&lt;p&gt;This is 3 times more than necessary. The first two are called by &lt;em&gt;factory_tool.doCreate&lt;/em&gt;, and the two last are in &lt;em&gt;processForm&lt;/em&gt;.&lt;/p&gt;
&lt;h3&gt;Avoiding reindexing&lt;/h3&gt;
&lt;p&gt;All the reindexing was happening in methods called by &lt;em&gt;content_edit_impl&lt;/em&gt;, and all reindexing went through &lt;em&gt;CatalogMultiplex&lt;/em&gt;. In &lt;em&gt;experimental.contentcreation&lt;/em&gt; we already take advantage of the fact that &lt;em&gt;CatalogMultiplex&lt;/em&gt; gets a list of all catalogs to index in, and by returning an empty list, the object is not indexed. The strategy would be to let &lt;em&gt;content_edit_impl&lt;/em&gt; change the result of the catalog listing while the reindexing method was called, then finally do 1 reindex afterwards.&lt;/p&gt;
&lt;p&gt;First of all we needed to override the &lt;em&gt;content_edit_impl&lt;/em&gt; script. In Plone, it is implemented as a skin script, which enables easy customization. As we needed trusted code, we added it to the patch in &lt;em&gt;experimental.contentcreation&lt;/em&gt; and set it as an attribute to the &lt;em&gt;Portal&lt;/em&gt; class, which prevents the use of the script in &lt;em&gt;portal_skins&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Before calling &lt;em&gt;doCreate&lt;/em&gt; and &lt;em&gt;processForm&lt;/em&gt; from &lt;em&gt;content_edit_impl&lt;/em&gt;, we create a lambda function that returns an empty list and set the &lt;em&gt;getCatalogsByType&lt;/em&gt; method of the Archetypes tool object to the newly created lambda function. In addition, we set &lt;em&gt;_p_changed&lt;/em&gt; to &lt;em&gt;False&lt;/em&gt; on the Archetypes tool to avoid the transaction machinery trying to save the function during savepoint.&lt;/p&gt;
&lt;p&gt;After &lt;em&gt;doCreate&lt;/em&gt; and &lt;em&gt;processForm&lt;/em&gt;, we delete the function object and reset &lt;em&gt;_p_changed&lt;/em&gt; again, before doing a single and final &lt;em&gt;reindexObject&lt;/em&gt;.&lt;/p&gt;
&lt;h3&gt;&lt;img class="image-right" src="resolveuid/413da58e760aa535a016908c678d47c6" alt="Redundant reindexing" /&gt;The result&lt;/h3&gt;
&lt;p&gt;No performance blog posting without a graph. We tested the setup with JMeter on a laptop, 10 loops for each scenario. The blue bar is content creation with &lt;em&gt;experimental.contentcreation&lt;/em&gt; with 1 reindex.&lt;/p&gt;
&lt;p&gt;Our tests show that time went down from 567ms in regular Plone to 203ms with &lt;em&gt;experimental.contentcreation&lt;/em&gt; and the redundant reindexing removal. &lt;em&gt;experimental.contentcreation&lt;/em&gt; without reindexing removal was 284ms.&lt;/p&gt;
&lt;p&gt;If you have converters to handle uploaded files and more fields and indexes in the catalog, the time difference will be even bigger.&lt;/p&gt;
&lt;h3&gt;Future&lt;/h3&gt;
&lt;p&gt;We also created a &lt;em&gt;plone.app.content&lt;/em&gt; based content type with formlib forms to compare response times compared to regular Plone. While not directly comparable and not feature complete, the numbers give an indication of what to expect in the future, and why people are looking into Zope 3 technology.&lt;/p&gt;
&lt;h3&gt;Try it out for yourself&lt;/h3&gt;
&lt;p&gt;To try it out for yourself, you can check out &lt;a href="http://svn.plone.org/svn/collective/experimental.contentcreation/trunk"&gt;experimental.contentcreation&lt;/a&gt; from SVN, add it to your buildout (don't forget the ZCML slug) and restart Zope.&lt;/p&gt;
&lt;p&gt;
-- Helge Tesdal&lt;/p&gt;

     
</description>

        <dc:publisher>No publisher</dc:publisher>        

  <dc:creator> 
      Helge Tesdal
      - Jarn 
  </dc:creator>
  
  
      
     
          <dc:rights></dc:rights>                <dc:date>2008-02-17T22:11:31Z</dc:date>        <dc:type>Blog Posting</dc:type>    </item>
    <item rdf:about="http://www.jarn.com/blog/membrane-performance">        <title>Membrane performance</title>        <link>http://www.jarn.com/blog/membrane-performance</link>        

<description>            

 Optimization of the object_implements method in Membrane 
 
&lt;h3&gt;The challenge&lt;/h3&gt;
&lt;p&gt;While looking at content creation in a Membrane scenario, we noticed that &lt;em&gt;object_implements&lt;/em&gt; took a lot of time. &lt;em&gt;object_implements&lt;/em&gt; is a catalog index wrapper that lists both the directly implemented interfaces &lt;strong&gt;and&lt;/strong&gt; any interfaces that can be adapted into. This is used when looking up user objects, as you normally associate adapters with your member types to make them behave like users.&lt;/p&gt;
&lt;p&gt;There was a note in &lt;em&gt;object_implements&lt;/em&gt; about it being slow.
Timing the method call while running tests indicated that the method
typically took &lt;strong&gt;1.2 seconds&lt;/strong&gt; on a MBP laptop. It also did not help that objects are reindexed 4 times when creating content, but that's &lt;a title="Getting rid of redundant reindexing" href="resolveuid/36e1ea51b7421a9435fdf93a40d3483d"&gt;another story&lt;/a&gt;.&lt;/p&gt;
&lt;h3&gt;The problem&lt;/h3&gt;
&lt;p&gt;Previously, &lt;em&gt;object_implements&lt;/em&gt; was using the &lt;em&gt;getRequiredAdapters&lt;/em&gt;&amp;nbsp; method from &lt;em&gt;zope.app.apidoc.component&lt;/em&gt; to list all required adapters for an interface. &lt;em&gt;getRequiredAdapters&lt;/em&gt; would check all adapters and instantiate a registration info object for each matching adapter. It would be called once for each interface implemented by the object currently being examined. Judging by the package name, this info object was originally intended to be used for API documentation, and contains more info than we need for this use case.&lt;/p&gt;
&lt;h3&gt;Poking the adapter registry&lt;/h3&gt;
&lt;p&gt;As we were not aware of any current methods in the adapter registries that would give the result we were looking for, we started &lt;a href="http://dev.plone.org/collective/changeset/58797"&gt;poking the internals of the registry&lt;/a&gt; from membrane. The registry has a dictionary of interfaces and their corresponding adapters, and we used that to look up the adapters. If an exception occurs in the new code, we have a fallback to the old code.&lt;/p&gt;
&lt;p&gt;Poking the internals of the adapter registry is not future proof, as we are circumventing interfaces and depending on the internal data structures of the adapter registry to stay the same. While not very likely to change, the data structure might change between Zope versions - requiring us to update Membrane.&lt;/p&gt;
&lt;p&gt;&lt;img class="image-right" src="resolveuid/d848b317be8bf81ad27bc9992ed34921" alt="object_implements optimization" /&gt;&lt;/p&gt;
&lt;h3&gt;Measuring improvement&lt;/h3&gt;
&lt;p&gt;After testing again, the time spent in &lt;em&gt;object_implements&lt;/em&gt; was &lt;strong&gt;0.0006&lt;/strong&gt; seconds, and the set of interfaces returned were exactly the same with both methods.&lt;/p&gt;
&lt;p&gt;The difference was difficult to express in our regular go-faster-graphs, so we used an area plot instead. The four pixels on the right indicate the time after optimization relative to before the optimization.&lt;/p&gt;
&lt;p&gt;This change is checked in on &lt;a href="http://dev.plone.org/collective/changeset/58797"&gt;membrane trunk&lt;/a&gt;, and will be part of the next release unless there are any unforeseen problems.&lt;/p&gt;
&lt;p&gt;
--&lt;br /&gt;
Helge Tesdal&lt;/p&gt;

     
</description>

        <dc:publisher>No publisher</dc:publisher>        

  <dc:creator> 
      Helge Tesdal
      - Jarn 
  </dc:creator>
  
  
      
     
          <dc:rights></dc:rights>                <dc:date>2008-02-17T21:32:19Z</dc:date>        <dc:type>Blog Posting</dc:type>    </item>
    <item rdf:about="http://www.jarn.com/blog/plone-2-5-performance">        <title>Plone 2.5 performance</title>        <link>http://www.jarn.com/blog/plone-2-5-performance</link>        

<description>            

 Profiling of content creation and teamspace scenario in Plone 2.5, and publishing contentmenu and factoryhack. 
 
&lt;p&gt;We have blogged about performance before, after doing &lt;a title="Improving Plone performance" href="resolveuid/a8edf29a40dc8dd8dc4cf64f6ac04e79"&gt;profiling for Plone 2.5&lt;/a&gt; and during the &lt;a title="Plone performance sprint" href="resolveuid/a72bdfd5ff78f1636ad53d5cb3125260"&gt;Copenhagen Performance Sprint where we made experimental.contentcreation&lt;/a&gt;. Prior to experimental.contentcreation we made two Plone 2.5 products named factoryhack and contentmenu that are now available in the &lt;a href="http://dev.plone.org/collective/browser/experimental.contentcreation/plone2.5"&gt;collective&lt;/a&gt;.&lt;/p&gt;
&lt;h3&gt;Performance improvements&lt;/h3&gt;
&lt;p&gt;First of all we'll take a look at what you'll get from these products by setting up some tests with jmeter. Each test is run 10 times after
warming up 2 times. Neither of the tests were done on plain Plone, they
have several add on products installed, and other factors that affect
performance. The results can not be used as an absolute benchmark on
Plone performance, but are useful for showing relative results with and
without the optimizations.&lt;/p&gt;
&lt;p&gt;The first test shows results for
content creation. Listing is listing folder contents, Addform is
showing the addform to add content in the folder, Create is pressing
the save button and creating the content, and show is displaying the
newly created content.&lt;/p&gt;
&lt;img class="image-inline" src="resolveuid/ddf3744637278c126448c3dfb670d05a" alt="Plone 2.5 optimizations when creating content" /&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;The
second test is for a teamspace scenario. Teamspaces is viewing a
listing of teamspaces, Teamspace is viewing one teamspace, Subfolder 1
is listing contents in a subfolder of Teamspace, and Subfolder 2 is
another folder, parallell to Subfolder 1.&lt;/p&gt;
&lt;img class="image-inline" src="resolveuid/8546508399128cff2d75bb5d5d38d6cd" alt="Plone 2.5 optimizations in a teamspace scenario" /&gt;
&lt;h3&gt;Install&lt;/h3&gt;
&lt;p&gt;If you want to try this for yourself, you can check out the products into your Products directory using command line svn or a client like TortoiseSVN:&lt;/p&gt;
&lt;pre&gt;svn co https://svn.plone.org/svn/collective/experimental.contentcreation/plone2.5/factoryhack factoryhack&lt;/pre&gt;
&lt;pre&gt;svn co https://svn.plone.org/svn/collective/experimental.contentcreation/plone2.5/contentmenu contentmenu&lt;/pre&gt;
&lt;p&gt;Content menu then has to be installed in the install products control panel.&lt;/p&gt;
&lt;h3&gt;Technical&lt;/h3&gt;
&lt;p&gt;The technical details are covered pretty well in the two previous blog postings [&lt;a title="Improving Plone performance" href="resolveuid/a8edf29a40dc8dd8dc4cf64f6ac04e79"&gt;1&lt;/a&gt;][&lt;a title="Plone performance sprint" href="resolveuid/a72bdfd5ff78f1636ad53d5cb3125260"&gt;2&lt;/a&gt;].&lt;/p&gt;
&lt;p&gt;Factoryhack is mainly about optimizing the portal factory tool, but also the type listings. It is implemented as a monkey patch, meaning that it it automatically applies itself when Zope starts, and is completely gone as soon as you remove it from the Products directory.&lt;/p&gt;
&lt;p&gt;Contentmenu is about improving the type listings further. It is installed in the control panel and provides a skin override. It does not alter the data in any way, and will be gone as soon as you uninstall in control panel and remove from Products directory.&lt;/p&gt;
&lt;h3&gt;Disclaimer&lt;/h3&gt;
&lt;p&gt;Note that the type listings are optimized by bypassing the regular security machinery and trying to emulate it in a more efficient way by gathering all local roles first, then check against roles required for adding content. This is working in production, but if you experience unexpected results in the add content dropdown after installing these products, you will have to uninstall them again. It does not affect actual create permissions, only the drop down menu that lists the types available. The worst that can happen is that you don't see all content types you are allowed to create, or get an error message because you are trying to add a content type without really being allowed to.&lt;br /&gt;&lt;br /&gt;-- Helge&lt;/p&gt;

     
</description>

        <dc:publisher>No publisher</dc:publisher>        

  <dc:creator> 
      Helge Tesdal
      - Jarn 
  </dc:creator>
  
  
      
     
          <dc:rights></dc:rights>                <dc:date>2008-02-08T14:57:14Z</dc:date>        <dc:type>Blog Posting</dc:type>    </item>
    <item rdf:about="http://www.jarn.com/blog/announcing-plone-enterprise-forum">        <title>Announcing Plone Enterprise Forum</title>        <link>http://www.jarn.com/blog/announcing-plone-enterprise-forum</link>        

<description>            

  
 
&lt;p&gt;&lt;br /&gt;We are proud and happy to announce a new interest group and mailing list: "&lt;em&gt;Plone in the Enterprise&lt;/em&gt;".&lt;br /&gt;There is a growing interest in features for using Plone in Enterprise-level deployments like:&lt;/p&gt;
&lt;ul&gt;&lt;li&gt;scaling to handle hundreds or thousands of parallel authenticated users&lt;/li&gt;&lt;li&gt;Enterprise search (being able to quickly search through millions of objects)&lt;/li&gt;&lt;li&gt;Integration &lt;/li&gt;&lt;li&gt;Clustering and hosting solutions&lt;/li&gt;&lt;li&gt;High availability architcture&lt;/li&gt;&lt;li&gt;more…&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;We are now launching a separate forum for the discussion of Plone in the Enterprise.&lt;br /&gt;There are already many interesting projects happening, and the sooner we can join our efforts the better it will be for the world of large-scale Plone. Let's share experiences, needs, war stories and help each other on development of large-scale features:&lt;br /&gt;The mailing list is available at&lt;br /&gt;&lt;a href="http://lists.plone.org/mailman/listinfo/enterprise"&gt;http://lists.plone.org/mailman/listinfo/enterprise&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;It is available in Gmane for those of us that prefer a newsgroup interface:&lt;br /&gt;&lt;a href="news:gmane.comp.web.zope.plone.enterprise"&gt;gmane.comp.web.zope.plone.enterprise&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;and as a web-forum at Nabble:&lt;br /&gt;&lt;a href="http://www.nabble.com/Enterprise-f30548.html"&gt;http://www.nabble.com/Enterprise-f30548.html&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;If you care about enterprise level Plone, Please join us!&lt;/p&gt;
&lt;p&gt;--&lt;/p&gt;
&lt;p&gt;Geir Bækholt&lt;/p&gt;

     
</description>

        <dc:publisher>No publisher</dc:publisher>        

  <dc:creator> 
      Geir Bækholt
      - Jarn 
  </dc:creator>
  
  
      
     
          <dc:rights></dc:rights>                <dc:date>2008-01-28T22:43:04Z</dc:date>        <dc:type>Blog Posting</dc:type>    </item>
    <item rdf:about="http://www.jarn.com/blog/zope-town-liberia">        <title>Zope Town, Liberia</title>        <link>http://www.jarn.com/blog/zope-town-liberia</link>        

<description>            

  
 &lt;p&gt;&lt;a href="http://maps.google.com/maps?f=q&amp;amp;hl=en&amp;amp;geocode=&amp;amp;time=&amp;amp;date=&amp;amp;ttype=&amp;amp;q=zope+town,+liberia&amp;amp;sll=38.134557,-95.712891&amp;amp;sspn=43.379021,82.792969&amp;amp;ie=UTF8&amp;amp;ll=6.54456,-10.513916&amp;amp;spn=1.729921,2.58728&amp;amp;z=9&amp;amp;iwloc=addr&amp;amp;om=1"&gt;&lt;img class="image-right" src="resolveuid/99a8650c2c9a982ac268ec09ddef0d44" alt="Zope town" /&gt;&lt;/a&gt;By accident, we stumbled across this remote little &lt;a href="http://maps.google.com/maps?f=q&amp;amp;hl=en&amp;amp;geocode=&amp;amp;time=&amp;amp;date=&amp;amp;ttype=&amp;amp;q=zope+town,+liberia&amp;amp;sll=38.134557,-95.712891&amp;amp;sspn=43.379021,82.792969&amp;amp;ie=UTF8&amp;amp;ll=6.54456,-10.513916&amp;amp;spn=1.729921,2.58728&amp;amp;z=9&amp;amp;iwloc=addr&amp;amp;om=1"&gt;town in Liberia, called Zope Town&lt;/a&gt; (sometimes also referred to as Zopita).&lt;/p&gt;
&lt;p&gt;Fun :)&lt;/p&gt;

     
</description>

        <dc:publisher>No publisher</dc:publisher>        

  <dc:creator> 
      Geir Bækholt
      - Jarn 
  </dc:creator>
  
  
      
     
          <dc:rights></dc:rights>                <dc:date>2007-11-17T21:56:52Z</dc:date>        <dc:type>Blog Posting</dc:type>    </item>
    <item rdf:about="http://www.jarn.com/blog/the-classic-portlet-a-first-class-plone-3-citizen">        <title>The classic portlet, a first-class Plone 3 citizen</title>        <link>http://www.jarn.com/blog/the-classic-portlet-a-first-class-plone-3-citizen</link>        

<description>            

  
 &lt;p&gt;Reading &lt;a href="http://www.upfrontsystems.co.za/Members/roche/where-im-calling-from/meeting-plone-3"&gt;a recent comment about portlets in Plone 3&lt;/a&gt;, i was baffled by the negativity, until i realized that the man is simply suffering from the slight misconception that the classic portlet is something he is not supposed to use. (probably due to me not writing &lt;a href="http://martinaspeli.net/articles/portlet-sanity"&gt;the tutorial Martin rightfully expects me to write&lt;/a&gt;)&lt;/p&gt;
&lt;h3&gt;Complexity&lt;/h3&gt;
&lt;p&gt;Roche is unhappy that portlets are now more complex than they were before.&lt;br /&gt;Fair enough. This is a pattern we have seen for thousands of years. To accomodate new needs or desires, growth or increasing complexity of society, technology grows more complex.&lt;/p&gt;&lt;img class="image-right" src="resolveuid/7711144d87b39dace056bf998134e291/image_thumb" alt="Balloon" /&gt;&lt;p&gt;Let's use flight as an example: A hot air balloon is a fairly simple instrument, and can be built by almost anyone with motivation and a bit of resources. But even though hot air balloons can be perfectly good (even the best) for many use cases,&amp;nbsp; they also have limitations; they are&amp;nbsp; slow, they have limited cargo capabilities and are hard to navigate. Upgrading to a simple aeroplane may be tempting as it can help resolve these issues.&amp;nbsp; But upgrading from a balloon to a plane will also lead to more complex technology; aerodynamics, combustion engines, airfield construction…  Moving another step up the ladder into organised passenger traffic, you'll end up with airports, air traffic controllers, ticket management systems and lots of organizational issues too.&lt;/p&gt;
&lt;p&gt;The neat thing is that even in today's world of organized passenger air traffic, there is room for the hot air balloon. In many scenarios, the simple, flexible and agile tool (not to mention cheap), is preferable to complex engineering.&lt;/p&gt;
&lt;h3&gt;Give me a classic!&lt;/h3&gt;
&lt;p&gt;Many of us have been suffering from the lack of a proper portlet management system in Plone. Given a deployment of any reasonable complexity, it was just too much to handle with the tools we had.&lt;br /&gt;The reason i am writing this is that some people seem to be suffering from the misconception that the old-style portlet, the classic portlet, — &lt;em&gt;the hot air balloon of portlets&lt;/em&gt;, is deprecated and not recommended in real-life use. This is completely wrong! Given the late trend of integrators being suspicious of the added complexity and allegedly lacking TTW-support of Plone 3, i feel it is necessary to clarify this bit for the non-developers out there:&lt;/p&gt;
&lt;h3&gt;The classic portlet, a first-class Plone citizen:&lt;/h3&gt;
&lt;p&gt;A lot of effort (Kudos to &lt;a href="http://martinaspeli.net"&gt;Martin&lt;/a&gt;) has been put into making it simple to work with portlets for integrators. And even better: in addition to being able to continue working with the portlets as before you get to combine it with the powers the new portlet engine brings, and add extra free superpowers without having to break a sweat: Even with single-template-based classic portlets you get new stuff from plone.portlets and plone 3:&amp;nbsp;&lt;/p&gt;
&lt;ul&gt;&lt;li&gt;Your portlet can be assigned (and unassigned or blocked) in the UI, in Plone, not just in ZMI valley where no real user will ever venture.&lt;/li&gt;&lt;li&gt;Your portlet can now be assigned to users' dashboards&lt;/li&gt;&lt;li&gt;Your portlet can now be assigned to groups of users&lt;/li&gt;&lt;li&gt;Your portlet can now be assigned to content types&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;In exchange for all these new features, you have to sacrifice exactly *&lt;strong&gt;nothing&lt;/strong&gt;*. You don't even have to rewrite your template. You don't have to touch&amp;nbsp; three python classes or any zcml files. — &lt;strong&gt;Simply add a classic portlet in the plone interface, paste the path to your template and you are good to go!&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;In addition to all this, developers will also soon start distributing usable portlets as eggs, so you can plug all sorts of extra functionality on top — and you'll still not be chewing on the extra complexity.&lt;/p&gt;
&lt;p&gt;-- &lt;br /&gt;Geir Bækholt&lt;/p&gt;

     
</description>

        <dc:publisher>No publisher</dc:publisher>        

  <dc:creator> 
      Geir Bækholt
      - Jarn 
  </dc:creator>
  
  
      
     
          <dc:rights></dc:rights>                <dc:date>2007-11-10T23:58:26Z</dc:date>        <dc:type>Blog Posting</dc:type>    </item>
    <item rdf:about="http://www.jarn.com/blog/one-cookie-please">        <title>One cookie please, but hold the pickles</title>        <link>http://www.jarn.com/blog/one-cookie-please</link>        

<description>            

 The python pickle module is dangerous, didn't you know? 
 
&lt;h3&gt;All your base are belong to us&lt;/h3&gt;
&lt;p&gt;By now you all should have installed &lt;a href="http://plone.org/products/plone-hotfix/releases/20071106"&gt;last Tuesday's Hotfix&lt;/a&gt;. If you haven't yet, but are running Plone 2.5 or Plone 3.0 websites, you should do so &lt;strong&gt;yesterday&lt;/strong&gt;, or at least as soon as humanly possible.&lt;/p&gt;
&lt;p&gt;&lt;img class="image-right" src="resolveuid/fd511fd4401bcac35847c45ad2ff4ffd/image_mini" alt="Pickle" /&gt;The Hotfix patches a serious security problem in the statusmessages and linkintegrity modules, where network-supplied data was interpreted as &lt;a href="http://docs.python.org/lib/module-pickle.html"&gt;pickles&lt;/a&gt;. "Network-supplied" data in this case means both cookies and form data, and no authentication is required to exploit the holes.&lt;/p&gt;
&lt;h3&gt;What happen ?&lt;/h3&gt;
&lt;p&gt;The basic problem with the holes is that the Plone community was totally unaware of how dangerous the pickle module really is. Hanno Schlichting did file a &lt;a href="http://dev.plone.org/plone/ticket/6943"&gt;report&lt;/a&gt; a few months ago stating that the code was potentially dangerous, but even he didn't fully appreciate that pickles are a security hole only waiting for attacker input. The scary thing here is that the code in question was written by extremely capable and experienced developers, but none of them were aware of the fact that you cannot ever use pickles to load user-supplied data.&lt;/p&gt;
&lt;p&gt;What is needed then, is education. This is my contribution.&lt;/p&gt;
&lt;h3&gt;You are on the way to destruction&lt;/h3&gt;
&lt;p&gt;So what is wrong with pickles? They are just a damn handy way to serialize arbitrary data into binary strings and back again, right?&lt;/p&gt;
&lt;p&gt;Yes, they are that, but the pickle format used is also a &lt;a href="http://peadrop.com/blog/2007/06/18/pickle-an-interesting-stack-language/"&gt;simple stack language&lt;/a&gt; that allows the creation of arbitrary python structures, and execute them. This stack language allows you to import modules (the 'c' symbol), and apply arguments to callables (the 'R' symbol), thus causing code to be run. Combine this with the python built-in methods &lt;em&gt;eval&lt;/em&gt; and &lt;em&gt;compile&lt;/em&gt; and you have the perfect vehicle for an attacker to have the pickle loader routine execute arbitrary python code when loading a well-crafted pickle. Just image what an attacker could do with that to your Zope server. Do you think you'll ever be sure you got all the backdoors out of your Data.fs?&lt;/p&gt;
&lt;h3&gt;We get signal&lt;/h3&gt;
&lt;p&gt;So next time you need to preserve data across HTTP requests, please do not be tempted to use the pickle module to create strings for you. Rarely will you have anything more than a handful of simple datatypes to pass along anyway, so just invent a simple dataformat and use that instead. (No, using a subclass of the python implementation of pickle is not a simpler solution).&lt;/p&gt;
&lt;p&gt;With statusmessages for example, each message consists of a message and a type string, both unicode. So we changed to a hand-rolled format using a 2 byte length header (11 bits of message length, 5 for the type) directly followed by the message and type strings (encoded to utf-8). When reading this from a cookie again later, the decoder simply has to read the lengths from the first 2 bytes, then read the right amount of characters to get the message and type back. A similar method was used to encode the linkintegrity data. Simple, effective, and impervious to attacks.&lt;/p&gt;
&lt;p&gt;--&lt;br /&gt;Martijn Pieters&lt;/p&gt;
&lt;p class="discreet"&gt;Congratulation!!
&lt;br /&gt; A.D.2111
&lt;br /&gt; All bases of CATS were destroyed.
&lt;br /&gt; It seems to be peaceful.
&lt;br /&gt; But it is incorrect. CATS is still alive.
&lt;br /&gt; ZIG-01 must fight against CATS again.
&lt;br /&gt; And down with them completely !
&lt;br /&gt; Good luck.
&lt;br /&gt;-- &lt;a href="http://en.wikipedia.org/wiki/All_your_base_are_belong_to_us"&gt;Zero Wing, 1989&lt;/a&gt;&lt;/p&gt;

     
</description>

        <dc:publisher>No publisher</dc:publisher>        

  <dc:creator> 
      Martijn Pieters
      - Jarn 
  </dc:creator>
  
  
      
     
          <dc:rights></dc:rights>                <dc:date>2007-11-09T23:08:33Z</dc:date>        <dc:type>Blog Posting</dc:type>    </item>
    <item rdf:about="http://www.jarn.com/blog/feedmixer">        <title>FeedMixer</title>        <link>http://www.jarn.com/blog/feedmixer</link>        

<description>            

  
 
&lt;h2&gt;Hungry for information&lt;/h2&gt;
&lt;p&gt;The world is a highly dynamic place: an amazing amount of things are happening around us at an incredible place. And we humans, being the curious beings that we are, want to know exactly what is happening. Our need for information is so large that we have build an army of tools to manage information. The latest trend in that area are&amp;nbsp; &lt;a href="http://en.wikipedia.org/wiki/Web_feed"&gt;Web Feeds&lt;/a&gt;: channels with output little bits of information you can subscribe to.&lt;/p&gt;
&lt;p&gt; Feeds have several good qualities: they are easy to access, and you can do so using any of the thousands libraries and applications that support the popular RSS and Atom formats. This also makes them very useful as a method to get data from one system to another system.&lt;/p&gt;
&lt;h2&gt;&lt;img class="image-right" src="resolveuid/51a8a3d31abae9587a466a1df9a0a67b/image_mini" alt="Octopus mixer" /&gt;A feed on my own menu&lt;/h2&gt;
&lt;p&gt;One place where we want to be able to use feeds is on our websites. Particularly we have a customer who was interested in being able to accumulate data from several feeds and present them as a single listing of news items. Plone 3 already included a RSS portlet which could handle a single feed and present that in a portlet. Originally we planned to extend this portlet to be able to handle multiple feeds. This quickly turned out to be a bad idea: the RSS portlet was designed to act as a very simple to use window into a news source, and does a very good job at that: it is easy to configure, automatically picks up title and URL for the news source and outputs a standard Plone portlet using those. Extending that to handle multiple feeds would result in a something that was too complex for its original use case and not convenient for multiple feeds as well. The worst of both worlds.&lt;/p&gt;
&lt;p&gt;So we scrapped that idea and implemented a new package: &lt;a href="http://plone.org/products/collective.portlet.feedmixer"&gt;FeedMixer&lt;/a&gt;. Or &lt;a href="http://pypi.python.org/pypi/collective.portlet.feedmixer"&gt;collective.portlet.feedmixer&lt;/a&gt; if prefer the exact python package name. Just like the standard Plone 3 RSS portlet FeedMixer aims to be as simple as possible to use. You can specify the portlet title, number of items to show and as many URLs as you want and in return you will get a portlet with the latest news items from all your sources. And if you want to see more results there is also a handy page which shows the complete entry list from all feeds.&lt;/p&gt;
&lt;h2&gt;Do you serve fast food, euh, feed?&lt;/h2&gt;
&lt;p&gt;One problem with feeds is that they are generally not very fast: software which processes feeds regularly asks feed publishers for the latest which can put a huge load on publishers. On the client side you do not want to wait for a system to reload the feed data, process it and show you the results. You want your feed, and you want it fast.&lt;/p&gt;
&lt;p&gt;FeedMixer accomplishes that by reusing the caching infrastructure in Plone 3. It uses the &lt;em&gt;memoize&lt;/em&gt; caching infrastructure to find a global cache where all feed data can be stored. Normally this is a RAMCache, but if you are using multiple Zope instances you can easily change this to use a shared &lt;a href="http://www.danga.com/memcached/"&gt;memcached&lt;/a&gt; cache instead. That means that if one of your Zope instances refreshes a feed &lt;em&gt;all&lt;/em&gt; your instances will immediately be able to use it. Since the Zope caches may have a longer timeout setting then you want to use for your feed data you can also configure a maximum timeout directly in a FeedMixer portlet.&lt;/p&gt;
&lt;p&gt;If FeedMixer needs to refresh data it will try to use the &lt;a href="http://en.wikipedia.org/wiki/HTTP_ETag"&gt;ETags&lt;/a&gt; and the HTTP Last-Modified header to only download the feed if it has changed on the server.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;-- &lt;span&gt;&lt;br /&gt;Wichert Akkerman&lt;/span&gt;&lt;/p&gt;

     
</description>

        <dc:publisher>No publisher</dc:publisher>        

  <dc:creator> 
      Wichert Akkerman
      - Jarn 
  </dc:creator>
  
  
      
     
          <dc:rights></dc:rights>                <dc:date>2007-11-05T21:54:40Z</dc:date>        <dc:type>Blog Posting</dc:type>    </item>
    <item rdf:about="http://www.jarn.com/blog/small-change-big-effect">        <title>Small change, big effect</title>        <link>http://www.jarn.com/blog/small-change-big-effect</link>        

<description>            

 How changing one line halved the time it took to rename a Plone folder. 
 
&lt;p&gt;Here at the Plone Performance sprint, Matt Hamilton and Sasha Vincic are homing in on the Catalog and folder renaming. As Sasha already &lt;a href="http://valentinewebsystems.com/archive/2007/11/02/indexing-in-plone-got-twice-as-fast"&gt;reported earlier&lt;/a&gt;, they identified the object_provides index as a potential bottleneck.&lt;/p&gt;
&lt;h3&gt;The object_provides index&lt;/h3&gt;
&lt;p&gt;The index is filled with interface identifiers, strings representing the actual interfaces. The data for the index comes from a small method in Products.CMFPlone.CatalogTool, object_provides, which looked like this:&lt;/p&gt;
&lt;pre&gt;def object_provides(object, portal, **kw): &lt;br /&gt;    return [interfaceToName(portal, i) for i in providedBy(object).flattened()]&lt;/pre&gt;
&lt;p&gt;So, for each interface declared by an object, interfaceToName is invoked. The purpose of interfaceToName is to provide a way to turn an
interface to a string that can be used to later turn that string back
into an interface, through the queryInterface method, interfaceToName's
sibling.&lt;/p&gt;
&lt;p&gt;Now the problem with interfaceToName is that it has to iterate over the whole utilities registry to find all interfaces registered as utilities just to find out what name it was registered with. This is a slow process, but a necessary one; although the default name for an interface is it's &lt;em&gt;dotted name&lt;/em&gt; (the python identifier path to their definition), some special classes of interfaces are registered with a different name. For example, when registering a Zope3-style browser menu, an interface is generated for the menu, and registered with a zope.app.menus prefix.&lt;/p&gt;
&lt;h3&gt;No need for interfaceToName&lt;/h3&gt;
&lt;p&gt;Luckily, for the object_provides index use-case, interfaceToName is overkill. First of all, object_provides indexes declared interfaces on content objects only, and therefore will never encounter any of the "special" interfaces.&lt;/p&gt;
&lt;p&gt;But more importantly, the index contents are never used to find the original interfaces again. Quite the contrary, it is only used to search what objects provide a given interface, and the developer querying the catalog will have to generate the same string format every time they search. So, with the index using interfaceToName to fill the index, searching the index also requires developers to use interfaceToName to query the index. Search for IATFolder? Pass in interfaceToName(IATFolder) and hit the same performance problem.&lt;/p&gt;
&lt;h3&gt;&lt;img class="image-right" src="resolveuid/68b2b43ca342a742e322de2ee41e36dd/image_preview" alt="Renaming performance increase" /&gt;&lt;/h3&gt;
&lt;h3&gt;Unique identifier&lt;/h3&gt;
&lt;p&gt;So if interfaceToName is overkill, what unique identifier should we use then? As we already mentioned, when you register an interface in the first place, the default name is the dotted name of the interface. It's a unique identifier, as it's the name under which python stores it in memory. It is available as the &lt;em&gt;__identifier__&lt;/em&gt; attribute on the interface. As it's unique, and available directly from the interfaces themselves, it's ideally suited for both indexing and searching.&lt;/p&gt;
&lt;p&gt;Of course, this means that if we use __identifier__ then you should use the same attribute when querying the index. Because __identifier__ (or __module__ + '.' + __name__, which is the same) is already the default for interfaceToName, this is what Plone developers have been using anyway.&lt;/p&gt;
&lt;p&gt;So we changed the indexing method to:&lt;/p&gt;
&lt;pre&gt;def object_provides(object, portal, **kw): &lt;br /&gt;    return [i.__identifier__ for i in providedBy(object).flattened()]&lt;/pre&gt;
&lt;p&gt;and presto, indexing was more than twice as fast, as shown by the pretty graph on the right. We tested this by having JMeter rename a folder with 20 documents in it, 40 times.&lt;/p&gt;
&lt;p&gt;Not bad for a one-line change.&lt;/p&gt;
&lt;p&gt;--&lt;br /&gt;Martijn Pieters&lt;/p&gt;

     
</description>

        <dc:publisher>No publisher</dc:publisher>        

  <dc:creator> 
      Martijn Pieters
      - Jarn 
  </dc:creator>
  
  
      
     
          <dc:rights></dc:rights>                <dc:date>2007-11-04T12:54:08Z</dc:date>        <dc:type>Blog Posting</dc:type>    </item>




</rdf:RDF>
