0)'; } error_log("Generating per-location usage stats"); // 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 if (date('G') == 7 && date('i') <= 15) { error_log("Updating stale calendar data"); $start = time(); } else { $start = 0; } $calendars = LocationInfo::getAllCalendars($start + 55); if ($start !== 0) { error_log('Updating calendars took ' . (time() - $start) . 's'); } } // 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; } error_log("Writing to DB"); Database::exec("INSERT INTO statistic (dateline, typeid, clientip, username, data) VALUES (:now, '~stats', '', '', :vals)", array( 'now' => $NOW, 'vals' => json_encode($data), )); } function state_cleanup() { error_log("Looking for machines that stopped reporting state without logging a shutdown/hibernate..."); // 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'"); // 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'"); // Check results 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); } } } } state_cleanup(); logstats(); if (mt_rand(1, 10) === 1) { error_log("Deleting old statistic entries"); Database::exec("DELETE FROM statistic WHERE (UNIX_TIMESTAMP() - 86400 * 365 * 2) > dateline"); if (mt_rand(1, 100) === 1) { error_log("Optimizing statistic table"); Database::exec("OPTIMIZE TABLE statistic"); } } if (mt_rand(1, 10) === 1) { error_log("Deleting old machine entries"); Database::exec("DELETE FROM machine WHERE (UNIX_TIMESTAMP() - 86400 * 365 * 2) > lastseen"); if (mt_rand(1, 100) === 1) { error_log("Optimizing machine table"); Database::exec("OPTIMIZE TABLE machine"); } } error_log("Statistics cronjob done");