@@ -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