Changeset 4366


Ignore:
Timestamp:
Oct 1, 2008, 10:47:15 PM (16 years ago)
Author:
osimons
Message:

TocMacro: Fixed a serious bug whereby the 0.11 version of the macro would keep a database connection open after execution.

This innocent-looking line...

self.formatter = formatter

... essentially attaches the transient formatter and its formatter.db connection to the instantiated plugin/component that lives for the lifetime of the environment (that in most setups gets cached for the duration of the process or until event like config change forces reload). Next time the macro executes it will free the old connection, and replace it with the new.

The problem continually ties up 1 connection of a process-wide default maximum number of 10. Many projects using the macro can get to the point where it locks the process due to no database connections being available - failing with TimeoutError. Particularly dangerous with embedded interpreter on Apache for Windows as it serves all requests using just a single process.

Code is changed to not persist the formatter, but instead pass it around as needed.

To all users of 0.11 version: Please upgrade!

File:
1 edited

Legend:

Unmodified
Added
Removed
  • tocmacro/0.11/tractoc/macro.py

    r3418 r4366  
    104104   
    105105    def expand_macro(self, formatter, name, args):
    106         self.formatter = formatter
    107         self.context = formatter.context
    108         self.resource = formatter.context.resource
     106        context = formatter.context
     107        resource = formatter.context.resource
    109108       
    110109        # Bail out if we are in a no-float zone
     
    113112            return ''
    114113       
    115         current_page = self.resource.id
     114        current_page = resource.id
    116115         
    117116        # Split the args
     
    185184        active = len(pagenames) > 1
    186185        for pagename in pagenames:
    187             page_resource = self.resource(id=pagename)
    188             if not 'WIKI_VIEW' in self.context.perm(page_resource):
     186            page_resource = resource(id=pagename)
     187            if not 'WIKI_VIEW' in context.perm(page_resource):
    189188                # Not access to the page, so should not be included
    190189                continue
    191190            if 'title_index' in params:
    192                 self._render_title_index(ol, page_resource, active and \
    193                             pagename == current_page,
     191                self._render_title_index(formatter, ol, page_resource,
     192                            active and pagename == current_page,
    194193                            params['min_depth'] < 2)
    195194            else:
    196                 self._render_page_outline(ol, page_resource, active, params)
     195                self._render_page_outline(formatter, ol, page_resource,
     196                                                        active, params)
    197197        return base
    198198
    199     def get_page_text(self, page_resource):
     199    def get_page_text(self, formatter, page_resource):
    200200        """Return a tuple of `(text, exists)` for the given page (resource)."""
    201         if page_resource.id == self.resource.id:
    202             return (self.formatter.source, True)
     201        if page_resource.id == formatter.context.resource.id:
     202            return (formatter.source, True)
    203203        else:
    204204            page = WikiPage(self.env, page_resource)
    205205            return (page.text, page.exists)
    206206
    207     def _render_title_index(self, ol, page_resource, active, show_title):
    208         page_text, page_exists = self.get_page_text(page_resource)
     207    def _render_title_index(self, formatter, ol, page_resource, active, show_title):
     208        page_text, page_exists = self.get_page_text(formatter, page_resource)
    209209        if not page_exists:
    210210            ol.append(system_message('Error: No page matching %s found' %
    211211                                     page_resource.id))
    212212            return
    213         ctx = self.context(page_resource)
     213        ctx = formatter.context(page_resource)
    214214        fmt = OutlineFormatter(self.env, ctx)
    215215        fmt.format(page_text, NullOut())
     
    222222                      class_= active and 'active' or None)))
    223223
    224     def _render_page_outline(self, ol, page_resource, active, params):
     224    def _render_page_outline(self, formatter, ol, page_resource, active, params):
    225225        page = params.get('root', '') + page_resource.id
    226         page_text, page_exists = self.get_page_text(page_resource)
     226        page_text, page_exists = self.get_page_text(formatter, page_resource)
    227227        if page_exists:
    228             ctx = self.context(page_resource)
     228            ctx = formatter.context(page_resource)
    229229            fmt = OutlineFormatter(self.env, ctx)
    230230            fmt.format(page_text, NullOut())
    231231            outline_tree(self.env, ol, fmt.outline, ctx,
    232                          active and page_resource.id == self.resource.id,
    233                          params['min_depth'], params['max_depth'])
     232                    active and page_resource.id == formatter.context.resource.id,
     233                    params['min_depth'], params['max_depth'])
    234234        else:
    235235            ol.append(system_message('Error: Page %s does not exist' %
Note: See TracChangeset for help on using the changeset viewer.