Cache Problem Testcases

This commit is contained in:
cuom1999 2021-05-24 23:22:56 -05:00
parent c76b1a4ed1
commit 6c66f96e9d
2 changed files with 72 additions and 48 deletions

View file

@ -1,6 +1,8 @@
from collections import defaultdict from collections import defaultdict
from math import e from math import e
import os, zipfile
from django.conf import settings
from django.core.cache import cache from django.core.cache import cache
from django.db.models import Case, Count, ExpressionWrapper, F, Max, Q, When from django.db.models import Case, Count, ExpressionWrapper, F, Max, Q, When
from django.db.models.fields import FloatField from django.db.models.fields import FloatField
@ -145,3 +147,61 @@ def hot_problems(duration, limit):
cache.set(cache_key, qs, 900) cache.set(cache_key, qs, 900)
return qs return qs
def get_visible_content(data):
data = data or b''
data = data.replace(b'\r\n', b'\r').replace(b'\r', b'\n')
data = data.decode('utf-8')
if (len(data) > settings.TESTCASE_VISIBLE_LENGTH):
data = data[:settings.TESTCASE_VISIBLE_LENGTH]
data += '.' * 3
return data
def get_cachekey_file(file):
return file.replace(' ', '===')
def get_problem_case(problem, files):
result = {}
uncached_files = []
for file in files:
cache_key = 'problem_archive:%s:%s' % (problem.code, get_cachekey_file(file))
qs = cache.get(cache_key)
if qs is None:
uncached_files.append(file)
else:
result['file'] = qs
if not uncached_files:
return result
archive_path = os.path.join(settings.DMOJ_PROBLEM_DATA_ROOT,
str(problem.data_files.zipfile))
if not os.path.exists(archive_path):
raise Exception(
'archive file "%s" does not exist' % archive_path)
try:
archive = zipfile.ZipFile(archive_path, 'r')
except zipfile.BadZipfile:
raise Exception('bad archive: "%s"' % archive_path)
for file in uncached_files:
cache_key = 'problem_archive:%s:%s' % (problem.code, get_cachekey_file(file))
with archive.open(file) as f:
s = f.read(settings.TESTCASE_VISIBLE_LENGTH + 3)
# add this so there are no characters left behind (ex, 'á' = 2 utf-8 chars)
while True:
try:
s.decode('utf-8')
break
except UnicodeDecodeError:
s += f.read(1)
qs = get_visible_content(s)
cache.set(cache_key, qs, 86400)
result[file] = qs
return result

View file

@ -43,6 +43,7 @@ from judge.utils.problems import get_result_data
from judge.utils.problems import user_authored_ids from judge.utils.problems import user_authored_ids
from judge.utils.problems import user_completed_ids from judge.utils.problems import user_completed_ids
from judge.utils.problems import user_editable_ids from judge.utils.problems import user_editable_ids
from judge.utils.problems import get_problem_case
from judge.utils.raw_sql import join_sql_subquery, use_straight_join from judge.utils.raw_sql import join_sql_subquery, use_straight_join
from judge.utils.views import DiggPaginatorMixin from judge.utils.views import DiggPaginatorMixin
from judge.utils.views import TitleMixin from judge.utils.views import TitleMixin
@ -137,60 +138,23 @@ def group_test_cases(cases):
return result return result
def read_head_archive(archive, file): def get_cases_data(submission):
with archive.open(file) as f:
s = f.read(settings.TESTCASE_VISIBLE_LENGTH + 3)
# add this so there are no characters left behind (ex, 'á' = 2 utf-8 chars)
while True:
try:
s.decode('utf-8')
break
except UnicodeDecodeError:
s += f.read(1)
return s
def get_visible_content(data):
data = data or b''
data = data.replace(b'\r\n', b'\r').replace(b'\r', b'\n')
data = data.decode('utf-8')
if (len(data) > settings.TESTCASE_VISIBLE_LENGTH):
data = data[:settings.TESTCASE_VISIBLE_LENGTH]
data += '.' * 3
return data
def get_input_answer(case, archive):
result = {'input': '', 'answer': ''}
if (len(case.input_file)):
result['input'] = get_visible_content(read_head_archive(archive, case.input_file))
if (len(case.output_file)):
result['answer'] = get_visible_content(read_head_archive(archive, case.output_file))
return result
def get_problem_data(submission):
archive_path = os.path.join(settings.DMOJ_PROBLEM_DATA_ROOT,
str(submission.problem.data_files.zipfile))
if not os.path.exists(archive_path):
raise Exception(
'archive file "%s" does not exist' % archive_path)
try:
archive = zipfile.ZipFile(archive_path, 'r')
except zipfile.BadZipfile:
raise Exception('bad archive: "%s"' % archive_path)
testcases = ProblemTestCase.objects.filter(dataset=submission.problem)\ testcases = ProblemTestCase.objects.filter(dataset=submission.problem)\
.order_by('order') .order_by('order')
if (submission.is_pretested): if (submission.is_pretested):
testcases = testcases.filter(is_pretest=True) testcases = testcases.filter(is_pretest=True)
files = []
for case in testcases:
if case.input_file: files.append(case.input_file)
if case.output_file: files.append(case.output_file)
case_data = get_problem_case(submission.problem, files)
problem_data = {} problem_data = {}
for count, case in enumerate(testcases): for count, case in enumerate(testcases):
problem_data[count + 1] = get_input_answer(case, archive) problem_data[count + 1] = {'input': case_data[case.input_file],
'answer': case_data[case.output_file]}
return problem_data return problem_data
@ -210,7 +174,7 @@ class SubmissionStatus(SubmissionDetailBase):
if (contest is not None): if (contest is not None):
prefix_length = contest.problem.output_prefix_override prefix_length = contest.problem.output_prefix_override
if ((contest is None or prefix_length > 0) or self.request.user.is_superuser): if ((contest is None or prefix_length > 0) or self.request.user.is_superuser):
context['cases_data'] = get_problem_data(submission) context['cases_data'] = get_cases_data(submission)
try: try:
lang_limit = submission.problem.language_limits.get( lang_limit = submission.problem.language_limits.get(