Add type check for cache

This commit is contained in:
cuom1999 2024-05-08 10:15:55 -05:00
parent f1ba0e79c1
commit 0ea822f7a0
10 changed files with 35 additions and 13 deletions

View file

@ -5,6 +5,8 @@ from django.core.handlers.wsgi import WSGIRequest
import hashlib import hashlib
from judge.logging import log_debug
MAX_NUM_CHAR = 50 MAX_NUM_CHAR = 50
NONE_RESULT = "__None__" NONE_RESULT = "__None__"
@ -26,7 +28,7 @@ def filter_args(args_list):
l0_cache = caches["l0"] if "l0" in caches else None l0_cache = caches["l0"] if "l0" in caches else None
def cache_wrapper(prefix, timeout=None): def cache_wrapper(prefix, timeout=None, expected_type=None):
def get_key(func, *args, **kwargs): def get_key(func, *args, **kwargs):
args_list = list(args) args_list = list(args)
signature_args = list(signature(func).parameters.keys()) signature_args = list(signature(func).parameters.keys())
@ -54,10 +56,23 @@ def cache_wrapper(prefix, timeout=None):
cache.set(key, value, timeout) cache.set(key, value, timeout)
def decorator(func): def decorator(func):
def _validate_type(cache_key, result):
if expected_type and not isinstance(result, expected_type):
data = {
"function": f"{func.__module__}.{func.__qualname__}",
"result": str(result)[:30],
"expected_type": expected_type,
"type": type(result),
"key": cache_key,
}
log_debug("invalid_key", data)
return False
return True
def wrapper(*args, **kwargs): def wrapper(*args, **kwargs):
cache_key = get_key(func, *args, **kwargs) cache_key = get_key(func, *args, **kwargs)
result = _get(cache_key) result = _get(cache_key)
if result is not None: if result is not None and _validate_type(cache_key, result):
_set_l0(cache_key, result) _set_l0(cache_key, result)
if type(result) == str and result == NONE_RESULT: if type(result) == str and result == NONE_RESULT:
result = None result = None

View file

@ -1,7 +1,12 @@
import logging import logging
error_log = logging.getLogger("judge.errors") error_log = logging.getLogger("judge.errors")
debug_log = logging.getLogger("judge.debug")
def log_exception(msg): def log_exception(msg):
error_log.exception(msg) error_log.exception(msg)
def log_debug(category, data):
debug_log.info(f"{category}: {data}")

View file

@ -23,7 +23,7 @@ class BookMark(models.Model):
linked_object = GenericForeignKey("content_type", "object_id") linked_object = GenericForeignKey("content_type", "object_id")
@cache_wrapper(prefix="BMgb") @cache_wrapper(prefix="BMgb")
def get_bookmark(self, user): def is_bookmarked_by(self, user):
return MakeBookMark.objects.filter(bookmark=self, user=user).exists() return MakeBookMark.objects.filter(bookmark=self, user=user).exists()
class Meta: class Meta:
@ -53,7 +53,7 @@ class MakeBookMark(models.Model):
verbose_name_plural = _("make bookmarks") verbose_name_plural = _("make bookmarks")
@cache_wrapper(prefix="gocb") @cache_wrapper(prefix="gocb", expected_type=BookMark)
def _get_or_create_bookmark(content_type, object_id): def _get_or_create_bookmark(content_type, object_id):
bookmark, created = BookMark.objects.get_or_create( bookmark, created = BookMark.objects.get_or_create(
content_type=content_type, content_type=content_type,
@ -70,5 +70,5 @@ class Bookmarkable:
def dirty_bookmark(bookmark, profile): def dirty_bookmark(bookmark, profile):
bookmark.get_bookmark.dirty(bookmark, profile) bookmark.is_bookmarked_by.dirty(bookmark, profile)
_get_or_create_bookmark.dirty(bookmark.content_type, bookmark.object_id) _get_or_create_bookmark.dirty(bookmark.content_type, bookmark.object_id)

View file

@ -133,7 +133,7 @@ class BlogPost(models.Model, PageVotable, Bookmarkable):
and self.authors.filter(id=user.profile.id).exists() and self.authors.filter(id=user.profile.id).exists()
) )
@cache_wrapper(prefix="BPga") @cache_wrapper(prefix="BPga", expected_type=models.query.QuerySet)
def get_authors(self): def get_authors(self):
return self.authors.only("id") return self.authors.only("id")

