Example #1
0
/**
 * Update tables used for efficiently computing team ranks
 *
 * Given a contestid and teamid (re)calculate the time
 * and solved problems for a team. Third parameter indictates
 * if the cache for jury or public should be updated.
 *
 * Due to current transactions usage, this function MUST NOT contain
 * any START TRANSACTION or COMMIT statements.
 */
function updateRankCache($cid, $team, $jury)
{
    global $DB;
    logmsg(LOG_DEBUG, "updateRankCache '{$cid}' '{$team}' '{$jury}'");
    $team_penalty = $DB->q("VALUE SELECT penalty FROM team WHERE teamid = %i", $team);
    // Find table name
    $tblname = $jury ? 'jury' : 'public';
    // First acquire an advisory lock to prevent other calls to
    // calcScoreRow() from interfering with our update.
    $lockstr = "domjudge.{$cid}.{$team}.{$tblname}";
    if ($DB->q("VALUE SELECT GET_LOCK('{$lockstr}',3)") != 1) {
        error("updateRankCache failed to obtain lock '{$lockstr}'");
    }
    // Fetch values from scoreboard cache per problem
    $scoredata = $DB->q("SELECT submissions, is_correct, cp.points, totaltime\n\t\t\t     FROM scorecache_{$tblname}\n\t\t\t     LEFT JOIN contestproblem cp USING(probid,cid)\n\t\t\t     WHERE cid = %i and teamid = %i", $cid, $team);
    $num_points = 0;
    $total_time = $team_penalty;
    while ($srow = $scoredata->next()) {
        // Only count solved problems
        if ($srow['is_correct']) {
            $penalty = calcPenaltyTime($srow['is_correct'], $srow['submissions']);
            $num_points += $srow['points'];
            $total_time += $srow['totaltime'] + $penalty;
        }
    }
    // Update the rank cache table
    $DB->q("REPLACE INTO rankcache_{$tblname}\n\t        (cid, teamid, points, totaltime)\n\t        VALUES (%i,%i,%i,%i)", $cid, $team, $num_points, $total_time);
    // Release the lock
    if ($DB->q("VALUE SELECT RELEASE_LOCK('{$lockstr}')") != 1) {
        error("updateRankCache failed to release lock '{$lockstr}'");
    }
}
Example #2
0
/**
 * Output a team row from the scoreboard based on the cached data in
 * table 'scoreboard'.
 */
