Edgewall Software

Ticket #6436: t6436-slowness-query-r7610.diff

File t6436-slowness-query-r7610.diff, 9.4 KB (added by cboos, 4 years ago)

Updated patch, doing the restrict_owner transformations outside of the TicketSystem(env).get_ticket_fields()

  • trac/ticket/api.py

     
    1616 
    1717import re 
    1818from datetime import datetime 
     19try: 
     20    import threading 
     21except ImportError: 
     22    import dummy_threading as threading 
    1923 
    2024from genshi.builder import tag 
    2125 
    2226from trac.config import * 
    2327from trac.core import * 
    24 from trac.perm import IPermissionRequestor, PermissionSystem, PermissionError 
     28from trac.perm import IPermissionRequestor, PermissionCache, PermissionSystem 
    2529from trac.resource import IResourceManager 
    26 from trac.util import Ranges 
     30from trac.util import Ranges, arity 
    2731from trac.util.compat import set, sorted 
    2832from trac.util.datefmt import utc 
    2933from trac.util.text import shorten_line, obfuscate_email_address 
     
    157161    def __init__(self): 
    158162        self.log.debug('action controllers for ticket workflow: %r' %  
    159163                [c.__class__.__name__ for c in self.action_controllers]) 
     164        self._fields_lock = threading.RLock() 
    160165 
    161166    # Public API 
    162167 
     
    185190 
    186191    def get_ticket_fields(self): 
    187192        """Returns the list of fields available for tickets.""" 
     193        # This is now cached - as it makes quite a number of things faster, 
     194        # e.g. #6436 
     195        if self._fields is None: 
     196            self._fields_lock.acquire() 
     197            try: 
     198                self._fields = self._get_ticket_fields() 
     199            finally: 
     200                self._fields_lock.release() 
     201        return [f.copy() for f in self._fields] 
     202 
     203    def reset_ticket_fields(self): 
     204        self._fields_lock.acquire() 
     205        try: 
     206            self._fields = None 
     207            self.config.touch() # brute force approach for now 
     208        finally: 
     209            self._fields_lock.release() 
     210 
     211    _fields = None 
     212    def _get_ticket_fields(self): 
    188213        from trac.ticket import model 
    189214 
    190215        db = self.env.get_db_cnx() 
     
    195220            field = {'name': name, 'type': 'text', 'label': name.title()} 
    196221            fields.append(field) 
    197222 
    198         # Owner field, can be text or drop-down depending on configuration 
     223        # Owner field, by default text but can be changed dynamically  
     224        # into a drop-down depending on configuration (restrict_owner=true) 
    199225        field = {'name': 'owner', 'label': 'Owner'} 
    200         if self.restrict_owner: 
    201             field['type'] = 'select' 
    202             perm = PermissionSystem(self.env) 
    203             field['options'] = perm.get_users_with_permission('TICKET_MODIFY') 
    204             field['options'].sort() 
    205             field['optional'] = True 
    206         else: 
    207             field['type'] = 'text' 
     226        field['type'] = 'text' 
    208227        fields.append(field) 
    209228 
    210229        # Description 
     
    256275        return fields 
    257276 
    258277    def get_custom_fields(self): 
     278        if self._custom_fields is None: 
     279            self._fields_lock.acquire() 
     280            try: 
     281                self._custom_fields = self._get_custom_fields() 
     282            finally: 
     283                self._fields_lock.release() 
     284        return [f.copy() for f in self._custom_fields] 
     285 
     286    _custom_fields = None 
     287    def _get_custom_fields(self): 
    259288        fields = [] 
    260289        config = self.config['ticket-custom'] 
    261290        for name in [option for option, value in config.options() 
     
    280309        fields.sort(lambda x, y: cmp(x['order'], y['order'])) 
    281310        return fields 
    282311 
     312    def eventually_restrict_owner(self, field, ticket=None): 
     313        """Restrict given owner field to be a list of users having 
     314        the TICKET_MODIFY permission (for the given ticket) 
     315        """ 
     316        if self.restrict_owner: 
     317            field['type'] = 'select' 
     318            possible_owners = [] 
     319            for user in PermissionSystem(self.env) \ 
     320                    .get_users_with_permission('TICKET_MODIFY'): 
     321                if not ticket or \ 
     322                        'TICKET_MODIFY' in PermissionCache(self.env, user, 
     323                                                           ticket.resource): 
     324                    possible_owners.append(user) 
     325            possible_owners.sort() 
     326            field['options'] = possible_owners 
     327            field['optional'] = True 
     328 
    283329    # IPermissionRequestor methods 
    284330 
    285331    def get_permission_actions(self): 
  • trac/ticket/web_ui.py

     
    10671067    def _prepare_fields(self, req, ticket): 
    10681068        context = Context.from_request(req, ticket.resource) 
    10691069        fields = [] 
    1070         ownerField = None 
     1070        owner_field = None 
    10711071        for field in ticket.fields: 
    10721072            name = field['name'] 
    10731073            type_ = field['type'] 
     
    10771077                        'resolution'): 
    10781078                field['skip'] = True 
    10791079            elif name == 'owner': 
     1080                TicketSystem(self.env).eventually_restrict_owner(field, ticket) 
     1081                type_ = field['type'] 
    10801082                field['skip'] = True 
    10811083                if not ticket.exists: 
    10821084                    field['label'] = 'Assign to' 
    10831085                    if 'TICKET_MODIFY' in req.perm(ticket.resource): 
    10841086                        field['skip'] = False 
    1085                         ownerField = field 
     1087                        owner_field = field 
    10861088            elif name == 'milestone': 
    10871089                milestones = [(opt, Milestone(self.env, opt)) 
    10881090                              for opt in field['options']] 
     
    11471149            fields.append(field) 
    11481150         
    11491151        # Move owner field to end when shown 
    1150         if ownerField is not None: 
    1151             fields.remove(ownerField) 
    1152             fields.append(ownerField) 
     1152        if owner_field is not None: 
     1153            fields.remove(owner_field) 
     1154            fields.append(owner_field) 
    11531155        return fields 
    11541156         
    11551157    def _insert_ticket_data(self, req, ticket, data, author_id, field_changes): 
  • trac/ticket/model.py

     
    408408            db.commit() 
    409409        self.value = self._old_value = None 
    410410        self.name = self._old_name = None 
     411        TicketSystem(self.env).reset_ticket_fields() 
    411412 
    412413    def insert(self, db=None): 
    413414        assert not self.exists, 'Cannot insert existing %s' % self.type 
     
    433434            db.commit() 
    434435        self._old_name = self.name 
    435436        self._old_value = self.value 
     437        TicketSystem(self.env).reset_ticket_fields() 
    436438 
    437439    def update(self, db=None): 
    438440        assert self.exists, 'Cannot update non-existent %s' % self.type 
     
    459461            db.commit() 
    460462        self._old_name = self.name 
    461463        self._old_value = self.value 
     464        TicketSystem(self.env).reset_ticket_fields() 
    462465 
    463466    def select(cls, env, db=None): 
    464467        if not db: 
     
    545548 
    546549        if handle_ta: 
    547550            db.commit() 
     551        TicketSystem(self.env).reset_ticket_fields() 
    548552 
    549553    def insert(self, db=None): 
    550554        assert not self.exists, 'Cannot insert existing component' 
     
    564568 
    565569        if handle_ta: 
    566570            db.commit() 
     571        TicketSystem(self.env).reset_ticket_fields() 
    567572 
    568573    def update(self, db=None): 
    569574        assert self.exists, 'Cannot update non-existent component' 
     
    589594 
    590595        if handle_ta: 
    591596            db.commit() 
     597        TicketSystem(self.env).reset_ticket_fields() 
    592598 
    593599    def select(cls, env, db=None): 
    594600        if not db: 
     
    669675 
    670676        if handle_ta: 
    671677            db.commit() 
     678        TicketSystem(self.env).reset_ticket_fields() 
    672679 
    673680    def insert(self, db=None): 
    674681        assert self.name, 'Cannot create milestone with no name' 
     
    688695 
    689696        if handle_ta: 
    690697            db.commit() 
     698        TicketSystem(self.env).reset_ticket_fields() 
    691699 
    692700    def update(self, db=None): 
    693701        assert self.name, 'Cannot update milestone with no name' 
     
    713721 
    714722        if handle_ta: 
    715723            db.commit() 
     724        TicketSystem(self.env).reset_ticket_fields() 
    716725 
    717726    def select(cls, env, include_completed=True, db=None): 
    718727        if not db: 
     
    775784 
    776785        if handle_ta: 
    777786            db.commit() 
     787        TicketSystem(self.env).reset_ticket_fields() 
    778788 
    779789    def insert(self, db=None): 
    780790        assert not self.exists, 'Cannot insert existing version' 
     
    794804 
    795805        if handle_ta: 
    796806            db.commit() 
     807        TicketSystem(self.env).reset_ticket_fields() 
    797808 
    798809    def update(self, db=None): 
    799810        assert self.exists, 'Cannot update non-existent version' 
     
    819830 
    820831        if handle_ta: 
    821832            db.commit() 
     833        TicketSystem(self.env).reset_ticket_fields() 
    822834 
    823835    def select(cls, env, db=None): 
    824836        if not db: 
  • trac/ticket/query.py

     
    885885            orig_time = query_time 
    886886 
    887887        context = Context.from_request(req, 'query') 
     888        owner_field = [f for f in query.fields if f['name'] == 'owner'] 
     889        if owner_field: 
     890            TicketSystem(self.env).eventually_restrict_owner(owner_field[0]) 
    888891        data = query.template_data(context, tickets, orig_list, orig_time, req) 
    889892 
    890893        # For clients without JavaScript, we add a new constraint here if