Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit d284ddd

Browse files
committed
Lock, and transaction-free entry_point update
1 parent 8f7f672 commit d284ddd

File tree

1 file changed

+69
-14
lines changed

1 file changed

+69
-14
lines changed

‎webapp/src/Controller/API/JudgehostController.php‎

Lines changed: 69 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -313,33 +313,88 @@ public function updateJudgingAction(
313313
}
314314

315315
if ($request->request->has('output_compile')) {
316+
$output_compile = base64_decode($request->request->get('output_compile'));
317+
316318
// Note: we use ->get here instead of ->has since entry_point can be the empty string and then we do not
317319
// want to update the submission or send out an update event
318320
if ($request->request->get('entry_point')) {
319-
$this->em->wrapInTransaction(function () use ($query, $request, &$judging) {
320-
$submission = $judging->getSubmission();
321-
if ($submission->getEntryPoint() === $request->request->get('entry_point')) {
322-
return;
321+
// Lock-free setting of, and detection of mismatched entry_point.
322+
$submission = $judging->getSubmission();
323+
324+
// Retrieve, and update the current entrypoint.
325+
$oldEntryPoint = $submission->getEntryPoint();
326+
$newEntryPoint = $request->request->get('entry_point');
327+
328+
329+
if ($oldEntryPoint === $newEntryPoint) {
330+
// Nothing to do
331+
} else if (!empty($oldEntryPoint)) {
332+
// Conflict detected disable the judgehost.
333+
$disabled = [
334+
'kind' => 'judgehost',
335+
'hostname' => $judgehost->getHostname(),
336+
];
337+
$error = new InternalError();
338+
$error
339+
->setJudging($judging)
340+
->setContest($judging->getContest())
341+
->setDescription('Reported EntryPoint conflict difference for j' . $judging->getJudgingid().'. Expected: "' . $oldEntryPoint. '", received: "' . $newEntryPoint . '".')
342+
->setJudgehostlog(base64_encode('New compilation output: ' . $output_compile))
343+
->setTime(Utils::now())
344+
->setDisabled($disabled);
345+
$this->em->persist($error);
346+
} else {
347+
// Update needed. Note, conflicts might still be possible.
348+
349+
$rowsAffected = $this->em->createQueryBuilder()
350+
->update(Submission::class, 's')
351+
->set('entry_point', $newEntryPoint)
352+
->where('submitid = :id')
353+
->andWhere('entry_point IS NULL')
354+
->setParameter('id', $submission->getSubmitid())
355+
->getQuery()
356+
->execute();
357+
358+
if ($rowsAffected == 0) {
359+
// There is a potential conflict, two options.
360+
// The new entry point is either the same (no issue) or different (conflict).
361+
// Read the entrypoint and check.
362+
$this->em->clear();
363+
$currentEntryPoint = $query->getOneOrNullResult()->getSubmission()->getEntryPoint();
364+
if ($newEntryPoint !== $currentEntryPoint) {
365+
// Conflict detected disable the judgehost.
366+
$disabled = [
367+
'kind' => 'judgehost',
368+
'hostname' => $judgehost->getHostname(),
369+
];
370+
$error = new InternalError();
371+
$error
372+
->setJudging($judging)
373+
->setContest($judging->getContest())
374+
->setDescription('Reported EntryPoint conflict difference for j' . $judging->getJudgingid().'. Expected: "' . $oldEntryPoint. '", received: "' . $newEntryPoint . '".')
375+
->setJudgehostlog(base64_encode('New compilation output: ' . $output_compile))
376+
->setTime(Utils::now())
377+
->setDisabled($disabled);
378+
$this->em->persist($error);
379+
}
380+
} else {
381+
$submissionId = $submission->getSubmitid();
382+
$contestId = $submission->getContest()->getCid();
383+
$this->eventLogService->log('submission', $submissionId,
384+
EventLogService::ACTION_UPDATE, $contestId);
323385
}
324-
$submission->setEntryPoint($request->request->get('entry_point'));
325-
$this->em->flush();
326-
$submissionId = $submission->getSubmitid();
327-
$contestId = $submission->getContest()->getCid();
328-
$this->eventLogService->log('submission', $submissionId,
329-
EventLogService::ACTION_UPDATE, $contestId);
330386

331-
// As EventLogService::log() will clear the entity manager, so the judging has
332-
// now become detached. We will have to reload it.
387+
// As EventLogService::log() will clear the entity manager, both branches clear the entity manager.
388+
// The judging is now detached, reload it.
333389
/** @var Judging $judging */
334390
$judging = $query->getOneOrNullResult();
335-
});
391+
}
336392
}
337393

338394
// Reload judgehost just in case it got cleared above.
339395
/** @var Judgehost $judgehost */
340396
$judgehost = $this->em->getRepository(Judgehost::class)->findOneBy(['hostname' => $hostname]);
341397

342-
$output_compile = base64_decode($request->request->get('output_compile'));
343398
if ($request->request->getBoolean('compile_success')) {
344399
if ($judging->getOutputCompile() === null) {
345400
$judging

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /