Mercurial > p > roundup > code
comparison roundup/cgi/templating.py @ 8125:b358da7c89e5 permission-performance
Optimize filtering of search results
Now the Permission class constructor takes an optional argument
'filter'. Now if we do not find a permission on the whole class *and*
all permission objects on the current class with a check method also
have a filter method we can improve search performance by filtering in
the database (instead of in python).
| author | Ralf Schlatterbeck <rsc@runtux.com> |
|---|---|
| date | Mon, 21 Oct 2024 16:11:13 +0200 |
| parents | 2a4d0413bd20 |
| children | f7bd22bdef9d |
comparison
equal
deleted
inserted
replaced
| 8121:2a4d0413bd20 | 8125:b358da7c89e5 |
|---|---|
| 3419 """ % (self._client.client_nonce, self.base) | 3419 """ % (self._client.client_nonce, self.base) |
| 3420 | 3420 |
| 3421 def batch(self, permission='View'): | 3421 def batch(self, permission='View'): |
| 3422 """ Return a batch object for results from the "current search" | 3422 """ Return a batch object for results from the "current search" |
| 3423 """ | 3423 """ |
| 3424 check = self._client.db.security.hasPermission | 3424 sec = self._client.db.security |
| 3425 check = sec.hasPermission | |
| 3425 userid = self._client.userid | 3426 userid = self._client.userid |
| 3426 if not check('Web Access', userid): | 3427 if not check('Web Access', userid): |
| 3427 return Batch(self.client, [], self.pagesize, self.startwith, | 3428 return Batch(self.client, [], self.pagesize, self.startwith, |
| 3428 classname=self.classname) | 3429 classname=self.classname) |
| 3429 | 3430 |
| 3452 else: | 3453 else: |
| 3453 matches = None | 3454 matches = None |
| 3454 | 3455 |
| 3455 # filter for visibility | 3456 # filter for visibility |
| 3456 item_ids = klass.filter(matches, filterspec, sort, group) | 3457 item_ids = klass.filter(matches, filterspec, sort, group) |
| 3457 if check(permission, userid, self.classname, only_no_check = True): | 3458 cn = self.classname |
| 3459 if check(permission, userid, cn, only_no_check = True): | |
| 3458 allowed = item_ids | 3460 allowed = item_ids |
| 3459 else: | 3461 else: |
| 3460 allowed = [id for id in item_ids | 3462 # Note that is_filterable returns True if no permissions are |
| 3461 if check(permission, userid, self.classname, itemid=id)] | 3463 # found. This makes it fail early (with an empty allowed list) |
| 3464 # instead of running through all ids with an empty | |
| 3465 # permission list. | |
| 3466 if sec.is_filterable(permission, userid, cn): | |
| 3467 new_ids = set(item_ids) | |
| 3468 confirmed = set() | |
| 3469 for perm in sec.filter_iter(permission, userid, cn): | |
| 3470 fargs = perm.filter(self._client.db, userid, klass) | |
| 3471 for farg in fargs: | |
| 3472 farg.update(sort=sort, group=group, retired=False) | |
| 3473 result = klass.filter(list(new_ids), **farg) | |
| 3474 new_ids.difference_update(result) | |
| 3475 confirmed.update(result) | |
| 3476 # all allowed? | |
| 3477 if not new_ids: | |
| 3478 break | |
| 3479 # all allowed? | |
| 3480 if not new_ids: | |
| 3481 break | |
| 3482 allowed = list(confirmed) | |
| 3483 else: | |
| 3484 allowed = [id for id in item_ids | |
| 3485 if check(permission, userid, cn, itemid=id)] | |
| 3462 | 3486 |
| 3463 # return the batch object, using IDs only | 3487 # return the batch object, using IDs only |
| 3464 return Batch(self.client, allowed, self.pagesize, self.startwith, | 3488 return Batch(self.client, allowed, self.pagesize, self.startwith, |
| 3465 classname=self.classname) | 3489 classname=self.classname) |
| 3466 | 3490 |