View file

@ -49,7 +49,7 @@ class PageVoteVoter(models.Model):
verbose_name_plural = _("pagevote votes") verbose_name_plural = _("pagevote votes")
@cache_wrapper(prefix="gocp") @cache_wrapper(prefix="gocp", expected_type=PageVote)
def _get_or_create_pagevote(content_type, object_id): def _get_or_create_pagevote(content_type, object_id):
pagevote, created = PageVote.objects.get_or_create( pagevote, created = PageVote.objects.get_or_create(
content_type=content_type, content_type=content_type,

View file

@ -440,7 +440,7 @@ class Problem(models.Model, PageVotable, Bookmarkable):
"profile_id", flat=True "profile_id", flat=True
) )
@cache_wrapper(prefix="Pga") @cache_wrapper(prefix="Pga", expected_type=models.query.QuerySet)
def get_authors(self): def get_authors(self):
return self.authors.only("id") return self.authors.only("id")

View file

@ -581,7 +581,7 @@ def on_user_save(sender, instance, **kwargs):
pass pass
@cache_wrapper(prefix="Pgbi3") @cache_wrapper(prefix="Pgbi3", expected_type=dict)
def _get_basic_info(profile_id): def _get_basic_info(profile_id):
profile = ( profile = (
Profile.objects.select_related("user") Profile.objects.select_related("user")

View file

@ -7,6 +7,8 @@ from django.contrib.sites.shortcuts import get_current_site
from django.core.cache import cache from django.core.cache import cache
from django.utils.functional import SimpleLazyObject, new_method_proxy from django.utils.functional import SimpleLazyObject, new_method_proxy
from mptt.querysets import TreeQuerySet
from .models import MiscConfig, NavigationBar, Profile from .models import MiscConfig, NavigationBar, Profile
from judge.caching import cache_wrapper from judge.caching import cache_wrapper
@ -52,7 +54,7 @@ def comet_location(request):
return {"EVENT_DAEMON_LOCATION": websocket, "EVENT_DAEMON_POLL_LOCATION": poll} return {"EVENT_DAEMON_LOCATION": websocket, "EVENT_DAEMON_POLL_LOCATION": poll}
@cache_wrapper(prefix="nb") @cache_wrapper(prefix="nb", expected_type=TreeQuerySet)
def _nav_bar(): def _nav_bar():
return NavigationBar.objects.all() return NavigationBar.objects.all()

View file

@ -167,7 +167,7 @@ def editable_problems(user, profile=None):
return subquery return subquery
@cache_wrapper(prefix="hp", timeout=900) @cache_wrapper(prefix="hp", timeout=14400)
def hot_problems(duration, limit): def hot_problems(duration, limit):
qs = Problem.get_public_problems().filter( qs = Problem.get_public_problems().filter(
submission__date__gt=timezone.now() - duration submission__date__gt=timezone.now() - duration
@ -224,7 +224,7 @@ def hot_problems(duration, limit):
return qs return qs
@cache_wrapper(prefix="grp", timeout=26400) @cache_wrapper(prefix="grp", timeout=14400)
def get_related_problems(profile, problem, limit=8): def get_related_problems(profile, problem, limit=8):
if not profile or not settings.ML_OUTPUT_PATH: if not profile or not settings.ML_OUTPUT_PATH:
return None return None

View file

@ -37,7 +37,7 @@
{% endif %} {% endif %}
<span class="actionbar-block"> <span class="actionbar-block">
<span id="bookmark-button-{{bookmark.id}}" <span id="bookmark-button-{{bookmark.id}}"
class="bookmark-button actionbar-button {% if bookmark.get_bookmark(request.profile) == True %} bookmarked {% endif %}" class="bookmark-button actionbar-button {% if bookmark.is_bookmarked_by(request.profile) %} bookmarked {% endif %}"
onclick="javascript:bookmark({{ bookmark.id }}, event)"> onclick="javascript:bookmark({{ bookmark.id }}, event)">
<i class="fa fa-bookmark-o" style="font-size: large;"></i> <i class="fa fa-bookmark-o" style="font-size: large;"></i>
<span class="actionbar-text">{{_("Bookmark")}}</span> <span class="actionbar-text">{{_("Bookmark")}}</span>