mirror of
https://github.com/ZoneMinder/zoneminder.git
synced 2026-10-29 09:48:32 -04:00
Storage.DiskSpace defaults to NULL on fresh installs, and zmc's DiskSpace = DiskSpace + N leaves it NULL. Storage::event_disk_space() treated NULL as uncached and ran SUM(DiskSpace) over Events on every navbar render and status refresh, taking seconds per page on large Events tables. Write the computed sum back to the Storage row (only while it is still NULL, so a value set by zmaudit is not overwritten). Later page loads use the stored value and zmc keeps it current. COALESCE the sum so a storage area with no events stores 0 instead of NULL. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
173 lines
5.5 KiB
PHP
173 lines
5.5 KiB
PHP
<?php
|
|
namespace ZM;
|
|
require_once('database.php');
|
|
require_once('Event.php');
|
|
require_once('Object.php');
|
|
|
|
class Storage extends ZM_Object {
|
|
protected static $table = 'Storage';
|
|
|
|
public $Id;
|
|
public $Path;
|
|
public $Name;
|
|
public $Type = 'local';
|
|
public $Url;
|
|
public $DiskSpace;
|
|
public $Scheme = 'Medium';
|
|
public $ServerId;
|
|
public $DoDelete = 1;
|
|
public $Enabled = 1;
|
|
|
|
protected $defaults = array(
|
|
'Id' => null,
|
|
'Path' => array('type'=>'text','filter_regexp'=>array('/[^\w\-\.\(\)\:\/ ]/','/\/$/'), 'default'=>''),
|
|
'Name' => array('type'=>'text','filter_regexp'=>'/[^\w\-\.\(\)\:\/ ]/', 'default'=>'Storage'),
|
|
'Type' => 'local',
|
|
'Url' => '',
|
|
'DiskSpace' => null,
|
|
'Scheme' => 'Medium',
|
|
'ServerId' => 0,
|
|
'DoDelete' => 1,
|
|
'Enabled' => 1,
|
|
);
|
|
public static function find($parameters = array(), $options = array()) {
|
|
return ZM_Object::_find(self::class, $parameters, $options);
|
|
}
|
|
|
|
public static function find_one($parameters = array(), $options = array()) {
|
|
return ZM_Object::_find_one(self::class, $parameters, $options);
|
|
}
|
|
|
|
public function Path($new=null) {
|
|
if ( $new ) $this->{'Path'} = $new;
|
|
if ( isset($this->{'Path'}) and ( $this->{'Path'} != '' ) ) {
|
|
return $this->{'Path'};
|
|
} else if ( ! isset($this->{'Id'}) ) {
|
|
$path = ZM_DIR_EVENTS;
|
|
if ( $path[0] != '/' ) {
|
|
$this->{'Path'} = ZM_PATH_WEB.'/'.ZM_DIR_EVENTS;
|
|
} else {
|
|
$this->{'Path'} = ZM_DIR_EVENTS;
|
|
}
|
|
return $this->{'Path'};
|
|
}
|
|
return $this->{'Name'};
|
|
}
|
|
public function Name($new=null) {
|
|
if ( $new )
|
|
$this->{'Name'} = $new;
|
|
if ( isset($this->{'Name'}) and ( $this->{'Name'} != '' ) ) {
|
|
return $this->{'Name'};
|
|
} else if ( ! isset($this->{'Id'}) ) {
|
|
return 'Default';
|
|
}
|
|
return $this->{'Name'};
|
|
}
|
|
|
|
public function Events() {
|
|
if ( $this->{'Id'} and ! isset($this->{'Events'}) ) {
|
|
$this->{'Events'} = Event::find(array('StorageId'=>$this->{'Id'}));
|
|
}
|
|
if ( ! isset($this->{'Events'}) ) {
|
|
$this->{'Events'} = array();
|
|
}
|
|
return $this->{'Events'};
|
|
}
|
|
|
|
public function EventCount() {
|
|
if ( (! property_exists($this, 'EventCount')) or (!$this->{'EventCount'}) ) {
|
|
$this->{'EventCount'} = dbFetchOne('SELECT COUNT(*) AS EventCount FROM Events WHERE StorageId=?', 'EventCount', array($this->Id()));
|
|
}
|
|
return $this->{'EventCount'};
|
|
}
|
|
|
|
public function disk_used_blocks() {
|
|
$df = shell_exec('df '.escapeshellarg($this->Path()));
|
|
$space = -1;
|
|
if ( preg_match('/\s(\d+)\s+\d+\s+\d+%/ms', $df, $matches) )
|
|
$space = $matches[1];
|
|
return $space;
|
|
}
|
|
|
|
public function disk_usage_percent() {
|
|
$path = $this->Path();
|
|
if ( ! $path ) {
|
|
Warning('Storage::disk_usage_percent: path is empty');
|
|
return 0;
|
|
} else if ( ! file_exists($path) ) {
|
|
Warning("Storage::disk_usage_percent: path $path does not exist");
|
|
return 0;
|
|
}
|
|
|
|
$total = $this->disk_total_space();
|
|
if ( ! $total ) {
|
|
Error('disk_total_space returned false for ' . $path);
|
|
return 0;
|
|
}
|
|
$used = $this->disk_used_space();
|
|
$usage = round(($used / $total) * 100);
|
|
//Debug("Used $usage = round( ( $used / $total ) * 100 )");
|
|
return $usage;
|
|
}
|
|
|
|
public function disk_total_space() {
|
|
if ( !property_exists($this, 'disk_total_space') ) {
|
|
$path = $this->Path();
|
|
if ( file_exists($path) ) {
|
|
$this->{'disk_total_space'} = disk_total_space($path);
|
|
} else {
|
|
Error("Path $path does not exist.");
|
|
$this->{'disk_total_space'} = 0;
|
|
}
|
|
}
|
|
return $this->{'disk_total_space'};
|
|
}
|
|
|
|
public function disk_used_space() {
|
|
# This isn't a function like this in php, so we have to add up the space used in each event.
|
|
if ( ( !property_exists($this, 'disk_used_space')) or !$this->{'disk_used_space'} ) {
|
|
if ( $this->Type() == 's3fs' ) {
|
|
$this->{'disk_used_space'} = $this->event_disk_space();
|
|
} else {
|
|
$path = $this->Path();
|
|
if ( file_exists($path) ) {
|
|
$this->{'disk_used_space'} = disk_total_space($path) - disk_free_space($path);
|
|
} else {
|
|
Error("Path $path does not exist.");
|
|
$this->{'disk_used_space'} = 0;
|
|
}
|
|
}
|
|
}
|
|
return $this->{'disk_used_space'};
|
|
} // end function disk_used_space
|
|
|
|
public function event_disk_space() {
|
|
# This isn't a function like this in php, so we have to add up the space used in each event.
|
|
if ( (! property_exists($this, 'DiskSpace')) or (!isset($this->{'DiskSpace'})) ) {
|
|
$this->{'DiskSpace'} = dbFetchOne('SELECT COALESCE(SUM(DiskSpace),0) AS DiskSpace FROM Events WHERE StorageId=? AND DiskSpace IS NOT NULL', 'DiskSpace', array($this->Id()));
|
|
# Store it so the sum is not recomputed on every page load. zmc only adds to a non-NULL value.
|
|
dbQuery('UPDATE Storage SET DiskSpace=? WHERE Id=? AND DiskSpace IS NULL', array($this->{'DiskSpace'}, $this->Id()));
|
|
}
|
|
return $this->{'DiskSpace'};
|
|
} // end function event_disk_space
|
|
|
|
public function Server() {
|
|
if ( ! property_exists($this, 'Server') ) {
|
|
if ( property_exists($this, 'ServerId') ) {
|
|
$this->{'Server'} = Server::find_one(array('Id'=>$this->{'ServerId'}));
|
|
|
|
if ( !$this->{'Server'} ) {
|
|
if ( $this->{'ServerId'} )
|
|
Error('No Server record found for server id ' . $this->{'ServerId'});
|
|
$this->{'Server'} = new Server();
|
|
}
|
|
} else {
|
|
$this->{'Server'} = new Server();
|
|
}
|
|
}
|
|
return $this->{'Server'};
|
|
}
|
|
|
|
} // end class Storage
|
|
?>
|