<?php
function logstats()
{
$NOW = time();
$cutoff = $NOW - 86400 * 30;
$join = $where = '';
if (Module::get('runmode') !== false) {
$join = 'LEFT JOIN runmode r USING (machineuuid)';
$where = 'AND (r.isclient IS NULL OR r.isclient <> 0)';
}
// Get total/online/in-use
$known = Database::queryKeyValueList("SELECT locationid, Count(*) AS val FROM machine m
$join WHERE m.lastseen > $cutoff $where
GROUP BY locationid");
$on = Database::queryKeyValueList("SELECT locationid, Count(*) AS val FROM machine m
$join WHERE m.state IN ('IDLE', 'OCCUPIED') $where
GROUP BY locationid");
$used = Database::queryKeyValueList("SELECT locationid, Count(*) AS val FROM machine m
$join WHERE m.state = 'OCCUPIED' $where
GROUP BY locationid");
// Get calendar data if available
if (Module::isAvailable('locationinfo')) {
// Refresh all calendars around 07:00
$calendars = LocationInfo::getAllCalendars(date('G') != 7 || date('i') >= 10);
}
// Mash together
$data = ['usage' => []];
foreach ($known as $lid => $val) {
$entry = ['t' => $val];
if (isset($on[$lid])) {
$entry['o'] = $on[$lid];
}
if (isset($used[$lid])) {
$entry['u'] = $used[$lid];
}
if (isset($calendars[$lid])) {
$title = LocationInfo::extractCurrentEvent($calendars[$lid]);
if (!empty($title)) {
$entry['event'] = $title;
}
}
$data['usage'][$lid] = $entry;
}
Database::exec("INSERT INTO statistic (dateline, typeid, clientip, username, data) VALUES (:now, '~stats', '', '', :vals)", array(
'now' => $NOW,
'vals' => json_encode($data),
));
}
function state_cleanup()
{
// Fix online state of machines that crashed
$standby = time() - 86400 * 4; // Reset standby machines after four days
$on = time() - 610; // Reset others after ~10 minutes
// Query for logging
$res = Database::simpleQuery("SELECT machineuuid, clientip, state, logintime, lastseen, live_memfree, live_swapfree, live_tmpfree
FROM machine WHERE lastseen < If(state = 'STANDBY', $standby, $on) AND state <> 'OFFLINE'");
foreach ($res as $row) {
ClientLog::write($row, 'machine-mismatch-cron',
'Client timed out, last known state is ' . $row['state']
. '. Free RAM: ' . Util::readableFileSize($row['live_memfree'], -1, 2)
. ', free Swap: ' . Util::readableFileSize($row['live_swapfree'], -1, 2)
. ', free ID44: ' . Util::readableFileSize($row['live_tmpfree'], -1, 2));
if ($row['state'] === 'OCCUPIED') {
$length = $row['lastseen'] - $row['logintime'];
if ($length > 0 && $length < 86400 * 7) {
Statistics::logMachineState($row['machineuuid'], $row['clientip'], Statistics::SESSION_LENGTH, $row['logintime'], $length);
}
} elseif ($row['state'] === 'STANDBY') {
$length = time() - $row['lastseen'];
if ($length > 0 && $length < 86400 * 7) {
Statistics::logMachineState($row['machineuuid'], $row['clientip'], Statistics::SUSPEND_LENGTH, $row['lastseen'], $length);
}
}
}
// Update -- yes this is not atomic. Should be sufficient for simple warnings and bookkeeping though.
Database::exec("UPDATE machine SET logintime = 0, state = 'OFFLINE' WHERE lastseen < If(state = 'STANDBY', $standby, $on) AND state <> 'OFFLINE'");
}
state_cleanup();
logstats();
if (mt_rand(1, 10) === 1) {
Database::exec("DELETE FROM statistic WHERE (UNIX_TIMESTAMP() - 86400 * 365 * 2) > dateline");
if (mt_rand(1, 100) === 1) {
Database::exec("OPTIMIZE TABLE statistic");
}
}
if (mt_rand(1, 10) === 1) {
Database::exec("DELETE FROM machine WHERE (UNIX_TIMESTAMP() - 86400 * 365 * 2) > lastseen");
if (mt_rand(1, 100) === 1) {
Database::exec("OPTIMIZE TABLE machine");
}
}