Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
104 changes: 43 additions & 61 deletions judge/judgedaemon.main.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
{
private static ?JudgeDaemon $instance = null;

private array $endpoints = [];
private ?array $endpoint = null;
private array $domjudge_config = [];
private string $myhost;
private int $verbose = LOG_INFO;
Expand All @@ -35,8 +35,6 @@
private ?string $lastrequest = '';
private float $waittime = self::INITIAL_WAITTIME_SEC;

private ?string $endpointID = null;

private array $langexts = [];

private $lockfile;
Expand Down Expand Up @@ -221,10 +219,7 @@
error("chroot validation check failed");
}

foreach (array_keys($this->endpoints) as $id) {
$this->endpointID = $id;
$this->registerJudgehost();
}
$this->registerJudgehost();

// Populate the DOMjudge configuration initially
$this->djconfigRefresh();
Expand All @@ -248,34 +243,21 @@

private function loop(): void
{
$endpointIDs = array_keys($this->endpoints);
$currentEndpoint = 0;
$lastWorkdir = null;
$workdirpath = JUDGEDIR . "/$this->myhost/endpoint-" . $this->endpoint['id'];

while (true) {
// If all endpoints are waiting, sleep for a bit.
$dosleep = true;
foreach ($this->endpoints as $id => $endpoint) {
if ($endpoint['errorred']) {
$this->endpointID = $id;
$this->registerJudgehost();
}
if (!$endpoint['waiting']) {
$dosleep = false;
$this->waittime = self::INITIAL_WAITTIME_SEC;
break;
}
if ($this->endpoint['errorred']) {
$this->registerJudgehost();
}
// Sleep only if everything is "waiting" and only if we're looking at the first endpoint again.
if ($dosleep && $currentEndpoint == 0) {

if ($this->endpoint['waiting']) {
dj_sleep($this->waittime);
$this->waittime = min($this->waittime * 2, self::MAXIMAL_WAITTIME_SEC);
} else {
$this->waittime = self::INITIAL_WAITTIME_SEC;
}

// Cycle through endpoints.
$currentEndpoint = ($currentEndpoint + 1) % count($this->endpoints);
$this->endpointID = $endpointIDs[$currentEndpoint];
$workdirpath = JUDGEDIR . "/$this->myhost/endpoint-$this->endpointID";

// Check whether we have received an exit signal
if (function_exists('pcntl_signal_dispatch')) {
pcntl_signal_dispatch();
Expand Down Expand Up @@ -308,12 +290,12 @@
exit;
}

if ($this->endpoints[$this->endpointID]['errorred']) {
if ($this->endpoint['errorred']) {
continue;
}


if ($this->endpoints[$this->endpointID]['waiting'] === false) {
if ($this->endpoint['waiting'] === false) {
$this->checkDiskSpace($workdirpath);
}

Expand All @@ -330,13 +312,13 @@

// Nothing returned -> no open work for us.
if (empty($row)) {
if (!$this->endpoints[$this->endpointID]["waiting"]) {
$this->endpoints[$this->endpointID]["waiting"] = true;
if (!$this->endpoint["waiting"]) {
$this->endpoint["waiting"] = true;
if ($lastWorkdir !== null) {
$this->cleanupJudging($lastWorkdir);
$lastWorkdir = null;
}
logmsg(LOG_INFO, "No submissions in queue (for endpoint $this->endpointID), waiting...");
logmsg(LOG_INFO, "No submissions in queue (for endpoint " . $this->endpoint['id'] . "), waiting...");
$judgehosts = $this->request('judgehosts', 'GET');
if ($judgehosts !== null) {
$judgehosts = dj_json_decode($judgehosts);
Expand All @@ -350,7 +332,7 @@
}

// We have gotten a work packet.
$this->endpoints[$this->endpointID]["waiting"] = false;
$this->endpoint["waiting"] = false;

// All tasks are guaranteed to be of the same type.
// If $row is empty, we already continued.
Expand Down Expand Up @@ -542,16 +524,16 @@
private function handleTask(string $type, array $row, ?string &$lastWorkdir, string $workdirpath): void
{
if ($type == 'try_again') {
if (!$this->endpoints[$this->endpointID]['retrying']) {
if (!$this->endpoint['retrying']) {
logmsg(LOG_INFO, "API indicated to retry fetching work (this might take a while to clean up).");
}
$this->endpoints[$this->endpointID]['retrying'] = true;
$this->endpoint['retrying'] = true;
return;
}
$this->endpoints[$this->endpointID]['retrying'] = false;
$this->endpoint['retrying'] = false;

logmsg(LOG_INFO,
"⇝ Received " . sizeof($row) . " '" . $type . "' judge tasks (endpoint $this->endpointID)");
"⇝ Received " . sizeof($row) . " '" . $type . "' judge tasks (endpoint " . $this->endpoint['id'] . ")");

if ($type == 'prefetch') {
$this->handlePrefetchTask($row, $lastWorkdir, $workdirpath);
Expand Down Expand Up @@ -657,10 +639,12 @@
error("Error parsing REST API credentials. Invalid format in line $lineno.");
}
[$endpointID, $resturl, $restuser, $restpass] = $items;
if (array_key_exists($endpointID, $this->endpoints)) {
error("Error parsing REST API credentials. Duplicate endpoint ID '$endpointID' in line $lineno.");

if ($this->endpoint !== null) {
error("Error parsing REST API credentials. Multiple endpoints are not supported.");
}
$this->endpoints[$endpointID] = [
$this->endpoint = [
"id" => $endpointID,
"url" => $resturl,
"user" => $restuser,
"pass" => $restpass,
Expand All @@ -670,7 +654,7 @@
"retrying" => false,
];
}
if (count($this->endpoints) <= 0) {
if ($this->endpoint === null) {
error("Error parsing REST API credentials: no endpoints found.");
}
}
Expand All @@ -687,11 +671,9 @@

private function closeCurlHandles(): void
{
foreach ($this->endpoints as $id => $endpoint) {
if (!empty($endpoint['ch'])) {
curl_close($endpoint['ch']);
unset($this->endpoints[$id]['ch']);
}
if (!empty($this->endpoint['ch'])) {
curl_close($this->endpoint['ch']);
unset($this->endpoint['ch']);
}
}

Expand All @@ -708,8 +690,8 @@
$this->lastrequest = $url;
}

$requestUrl = $this->endpoints[$this->endpointID]['url'] . "/" . $url;
$curl_handle = $this->endpoints[$this->endpointID]['ch'];
$requestUrl = $this->endpoint['url'] . "/" . $url;
$curl_handle = $this->endpoint['ch'];
if ($verb == 'GET') {
$requestUrl .= '?' . $data;
}
Expand Down Expand Up @@ -778,15 +760,15 @@
error($errstr);
} else {
warning($errstr);
$this->endpoints[$this->endpointID]['errorred'] = true;
$this->endpoint['errorred'] = true;
return null;
}
}

if ($this->endpoints[$this->endpointID]['errorred']) {
$this->endpoints[$this->endpointID]['errorred'] = false;
$this->endpoints[$this->endpointID]['waiting'] = false;
logmsg(LOG_NOTICE, "Reconnected to endpoint $this->endpointID.");
if ($this->endpoint['errorred']) {
$this->endpoint['errorred'] = false;
$this->endpoint['waiting'] = false;
logmsg(LOG_NOTICE, "Reconnected to endpoint " . $this->endpoint['id'] . ".");
}

return $response;
Expand Down Expand Up @@ -857,7 +839,7 @@
return trim(ob_get_clean());
}

private function runCommandSafe(array $command_parts, & $retval = DONT_CARE, $log_nonzero_exitcode = true): bool

Check failure on line 842 in judge/judgedaemon.main.php

View workflow job for this annotation

GitHub Actions / phpcs

Expected 0 spaces after reference operator for argument &quot;$retval&quot;; 1 found
{
if (empty($command_parts)) {
logmsg(LOG_WARNING, "Need at least the command that should be called.");
Expand All @@ -869,7 +851,7 @@

logmsg(LOG_DEBUG, "Executing command: $command");
system($command, $retval_local);
if ($retval !== DONT_CARE) $retval = $retval_local;

Check failure on line 854 in judge/judgedaemon.main.php

View workflow job for this annotation

GitHub Actions / phpcs

Inline control structures are not allowed

if ($retval_local !== 0) {
if ($log_nonzero_exitcode) {
Expand All @@ -889,7 +871,7 @@
int $judgeTaskId,
bool $combined_run_compare = false
): array
{

Check failure on line 874 in judge/judgedaemon.main.php

View workflow job for this annotation

GitHub Actions / phpcs

The closing parenthesis and the opening brace of a multi-line function declaration must be on the same line
[$execrunpath, $error, $buildlogpath] = $this->fetchExecutableInternal($workdirpath, $type, $execid, $hash, $combined_run_compare);
if (isset($error)) {
$extra_log = null;
Expand Down Expand Up @@ -918,7 +900,7 @@
string $hash,
bool $combined_run_compare = false
): array
{

Check failure on line 903 in judge/judgedaemon.main.php

View workflow job for this annotation

GitHub Actions / phpcs

The closing parenthesis and the opening brace of a multi-line function declaration must be on the same line
$execdir = join('/', [
$workdirpath,
'executable',
Expand Down Expand Up @@ -1083,7 +1065,7 @@

private function registerJudgehost(): void
{
$endpoint = &$this->endpoints[$this->endpointID];
$endpoint = &$this->endpoint;

// Only try to register every 30s.
$now = time();
Expand All @@ -1093,11 +1075,11 @@
}
$endpoint['last_attempt'] = $now;

logmsg(LOG_NOTICE, "Registering judgehost on endpoint $this->endpointID: " . $endpoint['url']);
$this->endpoints[$this->endpointID]['ch'] = $this->setupCurlHandle($endpoint['user'], $endpoint['pass']);
logmsg(LOG_NOTICE, "Registering judgehost on endpoint " . $this->endpoint['id'] . ": " . $endpoint['url']);
$this->endpoint['ch'] = $this->setupCurlHandle($endpoint['user'], $endpoint['pass']);

// Create directory where to test submissions
$workdirpath = JUDGEDIR . "/$this->myhost/endpoint-$this->endpointID";
$workdirpath = JUDGEDIR . "/$this->myhost/endpoint-" . $this->endpoint['id'];
if (!$this->runCommandSafe(['mkdir', '-p', "$workdirpath/testcase"])) {
error("Could not create $workdirpath");
}
Expand All @@ -1108,7 +1090,7 @@
// they have and will not be finished. Give them back.
$unfinished = $this->request('judgehosts', 'POST', ['hostname' => urlencode($this->myhost)], false);
if ($unfinished === null) {
logmsg(LOG_WARNING, "Registering judgehost on endpoint $this->endpointID failed.");
logmsg(LOG_WARNING, "Registering judgehost on endpoint " . $this->endpoint['id'] . " failed.");
} else {
$unfinished = dj_json_decode($unfinished);
foreach ($unfinished as $jud) {
Expand All @@ -1123,12 +1105,12 @@
private function disable(
string $kind,
string $idcolumn,
$id,

Check failure on line 1108 in judge/judgedaemon.main.php

View workflow job for this annotation

GitHub Actions / phpcs

Multi-line function declaration not indented correctly; expected 8 spaces but found 16
string $description,
?int $judgeTaskId = null,
?string $extra_log = null
): void
{

Check failure on line 1113 in judge/judgedaemon.main.php

View workflow job for this annotation

GitHub Actions / phpcs

The closing parenthesis and the opening brace of a multi-line function declaration must be on the same line
$disabled = dj_json_encode(['kind' => $kind, $idcolumn => $id]);
$judgehostlog = $this->readJudgehostLog();
if (isset($extra_log)) {
Expand Down Expand Up @@ -1198,7 +1180,7 @@
?string $daemonid,
int $output_storage_limit
): bool
{

Check failure on line 1183 in judge/judgedaemon.main.php

View workflow job for this annotation

GitHub Actions / phpcs

The closing parenthesis and the opening brace of a multi-line function declaration must be on the same line
// Reuse compilation if it already exists.
if (file_exists("$workdir/compile.success")) {
return true;
Expand Down Expand Up @@ -1683,8 +1665,8 @@

// The child should use its own curl handle to avoid issues with sharing handles
// between processes.
$endpoint = $this->endpoints[$this->endpointID];
$this->endpoints[$this->endpointID]['ch'] = $this->setupCurlHandle($endpoint['user'], $endpoint['pass']);
$endpoint = $this->endpoint;
$this->endpoint['ch'] = $this->setupCurlHandle($endpoint['user'], $endpoint['pass']);
}
} elseif ($asynchronous) {
logmsg(LOG_WARNING, "pcntl extension not available, reporting result for jt$judgeTaskId synchronously.");
Expand Down
Loading