Aggressive caching of settings

This commit is contained in:
Raphael Michel
2016-11-08 15:11:58 +01:00
parent 368d04ae72
commit c53691cb8c
4 changed files with 45 additions and 10 deletions
+1
View File
@@ -49,6 +49,7 @@ class Event(LoggedModel):
:type plugins: str :type plugins: str
""" """
settings_namespace = 'event'
organizer = models.ForeignKey(Organizer, related_name="events", on_delete=models.PROTECT) organizer = models.ForeignKey(Organizer, related_name="events", on_delete=models.PROTECT)
name = I18nCharField( name = I18nCharField(
max_length=200, max_length=200,
+1
View File
@@ -22,6 +22,7 @@ class Organizer(LoggedModel):
:type slug: str :type slug: str
""" """
settings_namespace = 'organizer'
name = models.CharField(max_length=200, name = models.CharField(max_length=200,
verbose_name=_("Name")) verbose_name=_("Name"))
slug = models.SlugField( slug = models.SlugField(
+36 -9
View File
@@ -1,6 +1,8 @@
import decimal import decimal
import json import json
from datetime import date, datetime, time from datetime import date, datetime, time
from django.core.cache import cache
from typing import Any, Dict, Optional from typing import Any, Dict, Optional
import dateutil.parser import dateutil.parser
@@ -316,17 +318,32 @@ class SettingsProxy:
self._obj = obj self._obj = obj
self._parent = parent self._parent = parent
self._cached_obj = None self._cached_obj = None
self._write_cached_obj = None
self._type = type self._type = type
def _cache(self) -> Dict[str, Any]: def _cache(self) -> Dict[str, Any]:
if self._cached_obj is None: if self._cached_obj is None:
self._cached_obj = {} self._cached_obj = cache.get_or_set(
for setting in self._obj.setting_objects.all(): 'settings_{}_{}'.format(self._obj.settings_namespace, self._obj.pk),
self._cached_obj[setting.key] = setting lambda: {s.key: s.value for s in self._obj.setting_objects.all()},
timeout=1800
)
return self._cached_obj return self._cached_obj
def _write_cache(self) -> Dict[str, Any]:
if self._write_cached_obj is None:
self._write_cached_obj = {
s.key: s for s in self._obj.setting_objects.all()
}
return self._write_cached_obj
def _flush(self) -> None: def _flush(self) -> None:
self._cached_obj = None self._cached_obj = None
self._write_cached_obj = None
self._flush_external_cache()
def _flush_external_cache(self):
cache.delete('settings_{}_{}'.format(self._obj.settings_namespace, self._obj.pk))
def freeze(self) -> dict: def freeze(self) -> dict:
""" """
@@ -338,7 +355,7 @@ class SettingsProxy:
settings[key] = self._unserialize(v['default'], v['type']) settings[key] = self._unserialize(v['default'], v['type'])
if self._parent: if self._parent:
settings.update(self._parent.settings.freeze()) settings.update(self._parent.settings.freeze())
for key, value in self._cache().items(): for key in self._cache():
settings[key] = self.get(key) settings[key] = self.get(key)
return settings return settings
@@ -413,7 +430,7 @@ class SettingsProxy:
as_type = DEFAULTS[key]['type'] as_type = DEFAULTS[key]['type']
if key in self._cache(): if key in self._cache():
value = self._cache()[key].value value = self._cache()[key]
else: else:
value = None value = None
if self._parent: if self._parent:
@@ -445,13 +462,16 @@ class SettingsProxy:
""" """
Stores a setting to the database of its object. Stores a setting to the database of its object.
""" """
if key in self._cache(): wc = self._write_cache()
s = self._cache()[key] if key in wc:
s = wc[key]
else: else:
s = self._type(object=self._obj, key=key) s = self._type(object=self._obj, key=key)
s.value = self._serialize(value) s.value = self._serialize(value)
s.save() s.save()
self._cache()[key] = s self._cache()[key] = s.value
wc[key] = s
self._flush_external_cache()
def __delattr__(self, key: str) -> None: def __delattr__(self, key: str) -> None:
if key.startswith('_'): if key.startswith('_'):
@@ -465,10 +485,15 @@ class SettingsProxy:
""" """
Deletes a setting from this object's storage. Deletes a setting from this object's storage.
""" """
if key in self._write_cache():
self._write_cache()[key].delete()
del self._write_cache()[key]
if key in self._cache(): if key in self._cache():
self._cache()[key].delete()
del self._cache()[key] del self._cache()[key]
self._flush_external_cache()
class SettingsSandbox: class SettingsSandbox:
""" """
@@ -515,8 +540,10 @@ class SettingsSandbox:
class GlobalSettingsObject(): class GlobalSettingsObject():
settings_namespace = 'global'
def __init__(self): def __init__(self):
self.settings = SettingsProxy(self, type=GlobalSetting) self.settings = SettingsProxy(self, type=GlobalSetting)
self.setting_objects = GlobalSetting.objects self.setting_objects = GlobalSetting.objects
self.slug = '_global' self.slug = '_global'
self.pk = '_global'
+7 -1
View File
@@ -21,11 +21,14 @@ class SettingsTestCase(TestCase):
'type': str 'type': str
} }
self.global_settings = GlobalSettingsObject() self.global_settings = GlobalSettingsObject()
self.global_settings.settings._flush()
self.organizer = Organizer.objects.create(name='Dummy', slug='dummy') self.organizer = Organizer.objects.create(name='Dummy', slug='dummy')
self.organizer.settings._flush()
self.event = Event.objects.create( self.event = Event.objects.create(
organizer=self.organizer, name='Dummy', slug='dummy', organizer=self.organizer, name='Dummy', slug='dummy',
date_from=now(), date_from=now(),
) )
self.event.settings._flush()
def test_global_set_explicit(self): def test_global_set_explicit(self):
self.global_settings.settings.test = 'foo' self.global_settings.settings.test = 'foo'
@@ -287,8 +290,11 @@ class SettingsTestCase(TestCase):
self.event.organizer.settings.set('bar', 'baz') self.event.organizer.settings.set('bar', 'baz')
self.event.organizer.settings.set('foo', 'baz') self.event.organizer.settings.set('foo', 'baz')
self.event.settings.set('foo', 'bar') self.event.settings.set('foo', 'bar')
frozen = self.event.settings.freeze()
self.event.settings.set('foo', 'notfrozen')
try: try:
self.assertEqual(self.event.settings.freeze(), { self.assertEqual(frozen, {
'test_default': 'def', 'test_default': 'def',
'bar': 'baz', 'bar': 'baz',
'foo': 'bar' 'foo': 'bar'