From 1587192ff9d44559ac3df277f2db9f7af6a7899a Mon Sep 17 00:00:00 2001 From: zemal Date: Tue, 15 Aug 2017 21:05:41 +0800 Subject: [PATCH] add problem_statistic_info --- judge/dispatcher.py | 42 ++++++++++--------- problem/migrations/0005_auto_20170815_1258.py | 26 ++++++++++++ problem/models.py | 3 ++ submission/views/oj.py | 12 +++--- utils/cache.py | 2 +- 5 files changed, 58 insertions(+), 27 deletions(-) create mode 100644 problem/migrations/0005_auto_20170815_1258.py diff --git a/judge/dispatcher.py b/judge/dispatcher.py index 501eabf8..c64fb4df 100644 --- a/judge/dispatcher.py +++ b/judge/dispatcher.py @@ -14,7 +14,7 @@ from contest.models import ContestRuleType, ACMContestRank, OIContestRank from judge.languages import languages from problem.models import Problem, ProblemRuleType, ContestProblem from submission.models import JudgeStatus, Submission -from utils.cache import judge_queue_cache +from utils.cache import judge_cache from utils.constants import CacheKey logger = logging.getLogger(__name__) @@ -22,10 +22,10 @@ logger = logging.getLogger(__name__) # 继续处理在队列中的问题 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 - data = json.loads(judge_queue_cache.rpop(CacheKey.waiting_queue)) + data = json.loads(judge_cache.rpop(CacheKey.waiting_queue)) judge_task.delay(**data) @@ -33,7 +33,7 @@ class JudgeDispatcher(object): def __init__(self, submission_id, problem_id): token = JudgeServerToken.objects.first().token 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) if self.submission.contest_id: self.problem = ContestProblem.objects.select_related("contest")\ @@ -98,8 +98,8 @@ class JudgeDispatcher(object): "spj_compile_config": spj_config.get("compile"), "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 resp = self._request(urljoin(server.service_url, "/judge"), data=data) @@ -123,11 +123,12 @@ class JudgeDispatcher(object): self.submission.save() self.release_judge_res(server.id) + self.update_problem_status() + if self.submission.contest_id: - self.update_contest_problem_status() self.update_contest_rank() else: - self.update_problem_status() + self.update_user_profile() # 至此判题结束,尝试处理任务队列中剩余的任务 process_pending_task() @@ -138,13 +139,21 @@ class JudgeDispatcher(object): return self._request(urljoin(service_url, "compile_spj"), data=data) def update_problem_status(self): + self.problem.add_submission_number() + if self.submission.result == JudgeStatus.ACCEPTED: + self.problem.add_ac_number() with transaction.atomic(): - # 更新problem计数器 - self.problem = Problem.objects.select_for_update().get(id=self.problem.id) - self.problem.add_submission_number() - if self.submission.result == JudgeStatus.ACCEPTED: - self.problem.add_ac_number() + 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 = User.objects.select_for_update().get(id=self.submission.user_id) user_profile = user.userprofile @@ -163,13 +172,6 @@ class JudgeDispatcher(object): user_profile.problems_status = 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): if self.contest.real_time_rank: cache.delete(str(self.contest.id) + "_rank_cache") diff --git a/problem/migrations/0005_auto_20170815_1258.py b/problem/migrations/0005_auto_20170815_1258.py new file mode 100644 index 00000000..19496966 --- /dev/null +++ b/problem/migrations/0005_auto_20170815_1258.py @@ -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={}), + ), + ] diff --git a/problem/models.py b/problem/models.py index 0a8fda25..6915ee08 100644 --- a/problem/models.py +++ b/problem/models.py @@ -57,6 +57,9 @@ class AbstractProblem(models.Model): source = models.CharField(max_length=200, blank=True, null=True) total_submit_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: db_table = "problem" diff --git a/submission/views/oj.py b/submission/views/oj.py index af3584f3..5af28974 100644 --- a/submission/views/oj.py +++ b/submission/views/oj.py @@ -95,21 +95,21 @@ class SubmissionListAPI(APIView): if request.GET.get("contest_id"): return self._get_contest_submission_list(request) - subs = Submission.objects.filter(contest_id__isnull=True) - return self.process_submissions(request, subs) + submissions = Submission.objects.filter(contest_id__isnull=True) + return self.process_submissions(request, submissions) @check_contest_permission def _get_contest_submission_list(self, request): subs = Submission.objects.filter(contest_id=self.contest.id) 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") 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": - subs = subs.filter(user_id=request.user.id) - data = self.paginate_data(request, subs) + submissions = submissions.filter(user_id=request.user.id) + data = self.paginate_data(request, submissions) data["results"] = SubmissionListSerializer(data["results"], many=True, user=request.user).data return self.success(data) diff --git a/utils/cache.py b/utils/cache.py index d72c81a0..c77131f6 100644 --- a/utils/cache.py +++ b/utils/cache.py @@ -1,6 +1,6 @@ from django.conf import settings 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) default_cache = get_redis_connection("default")