function putTeamRow($cdata, $teamids)
{
    global $DB;
    if (empty($cdata)) {
        return;
    }
    $fdata = calcFreezeData($cdata);
    $displayrank = IS_JURY || !$fdata['showfrozen'];
    $cid = $cdata['cid'];
    if (!$fdata['cstarted']) {
        if (!IS_JURY) {
            global $teamdata;
            echo "<h2 id=\"teamwelcome\">welcome team <span id=\"teamwelcometeam\">" . htmlspecialchars($teamdata['name']) . "</span>!</h2>\n\n";
            echo "<h3 id=\"contestnotstarted\">contest is " . printContestStart($cdata) . "</h3>\n\n";
        }
        return;
    }
    // For computing team row, use smart trick when only a single team is requested such
    // that we don't need to compute the whole scoreboard.
    // This does not fully populate the summary, so the first correct problem per problem
    // is not computed and hence not shown in the individual team row.
    if (count($teamids) == 1) {
        $teams = getTeams(array("teams" => $teamids), true, $cdata);
        $probs = getProblems($cdata);
        $SCORES = initScores($teams);
        $SUMMARY = initSummary($probs);
        // Calculate rank, num points and total time from rank cache
        foreach ($teams as $teamid => $team) {
            $totals = $DB->q("MAYBETUPLE SELECT points, totaltime\n\t\t\t                  FROM rankcache_jury\n\t\t\t                  WHERE cid = %i\n\t\t\t                  AND teamid = %i", $cid, $teamid);
            if ($totals != null) {
                $SCORES[$teamid]['num_points'] = $totals['points'];
                $SCORES[$teamid]['total_time'] = $totals['totaltime'];
            }
            if ($displayrank) {
                $SCORES[$teamid]['rank'] = calcTeamRank($cdata, $teamid, $totals, true);
            }
        }
        // Get values for this team about problems from scoreboard cache
        $MATRIX = array();
        $scoredata = $DB->q("SELECT * FROM scorecache_jury WHERE cid = %i AND teamid = %i", $cid, current($teamids));
        // loop all info the scoreboard cache and put it in our own datastructure
        while ($srow = $scoredata->next()) {
            // skip this row if the problem is not known by us
            if (!array_key_exists($srow['probid'], $probs)) {
                continue;
            }
            $penalty = calcPenaltyTime($srow['is_correct'], $srow['submissions']);
            // fill our matrix with the scores from the database
            $MATRIX[$srow['teamid']][$srow['probid']] = array('is_correct' => (bool) $srow['is_correct'], 'num_submissions' => $srow['submissions'], 'num_pending' => $srow['pending'], 'time' => $srow['totaltime'], 'penalty' => $penalty);
        }
        // Fill in empty places in the matrix
        foreach (array_keys($teams) as $team) {
            foreach (array_keys($probs) as $prob) {
                // provide default scores when nothing submitted for this team,problem yet
                if (!isset($MATRIX[$team][$prob])) {
                    $MATRIX[$team][$prob] = array('is_correct' => FALSE, 'num_submissions' => 0, 'num_pending' => 0, 'time' => 0, 'penalty' => 0);
                }
            }
        }
        // Combine into data as genScoreBoard returns it
        $sdata = array('matrix' => $MATRIX, 'scores' => $SCORES, 'summary' => $SUMMARY, 'teams' => $teams, 'problems' => $probs, 'categories' => null);
    } else {
        // Otherwise, calculate scoreboard as jury to display non-visible teams
        $sdata = genScoreBoard($cdata, TRUE);
    }
    // Render the row based on this info
    $myteamid = null;
    $static = FALSE;
    if (!IS_JURY) {
        echo "<div id=\"teamscoresummary\">\n";
    }
    renderScoreBoardTable($sdata, $myteamid, $static, $teamids, $displayrank, TRUE, FALSE);
    if (!IS_JURY) {
        echo "</div>\n\n";
    }
    return;
}
Example #3
0
/**
 * Update tables used for efficiently computing team ranks
 *
 * Given a contestid and teamid (re)calculate the time
 * and solved problems for a team.
 *
 * Due to current transactions usage, this function MUST NOT contain
 * any START TRANSACTION or COMMIT statements.
 */
function updateRankCache($cid, $team)
{
    global $DB;
    logmsg(LOG_DEBUG, "updateRankCache '{$cid}' '{$team}'");
    $team_penalty = $DB->q("VALUE SELECT penalty FROM team WHERE teamid = %i", $team);
    // First acquire an advisory lock to prevent other calls to
    // calcScoreRow() from interfering with our update.
    $lockstr = "domjudge.{$cid}.{$team}";
    if ($DB->q("VALUE SELECT GET_LOCK('{$lockstr}',3)") != 1) {
        error("updateRankCache failed to obtain lock '{$lockstr}'");
    }
    // Fetch values from scoreboard cache per problem
    $scoredata = $DB->q("SELECT *, cp.points\n\t                     FROM scorecache\n\t                     LEFT JOIN contestproblem cp USING(probid,cid)\n\t                     WHERE cid = %i and teamid = %i", $cid, $team);
    $num_points = array('public' => 0, 'restricted' => 0);
    $total_time = array('public' => $team_penalty, 'restricted' => $team_penalty);
    while ($srow = $scoredata->next()) {
        // Only count solved problems
        foreach (array('public', 'restricted') as $variant) {
            if ($srow['is_correct_' . $variant]) {
                $penalty = calcPenaltyTime($srow['is_correct_' . $variant], $srow['submissions_' . $variant]);
                $num_points[$variant] += $srow['points'];
                $total_time[$variant] += scoretime($srow['solvetime_' . $variant]) + $penalty;
            }
        }
    }
    // Update the rank cache table
    $DB->q("REPLACE INTO rankcache (cid, teamid,\n\t        points_restricted, totaltime_restricted,\n\t        points_public, totaltime_public)\n\t        VALUES (%i,%i,%i,%i,%i,%i)", $cid, $team, $num_points['restricted'], $total_time['restricted'], $num_points['public'], $total_time['public']);
    // Release the lock
    if ($DB->q("VALUE SELECT RELEASE_LOCK('{$lockstr}')") != 1) {
        error("updateRankCache failed to release lock '{$lockstr}'");
    }
}