From a0da0b5fa6d87a65500858ad6fe72e8ce847d486 Mon Sep 17 00:00:00 2001 From: virusdefender Date: Tue, 27 Mar 2018 13:14:11 +0800 Subject: [PATCH 1/2] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E4=BA=86=20submission=5F?= =?UTF-8?q?number=20=E4=B8=8D=E5=8F=98=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- judge/dispatcher.py | 16 ++++++++-------- judge/tasks.py | 4 ++-- submission/views/admin.py | 5 ++--- 3 files changed, 12 insertions(+), 13 deletions(-) diff --git a/judge/dispatcher.py b/judge/dispatcher.py index 2e433435..eaa010fa 100644 --- a/judge/dispatcher.py +++ b/judge/dispatcher.py @@ -85,10 +85,13 @@ class SPJCompiler(DispatcherBase): class JudgeDispatcher(DispatcherBase): - def __init__(self, submission_id, problem_id): + def __init__(self, submission_id, problem_id, is_rejudge=False): super().__init__() self.submission = Submission.objects.get(id=submission_id) self.contest_id = self.submission.contest_id + self.is_rejudge = is_rejudge + self.last_result = None + if self.contest_id: self.problem = Problem.objects.select_related("contest").get(id=problem_id, contest_id=self.contest_id) self.contest = self.problem.contest @@ -119,7 +122,7 @@ class JudgeDispatcher(DispatcherBase): def judge(self): server = self.choose_judge_server() if not server: - data = {"submission_id": self.submission.id, "problem_id": self.problem.id} + data = {"submission_id": self.submission.id, "problem_id": self.problem.id, "is_rejudge": self.is_rejudge} cache.lpush(CacheKey.waiting_queue, json.dumps(data)) return @@ -150,11 +153,8 @@ class JudgeDispatcher(DispatcherBase): "spj_compile_config": spj_config.get("compile"), "spj_src": self.problem.spj_code } - self.last_result = None - try: - self.last_result = Submission.objects.get(id=self.submission.id).result - except Submission.DoesNotExist: - pass + self.last_result = self.submission.result + Submission.objects.filter(id=self.submission.id).update(result=JudgeStatus.JUDGING) resp = self._request(urljoin(server.service_url, "/judge"), data=data) @@ -197,7 +197,7 @@ class JudgeDispatcher(DispatcherBase): with transaction.atomic(): # update problem status problem = Problem.objects.select_for_update().get(contest_id=self.contest_id, id=self.problem.id) - if not self.last_result: + if not self.is_rejudge: problem.submission_number += 1 if self.submission.result == JudgeStatus.ACCEPTED: if self.last_result != JudgeStatus.ACCEPTED: diff --git a/judge/tasks.py b/judge/tasks.py index eda9e0f4..a0fab546 100644 --- a/judge/tasks.py +++ b/judge/tasks.py @@ -4,5 +4,5 @@ from judge.dispatcher import JudgeDispatcher @shared_task -def judge_task(submission_id, problem_id): - JudgeDispatcher(submission_id, problem_id).judge() +def judge_task(submission_id, problem_id, is_rejudge=False): + JudgeDispatcher(submission_id, problem_id, is_rejudge=is_rejudge).judge() diff --git a/submission/views/admin.py b/submission/views/admin.py index 679360b6..0638b970 100644 --- a/submission/views/admin.py +++ b/submission/views/admin.py @@ -10,15 +10,14 @@ class SubmissionRejudgeAPI(APIView): def get(self, request): id = request.GET.get("id") if not id: - return self.error("Paramater error, id is required") + return self.error("Parameter error, id is required") try: submission = Submission.objects.select_related("problem").get(id=id, contest_id__isnull=True) except Submission.DoesNotExist: return self.error("Submission does not exists") - submission.result = JudgeStatus.PENDING submission.info = {} submission.statistic_info = {} submission.save() - judge_task.delay(submission.id, submission.problem.id) + judge_task.delay(submission.id, submission.problem.id, is_rejudge=True) return self.success() From 2e50910931fc10c7d13086889f7fde7e46eeb62c Mon Sep 17 00:00:00 2001 From: virusdefender Date: Tue, 27 Mar 2018 13:53:30 +0800 Subject: [PATCH 2/2] add migration to correct database record; rejudge function now can work normally. --- judge/dispatcher.py | 62 ++++++++++++++----- judge/tasks.py | 4 +- .../migrations/0010_fix_submission_number.py | 38 ++++++++++++ submission/views/admin.py | 4 +- 4 files changed, 90 insertions(+), 18 deletions(-) create mode 100644 submission/migrations/0010_fix_submission_number.py diff --git a/judge/dispatcher.py b/judge/dispatcher.py index eaa010fa..0e14a196 100644 --- a/judge/dispatcher.py +++ b/judge/dispatcher.py @@ -85,12 +85,11 @@ class SPJCompiler(DispatcherBase): class JudgeDispatcher(DispatcherBase): - def __init__(self, submission_id, problem_id, is_rejudge=False): + def __init__(self, submission_id, problem_id): super().__init__() self.submission = Submission.objects.get(id=submission_id) self.contest_id = self.submission.contest_id - self.is_rejudge = is_rejudge - self.last_result = None + self.last_result = self.submission.result if self.submission.info else None if self.contest_id: self.problem = Problem.objects.select_related("contest").get(id=problem_id, contest_id=self.contest_id) @@ -122,7 +121,7 @@ class JudgeDispatcher(DispatcherBase): def judge(self): server = self.choose_judge_server() if not server: - data = {"submission_id": self.submission.id, "problem_id": self.problem.id, "is_rejudge": self.is_rejudge} + data = {"submission_id": self.submission.id, "problem_id": self.problem.id} cache.lpush(CacheKey.waiting_queue, json.dumps(data)) return @@ -153,7 +152,6 @@ class JudgeDispatcher(DispatcherBase): "spj_compile_config": spj_config.get("compile"), "spj_src": self.problem.spj_code } - self.last_result = self.submission.result Submission.objects.filter(id=self.submission.id).update(result=JudgeStatus.JUDGING) @@ -181,30 +179,66 @@ class JudgeDispatcher(DispatcherBase): if self.contest_id: if self.contest.status != ContestStatus.CONTEST_UNDERWAY or \ User.objects.get(id=self.submission.user_id).is_contest_admin(self.contest): - logger.info("Contest debug mode, id: " + str(self.contest_id) + ", submission id: " + self.submission.id) + logger.info( + "Contest debug mode, id: " + str(self.contest_id) + ", submission id: " + self.submission.id) return self.update_contest_problem_status() self.update_contest_rank() else: - self.update_problem_status() + if self.last_result: + self.update_problem_status_rejudge() + else: + self.update_problem_status() # 至此判题结束,尝试处理任务队列中剩余的任务 process_pending_task() + def update_problem_status_rejudge(self): + result = str(self.submission.result) + problem_id = str(self.problem.id) + with transaction.atomic(): + # update problem status + problem = Problem.objects.select_for_update().get(contest_id=self.contest_id, id=self.problem.id) + if self.last_result != JudgeStatus.ACCEPTED and self.submission.result == JudgeStatus.ACCEPTED: + problem.accepted_number += 1 + problem_info = problem.statistic_info + problem_info[self.last_result] = problem_info.get(self.last_result, 1) - 1 + problem_info[result] = problem_info.get(result, 0) + 1 + problem.save(update_fields=["accepted_number", "statistic_info"]) + + profile = User.objects.select_for_update().get(id=self.submission.user_id).userprofile + if problem.rule_type == ProblemRuleType.ACM: + acm_problems_status = profile.acm_problems_status.get("problems", {}) + if acm_problems_status[problem_id]["status"] != JudgeStatus.ACCEPTED: + acm_problems_status[problem_id]["status"] = self.submission.result + if self.submission.result == JudgeStatus.ACCEPTED: + profile.accepted_number += 1 + profile.acm_problems_status["problems"] = acm_problems_status + profile.save(update_fields=["accepted_number", "acm_problems_status"]) + + else: + oi_problems_status = profile.oi_problems_status.get("problems", {}) + score = self.submission.statistic_info["score"] + if oi_problems_status[problem_id]["status"] != JudgeStatus.ACCEPTED: + # minus last time score, add this tim score + profile.add_score(this_time_score=score, + last_time_score=oi_problems_status[problem_id]["score"]) + oi_problems_status[problem_id]["score"] = score + oi_problems_status[problem_id]["status"] = self.submission.result + if self.submission.result == JudgeStatus.ACCEPTED: + profile.accepted_number += 1 + profile.oi_problems_status["problems"] = oi_problems_status + profile.save(update_fields=["accepted_number", "oi_problems_status"]) + def update_problem_status(self): result = str(self.submission.result) problem_id = str(self.problem.id) with transaction.atomic(): # update problem status problem = Problem.objects.select_for_update().get(contest_id=self.contest_id, id=self.problem.id) - if not self.is_rejudge: - problem.submission_number += 1 + problem.submission_number += 1 if self.submission.result == JudgeStatus.ACCEPTED: - if self.last_result != JudgeStatus.ACCEPTED: - problem.accepted_number += 1 - else: - if self.last_result == JudgeStatus.ACCEPTED: - problem.accepted_number -= 1 + problem.accepted_number += 1 problem_info = problem.statistic_info problem_info[result] = problem_info.get(result, 0) + 1 problem.save(update_fields=["accepted_number", "submission_number", "statistic_info"]) diff --git a/judge/tasks.py b/judge/tasks.py index a0fab546..eda9e0f4 100644 --- a/judge/tasks.py +++ b/judge/tasks.py @@ -4,5 +4,5 @@ from judge.dispatcher import JudgeDispatcher @shared_task -def judge_task(submission_id, problem_id, is_rejudge=False): - JudgeDispatcher(submission_id, problem_id, is_rejudge=is_rejudge).judge() +def judge_task(submission_id, problem_id): + JudgeDispatcher(submission_id, problem_id).judge() diff --git a/submission/migrations/0010_fix_submission_number.py b/submission/migrations/0010_fix_submission_number.py new file mode 100644 index 00000000..1a752350 --- /dev/null +++ b/submission/migrations/0010_fix_submission_number.py @@ -0,0 +1,38 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.db import migrations +from django.db.models import Count + + +def fix_rejudge_bugs(apps, schema_editor): + Submission = apps.get_model("submission", "Submission") + Problem = apps.get_model("problem", "Problem") + User = apps.get_model("account", "User") + + for item in Problem.objects.filter(contest__isnull=True): + submissions = Submission.objects.filter(problem=item) + item.submission_number = submissions.count() + results_count = submissions.annotate(count=Count('result')).values('result', 'count') + for stat in results_count: + if stat["result"] == 0: + item.accepted_number = stat["count"] + item.statistic_info[str(stat)] = stat["count"] + item.save(update_fields=["submission_number", "accepted_number", "statistic_info"]) + + for user in User.objects.all(): + submissions = Submission.objects.filter(user_id=user.id) + profile = user.userprofile + profile.submission_number = submissions.count() + profile.accepted_number = submissions.filter(result=0).count() + profile.save(update_fields=["submission_number", "accepted_number"]) + + +class Migration(migrations.Migration): + dependencies = [ + ('submission', '0009_delete_user_output'), + ] + + operations = [ + migrations.RunPython(fix_rejudge_bugs, reverse_code=migrations.RunPython.noop) + ] diff --git a/submission/views/admin.py b/submission/views/admin.py index 0638b970..5a5cdf59 100644 --- a/submission/views/admin.py +++ b/submission/views/admin.py @@ -2,7 +2,7 @@ from account.decorators import super_admin_required from judge.tasks import judge_task # from judge.dispatcher import JudgeDispatcher from utils.api import APIView -from ..models import Submission, JudgeStatus +from ..models import Submission class SubmissionRejudgeAPI(APIView): @@ -19,5 +19,5 @@ class SubmissionRejudgeAPI(APIView): submission.statistic_info = {} submission.save() - judge_task.delay(submission.id, submission.problem.id, is_rejudge=True) + judge_task.delay(submission.id, submission.problem.id) return self.success()