Skip to content
This repository has been archived by the owner on Apr 26, 2024. It is now read-only.

Commit

Permalink
Implement and use an @lru_cache decorator (#8595)
Browse files Browse the repository at this point in the history
We don't always need the full power of a DeferredCache.
  • Loading branch information
richvdh authored Oct 30, 2020
1 parent fd7c743 commit cbc82aa
Show file tree
Hide file tree
Showing 4 changed files with 272 additions and 61 deletions.
1 change: 1 addition & 0 deletions changelog.d/8595.misc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Implement and use an @lru_cache decorator.
37 changes: 24 additions & 13 deletions synapse/push/bulk_push_rule_evaluator.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@
# limitations under the License.

import logging
from collections import namedtuple

import attr
from prometheus_client import Counter

from synapse.api.constants import EventTypes, Membership, RelationTypes
Expand All @@ -26,7 +26,8 @@
from synapse.state import POWER_KEY
from synapse.util.async_helpers import Linearizer
from synapse.util.caches import register_cache
from synapse.util.caches.descriptors import cached
from synapse.util.caches.descriptors import lru_cache
from synapse.util.caches.lrucache import LruCache

from .push_rule_evaluator import PushRuleEvaluatorForEvent

Expand Down Expand Up @@ -120,7 +121,7 @@ async def _get_rules_for_event(self, event, context):
dict of user_id -> push_rules
"""
room_id = event.room_id
rules_for_room = await self._get_rules_for_room(room_id)
rules_for_room = self._get_rules_for_room(room_id)

rules_by_user = await rules_for_room.get_rules(event, context)

Expand All @@ -138,7 +139,7 @@ async def _get_rules_for_event(self, event, context):

return rules_by_user

@cached()
@lru_cache()
def _get_rules_for_room(self, room_id):
"""Get the current RulesForRoom object for the given room id
Expand Down Expand Up @@ -275,12 +276,14 @@ class RulesForRoom:
the entire cache for the room.
"""

def __init__(self, hs, room_id, rules_for_room_cache, room_push_rule_cache_metrics):
def __init__(
self, hs, room_id, rules_for_room_cache: LruCache, room_push_rule_cache_metrics
):
"""
Args:
hs (HomeServer)
room_id (str)
rules_for_room_cache(Cache): The cache object that caches these
rules_for_room_cache: The cache object that caches these
RoomsForUser objects.
room_push_rule_cache_metrics (CacheMetric)
"""
Expand Down Expand Up @@ -489,13 +492,21 @@ def update_cache(self, sequence, members, rules_by_user, state_group):
self.state_group = state_group


class _Invalidation(namedtuple("_Invalidation", ("cache", "room_id"))):
# We rely on _CacheContext implementing __eq__ and __hash__ sensibly,
# which namedtuple does for us (i.e. two _CacheContext are the same if
# their caches and keys match). This is important in particular to
# dedupe when we add callbacks to lru cache nodes, otherwise the number
# of callbacks would grow.
@attr.attrs(slots=True, frozen=True)
class _Invalidation:
# _Invalidation is passed as an `on_invalidate` callback to bulk_get_push_rules,
# which means that it it is stored on the bulk_get_push_rules cache entry. In order
# to ensure that we don't accumulate lots of redunant callbacks on the cache entry,
# we need to ensure that two _Invalidation objects are "equal" if they refer to the
# same `cache` and `room_id`.
#
# attrs provides suitable __hash__ and __eq__ methods, provided we remember to
# set `frozen=True`.

cache = attr.ib(type=LruCache)
room_id = attr.ib(type=str)

def __call__(self):
rules = self.cache.get_immediate(self.room_id, None, update_metrics=False)
rules = self.cache.get(self.room_id, None, update_metrics=False)
if rules:
rules.invalidate_all()
Loading

0 comments on commit cbc82aa

Please sign in to comment.