mirror of
https://mau.dev/maunium/synapse.git
synced 2024-12-14 15:53:51 +01:00
Don't hold onto full state in state cache (#13324)
This commit is contained in:
parent
10e4093839
commit
13341dde5a
2 changed files with 55 additions and 16 deletions
1
changelog.d/13324.misc
Normal file
1
changelog.d/13324.misc
Normal file
|
@ -0,0 +1 @@
|
||||||
|
Reduce the amount of state we store in the `state_cache`.
|
|
@ -14,7 +14,7 @@
|
||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
import heapq
|
import heapq
|
||||||
import logging
|
import logging
|
||||||
from collections import defaultdict
|
from collections import ChainMap, defaultdict
|
||||||
from typing import (
|
from typing import (
|
||||||
TYPE_CHECKING,
|
TYPE_CHECKING,
|
||||||
Any,
|
Any,
|
||||||
|
@ -92,8 +92,11 @@ class _StateCacheEntry:
|
||||||
prev_group: Optional[int] = None,
|
prev_group: Optional[int] = None,
|
||||||
delta_ids: Optional[StateMap[str]] = None,
|
delta_ids: Optional[StateMap[str]] = None,
|
||||||
):
|
):
|
||||||
if state is None and state_group is None:
|
if state is None and state_group is None and prev_group is None:
|
||||||
raise Exception("Either state or state group must be not None")
|
raise Exception("One of state, state_group or prev_group must be not None")
|
||||||
|
|
||||||
|
if prev_group is not None and delta_ids is None:
|
||||||
|
raise Exception("If prev_group is set so must delta_ids")
|
||||||
|
|
||||||
# A map from (type, state_key) to event_id.
|
# A map from (type, state_key) to event_id.
|
||||||
#
|
#
|
||||||
|
@ -120,18 +123,48 @@ class _StateCacheEntry:
|
||||||
if self._state is not None:
|
if self._state is not None:
|
||||||
return self._state
|
return self._state
|
||||||
|
|
||||||
assert self.state_group is not None
|
if self.state_group is not None:
|
||||||
|
return await state_storage.get_state_ids_for_group(
|
||||||
|
self.state_group, state_filter
|
||||||
|
)
|
||||||
|
|
||||||
return await state_storage.get_state_ids_for_group(
|
assert self.prev_group is not None and self.delta_ids is not None
|
||||||
self.state_group, state_filter
|
|
||||||
|
prev_state = await state_storage.get_state_ids_for_group(
|
||||||
|
self.prev_group, state_filter
|
||||||
)
|
)
|
||||||
|
|
||||||
def __len__(self) -> int:
|
# ChainMap expects MutableMapping, but since we're using it immutably
|
||||||
# The len should is used to estimate how large this cache entry is, for
|
# its safe to give it immutable maps.
|
||||||
# cache eviction purposes. This is why if `self.state` is None it's fine
|
return ChainMap(self.delta_ids, prev_state) # type: ignore[arg-type]
|
||||||
# to return 1.
|
|
||||||
|
|
||||||
return len(self._state) if self._state else 1
|
def set_state_group(self, state_group: int) -> None:
|
||||||
|
"""Update the state group assigned to this state (e.g. after we've
|
||||||
|
persisted it).
|
||||||
|
|
||||||
|
Note: this will cause the cache entry to drop any stored state.
|
||||||
|
"""
|
||||||
|
|
||||||
|
self.state_group = state_group
|
||||||
|
|
||||||
|
# We clear out the state as we know longer need to explicitly keep it in
|
||||||
|
# the `state_cache` (as the store state group cache will do that).
|
||||||
|
self._state = None
|
||||||
|
|
||||||
|
def __len__(self) -> int:
|
||||||
|
# The len should be used to estimate how large this cache entry is, for
|
||||||
|
# cache eviction purposes. This is why it's fine to return 1 if we're
|
||||||
|
# not storing any state.
|
||||||
|
|
||||||
|
length = 0
|
||||||
|
|
||||||
|
if self._state:
|
||||||
|
length += len(self._state)
|
||||||
|
|
||||||
|
if self.delta_ids:
|
||||||
|
length += len(self.delta_ids)
|
||||||
|
|
||||||
|
return length or 1 # Make sure its not 0.
|
||||||
|
|
||||||
|
|
||||||
class StateHandler:
|
class StateHandler:
|
||||||
|
@ -320,7 +353,7 @@ class StateHandler:
|
||||||
current_state_ids=state_ids_before_event,
|
current_state_ids=state_ids_before_event,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
entry.state_group = state_group_before_event
|
entry.set_state_group(state_group_before_event)
|
||||||
else:
|
else:
|
||||||
state_group_before_event = entry.state_group
|
state_group_before_event = entry.state_group
|
||||||
|
|
||||||
|
@ -747,7 +780,7 @@ def _make_state_cache_entry(
|
||||||
old_state_event_ids = set(state.values())
|
old_state_event_ids = set(state.values())
|
||||||
if new_state_event_ids == old_state_event_ids:
|
if new_state_event_ids == old_state_event_ids:
|
||||||
# got an exact match.
|
# got an exact match.
|
||||||
return _StateCacheEntry(state=new_state, state_group=sg)
|
return _StateCacheEntry(state=None, state_group=sg)
|
||||||
|
|
||||||
# TODO: We want to create a state group for this set of events, to
|
# TODO: We want to create a state group for this set of events, to
|
||||||
# increase cache hits, but we need to make sure that it doesn't
|
# increase cache hits, but we need to make sure that it doesn't
|
||||||
|
@ -769,9 +802,14 @@ def _make_state_cache_entry(
|
||||||
prev_group = old_group
|
prev_group = old_group
|
||||||
delta_ids = n_delta_ids
|
delta_ids = n_delta_ids
|
||||||
|
|
||||||
return _StateCacheEntry(
|
if prev_group is not None:
|
||||||
state=new_state, state_group=None, prev_group=prev_group, delta_ids=delta_ids
|
# If we have a prev group and deltas then we can drop the new state from
|
||||||
)
|
# the cache (to reduce memory usage).
|
||||||
|
return _StateCacheEntry(
|
||||||
|
state=None, state_group=None, prev_group=prev_group, delta_ids=delta_ids
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
return _StateCacheEntry(state=new_state, state_group=None)
|
||||||
|
|
||||||
|
|
||||||
@attr.s(slots=True, auto_attribs=True)
|
@attr.s(slots=True, auto_attribs=True)
|
||||||
|
|
Loading…
Reference in a new issue