@@ -313,33 +313,88 @@ public function updateJudgingAction(
313
313
}
314
314
315
315
if ($ request ->request ->has ('output_compile ' )) {
316
+ $ output_compile = base64_decode ($ request ->request ->get ('output_compile ' ));
317
+
316
318
// Note: we use ->get here instead of ->has since entry_point can be the empty string and then we do not
317
319
// want to update the submission or send out an update event
318
320
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 );
323
385
}
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 );
330
386
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.
333
389
/** @var Judging $judging */
334
390
$ judging = $ query ->getOneOrNullResult ();
335
- });
391
+ }
336
392
}
337
393
338
394
// Reload judgehost just in case it got cleared above.
339
395
/** @var Judgehost $judgehost */
340
396
$ judgehost = $ this ->em ->getRepository (Judgehost::class)->findOneBy (['hostname ' => $ hostname ]);
341
397
342
- $ output_compile = base64_decode ($ request ->request ->get ('output_compile ' ));
343
398
if ($ request ->request ->getBoolean ('compile_success ' )) {
344
399
if ($ judging ->getOutputCompile () === null ) {
345
400
$ judging
0 commit comments