Take out a lock before modifying _CACHES (#7663)

This should fix #7610.
pull/7680/head
Richard van der Hoff 2020-06-10 18:27:49 +01:00 committed by GitHub
parent fcd6961441
commit 0df618f813
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 16 additions and 5 deletions

1
changelog.d/7663.bugfix Normal file
View File

@ -0,0 +1 @@
Fix intermittent exception during startup, introduced in Synapse 1.14.0.

View File

@ -15,6 +15,7 @@
import os import os
import re import re
import threading
from typing import Callable, Dict from typing import Callable, Dict
from ._base import Config, ConfigError from ._base import Config, ConfigError
@ -25,6 +26,9 @@ _CACHE_PREFIX = "SYNAPSE_CACHE_FACTOR"
# Map from canonicalised cache name to cache. # Map from canonicalised cache name to cache.
_CACHES = {} _CACHES = {}
# a lock on the contents of _CACHES
_CACHES_LOCK = threading.Lock()
_DEFAULT_FACTOR_SIZE = 0.5 _DEFAULT_FACTOR_SIZE = 0.5
_DEFAULT_EVENT_CACHE_SIZE = "10K" _DEFAULT_EVENT_CACHE_SIZE = "10K"
@ -66,7 +70,10 @@ def add_resizable_cache(cache_name: str, cache_resize_callback: Callable):
# Some caches have '*' in them which we strip out. # Some caches have '*' in them which we strip out.
cache_name = _canonicalise_cache_name(cache_name) 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 # Ensure all loaded caches are sized appropriately
# #
@ -87,7 +94,8 @@ class CacheConfig(Config):
os.environ.get(_CACHE_PREFIX, _DEFAULT_FACTOR_SIZE) os.environ.get(_CACHE_PREFIX, _DEFAULT_FACTOR_SIZE)
) )
properties.resize_all_caches_func = None properties.resize_all_caches_func = None
_CACHES.clear() with _CACHES_LOCK:
_CACHES.clear()
def generate_config_section(self, **kwargs): def generate_config_section(self, **kwargs):
return """\ return """\
@ -193,6 +201,8 @@ class CacheConfig(Config):
For each cache, run the mapped callback function with either For each cache, run the mapped callback function with either
a specific cache factor or the default, global one. a specific cache factor or the default, global one.
""" """
for cache_name, callback in _CACHES.items(): # block other threads from modifying _CACHES while we iterate it.
new_factor = self.cache_factors.get(cache_name, self.global_factor) with _CACHES_LOCK:
callback(new_factor) for cache_name, callback in _CACHES.items():
new_factor = self.cache_factors.get(cache_name, self.global_factor)
callback(new_factor)