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

Take out a lock before modifying _CACHES #7663

Merged
merged 2 commits into from
Jun 10, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions changelog.d/7663.bugfix
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Fix intermittent exception during startup, introduced in Synapse 1.14.0.
20 changes: 15 additions & 5 deletions synapse/config/cache.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@

import os
import re
import threading
from typing import Callable, Dict

from ._base import Config, ConfigError
Expand All @@ -25,6 +26,9 @@
# Map from canonicalised cache name to cache.
_CACHES = {}

# a lock on the contents of _CACHES
_CACHES_LOCK = threading.Lock()

_DEFAULT_FACTOR_SIZE = 0.5
_DEFAULT_EVENT_CACHE_SIZE = "10K"

Expand Down Expand Up @@ -66,7 +70,10 @@ def add_resizable_cache(cache_name: str, cache_resize_callback: Callable):
# Some caches have '*' in them which we strip out.
cache_name = _canonicalise_cache_name(cache_name)

_CACHES[cache_name] = cache_resize_callback
# sometimes caches are initialised from background threads, so we need to make
# sure we don't conflict with another thread running a resize operation
with _CACHES_LOCK:
_CACHES[cache_name] = cache_resize_callback

# Ensure all loaded caches are sized appropriately
#
Expand All @@ -87,7 +94,8 @@ def reset():
os.environ.get(_CACHE_PREFIX, _DEFAULT_FACTOR_SIZE)
)
properties.resize_all_caches_func = None
_CACHES.clear()
with _CACHES_LOCK:
_CACHES.clear()

def generate_config_section(self, **kwargs):
return """\
Expand Down Expand Up @@ -193,6 +201,8 @@ def resize_all_caches(self):
For each cache, run the mapped callback function with either
a specific cache factor or the default, global one.
"""
for cache_name, callback in _CACHES.items():
new_factor = self.cache_factors.get(cache_name, self.global_factor)
callback(new_factor)
# block other threads from modifying _CACHES while we iterate it.
with _CACHES_LOCK:
for cache_name, callback in _CACHES.items():
new_factor = self.cache_factors.get(cache_name, self.global_factor)
callback(new_factor)