add problem_statistic_info

This commit is contained in:
zemal 2017-08-15 21:05:41 +08:00
parent df185a233f
commit 1587192ff9
5 changed files with 58 additions and 27 deletions

View File

@ -14,7 +14,7 @@ from contest.models import ContestRuleType, ACMContestRank, OIContestRank
from judge.languages import languages from judge.languages import languages
from problem.models import Problem, ProblemRuleType, ContestProblem from problem.models import Problem, ProblemRuleType, ContestProblem
from submission.models import JudgeStatus, Submission from submission.models import JudgeStatus, Submission
from utils.cache import judge_queue_cache from utils.cache import judge_cache
from utils.constants import CacheKey from utils.constants import CacheKey
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@ -22,10 +22,10 @@ logger = logging.getLogger(__name__)
# 继续处理在队列中的问题 # 继续处理在队列中的问题
def process_pending_task(): def process_pending_task():
if judge_queue_cache.llen(CacheKey.waiting_queue): if judge_cache.llen(CacheKey.waiting_queue):
# 防止循环引入 # 防止循环引入
from judge.tasks import judge_task from judge.tasks import judge_task
data = json.loads(judge_queue_cache.rpop(CacheKey.waiting_queue)) data = json.loads(judge_cache.rpop(CacheKey.waiting_queue))
judge_task.delay(**data) judge_task.delay(**data)
@ -33,7 +33,7 @@ class JudgeDispatcher(object):
def __init__(self, submission_id, problem_id): def __init__(self, submission_id, problem_id):
token = JudgeServerToken.objects.first().token token = JudgeServerToken.objects.first().token
self.token = hashlib.sha256(token.encode("utf-8")).hexdigest() self.token = hashlib.sha256(token.encode("utf-8")).hexdigest()
self.redis_conn = judge_queue_cache self.redis_conn = judge_cache
self.submission = Submission.objects.get(pk=submission_id) self.submission = Submission.objects.get(pk=submission_id)
if self.submission.contest_id: if self.submission.contest_id:
self.problem = ContestProblem.objects.select_related("contest")\ self.problem = ContestProblem.objects.select_related("contest")\
@ -98,8 +98,8 @@ class JudgeDispatcher(object):
"spj_compile_config": spj_config.get("compile"), "spj_compile_config": spj_config.get("compile"),
"spj_src": self.problem.spj_code "spj_src": self.problem.spj_code
} }
self.submission.result = JudgeStatus.JUDGING
self.submission.save() Submission.objects.filter(id=self.submission.id).update(result=JudgeStatus.JUDGING)
# TODO: try catch # TODO: try catch
resp = self._request(urljoin(server.service_url, "/judge"), data=data) resp = self._request(urljoin(server.service_url, "/judge"), data=data)
@ -123,11 +123,12 @@ class JudgeDispatcher(object):
self.submission.save() self.submission.save()
self.release_judge_res(server.id) self.release_judge_res(server.id)
self.update_problem_status()
if self.submission.contest_id: if self.submission.contest_id:
self.update_contest_problem_status()
self.update_contest_rank() self.update_contest_rank()
else: else:
self.update_problem_status() self.update_user_profile()
# 至此判题结束,尝试处理任务队列中剩余的任务 # 至此判题结束,尝试处理任务队列中剩余的任务
process_pending_task() process_pending_task()
@ -138,13 +139,21 @@ class JudgeDispatcher(object):
return self._request(urljoin(service_url, "compile_spj"), data=data) return self._request(urljoin(service_url, "compile_spj"), data=data)
def update_problem_status(self): def update_problem_status(self):
with transaction.atomic():
# 更新problem计数器
self.problem = Problem.objects.select_for_update().get(id=self.problem.id)
self.problem.add_submission_number() self.problem.add_submission_number()
if self.submission.result == JudgeStatus.ACCEPTED: if self.submission.result == JudgeStatus.ACCEPTED:
self.problem.add_ac_number() self.problem.add_ac_number()
with transaction.atomic():
if self.submission.contest_id:
problem = ContestProblem.objects.select_for_update().get(_id=self.problem.id, contest_id=self.contest.id)
else:
problem = Problem.objects.select_related().get(_id=self.problem.id)
info = problem.statistic_info
info[self.submission.result] = info.get(self.submission.result, 0) + 1
problem.statistic_info = info
problem.save(update_fields=["statistic_info"])
def update_user_profile(self):
with transaction.atomic():
# 更新user profile # 更新user profile
user = User.objects.select_for_update().get(id=self.submission.user_id) user = User.objects.select_for_update().get(id=self.submission.user_id)
user_profile = user.userprofile user_profile = user.userprofile
@ -163,13 +172,6 @@ class JudgeDispatcher(object):
user_profile.problems_status = problems_status user_profile.problems_status = problems_status
user_profile.save(update_fields=["problems_status"]) user_profile.save(update_fields=["problems_status"])
def update_contest_problem_status(self):
with transaction.atomic():
problem = ContestProblem.objects.select_for_update().get(id=self.problem.id)
problem.add_submission_number()
if self.submission.result == JudgeStatus.ACCEPTED:
problem.add_ac_number()
def update_contest_rank(self): def update_contest_rank(self):
if self.contest.real_time_rank: if self.contest.real_time_rank:
cache.delete(str(self.contest.id) + "_rank_cache") cache.delete(str(self.contest.id) + "_rank_cache")

