<commit_before>import logging
import os
import time

from django import db
from django.utils import timezone

from judge import event_poster as event
from judge.caching import finished_submission
from judge.models import Submission, SubmissionTestCase, Problem, Judge, Language, LanguageLimit, RuntimeVersion
from .judgehandler import JudgeHandler

logger = logging.getLogger('judge.bridge')

UPDATE_RATE_LIMIT = 5
UPDATE_RATE_TIME = 0.5
TIMER = [time.time, time.clock][os.name == 'nt']


def _ensure_connection():
    try:
        db.connection.cursor().execute('SELECT 1').fetchall()
    except Exception:
        db.connection.close()


class DjangoJudgeHandler(JudgeHandler):
    def __init__(self, server, socket):
        super(DjangoJudgeHandler, self).__init__(server, socket)

        # each value is (updates, last reset)
        self.update_counter = {}

    def on_close(self):
        super(DjangoJudgeHandler, self).on_close()
        if self._working:
            submission = Submission.objects.get(id=self._working)
            submission.status = 'IE'
            submission.save()

    def get_related_submission_data(self, submission):
        _ensure_connection()  # We are called from the django-facing daemon thread. Guess what happens.

        pid, time, memory, short_circuit, lid, is_pretested = Submission.objects.filter(id=submission).\
            values_list('problem__id', 'problem__time_limit', 'problem__memory_limit',
                        'problem__short_circuit', 'language__id', 'is_pretested')[0]

        try:
            limit = LanguageLimit.objects.get(problem__id=pid, language__id=lid)
        except LanguageLimit.DoesNotExist:
            pass
        else:
            time, memory = limit.time_limit, limit.memory_limit
        return time, memory, short_circuit, is_pretested

    def _authenticate(self, id, key):
        try:
            judge = Judge.objects.get(name=id)
        except Judge.DoesNotExist:
            return False
        return judge.auth_key == key

    def _connected(self):
        judge = Judge.objects.get(name=self.name)
        judge.start_time = timezone.now()
        judge.online = True
        judge.problems = Problem.objects.filter(code__in=self.problems.keys())
        judge.runtimes = Language.objects.filter(key__in=self.executors.keys())

        # Delete now in case we somehow crashed and left some over from the last connection
        RuntimeVersion.objects.filter(judge=judge).delete()
        for lang in judge.runtimes.all():
            runtimes = []
            for idx, data in enumerate(self.executors[lang.key]):
                name, version = data
                runtimes.append(RuntimeVersion(language=lang, name=name, version='.'.join(map(str, version)),
                                               priority=idx, judge=judge))
            RuntimeVersion.objects.bulk_create(runtimes)
        judge.last_ip = self.client_address[0]
        judge.save()

    def _disconnected(self):
        Judge.objects.filter(name=self.name).update(online=False)
        RuntimeVersion.objects.filter(judge__name=self.name).delete()

    def _update_ping(self):
        try:
            Judge.objects.filter(name=self.name).update(ping=self.latency, load=self.load)
        except Exception as e:
            # What can I do? I don't want to tie this to MySQL.
            if e.__class__.__name__ == 'OperationalError' and e.__module__ == '_mysql_exceptions' and e.args[0] == 2006:
                db.connection.close()

    def on_submission_processing(self, packet):
        try:
            submission = Submission.objects.get(id=packet['submission-id'])
        except Submission.DoesNotExist:
            logger.warning('Unknown submission: %d', packet['submission-id'])
            return

        try:
            submission.judged_on = Judge.objects.get(name=self.name)
        except Judge.DoesNotExist:
            # Just in case. Is not necessary feature and is not worth the crash.
            pass

        submission.status = 'P'
        submission.save()
        event.post('sub_%d' % submission.id, {'type': 'processing'})
        if not submission.problem.is_public:
            return
        event.post('submissions', {'type': 'update-submission', 'id': submission.id,
                                   'state': 'processing', 'contest': submission.contest_key,
                                   'user': submission.user_id, 'problem': submission.problem_id,
                                   'status': submission.status, 'language': submission.language.key})

    def on_grading_begin(self, packet):
        super(DjangoJudgeHandler, self).on_grading_begin(packet)
        try:
            submission = Submission.objects.get(id=packet['submission-id'])
        except Submission.DoesNotExist:
            logger.warning('Unknown submission: %d', packet['submission-id'])
            return
        submission.status = 'G'

        # Update pretest state now that we know for sure whether the problem has pretest data
        submission.is_pretested = packet['pretested']
        submission.current_testcase = 1
        submission.batch = False
        submission.save()
        SubmissionTestCase.objects.filter(submission_id=submission.id).delete()
        event.post('sub_%d' % submission.id, {'type': 'grading-begin'})
        if not submission.problem.is_public:
            return
        event.post('submissions', {'type': 'update-submission', 'id': submission.id,
                                   'state': 'grading-begin', 'contest': submission.contest_key,
                                   'user': submission.user_id, 'problem': submission.problem_id,
                                   'status': submission.status, 'language': submission.language.key})

    def _submission_is_batch(self, id):
        submission = Submission.objects.get(id=id)
        submission.batch = True
        submission.save()

    def on_grading_end(self, packet):
        super(DjangoJudgeHandler, self).on_grading_end(packet)
        try:
            submission = Submission.objects.get(id=packet['submission-id'])
        except Submission.DoesNotExist:
            logger.warning('Unknown submission: %d', packet['submission-id'])
            return

        time = 0
        memory = 0
        points = 0.0
        total = 0
        status = 0
        status_codes = ['SC', 'AC', 'WA', 'MLE', 'TLE', 'IR', 'RTE', 'OLE']
        batches = {}  # batch number: (points, total)

        for case in SubmissionTestCase.objects.filter(submission=submission):
            time += case.time
            if not case.batch:
                points += case.points
                total += case.total
            else:
                if case.batch in batches:
                    batches[case.batch][0] = min(batches[case.batch][0], case.points)
                    batches[case.batch][1] = max(batches[case.batch][1], case.total)
                else:
                    batches[case.batch] = [case.points, case.total]
            memory = max(memory, case.memory)
            i = status_codes.index(case.status)
            if i > status:
                status = i

        for i in batches:
            points += batches[i][0]
            total += batches[i][1]

        points = round(points, 1)
        total = round(total, 1)
        submission.case_points = points
        submission.case_total = total

        sub_points = round(points / total * submission.problem.points if total > 0 else 0, 1)
        if not submission.problem.partial and sub_points != submission.problem.points:
            sub_points = 0

        submission.status = 'D'
        submission.time = time
        submission.memory = memory
        submission.points = sub_points
        submission.result = status_codes[status]
        submission.save()

        submission.user._updating_stats_only = True
        submission.user.calculate_points()
        submission.problem._updating_stats_only = True
        submission.problem.update_stats()

        if hasattr(submission, 'contest'):
            contest = submission.contest
            contest.points = round(points / total * contest.problem.points if total > 0 else 0, 1)
            if not contest.problem.partial and contest.points != contest.problem.points:
                contest.points = 0
            contest.save()
            submission.contest.participation.recalculate_score()
            submission.contest.participation.update_cumtime()

        finished_submission(submission)

        event.post('sub_%d' % submission.id, {
            'type': 'grading-end',<commit_msg>Round to 3 places for #417<commit_after>import logging
import os
import time

from django import db
from django.utils import timezone

from judge import event_poster as event
from judge.caching import finished_submission
from judge.models import Submission, SubmissionTestCase, Problem, Judge, Language, LanguageLimit, RuntimeVersion
from .judgehandler import JudgeHandler

logger = logging.getLogger('judge.bridge')

UPDATE_RATE_LIMIT = 5
UPDATE_RATE_TIME = 0.5
TIMER = [time.time, time.clock][os.name == 'nt']


def _ensure_connection():
    try:
        db.connection.cursor().execute('SELECT 1').fetchall()
    except Exception:
        db.connection.close()


class DjangoJudgeHandler(JudgeHandler):
    def __init__(self, server, socket):
        super(DjangoJudgeHandler, self).__init__(server, socket)

        # each value is (updates, last reset)
        self.update_counter = {}

    def on_close(self):
        super(DjangoJudgeHandler, self).on_close()
        if self._working:
            submission = Submission.objects.get(id=self._working)
            submission.status = 'IE'
            submission.save()

    def get_related_submission_data(self, submission):
        _ensure_connection()  # We are called from the django-facing daemon thread. Guess what happens.

        pid, time, memory, short_circuit, lid, is_pretested = Submission.objects.filter(id=submission).\
            values_list('problem__id', 'problem__time_limit', 'problem__memory_limit',
                        'problem__short_circuit', 'language__id', 'is_pretested')[0]

        try:
            limit = LanguageLimit.objects.get(problem__id=pid, language__id=lid)
        except LanguageLimit.DoesNotExist:
            pass
        else:
            time, memory = limit.time_limit, limit.memory_limit
        return time, memory, short_circuit, is_pretested

    def _authenticate(self, id, key):
        try:
            judge = Judge.objects.get(name=id)
        except Judge.DoesNotExist:
            return False
        return judge.auth_key == key

    def _connected(self):
        judge = Judge.objects.get(name=self.name)
        judge.start_time = timezone.now()
        judge.online = True
        judge.problems = Problem.objects.filter(code__in=self.problems.keys())
        judge.runtimes = Language.objects.filter(key__in=self.executors.keys())

        # Delete now in case we somehow crashed and left some over from the last connection
        RuntimeVersion.objects.filter(judge=judge).delete()
        for lang in judge.runtimes.all():
            runtimes = []
            for idx, data in enumerate(self.executors[lang.key]):
                name, version = data
                runtimes.append(RuntimeVersion(language=lang, name=name, version='.'.join(map(str, version)),
                                               priority=idx, judge=judge))
            RuntimeVersion.objects.bulk_create(runtimes)
        judge.last_ip = self.client_address[0]
        judge.save()

    def _disconnected(self):
        Judge.objects.filter(name=self.name).update(online=False)
        RuntimeVersion.objects.filter(judge__name=self.name).delete()

    def _update_ping(self):
        try:
            Judge.objects.filter(name=self.name).update(ping=self.latency, load=self.load)
        except Exception as e:
            # What can I do? I don't want to tie this to MySQL.
            if e.__class__.__name__ == 'OperationalError' and e.__module__ == '_mysql_exceptions' and e.args[0] == 2006:
                db.connection.close()

    def on_submission_processing(self, packet):
        try:
            submission = Submission.objects.get(id=packet['submission-id'])
        except Submission.DoesNotExist:
            logger.warning('Unknown submission: %d', packet['submission-id'])
            return

        try:
            submission.judged_on = Judge.objects.get(name=self.name)
        except Judge.DoesNotExist:
            # Just in case. Is not necessary feature and is not worth the crash.
            pass

        submission.status = 'P'
        submission.save()
        event.post('sub_%d' % submission.id, {'type': 'processing'})
        if not submission.problem.is_public:
            return
        event.post('submissions', {'type': 'update-submission', 'id': submission.id,
                                   'state': 'processing', 'contest': submission.contest_key,
                                   'user': submission.user_id, 'problem': submission.problem_id,
                                   'status': submission.status, 'language': submission.language.key})

    def on_grading_begin(self, packet):
        super(DjangoJudgeHandler, self).on_grading_begin(packet)
        try:
            submission = Submission.objects.get(id=packet['submission-id'])
        except Submission.DoesNotExist:
            logger.warning('Unknown submission: %d', packet['submission-id'])
            return
        submission.status = 'G'

        # Update pretest state now that we know for sure whether the problem has pretest data
        submission.is_pretested = packet['pretested']
        submission.current_testcase = 1
        submission.batch = False
        submission.save()
        SubmissionTestCase.objects.filter(submission_id=submission.id).delete()
        event.post('sub_%d' % submission.id, {'type': 'grading-begin'})
        if not submission.problem.is_public:
            return
        event.post('submissions', {'type': 'update-submission', 'id': submission.id,
                                   'state': 'grading-begin', 'contest': submission.contest_key,
                                   'user': submission.user_id, 'problem': submission.problem_id,
                                   'status': submission.status, 'language': submission.language.key})

    def _submission_is_batch(self, id):
        submission = Submission.objects.get(id=id)
        submission.batch = True
        submission.save()

    def on_grading_end(self, packet):
        super(DjangoJudgeHandler, self).on_grading_end(packet)
        try:
            submission = Submission.objects.get(id=packet['submission-id'])
        except Submission.DoesNotExist:
            logger.warning('Unknown submission: %d', packet['submission-id'])
            return

        time = 0
        memory = 0
        points = 0.0
        total = 0
        status = 0
        status_codes = ['SC', 'AC', 'WA', 'MLE', 'TLE', 'IR', 'RTE', 'OLE']
        batches = {}  # batch number: (points, total)

        for case in SubmissionTestCase.objects.filter(submission=submission):
            time += case.time
            if not case.batch:
                points += case.points
                total += case.total
            else:
                if case.batch in batches:
                    batches[case.batch][0] = min(batches[case.batch][0], case.points)
                    batches[case.batch][1] = max(batches[case.batch][1], case.total)
                else:
                    batches[case.batch] = [case.points, case.total]
            memory = max(memory, case.memory)
            i = status_codes.index(case.status)
            if i > status:
                status = i

        for i in batches:
            points += batches[i][0]
            total += batches[i][1]

        points = round(points, 1)
        total = round(total, 1)
        submission.case_points = points
        submission.case_total = total

        sub_points = round(points / total * submission.problem.points if total > 0 else 0, 3)
        if not submission.problem.partial and sub_points != submission.problem.points:
            sub_points = 0

        submission.status = 'D'
        submission.time = time
        submission.memory = memory
        submission.points = sub_points
        submission.result = status_codes[status]
        submission.save()

        submission.user._updating_stats_only = True
        submission.user.calculate_points()
        submission.problem._updating_stats_only = True
        submission.problem.update_stats()

        if hasattr(submission, 'contest'):
            contest = submission.contest
            contest.points = round(points / total * contest.problem.points if total > 0 else 0, 3)
            if not contest.problem.partial and contest.points != contest.problem.points:
                contest.points = 0
            contest.save()
            submission.contest.participation.recalculate_score()
            submission.contest.participation.update_cumtime()

        finished_submission(submission)

        event.post('sub_%d' % submission.id, {
            'type': 'grading-end',
{'fraction_non_alphanumeric': 0.10524181870836953, 'fraction_numerical': 0.004170286707211121, 'mean_word_length': 2.2638941398865784, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 9, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 16, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7194679', 'n_tokens_mistral': 4836, 'n_tokens_neox': 4670, 'n_words': 1048}