Skip to content

Commit e6406f8

Browse files
Drastically speed up creating rejudgings by using direct queries
On my laptop creating a rejudging for the whole of WF46 went from 807 seconds to 16 seconds, a 50x improvement.
1 parent 274d36a commit e6406f8

File tree

2 files changed

+66
-43
lines changed

2 files changed

+66
-43
lines changed

webapp/src/Service/DOMJudgeService.php

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1202,14 +1202,17 @@ public function maybeCreateJudgeTasks(Judging $judging, int $priority = JudgeTas
12021202
// - the new submission would get X+5+60 (since there's only one of their submissions still to be worked on),
12031203
// but we want to judge submissions of this team in order, so we take the current max (X+120) and add 1.
12041204
$teamPriority = (int)(max($result['max']+1, $submission->getSubmittime() + 60*$result['count']));
1205-
$queueTask = new QueueTask();
1206-
$queueTask->setJudging($judging)
1207-
->setPriority($priority)
1208-
->setTeam($team)
1209-
->setTeamPriority($teamPriority)
1210-
->setStartTime(null);
1211-
$this->em->persist($queueTask);
1212-
$this->em->flush();
1205+
// Use a direct query to speed things up
1206+
$this->em->getConnection()->executeQuery(
1207+
'INSERT INTO queuetask (judgingid, priority, teamid, teampriority, starttime)
1208+
VALUES (:judgingid, :priority, :teamid, :teampriority, null)',
1209+
[
1210+
'judgingid' => $judging->getJudgingid(),
1211+
'priority' => $priority,
1212+
'teamid' => $team->getTeamid(),
1213+
'teampriority' => $teamPriority,
1214+
]
1215+
);
12131216
}
12141217

12151218
public function getImmutableCompareExecutable(ContestProblem $problem): ImmutableExecutable

webapp/src/Service/RejudgingService.php

Lines changed: 55 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
use Doctrine\ORM\EntityManagerInterface;
1717
use Doctrine\ORM\NonUniqueResultException;
1818
use Doctrine\ORM\NoResultException;
19+
use Ramsey\Uuid\Uuid;
1920

2021
class RejudgingService
2122
{
@@ -99,43 +100,62 @@ public function createRejudging(
99100
}
100101

101102

102-
$this->em->wrapInTransaction(function () use (
103-
$priority,
104-
$singleJudging,
105-
$judging,
106-
$rejudging
107-
) {
108-
$this->em->getConnection()->executeStatement(
109-
'UPDATE submission SET rejudgingid = :rejudgingid WHERE submitid = :submitid AND rejudgingid IS NULL',
110-
[
111-
'rejudgingid' => $rejudging->getRejudgingid(),
112-
'submitid' => $judging->getSubmissionId(),
113-
]
114-
);
115-
116-
if ($singleJudging) {
117-
$teamid = $judging->getSubmission()->getTeamId();
118-
if ($teamid) {
119-
$this->em->getConnection()->executeStatement(
120-
'UPDATE team SET judging_last_started = null WHERE teamid = :teamid',
121-
[ 'teamid' => $teamid ]
122-
);
123-
}
103+
// $this->>em->wrapInTransaction flushes the entity manager, which is pretty slow.
104+
// So use the direct connection transaction API here.
105+
$this->em->getConnection()->beginTransaction();
106+
107+
$this->em->getConnection()->executeStatement(
108+
'UPDATE submission SET rejudgingid = :rejudgingid WHERE submitid = :submitid AND rejudgingid IS NULL',
109+
[
110+
'rejudgingid' => $rejudging->getRejudgingid(),
111+
'submitid' => $judging->getSubmissionId(),
112+
]
113+
);
114+
115+
if ($singleJudging) {
116+
$teamid = $judging->getSubmission()->getTeamId();
117+
if ($teamid) {
118+
$this->em->getConnection()->executeStatement(
119+
'UPDATE team SET judging_last_started = null WHERE teamid = :teamid',
120+
[ 'teamid' => $teamid ]
121+
);
124122
}
123+
}
125124

126-
// Give back judging, create a new one.
127-
$newJudging = new Judging();
128-
$newJudging
129-
->setContest($judging->getContest())
130-
->setValid(false)
131-
->setSubmission($judging->getSubmission())
132-
->setOriginalJudging($judging)
133-
->setRejudging($rejudging);
134-
$this->em->persist($newJudging);
135-
$this->em->flush();
136-
137-
$this->dj->maybeCreateJudgeTasks($newJudging, $priority);
138-
});
125+
// Give back judging, create a new one.
126+
// Use a direct query to speed things up.
127+
$this->em->getConnection()->executeStatement(
128+
'INSERT INTO judging (cid, valid, submitid, prevjudgingid, rejudgingid, uuid)
129+
VALUES (:cid, 0, :submitid, :prevjudgingid, :rejudgingid, :uuid)',
130+
[
131+
'cid' => $judging->getContest()->getCid(),
132+
'submitid' => $judging->getSubmissionId(),
133+
'prevjudgingid' => $judging->getJudgingId(),
134+
'rejudgingid' => $rejudging->getRejudgingid(),
135+
'uuid' => Uuid::uuid4()->toString(),
136+
]
137+
);
138+
$newJudgingId = $this->em->getConnection()->lastInsertId();
139+
$newJudging = $this->em->getRepository(Judging::class)
140+
->createQueryBuilder('j')
141+
->join('j.submission', 's')
142+
->join('s.contest_problem', 'cp')
143+
->join('s.language', 'l')
144+
->join('l.compile_executable', 'e')
145+
->join('cp.problem', 'p')
146+
->leftJoin('p.compare_executable', 'ce')
147+
->leftJoin('ce.immutableExecutable', 'ice')
148+
->leftJoin('p.run_executable', 're')
149+
->leftJoin('re.immutableExecutable', 'ire')
150+
->select('j', 's', 'cp', 'l', 'e', 'p', 'ce', 'ice', 're', 'ire')
151+
->andWhere('j.judgingid = :judgingid')
152+
->setParameter('judgingid', $newJudgingId)
153+
->getQuery()
154+
->getSingleResult();
155+
156+
$this->dj->maybeCreateJudgeTasks($newJudging, $priority);
157+
158+
$this->em->getConnection()->commit();
139159

140160
if (!$first) {
141161
$log .= ', ';

0 commit comments

Comments
 (0)