Changeset 52385

Show
Ignore:
Timestamp:
01/09/08 16:19:54 (2 years ago)
Author:
madarche
Message:

Fixed #1866: Dynamic treeview is a performance nightmare.

Stop that iteration by calling Tree Cache instead.
Avoid looping on all child documents. This is a minimal intervention though,
lots of getContents etc could still be avoided.

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • CPS3/products/CPSPortlets/trunk/CHANGES

    r52383 r52385  
    77Bug fixes 
    88~~~~~~~~~ 
     9- #1866: Dynamic treeview is a performance nightmare. 
    910- #1879: Highlighting of member space doesn't work for "3tabs" portlet. 
    1011New internal features 
  • CPS3/products/CPSPortlets/trunk/browser/treenodeview.py

    r32919 r52385  
    2222 
    2323""" 
     24import logging 
     25 
    2426from Products.CMFCore.utils import getToolByName 
    2527from AccessControl import Unauthorized 
     
    2931class TreeNodeView(BrowserView): 
    3032 
     33    log = logging.getLogger('CPSPortlets.browser.TreeNodeView') 
     34 
     35    def __init__(self, *args, **kwargs): 
     36        BrowserView.__init__(self, *args, **kwargs) 
     37        self.utool = getToolByName(self.context, 'portal_url') 
     38        self.tree_tool = getToolByName(self.context, 'portal_trees') 
     39 
    3140    def getNode(self, root=''): 
    3241        """ root is the url of the root node """ 
    33         utool = getToolByName(self.context, 'portal_url') 
     42        self.log.debug("getNode: root rpath=%s", root) 
     43        utool = self.utool 
    3444        portal_cpsportlets = getToolByName(self.context, 'portal_cpsportlets') 
    3545 
    36         base_url = utool.getBaseUrl() 
     46        base_url = self.utool.getBaseUrl() 
    3747        node = self._getRoot(root) 
    3848        object_id = node.getId() 
     
    4353        object_url = node.absolute_url_path() 
    4454        renderIcon = portal_cpsportlets.renderIcon 
    45         children = [self.getNode(object.absolute_url_path()
    46                     for object in self._folderishChildren(node)] 
     55        children = [self.getNode(item['rpath']
     56                    for item in self._folderishChildren(node)] 
    4757 
    4858        if object_url == context_url: 
     
    7383 
    7484    def _rootRestrictedTraverse(self, path): 
    75         utool = getToolByName(self.context, 'portal_url') 
    76         portal_path = utool.getPortalPath() 
    77         if not path.startswith(portal_path): 
    78             path = portal_path + path 
    79         return self.context.restrictedTraverse(path, default=None) 
     85         
     86        portal = self.utool.getPortalObject() 
     87        return portal.restrictedTraverse(path, default=None) 
    8088 
    8189    def _getRoot(self, root=''): 
     
    8896            return self._rootRestrictedTraverse(root) 
    8997 
     98    def _getTreeCache(self, folder, rpath=None): 
     99        """Find the TreeCache object for given folder. 
     100 
     101        Optional rpath can be passed to avoid computing it twice. 
     102 
     103        Implementation uses for now a big assumption on the tree naming and uses 
     104        rpath only 
     105        """ 
     106 
     107        if rpath is None: 
     108            if folder is None: 
     109                return 
     110            rpath = self.utool.getRpath(folder) 
     111         
     112        return getattr(self.tree_tool.aq_explicit, rpath.split('/', 1)[0], None) 
     113         
    90114    def _getContent(self, object): 
    91115        content = None 
     
    97121 
    98122    def _hasSubFolders(self, folder): 
    99         for id, item in folder.objectItems(): 
    100             if self._isFolderish(item): 
    101                 return True 
    102         return False 
    103  
    104     def _isFolderish(self, object): 
    105         return ((hasattr(object, 'isPrincipiaFolderish') and 
     123        rpath = self.utool.getRpath(folder) 
     124        tc = self._getTreeCache(folder, rpath=rpath) 
     125 
     126        if tc is None: 
     127            # costly fallback 
     128            for id, item in folder.objectItems(): 
     129                if self._isFolderish(item): 
     130                    return True 
     131            return False 
     132         
     133        # TODO cache this call for reuse ? 
     134        depth = len(rpath.split('/')) # depth of children (l-1+1=l) 
     135        return len(tc.getList(prefix=rpath,  
     136                              start_depth=depth,  
     137                              stop_depth=depth,filter=True)) > 0 
     138 
     139 
     140    def _isFolderish(self, object):  
     141       return ((hasattr(object, 'isPrincipiaFolderish') and 
    106142                object.isPrincipiaFolderish==1) and 
    107143                not (object.getId().startswith('.') or 
     
    109145 
    110146    def _folderishChildren(self, folder): 
    111         return [item for id, item in folder.objectItems() 
    112                 if self._isFolderish(item)] 
     147       """GR: now returns part of a treecache structure. """ 
     148       rpath = self.utool.getRpath(folder) 
     149       tc = self._getTreeCache(folder, rpath=rpath) 
     150       if tc is None: 
     151           # costly BBB fallback 
     152           return [{'rpath': '/'.join((rpath, id)),  
     153                    'id': id}  
     154                   for id, item in folder.objectItems() 
     155                   if self._isFolderish(item)] 
     156       depth = len(rpath.split('/')) # depth of children (l-1+1=l) 
     157       return tc.getList(prefix=rpath, start_depth=depth, stop_depth=depth, 
     158                         filter=True, order=True) 
    113159 
    114160    def _getFolderItems(self, context_obj=None, show_docs=0, 
     
    116162                        context_is_portlet=0, recursive=0, **kw): 
    117163 
     164        
     165        self.log.debug( 
     166            "Enter _getFolderItems context_obj=%s, context_rpath=%s",  
     167            context_obj, context_rpath) 
     168 
    118169        context = self.context 
    119         utool = getToolByName(context, 'portal_url') 
    120         base_url = utool.getBaseUrl() 
     170        base_url = self.utool.getBaseUrl() 
    121171 
    122172        if context_is_portlet: 
     
    179229            'coverage': 'coverage'} 
    180230 
    181         for object in bmf.contentValues(): 
    182             if not self._isFolderish(object): 
    183                 continue 
    184             object_id = object.getId() 
     231        for item in self._folderishChildren(bmf): 
     232            # GR: simply avoid contentValues, did not change anything else 
     233            # once object variable is set 
     234            object_id = item['id'] 
     235            if not bmf.hasObject(object_id): 
     236                continue 
     237            object = getattr(bmf, object_id) 
    185238 
    186239            # filter out objects that cannot be viewed 
     
    266319                content = content or self._getContent(object) 
    267320                if content is not None: 
    268                     description = getattr(content, 'Descriptichildrenon', '') 
     321                    description = getattr(content, 'Description', '') 
    269322 
    270323            object_url = object.absolute_url_path() 
    271324 
    272325            has_folderish_children = self._hasSubFolders(object) 
    273             children = [self.getNode(item.absolute_url_path()
     326            children = [self.getNode(item['rpath']
    274327                        for item in self._folderishChildren(object)] 
    275328            if object_url == context_url: