summaryrefslogtreecommitdiffstats
path: root/modules-available/statistics/hooks/cron.inc.php
blob: 4ba5e2f67e912dd1e3b2278fd01cf93db72bfae6 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
<?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");
	}
}