Cache prefetch
This commit is contained in:
parent
c2f6dba462
commit
2831a24b90
6 changed files with 70 additions and 34 deletions
|
@ -25,26 +25,18 @@ class Room(models.Model):
|
||||||
class Meta:
|
class Meta:
|
||||||
app_label = "chat_box"
|
app_label = "chat_box"
|
||||||
|
|
||||||
@cache_wrapper(prefix="Rinfo")
|
|
||||||
def _info(self):
|
|
||||||
last_msg = self.message_set.filter(hidden=False).first()
|
|
||||||
return {
|
|
||||||
"user_ids": [self.user_one.id, self.user_two.id],
|
|
||||||
"last_message": last_msg.body if last_msg else None,
|
|
||||||
}
|
|
||||||
|
|
||||||
@cached_property
|
@cached_property
|
||||||
def _cached_info(self):
|
def _cached_info(self):
|
||||||
return self._info()
|
return get_room_info(self.id)
|
||||||
|
|
||||||
def contain(self, profile):
|
def contain(self, profile):
|
||||||
return profile.id in self._cached_info["user_ids"]
|
return profile.id in [self.user_one_id, self.user_two_id]
|
||||||
|
|
||||||
def other_user(self, profile):
|
def other_user(self, profile):
|
||||||
return self.user_one if profile == self.user_two else self.user_two
|
return self.user_one if profile == self.user_two else self.user_two
|
||||||
|
|
||||||
def other_user_id(self, profile):
|
def other_user_id(self, profile):
|
||||||
user_ids = self._cached_info["user_ids"]
|
user_ids = [self.user_one_id, self.user_two_id]
|
||||||
return sum(user_ids) - profile.id
|
return sum(user_ids) - profile.id
|
||||||
|
|
||||||
def users(self):
|
def users(self):
|
||||||
|
@ -53,6 +45,10 @@ class Room(models.Model):
|
||||||
def last_message_body(self):
|
def last_message_body(self):
|
||||||
return self._cached_info["last_message"]
|
return self._cached_info["last_message"]
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def prefetch_room_cache(self, room_ids):
|
||||||
|
get_room_info.prefetch_multi([(i,) for i in room_ids])
|
||||||
|
|
||||||
|
|
||||||
class Message(models.Model):
|
class Message(models.Model):
|
||||||
author = models.ForeignKey(Profile, verbose_name=_("user"), on_delete=CASCADE)
|
author = models.ForeignKey(Profile, verbose_name=_("user"), on_delete=CASCADE)
|
||||||
|
@ -147,3 +143,11 @@ class Ignore(models.Model):
|
||||||
self.remove_ignore(current_user, friend)
|
self.remove_ignore(current_user, friend)
|
||||||
else:
|
else:
|
||||||
self.add_ignore(current_user, friend)
|
self.add_ignore(current_user, friend)
|
||||||
|
|
||||||
|
|
||||||
|
@cache_wrapper(prefix="Rinfo")
|
||||||
|
def get_room_info(room_id):
|
||||||
|
last_msg = Message.objects.filter(room_id=room_id).first()
|
||||||
|
return {
|
||||||
|
"last_message": last_msg.body if last_msg else None,
|
||||||
|
}
|
||||||
|
|
|
@ -34,7 +34,7 @@ from judge import event_poster as event
|
||||||
from judge.jinja2.gravatar import gravatar
|
from judge.jinja2.gravatar import gravatar
|
||||||
from judge.models import Friend
|
from judge.models import Friend
|
||||||
|
|
||||||
from chat_box.models import Message, Profile, Room, UserRoom, Ignore
|
from chat_box.models import Message, Profile, Room, UserRoom, Ignore, get_room_info
|
||||||
from chat_box.utils import encrypt_url, decrypt_url, encrypt_channel, get_unread_boxes
|
from chat_box.utils import encrypt_url, decrypt_url, encrypt_channel, get_unread_boxes
|
||||||
|
|
||||||
|
|
||||||
|
@ -231,7 +231,7 @@ def post_message(request):
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
Room._info.dirty(room)
|
get_room_info.dirty(room.id)
|
||||||
room.last_msg_time = new_message.time
|
room.last_msg_time = new_message.time
|
||||||
room.save()
|
room.save()
|
||||||
|
|
||||||
|
@ -363,6 +363,8 @@ def user_online_status_ajax(request):
|
||||||
def get_online_status(profile, other_profile_ids, rooms=None):
|
def get_online_status(profile, other_profile_ids, rooms=None):
|
||||||
if not other_profile_ids:
|
if not other_profile_ids:
|
||||||
return None
|
return None
|
||||||
|
Profile.prefetch_profile_cache(other_profile_ids)
|
||||||
|
|
||||||
joined_ids = ",".join([str(id) for id in other_profile_ids])
|
joined_ids = ",".join([str(id) for id in other_profile_ids])
|
||||||
other_profiles = Profile.objects.raw(
|
other_profiles = Profile.objects.raw(
|
||||||
f"SELECT * from judge_profile where id in ({joined_ids}) order by field(id,{joined_ids})"
|
f"SELECT * from judge_profile where id in ({joined_ids}) order by field(id,{joined_ids})"
|
||||||
|
@ -429,6 +431,7 @@ def get_status_context(profile, include_ignored=False):
|
||||||
|
|
||||||
recent_profile_ids = [str(i["other_user"]) for i in recent_profile]
|
recent_profile_ids = [str(i["other_user"]) for i in recent_profile]
|
||||||
recent_rooms = [int(i["id"]) for i in recent_profile]
|
recent_rooms = [int(i["id"]) for i in recent_profile]
|
||||||
|
Room.prefetch_room_cache(recent_rooms)
|
||||||
|
|
||||||
admin_list = (
|
admin_list = (
|
||||||
queryset.filter(display_rank="admin")
|
queryset.filter(display_rank="admin")
|
||||||
|
|
|
@ -74,7 +74,17 @@ def cache_wrapper(prefix, timeout=None):
|
||||||
if l0_cache:
|
if l0_cache:
|
||||||
l0_cache.delete(cache_key)
|
l0_cache.delete(cache_key)
|
||||||
|
|
||||||
|
def prefetch_multi(args_list):
|
||||||
|
keys = []
|
||||||
|
for args in args_list:
|
||||||
|
keys.append(get_key(func, *args))
|
||||||
|
results = cache.get_many(keys)
|
||||||
|
for key, result in results.items():
|
||||||
|
if result is not None:
|
||||||
|
_set_l0(key, result)
|
||||||
|
|
||||||
wrapper.dirty = dirty
|
wrapper.dirty = dirty
|
||||||
|
wrapper.prefetch_multi = prefetch_multi
|
||||||
|
|
||||||
return wrapper
|
return wrapper
|
||||||
|
|
||||||
|
|
|
@ -253,24 +253,9 @@ class Profile(models.Model):
|
||||||
max_length=300,
|
max_length=300,
|
||||||
)
|
)
|
||||||
|
|
||||||
@cache_wrapper(prefix="Pgbi2")
|
|
||||||
def _get_basic_info(self):
|
|
||||||
res = {
|
|
||||||
"email": self.user.email,
|
|
||||||
"username": self.user.username,
|
|
||||||
"mute": self.mute,
|
|
||||||
}
|
|
||||||
if self.user.first_name:
|
|
||||||
res["first_name"] = self.user.first_name
|
|
||||||
if self.user.last_name:
|
|
||||||
res["last_name"] = self.user.last_name
|
|
||||||
if self.profile_image:
|
|
||||||
res["profile_image_url"] = self.profile_image.url
|
|
||||||
return res
|
|
||||||
|
|
||||||
@cached_property
|
@cached_property
|
||||||
def _cached_info(self):
|
def _cached_info(self):
|
||||||
return self._get_basic_info()
|
return _get_basic_info(self.id)
|
||||||
|
|
||||||
@cached_property
|
@cached_property
|
||||||
def organization(self):
|
def organization(self):
|
||||||
|
@ -412,6 +397,10 @@ class Profile(models.Model):
|
||||||
or self.user.is_superuser
|
or self.user.is_superuser
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def prefetch_profile_cache(self, profile_ids):
|
||||||
|
_get_basic_info.prefetch_multi([(pid,) for pid in profile_ids])
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
indexes = [
|
indexes = [
|
||||||
models.Index(fields=["is_unlisted", "performance_points"]),
|
models.Index(fields=["is_unlisted", "performance_points"]),
|
||||||
|
@ -540,7 +529,7 @@ class OrganizationProfile(models.Model):
|
||||||
def on_user_save(sender, instance, **kwargs):
|
def on_user_save(sender, instance, **kwargs):
|
||||||
try:
|
try:
|
||||||
profile = instance.profile
|
profile = instance.profile
|
||||||
profile._get_basic_info.dirty(profile)
|
_get_basic_info.dirty(profile.id)
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
@ -551,4 +540,34 @@ def on_profile_save(sender, instance, **kwargs):
|
||||||
return
|
return
|
||||||
prev = sender.objects.get(id=instance.id)
|
prev = sender.objects.get(id=instance.id)
|
||||||
if prev.mute != instance.mute or prev.profile_image != instance.profile_image:
|
if prev.mute != instance.mute or prev.profile_image != instance.profile_image:
|
||||||
instance._get_basic_info.dirty(instance)
|
_get_basic_info.dirty(instance.id)
|
||||||
|
|
||||||
|
|
||||||
|
@cache_wrapper(prefix="Pgbi2")
|
||||||
|
def _get_basic_info(profile_id):
|
||||||
|
profile = (
|
||||||
|
Profile.objects.select_related("user")
|
||||||
|
.only(
|
||||||
|
"id",
|
||||||
|
"mute",
|
||||||
|
"profile_image",
|
||||||
|
"user__username",
|
||||||
|
"user__email",
|
||||||
|
"user__first_name",
|
||||||
|
"user__last_name",
|
||||||
|
)
|
||||||
|
.get(id=profile_id)
|
||||||
|
)
|
||||||
|
user = profile.user
|
||||||
|
res = {
|
||||||
|
"email": user.email,
|
||||||
|
"username": user.username,
|
||||||
|
"mute": profile.mute,
|
||||||
|
"first_name": user.first_name or None,
|
||||||
|
"last_name": user.last_name or None,
|
||||||
|
"profile_image_url": profile.profile_image.url
|
||||||
|
if profile.profile_image
|
||||||
|
else None,
|
||||||
|
}
|
||||||
|
res = {k: v for k, v in res.items() if v is not None}
|
||||||
|
return res
|
||||||
|
|
|
@ -470,6 +470,7 @@ class SubmissionsListBase(DiggPaginatorMixin, TitleMixin, ListView):
|
||||||
if context["in_hidden_subtasks_contest"]:
|
if context["in_hidden_subtasks_contest"]:
|
||||||
for submission in context["submissions"]:
|
for submission in context["submissions"]:
|
||||||
self.modify_attrs(submission)
|
self.modify_attrs(submission)
|
||||||
|
|
||||||
return context
|
return context
|
||||||
|
|
||||||
def get(self, request, *args, **kwargs):
|
def get(self, request, *args, **kwargs):
|
||||||
|
|
|
@ -457,14 +457,13 @@ class UserList(QueryStringSortMixin, InfinitePaginationMixin, TitleMixin, ListVi
|
||||||
queryset = (
|
queryset = (
|
||||||
Profile.objects.filter(is_unlisted=False)
|
Profile.objects.filter(is_unlisted=False)
|
||||||
.order_by(self.order, "id")
|
.order_by(self.order, "id")
|
||||||
.select_related("user")
|
|
||||||
.only(
|
.only(
|
||||||
"display_rank",
|
"display_rank",
|
||||||
"user__username",
|
|
||||||
"points",
|
"points",
|
||||||
"rating",
|
"rating",
|
||||||
"performance_points",
|
"performance_points",
|
||||||
"problem_count",
|
"problem_count",
|
||||||
|
"about",
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
if self.request.organization:
|
if self.request.organization:
|
||||||
|
@ -472,11 +471,11 @@ class UserList(QueryStringSortMixin, InfinitePaginationMixin, TitleMixin, ListVi
|
||||||
if (self.request.GET.get("friend") == "true") and self.request.profile:
|
if (self.request.GET.get("friend") == "true") and self.request.profile:
|
||||||
queryset = self.filter_friend_queryset(queryset)
|
queryset = self.filter_friend_queryset(queryset)
|
||||||
self.filter_friend = True
|
self.filter_friend = True
|
||||||
|
|
||||||
return queryset
|
return queryset
|
||||||
|
|
||||||
def get_context_data(self, **kwargs):
|
def get_context_data(self, **kwargs):
|
||||||
context = super(UserList, self).get_context_data(**kwargs)
|
context = super(UserList, self).get_context_data(**kwargs)
|
||||||
|
Profile.prefetch_profile_cache([u.id for u in context["users"]])
|
||||||
context["users"] = ranker(
|
context["users"] = ranker(
|
||||||
context["users"], rank=self.paginate_by * (context["page_obj"].number - 1)
|
context["users"], rank=self.paginate_by * (context["page_obj"].number - 1)
|
||||||
)
|
)
|
||||||
|
|
Loading…
Reference in a new issue