From 8b9f600e1ffbc18a88e62853c6e1b0c8724ad499 Mon Sep 17 00:00:00 2001 From: Johannes Meyer Date: Tue, 8 Aug 2023 15:18:25 +0200 Subject: [PATCH] IcingaDbState: Optimize queries There's no need to fetch more data than required. And issuing count queries only for benchmarks.. -.- Also bypasses ipl-orm to fetch results now. fixes #343 (cherry picked from commit 78ad4491d2b8c5c17c6df6cfa1f881588ad70553) --- .../Businessprocess/State/IcingaDbState.php | 103 ++++++++++-------- 1 file changed, 56 insertions(+), 47 deletions(-) diff --git a/library/Businessprocess/State/IcingaDbState.php b/library/Businessprocess/State/IcingaDbState.php index 9d3d8d27..134fed22 100644 --- a/library/Businessprocess/State/IcingaDbState.php +++ b/library/Businessprocess/State/IcingaDbState.php @@ -53,44 +53,57 @@ public function reallyRetrieveStatesFromBackend() { $config = $this->config; + $involvedHostNames = $config->listInvolvedHostNames(); + if (empty($involvedHostNames)) { + return $this; + } + Benchmark::measure(sprintf( 'Retrieving states for business process %s using Icinga DB backend', $config->getName() )); - $hosts = $config->listInvolvedHostNames(); - if (empty($hosts)) { - return $this; - } - - $queryHost = Host::on($this->backend)->with('state'); - $queryHost->filter(Filter::equal('host.name', $hosts)); - - $hostObject = $queryHost->getModel()->getTableName(); - - Benchmark::measure('Retrieved states for ' . $queryHost->count() . ' hosts in ' . $config->getName()); - - $queryService = Service::on($this->backend)->with([ - 'state', - 'host', - 'host.state' - ]); - - $queryService->filter(Filter::equal('host.name', $hosts)); - - Benchmark::measure('Retrieved states for ' . $queryService->count() . ' services in ' . $config->getName()); + $hosts = Host::on($this->backend)->columns([ + 'name' => 'host.name', + 'display_name' => 'host.display_name', + 'hard_state' => 'host.state.hard_state', + 'soft_state' => 'host.state.soft_state', + 'last_state_change' => 'host.state.last_state_change', + 'in_downtime' => 'host.state.in_downtime', + 'is_acknowledged' => 'host.state.is_acknowledged' + ])->filter(Filter::equal('host.name', $involvedHostNames)); + + $services = Service::on($this->backend)->columns([ + 'name' => 'service.name', + 'display_name' => 'service.display_name', + 'host_name' => 'host.name', + 'host_display_name' => 'host.display_name', + 'hard_state' => 'service.state.hard_state', + 'soft_state' => 'service.state.soft_state', + 'last_state_change' => 'service.state.last_state_change', + 'in_downtime' => 'service.state.in_downtime', + 'is_acknowledged' => 'service.state.is_acknowledged' + ])->filter(Filter::equal('host.name', $involvedHostNames)); + + // All of this is ipl-sql now, for performance reasons + foreach ($config->listInvolvedConfigs() as $cfg) { + $i = 0; + foreach ($this->backend->yieldAll($services->assembleSelect()) as $row) { + $i++; + + $this->handleDbRow($row, $cfg, 'service'); + } - $configs = $config->listInvolvedConfigs(); + Benchmark::measure("Retrieved states for $i services in " . $config->getName()); - $serviceObject = $queryService->getModel()->getTableName(); + $i = 0; + foreach ($this->backend->yieldAll($hosts->assembleSelect()) as $row) { + $i++; - foreach ($configs as $cfg) { - foreach ($queryService as $row) { - $this->handleDbRow($row, $cfg, $serviceObject); - } - foreach ($queryHost as $row) { - $this->handleDbRow($row, $cfg, $hostObject); + $this->handleDbRow($row, $cfg, 'host'); } + + Benchmark::measure("Retrieved states for $i hosts in " . $config->getName()); } Benchmark::measure('Got states for business process ' . $config->getName()); @@ -98,10 +111,10 @@ public function reallyRetrieveStatesFromBackend() return $this; } - protected function handleDbRow($row, BpConfig $config, $objectName) + protected function handleDbRow($row, BpConfig $config, $type) { - if ($objectName === 'service') { - $key = $row->host->name . ';' . $row->name; + if ($type === 'service') { + $key = $row->host_name . ';' . $row->name; } else { $key = $row->name . ';Hoststatus'; } @@ -114,33 +127,29 @@ protected function handleDbRow($row, BpConfig $config, $objectName) $node = $config->getNode($key); if ($this->config->usesHardStates()) { - if ($row->state->hard_state !== null) { - $node->setState($row->state->hard_state)->setMissing(false); + if ($row->hard_state !== null) { + $node->setState($row->hard_state)->setMissing(false); } } else { - if ($row->state->soft_state !== null) { - $node->setState($row->state->soft_state)->setMissing(false); + if ($row->soft_state !== null) { + $node->setState($row->soft_state)->setMissing(false); } } - if ($row->state->last_state_change !== null) { - if ($row->state->last_state_change instanceof DateTime) { - $node->setLastStateChange($row->state->last_state_change->getTimestamp()); + if ($row->last_state_change !== null) { + if ($row->last_state_change instanceof DateTime) { + $node->setLastStateChange($row->last_state_change->getTimestamp()); } else { - $node->setLastStateChange($row->state->last_state_change/1000); + $node->setLastStateChange($row->last_state_change/1000); } } - if ($row->state->in_downtime) { - $node->setDowntime(true); - } - if ($row->state->is_acknowledged) { - $node->setAck(true); - } + $node->setDowntime($row->in_downtime === 'y'); + $node->setAck($row->is_acknowledged === 'y'); $node->setAlias($row->display_name); if ($node instanceof ServiceNode) { - $node->setHostAlias($row->host->display_name); + $node->setHostAlias($row->host_display_name); } } }