diff options
author | Amber H. Brown <hawkowl@atleastfornow.net> | 2020-02-17 17:47:56 +1100 |
---|---|---|
committer | Amber H. Brown <hawkowl@atleastfornow.net> | 2020-02-17 17:47:56 +1100 |
commit | 5f508e728af3f842f78ec435fd0393dd3a07e854 (patch) | |
tree | eecf6826891b422b7ba21fcc00055f175b7a3866 | |
parent | Merge remote-tracking branch 'origin/develop' into hawkowl/cache-config-witho... (diff) | |
download | synapse-5f508e728af3f842f78ec435fd0393dd3a07e854.tar.xz |
add tests for individual cache sizing, and fix up the individual cache sizing logic that got deleted when resizing-on-the-fly did
-rw-r--r-- | synapse/config/cache.py | 30 | ||||
-rw-r--r-- | tests/config/test_cache.py | 66 |
2 files changed, 91 insertions, 5 deletions
diff --git a/synapse/config/cache.py b/synapse/config/cache.py index d6dadc5fde..dbc2971eeb 100644 --- a/synapse/config/cache.py +++ b/synapse/config/cache.py @@ -39,20 +39,35 @@ _DEFAULT_CONFIG = """\ # """ +# Callback to ensure that all caches are the correct size, registered when the +# configuration has been loaded. +_ENSURE_CORRECT_CACHE_SIZING = None + def add_resizable_cache(cache_name, cache_resize_callback): _CACHES[cache_name.lower()] = cache_resize_callback - cache_resize_callback(DEFAULT_CACHE_SIZE_FACTOR) + if _ENSURE_CORRECT_CACHE_SIZING: + _ENSURE_CORRECT_CACHE_SIZING() class CacheConfig(Config): section = "caches" _environ = os.environ + @staticmethod + def _reset(): + global DEFAULT_CACHE_SIZE_FACTOR + global _ENSURE_CORRECT_CACHE_SIZING + + DEFAULT_CACHE_SIZE_FACTOR = float(os.environ.get(_CACHE_PREFIX, 0.5)) + _ENSURE_CORRECT_CACHE_SIZING = None + _CACHES.clear() + def read_config(self, config, **kwargs): self.event_cache_size = self.parse_size(config.get("event_cache_size", "10K")) global DEFAULT_CACHE_SIZE_FACTOR + global _ENSURE_CORRECT_CACHE_SIZING cache_config = config.get("caches", {}) @@ -79,9 +94,7 @@ class CacheConfig(Config): individual_factors.update(individual_factors_config) - self.cache_factors = defaultdict( - lambda: self.global_factor - ) # type: DefaultDict[str, float] + self.cache_factors = dict() # type: Dict[str, float] for cache, factor in individual_factors.items(): if not isinstance(factor, (int, float)): @@ -89,3 +102,12 @@ class CacheConfig(Config): "caches.per_cache_factors.%s must be a number" % (cache.lower(),) ) self.cache_factors[cache.lower()] = factor + + # Register the global callback so that the individual cache sizes get set. + def ensure_cache_sizes(): + for cache_name, callback in _CACHES.items(): + new_factor = self.cache_factors.get(cache_name, self.global_factor) + callback(new_factor) + + _ENSURE_CORRECT_CACHE_SIZING = ensure_cache_sizes + _ENSURE_CORRECT_CACHE_SIZING() diff --git a/tests/config/test_cache.py b/tests/config/test_cache.py index 94370265f1..f8901a4612 100644 --- a/tests/config/test_cache.py +++ b/tests/config/test_cache.py @@ -14,7 +14,8 @@ # limitations under the License. from synapse.config._base import Config, RootConfig -from synapse.config.cache import CacheConfig +from synapse.config.cache import CacheConfig, add_resizable_cache +from synapse.util.caches.lrucache import LruCache from tests.unittest import TestCase @@ -28,6 +29,9 @@ class TestConfig(RootConfig): class CacheConfigTests(TestCase): + def setUp(self): + CacheConfig._reset() + def test_individual_caches_from_environ(self): """ Individual cache factors will be loaded from the environment. @@ -59,3 +63,63 @@ class CacheConfigTests(TestCase): dict(t.caches.cache_factors), {"foo": 2.0, "bar": 3.0, "something_or_other": 2.0}, ) + + def test_individual_instantiated_before_config_load(self): + """ + If a cache is instantiated before the config is read, it will be given + the default cache size in the interim, and then resized once the config + is loaded. + """ + cache = LruCache(100) + add_resizable_cache("foo", cache.set_cache_factor) + self.assertEqual(cache.max_size, 50) + + config = {"caches": {"per_cache_factors": {"foo": 3}}} + t = TestConfig() + t.read_config(config, config_dir_path="", data_dir_path="") + + self.assertEqual(cache.max_size, 300) + + def test_individual_instantiated_after_config_load(self): + """ + If a cache is instantiated after the config is read, it will be + immediately resized to the correct size given the per_cache_factor if + there is one. + """ + config = {"caches": {"per_cache_factors": {"foo": 2}}} + t = TestConfig() + t.read_config(config, config_dir_path="", data_dir_path="") + + cache = LruCache(100) + add_resizable_cache("foo", cache.set_cache_factor) + self.assertEqual(cache.max_size, 200) + + def test_global_instantiated_before_config_load(self): + """ + If a cache is instantiated before the config is read, it will be given + the default cache size in the interim, and then resized to the new + default cache size once the config is loaded. + """ + cache = LruCache(100) + add_resizable_cache("foo", cache.set_cache_factor) + self.assertEqual(cache.max_size, 50) + + config = {"caches": {"global_factor": 4}} + t = TestConfig() + t.read_config(config, config_dir_path="", data_dir_path="") + + self.assertEqual(cache.max_size, 400) + + def test_global_instantiated_after_config_load(self): + """ + If a cache is instantiated after the config is read, it will be + immediately resized to the correct size given the global factor if there + is no per-cache factor. + """ + config = {"caches": {"global_factor": 1.5}} + t = TestConfig() + t.read_config(config, config_dir_path="", data_dir_path="") + + cache = LruCache(100) + add_resizable_cache("foo", cache.set_cache_factor) + self.assertEqual(cache.max_size, 150) |