mirror of
https://github.com/Icinga/icingadb-web.git
synced 2026-06-09 08:42:14 -04:00
Merge pull request #389 from Icinga/reduce-redis-queries-to-a-single-one
Reduce redis queries to a single one
This commit is contained in:
commit
b04caba2c8
9 changed files with 128 additions and 37 deletions
|
|
@ -15,6 +15,7 @@ use Icinga\Module\Icingadb\Model\History;
|
|||
use Icinga\Module\Icingadb\Model\Host;
|
||||
use Icinga\Module\Icingadb\Model\Service;
|
||||
use Icinga\Module\Icingadb\Model\ServicestateSummary;
|
||||
use Icinga\Module\Icingadb\Redis\VolatileStateResults;
|
||||
use Icinga\Module\Icingadb\Web\Controller;
|
||||
use Icinga\Module\Icingadb\Widget\Detail\HostDetail;
|
||||
use Icinga\Module\Icingadb\Widget\Detail\HostInspectionDetail;
|
||||
|
|
@ -38,6 +39,7 @@ class HostController extends Controller
|
|||
$name = $this->params->getRequired('name');
|
||||
|
||||
$query = Host::on($this->getDb())->with(['state', 'icon_image']);
|
||||
$query->setResultSetClass(VolatileStateResults::class);
|
||||
$query->getSelectBase()
|
||||
->where(['host.name = ?' => $name]);
|
||||
|
||||
|
|
@ -188,6 +190,7 @@ class HostController extends Controller
|
|||
'host',
|
||||
'host.state'
|
||||
]);
|
||||
$services->setResultSetClass(VolatileStateResults::class);
|
||||
|
||||
$services
|
||||
->getSelectBase()
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ namespace Icinga\Module\Icingadb\Controllers;
|
|||
use Icinga\Exception\NotFoundError;
|
||||
use Icinga\Module\Icingadb\Model\Host;
|
||||
use Icinga\Module\Icingadb\Model\Hostgroupsummary;
|
||||
use Icinga\Module\Icingadb\Redis\VolatileStateResults;
|
||||
use Icinga\Module\Icingadb\Web\Controller;
|
||||
use Icinga\Module\Icingadb\Widget\ItemList\HostList;
|
||||
use Icinga\Module\Icingadb\Widget\ItemList\HostgroupList;
|
||||
|
|
@ -46,6 +47,7 @@ class HostgroupController extends Controller
|
|||
$db = $this->getDb();
|
||||
|
||||
$hosts = Host::on($db)->with(['state', 'state.last_comment', 'icon_image'])->utilize('hostgroup');
|
||||
$hosts->setResultSetClass(VolatileStateResults::class);
|
||||
|
||||
$hosts->getSelectBase()->where(['host_hostgroup.id = ?' => $this->hostgroup->id]);
|
||||
$this->applyRestrictions($hosts);
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ use Icinga\Module\Icingadb\Common\CommandActions;
|
|||
use Icinga\Module\Icingadb\Common\Links;
|
||||
use Icinga\Module\Icingadb\Model\Host;
|
||||
use Icinga\Module\Icingadb\Model\HoststateSummary;
|
||||
use Icinga\Module\Icingadb\Redis\VolatileStateResults;
|
||||
use Icinga\Module\Icingadb\Util\FeatureStatus;
|
||||
use Icinga\Module\Icingadb\Web\Control\SearchBar\ObjectSuggestions;
|
||||
use Icinga\Module\Icingadb\Web\Controller;
|
||||
|
|
@ -36,6 +37,7 @@ class HostsController extends Controller
|
|||
$db = $this->getDb();
|
||||
|
||||
$hosts = Host::on($db)->with(['state', 'icon_image', 'state.last_comment']);
|
||||
$hosts->setResultSetClass(VolatileStateResults::class);
|
||||
|
||||
$this->handleSearchRequest($hosts);
|
||||
|
||||
|
|
@ -124,6 +126,7 @@ class HostsController extends Controller
|
|||
$db = $this->getDb();
|
||||
|
||||
$hosts = Host::on($db)->with(['state', 'icon_image']);
|
||||
$hosts->setResultSetClass(VolatileStateResults::class);
|
||||
$summary = HoststateSummary::on($db)->with(['state']);
|
||||
|
||||
$this->filter($hosts);
|
||||
|
|
@ -194,6 +197,7 @@ class HostsController extends Controller
|
|||
$db = $this->getDb();
|
||||
|
||||
$hosts = Host::on($db)->with('state');
|
||||
$hosts->setResultSetClass(VolatileStateResults::class);
|
||||
|
||||
switch ($this->getRequest()->getActionName()) {
|
||||
case 'acknowledge':
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ use Icinga\Module\Icingadb\Common\ServiceLinks;
|
|||
use Icinga\Module\Icingadb\Hook\TabHook\HookActions;
|
||||
use Icinga\Module\Icingadb\Model\History;
|
||||
use Icinga\Module\Icingadb\Model\Service;
|
||||
use Icinga\Module\Icingadb\Redis\VolatileStateResults;
|
||||
use Icinga\Module\Icingadb\Web\Controller;
|
||||
use Icinga\Module\Icingadb\Widget\Detail\QuickActions;
|
||||
use Icinga\Module\Icingadb\Widget\Detail\ServiceDetail;
|
||||
|
|
@ -41,6 +42,8 @@ class ServiceController extends Controller
|
|||
'host',
|
||||
'host.state'
|
||||
]);
|
||||
$query->setResultSetClass(VolatileStateResults::class);
|
||||
|
||||
$query->getSelectBase()
|
||||
->where(['service.name = ?' => $name])
|
||||
->where(['service_host.name = ?' => $hostName]);
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ namespace Icinga\Module\Icingadb\Controllers;
|
|||
use Icinga\Exception\NotFoundError;
|
||||
use Icinga\Module\Icingadb\Model\Service;
|
||||
use Icinga\Module\Icingadb\Model\ServicegroupSummary;
|
||||
use Icinga\Module\Icingadb\Redis\VolatileStateResults;
|
||||
use Icinga\Module\Icingadb\Web\Controller;
|
||||
use Icinga\Module\Icingadb\Widget\ItemList\ServiceList;
|
||||
use Icinga\Module\Icingadb\Widget\ItemList\ServicegroupList;
|
||||
|
|
@ -52,6 +53,7 @@ class ServicegroupController extends Controller
|
|||
'host',
|
||||
'host.state'
|
||||
])->utilize('servicegroup');
|
||||
$services->setResultSetClass(VolatileStateResults::class);
|
||||
|
||||
$services->getSelectBase()->where(['service_servicegroup.id = ?' => $this->servicegroup->id]);
|
||||
$this->applyRestrictions($services);
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ use Icinga\Module\Icingadb\Common\Links;
|
|||
use Icinga\Module\Icingadb\Data\PivotTable;
|
||||
use Icinga\Module\Icingadb\Model\Service;
|
||||
use Icinga\Module\Icingadb\Model\ServicestateSummary;
|
||||
use Icinga\Module\Icingadb\Redis\VolatileStateResults;
|
||||
use Icinga\Module\Icingadb\Util\FeatureStatus;
|
||||
use Icinga\Module\Icingadb\Web\Control\ProblemToggle;
|
||||
use Icinga\Module\Icingadb\Web\Control\SearchBar\ObjectSuggestions;
|
||||
|
|
@ -45,6 +46,7 @@ class ServicesController extends Controller
|
|||
'host.state',
|
||||
'icon_image'
|
||||
]);
|
||||
$services->setResultSetClass(VolatileStateResults::class);
|
||||
|
||||
$this->handleSearchRequest($services);
|
||||
|
||||
|
|
@ -139,6 +141,7 @@ class ServicesController extends Controller
|
|||
'host',
|
||||
'host.state'
|
||||
]);
|
||||
$services->setResultSetClass(VolatileStateResults::class);
|
||||
$summary = ServicestateSummary::on($db)->with(['state']);
|
||||
|
||||
$this->filter($services);
|
||||
|
|
@ -214,6 +217,7 @@ class ServicesController extends Controller
|
|||
'host',
|
||||
'host.state'
|
||||
]);
|
||||
$query->setResultSetClass(VolatileStateResults::class);
|
||||
|
||||
$this->handleSearchRequest($query);
|
||||
|
||||
|
|
@ -317,6 +321,7 @@ class ServicesController extends Controller
|
|||
'host',
|
||||
'host.state'
|
||||
]);
|
||||
$services->setResultSetClass(VolatileStateResults::class);
|
||||
|
||||
switch ($this->getRequest()->getActionName()) {
|
||||
case 'acknowledge':
|
||||
|
|
|
|||
|
|
@ -1,34 +0,0 @@
|
|||
<?php
|
||||
|
||||
/* Icinga DB Web | (c) 2020 Icinga GmbH | GPLv2 */
|
||||
|
||||
namespace Icinga\Module\Icingadb\Model\Behavior;
|
||||
|
||||
use Exception;
|
||||
use Icinga\Module\Icingadb\Common\IcingaRedis;
|
||||
use Icinga\Module\Icingadb\Redis\VolatileState as RedisState;
|
||||
use ipl\Orm\Contract\RetrieveBehavior;
|
||||
use ipl\Orm\Model;
|
||||
|
||||
class VolatileState implements RetrieveBehavior
|
||||
{
|
||||
protected $state;
|
||||
|
||||
protected function getVolatileState()
|
||||
{
|
||||
if ($this->state === null) {
|
||||
$this->state = new RedisState(IcingaRedis::instance()->getConnection());
|
||||
}
|
||||
|
||||
return $this->state;
|
||||
}
|
||||
|
||||
public function retrieve(Model $model)
|
||||
{
|
||||
try {
|
||||
$this->getVolatileState()->fetch($model);
|
||||
} catch (Exception $e) {
|
||||
// Pass
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -6,10 +6,8 @@ namespace Icinga\Module\Icingadb\Model;
|
|||
|
||||
use Icinga\Module\Icingadb\Model\Behavior\BoolCast;
|
||||
use Icinga\Module\Icingadb\Model\Behavior\Timestamp;
|
||||
use Icinga\Module\Icingadb\Model\Behavior\VolatileState;
|
||||
use ipl\Orm\Behaviors;
|
||||
use ipl\Orm\Model;
|
||||
use ipl\Sql\Expression;
|
||||
|
||||
/**
|
||||
* Base class for the {@link HostState} and {@link ServiceState} models providing common columns.
|
||||
|
|
@ -54,7 +52,6 @@ abstract class State extends Model
|
|||
|
||||
public function createBehaviors(Behaviors $behaviors)
|
||||
{
|
||||
$behaviors->add(new VolatileState());
|
||||
$behaviors->add(new BoolCast([
|
||||
'is_problem',
|
||||
'is_handled',
|
||||
|
|
|
|||
109
library/Icingadb/Redis/VolatileStateResults.php
Normal file
109
library/Icingadb/Redis/VolatileStateResults.php
Normal file
|
|
@ -0,0 +1,109 @@
|
|||
<?php
|
||||
|
||||
/* Icinga DB Web | (c) 2021 Icinga GmbH | GPLv2 */
|
||||
|
||||
namespace Icinga\Module\Icingadb\Redis;
|
||||
|
||||
use Generator;
|
||||
use Icinga\Application\Benchmark;
|
||||
use Icinga\Module\Icingadb\Common\IcingaRedis;
|
||||
use Icinga\Module\Icingadb\Model\Host;
|
||||
use Icinga\Module\Icingadb\Model\Service;
|
||||
use ipl\Orm\Resolver;
|
||||
use ipl\Orm\ResultSet;
|
||||
use RuntimeException;
|
||||
|
||||
class VolatileStateResults extends ResultSet
|
||||
{
|
||||
public function current()
|
||||
{
|
||||
if ($this->position === null && ! $this->isCacheDisabled) {
|
||||
$this->rewind();
|
||||
}
|
||||
|
||||
return parent::current();
|
||||
}
|
||||
|
||||
public function key()
|
||||
{
|
||||
if ($this->position === null && ! $this->isCacheDisabled) {
|
||||
$this->rewind();
|
||||
}
|
||||
|
||||
return parent::key();
|
||||
}
|
||||
|
||||
public function rewind()
|
||||
{
|
||||
if ($this->position === null && ! $this->isCacheDisabled) {
|
||||
$this->advance();
|
||||
|
||||
Benchmark::measure('Applying Redis updates');
|
||||
$this->applyRedisUpdates();
|
||||
Benchmark::measure('Redis updates applied');
|
||||
}
|
||||
|
||||
parent::rewind();
|
||||
}
|
||||
|
||||
protected function applyRedisUpdates()
|
||||
{
|
||||
$type = null;
|
||||
$behaviors = null;
|
||||
|
||||
$states = [];
|
||||
$hostStates = [];
|
||||
foreach ($this as $row) {
|
||||
if ($type === null) {
|
||||
$behaviors = (new Resolver())->getBehaviors($row->state);
|
||||
|
||||
switch (true) {
|
||||
case $row instanceof Host:
|
||||
$type = 'host';
|
||||
break;
|
||||
case $row instanceof Service:
|
||||
$type = 'service';
|
||||
break;
|
||||
default:
|
||||
throw new RuntimeException('Volatile states can only be fetched for hosts and services');
|
||||
}
|
||||
}
|
||||
|
||||
$states[bin2hex($row->id)] = $row->state;
|
||||
if ($type === 'service' && $row->host instanceof Host) {
|
||||
$hostStates[bin2hex($row->host->id)] = $row->host->state;
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($this->fetchStates("icinga:{$type}:state", array_keys($states)) as $id => $data) {
|
||||
foreach ($data as $key => $value) {
|
||||
$data[$key] = $behaviors->retrieveProperty($value, $key);
|
||||
}
|
||||
|
||||
$states[$id]->setProperties($data);
|
||||
}
|
||||
|
||||
if ($type === 'service' && ! empty($hostStates)) {
|
||||
foreach ($this->fetchStates('icinga:host:state', array_keys($hostStates)) as $id => $data) {
|
||||
foreach ($data as $key => $value) {
|
||||
$data[$key] = $behaviors->retrieveProperty($value, $key);
|
||||
}
|
||||
|
||||
$hostStates[$id]->setProperties($data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected function fetchStates(string $key, array $ids): Generator
|
||||
{
|
||||
$results = IcingaRedis::instance()->getConnection()->hmget($key, $ids);
|
||||
foreach ($results as $i => $json) {
|
||||
if ($json !== null) {
|
||||
$data = json_decode($json, true);
|
||||
$data = array_intersect_key($data, array_flip(VolatileState::$keys));
|
||||
|
||||
yield $ids[$i] => $data;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Reference in a new issue