Rewriting Archiver. Database access optimization + thread safe.

This commit is contained in:
jerome 2014-05-06 14:21:27 +02:00 committed by Pepijn Over
parent 131ec1c7b4
commit 5c99a4bbd3
3 changed files with 75 additions and 53 deletions

View File

@ -36,10 +36,10 @@
*
* @see \psm\Util\Updater\Autorun
*/
namespace psm\Util\Updater;
namespace psm\Service;
use psm\Service\Database;
class StatusArchiver {
class Archiver {
/**
* Database service
@ -52,69 +52,87 @@ class StatusArchiver {
}
/**
* Archive the active records of a server before a certain date.
* Archive all server status records older than 1 week.
*
* Archiving means calculating averages per day, and storing 1 single
* history row for each day for this server.
*
* @param int $server_id
* @param \DateTime $date_before archive all records before this date
* history row for each day for each server.
*/
public function archive($server_id, \DateTime $date_before) {
// get all uptime records for this server
$q_records = $this->db->pdo()->prepare("
SELECT `date`,`status`,`latency`
FROM `".PSM_DB_PREFIX."servers_uptime`
WHERE `server_id` = :server_id AND `date` < :latest_date
");
$q_records->execute(array(
'server_id' => $server_id,
'latest_date' => $date_before->format('Y-m-d 00:00:00'),
));
$records = $q_records->fetchAll();
public function archiveStatus() {
$latest_date = new \DateTime('-1 week 0:0:0');
$timestamp = $latest_date->getTimestamp();
if(empty($records)) {
// Check if archiving is necessary
$last_archive = psm_get_conf('last_archive_time', 0);
if($timestamp <= $last_archive) {
return false;
}
$data_by_day = array();
psm_update_conf('last_archive_time', $timestamp);
// first group all records by day
foreach($records as $record) {
$day = date('Y-m-d', strtotime($record['date']));
if(!isset($data_by_day[$day])) {
$data_by_day[$day] = array();
// Lock tables to prevent simultaneous archiving (by other sessions or the cron job)
$this->db->exec('LOCK TABLES ' . PSM_DB_PREFIX . 'servers_uptime WRITE, ' . PSM_DB_PREFIX . 'servers_history WRITE');
$latest_date_str = $latest_date->format('Y-m-d 00:00:00');
$records = $this->db->execute(
"SELECT `server_id`,`date`,`status`,`latency`
FROM `" . PSM_DB_PREFIX."servers_uptime`
WHERE `date` < :latest_date
ORDER BY `date` ASC",
array('latest_date' => $latest_date_str));
if(!empty($records)) {
// first group all records by day and server_id
$data_by_day = array();
foreach($records as $record) {
$server_id = (int)$record['server_id'];
$day = date('Y-m-d', strtotime($record['date']));
if(!isset($data_by_day[$day][$server_id])) {
$data_by_day[$day][$server_id] = array();
}
$data_by_day[$day][$server_id][] = $record;
}
$data_by_day[$day][] = $record;
// now get history data day by day
$histories = array();
foreach($data_by_day as $day => $day_records) {
foreach ($day_records as $server_id => $server_day_records) {
$histories[] = $this->getHistoryForDay($day, $server_id, $server_day_records);
}
}
// Save all
$this->db->insertMultiple(PSM_DB_PREFIX.'servers_history', $histories);
// now remove all records from the uptime table
$this->db->execute(
"DELETE FROM `".PSM_DB_PREFIX."servers_uptime` WHERE `date` < :latest_date",
array('latest_date' => $latest_date_str),
false
);
}
// now lets sort out and save the history day by day
foreach($data_by_day as $day => $day_records) {
$history = $this->getHistoryForDay($day, $day_records);
$history['server_id'] = $server_id;
// Remove older history entries
$latest_date->modify('-1 year');
$this->db->execute(
"DELETE FROM `".PSM_DB_PREFIX."servers_history` WHERE `date` < :latest_date",
array('latest_date' => $latest_date->format('Y-m-d 00:00:00')),
false
);
// store the history for this day in the history table
$this->db->save(PSM_DB_PREFIX.'servers_history', $history);
}
// now remove all records from the uptime table
$q_records_cleanup = $this->db->pdo()->prepare("
DELETE FROM `".PSM_DB_PREFIX."servers_uptime`
WHERE `server_id` = :server_id AND `date` < :latest_date
");
$q_records_cleanup->execute(array(
'server_id' => $server_id,
'latest_date' => $date_before->format('Y-m-d 00:00:00'),
));
$this->db->exec('UNLOCK TABLES');
return true;
}
/**
* Build a history array for a certain day and its records
* Build a history array for a day records
* @param string $day
* @param int $server_id
* @param array $day_records
* @return array
*/
protected function getHistoryForDay($day, $day_records) {
protected function getHistoryForDay($day, $server_id, $day_records) {
$latencies = array();
$checks_failed = 0;
@ -129,6 +147,7 @@ class StatusArchiver {
$history = array(
'date' => $day,
'server_id' => $server_id,
'latency_min' => min($latencies),
'latency_avg' => array_sum($latencies) / count($latencies),
'latency_max' => max($latencies),

View File

@ -28,6 +28,7 @@
namespace psm\Util\Server;
use psm\Service\Database;
use psm\Service\Archiver;
/**
* History util, create HTML for server graphs
@ -56,6 +57,10 @@ class HistoryGraph {
* @return string
*/
public function createHTML($server_id) {
// Archive all records older than 1 week, if needed
$archiver = new Archiver($this->db);
$archiver->archiveStatus();
$now = new \DateTime();
$last_week = new \DateTime('-1 week 0:0:0');
$last_year = new \DateTime('-1 year -1 week 0:0:0');

View File

@ -29,6 +29,7 @@
namespace psm\Util\Updater;
use psm\Service\Database;
use psm\Service\User;
use psm\Service\Archiver;
/**
* Run an update on all servers.
@ -79,19 +80,16 @@ class Autorun {
$updater = new StatusUpdater($this->db);
$notifier = new StatusNotifier($this->db);
$archiver = new StatusArchiver($this->db);
$cleanup_date = new \DateTime();
$cleanup_date->modify('-1 week');
foreach($servers as $server) {
$status_old = ($server['status'] == 'on') ? true : false;
$status_new = $updater->update($server['server_id']);
// notify the nerds if applicable
$notifier->notify($server['server_id'], $status_old, $status_new);
// clean-up time!! archive all records older than 1 week
$archiver->archive($server['server_id'], $cleanup_date);
}
// clean-up time!! archive all records older than 1 week
$archiver = new Archiver($this->db);
$archiver->archiveStatus();
}
/**