View File

@ -0,0 +1,26 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.6 on 2017-08-15 12:58
from __future__ import unicode_literals
from django.db import migrations
import jsonfield.fields
class Migration(migrations.Migration):
dependencies = [
('problem', '0004_auto_20170501_0637'),
]
operations = [
migrations.AddField(
model_name='contestproblem',
name='statistic_info',
field=jsonfield.fields.JSONField(default={}),
),
migrations.AddField(
model_name='problem',
name='statistic_info',
field=jsonfield.fields.JSONField(default={}),
),
]

View File

@ -57,6 +57,9 @@ class AbstractProblem(models.Model):
source = models.CharField(max_length=200, blank=True, null=True) source = models.CharField(max_length=200, blank=True, null=True)
total_submit_number = models.BigIntegerField(default=0) total_submit_number = models.BigIntegerField(default=0)
total_accepted_number = models.BigIntegerField(default=0) total_accepted_number = models.BigIntegerField(default=0)
# {0: 0, 1: 0, 2: 0, 3: 0 ...}
# the first number means JudgeStatus, the second number present count
statistic_info = JSONField(default={})
class Meta: class Meta:
db_table = "problem" db_table = "problem"

View File

@ -95,21 +95,21 @@ class SubmissionListAPI(APIView):
if request.GET.get("contest_id"): if request.GET.get("contest_id"):
return self._get_contest_submission_list(request) return self._get_contest_submission_list(request)
subs = Submission.objects.filter(contest_id__isnull=True) submissions = Submission.objects.filter(contest_id__isnull=True)
return self.process_submissions(request, subs) return self.process_submissions(request, submissions)
@check_contest_permission @check_contest_permission
def _get_contest_submission_list(self, request): def _get_contest_submission_list(self, request):
subs = Submission.objects.filter(contest_id=self.contest.id) subs = Submission.objects.filter(contest_id=self.contest.id)
return self.process_submissions(request, subs) return self.process_submissions(request, subs)
def process_submissions(self, request, subs): def process_submissions(self, request, submissions):
problem_id = request.GET.get("problem_id") problem_id = request.GET.get("problem_id")
if problem_id: if problem_id:
subs = subs.filter(problem_id=problem_id) submissions = submissions.filter(problem_id=problem_id)
if request.GET.get("myself") and request.GET["myself"] == "1": if request.GET.get("myself") and request.GET["myself"] == "1":
subs = subs.filter(user_id=request.user.id) submissions = submissions.filter(user_id=request.user.id)
data = self.paginate_data(request, subs) data = self.paginate_data(request, submissions)
data["results"] = SubmissionListSerializer(data["results"], many=True, user=request.user).data data["results"] = SubmissionListSerializer(data["results"], many=True, user=request.user).data
return self.success(data) return self.success(data)

View File

@ -1,6 +1,6 @@
from django.conf import settings from django.conf import settings
from django_redis import get_redis_connection from django_redis import get_redis_connection
judge_queue_cache = get_redis_connection(settings.CACHE_JUDGE_QUEUE) judge_cache = get_redis_connection(settings.CACHE_JUDGE_QUEUE)
throttling_cache = get_redis_connection(settings.CACHE_THROTTLING) throttling_cache = get_redis_connection(settings.CACHE_THROTTLING)
default_cache = get_redis_connection("default") default_cache = get_redis_connection("default")