From 9cb6977b8e832e067ae0af545797fa69d234fb09 Mon Sep 17 00:00:00 2001 From: Johannes Meyer Date: Wed, 6 Oct 2021 15:33:22 +0200 Subject: [PATCH 1/3] Introduce new class `Icinga\Module\Icingadb\Redis\VolatileStateResults` --- .../Icingadb/Redis/VolatileStateResults.php | 109 ++++++++++++++++++ 1 file changed, 109 insertions(+) create mode 100644 library/Icingadb/Redis/VolatileStateResults.php diff --git a/library/Icingadb/Redis/VolatileStateResults.php b/library/Icingadb/Redis/VolatileStateResults.php new file mode 100644 index 00000000..f1b30f64 --- /dev/null +++ b/library/Icingadb/Redis/VolatileStateResults.php @@ -0,0 +1,109 @@ +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; + } + } + } +} From 9bd3f99673364a4046a7aa3e7440c16e5dceb107 Mon Sep 17 00:00:00 2001 From: Johannes Meyer Date: Wed, 6 Oct 2021 15:33:37 +0200 Subject: [PATCH 2/3] Drop class `Icinga\Module\Icingadb\Model\Behavior\VolatileState` --- .../Icingadb/Model/Behavior/VolatileState.php | 34 ------------------- library/Icingadb/Model/State.php | 3 -- 2 files changed, 37 deletions(-) delete mode 100644 library/Icingadb/Model/Behavior/VolatileState.php diff --git a/library/Icingadb/Model/Behavior/VolatileState.php b/library/Icingadb/Model/Behavior/VolatileState.php deleted file mode 100644 index 0a40bf44..00000000 --- a/library/Icingadb/Model/Behavior/VolatileState.php +++ /dev/null @@ -1,34 +0,0 @@ -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 - } - } -} diff --git a/library/Icingadb/Model/State.php b/library/Icingadb/Model/State.php index 4e6e372a..e17bee6f 100644 --- a/library/Icingadb/Model/State.php +++ b/library/Icingadb/Model/State.php @@ -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', From 7efb797fbbd73a09b6a23da094f8d2218d7c5ce9 Mon Sep 17 00:00:00 2001 From: Johannes Meyer Date: Wed, 6 Oct 2021 15:34:36 +0200 Subject: [PATCH 3/3] Utilize `VolatileStateResults` where applicable --- application/controllers/HostController.php | 3 +++ application/controllers/HostgroupController.php | 2 ++ application/controllers/HostsController.php | 4 ++++ application/controllers/ServiceController.php | 3 +++ application/controllers/ServicegroupController.php | 2 ++ application/controllers/ServicesController.php | 5 +++++ 6 files changed, 19 insertions(+) diff --git a/application/controllers/HostController.php b/application/controllers/HostController.php index 47e649d7..e3eedc16 100644 --- a/application/controllers/HostController.php +++ b/application/controllers/HostController.php @@ -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() diff --git a/application/controllers/HostgroupController.php b/application/controllers/HostgroupController.php index 383692d3..458c39e4 100644 --- a/application/controllers/HostgroupController.php +++ b/application/controllers/HostgroupController.php @@ -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); diff --git a/application/controllers/HostsController.php b/application/controllers/HostsController.php index 2c51e7e9..512d33cc 100644 --- a/application/controllers/HostsController.php +++ b/application/controllers/HostsController.php @@ -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': diff --git a/application/controllers/ServiceController.php b/application/controllers/ServiceController.php index 83d9463c..be6de10b 100644 --- a/application/controllers/ServiceController.php +++ b/application/controllers/ServiceController.php @@ -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]); diff --git a/application/controllers/ServicegroupController.php b/application/controllers/ServicegroupController.php index 91e59a0f..7ee8e862 100644 --- a/application/controllers/ServicegroupController.php +++ b/application/controllers/ServicegroupController.php @@ -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); diff --git a/application/controllers/ServicesController.php b/application/controllers/ServicesController.php index f9061bd8..0a31c957 100644 --- a/application/controllers/ServicesController.php +++ b/application/controllers/ServicesController.php @@ -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':