From 2532b760cd2a7c77b4307772fd62a70d532943d8 Mon Sep 17 00:00:00 2001 From: "Alexander A. Klimov" Date: Fri, 30 Aug 2019 16:08:16 +0200 Subject: [PATCH] Cache checkables tree built from Dependency#parents refs #1869 --- lib/icinga/dependency.cpp | 105 ++++++++++++++++++++++++++++++++++---- lib/icinga/dependency.hpp | 62 +++++++++++++++++++++- lib/icinga/dependency.ti | 2 +- 3 files changed, 158 insertions(+), 11 deletions(-) diff --git a/lib/icinga/dependency.cpp b/lib/icinga/dependency.cpp index f9b0c52f1..750f17839 100644 --- a/lib/icinga/dependency.cpp +++ b/lib/icinga/dependency.cpp @@ -179,14 +179,30 @@ void Dependency::BlameBadParents(String checkable) BOOST_THROW_EXCEPTION(ScriptError("Dependency '" + GetName() + "' references a parent host/service which doesn't exist: '" + std::move(checkable) + "'", GetDebugInfo())); } -void Dependency::RequireParents(const Value& parents) +std::unique_ptr Dependency::RequireParents(const Value& parents) { if (parents.IsString()) { auto checkableName (parents.Get()); - if (!(Service::GetByName(checkableName) || Host::GetByName(checkableName))) { - BlameBadParents(std::move(checkableName)); + { + auto service (Service::GetByName(checkableName)); + + if (service) { + return std::unique_ptr(new ParentsLeaf(std::move(service))); + } + } + + { + auto host (Host::GetByName(checkableName)); + + if (host) { + return std::unique_ptr(new ParentsLeaf(std::move(host))); + } } + + BlameBadParents(std::move(checkableName)); + + return nullptr; } else { auto dict (static_pointer_cast(parents.Get())); @@ -202,17 +218,32 @@ void Dependency::RequireParents(const Value& parents) Value serviceSpec; if (dict->Get(l_ParentsStrings.Service, &serviceSpec)) { auto serviceName (serviceSpec.Get()); + auto service (host->GetServiceByShortName(serviceName)); - if (!host->GetServiceByShortName(serviceName)) { + if (!service) { BlameBadParents(std::move(hostName) + "!" + std::move(serviceName)); } + + return std::unique_ptr(new ParentsLeaf(std::move(service))); + } else { + return std::unique_ptr(new ParentsLeaf(std::move(host))); } } else { - auto of (static_pointer_cast(dict->Get(l_ParentsStrings.Of).Get())); - ObjectLock ofLock (of); + std::vector> subTrees; + + { + auto of (static_pointer_cast(dict->Get(l_ParentsStrings.Of).Get())); + ObjectLock ofLock (of); - for (auto& val : of) { - RequireParents(val); + for (auto& val : of) { + subTrees.emplace_back(RequireParents(val)); + } + } + + if (dict->Get(l_ParentsStrings.Require).Get() == "any") { + return std::unique_ptr(new ParentsAny(std::move(subTrees))); + } else { + return std::unique_ptr(new ParentsAll(std::move(subTrees))); } } } @@ -253,8 +284,10 @@ void Dependency::OnAllConfigLoaded() auto parents (GetParents()); if (!parents.IsEmpty()) { - RequireParents(parents); + m_ParentsTree = RequireParents(parents); } + + m_ParentsTreeValidated = true; } void Dependency::Stop(bool runtimeRemoved) @@ -367,3 +400,57 @@ void Dependency::ValidateStates(const Lazy& lvalue, const Validation BOOST_THROW_EXCEPTION(ValidationError(this, { "states" }, "State filter is invalid for service dependency.")); } +static void FreezeRecursively(const Value& value) +{ + if (value.IsObject()) { + auto obj (value.Get()); + auto dict (dynamic_pointer_cast(obj)); + + if (dict) { + ObjectLock oLock (dict); + + for (auto& kv : dict) { + FreezeRecursively(kv.second); + } + + dict->Freeze(); + } else { + auto array (dynamic_pointer_cast(obj)); + + if (array) { + ObjectLock oLock (array); + + for (auto& val : array) { + FreezeRecursively(val); + } + + array->Freeze(); + } + } + } +} + +void Dependency::SetParents(const Value& value, bool suppress_events, const Value& cookie) +{ + auto clone (value.Clone()); + + FreezeRecursively(clone); + + if (m_ParentsTreeValidated) { + m_ParentsTree = value.IsEmpty() ? nullptr : RequireParents(clone); + } + + ObjectImpl::SetParents(clone, suppress_events, cookie); +} + +void Dependency::ParentsLeaf::GetAllLeavesFlat(std::set& out) const +{ + out.emplace(m_Checkable); +} + +void Dependency::ParentsBranch::GetAllLeavesFlat(std::set& out) const +{ + for (auto& subTree : m_SubTrees) { + subTree->GetAllLeavesFlat(out); + } +} diff --git a/lib/icinga/dependency.hpp b/lib/icinga/dependency.hpp index 64857a0a5..56d4dd641 100644 --- a/lib/icinga/dependency.hpp +++ b/lib/icinga/dependency.hpp @@ -5,6 +5,9 @@ #include "icinga/i2-icinga.hpp" #include "icinga/dependency-ti.hpp" +#include +#include +#include #include namespace icinga @@ -35,6 +38,8 @@ public: void ValidateStates(const Lazy& lvalue, const ValidationUtils& utils) override; + void SetParents(const Value& value, bool suppress_events = false, const Value& cookie = Empty) override; + static void EvaluateApplyRules(const intrusive_ptr& host); static void EvaluateApplyRules(const intrusive_ptr& service); @@ -45,15 +50,70 @@ protected: void Stop(bool runtimeRemoved) override; private: + class ParentsTree + { + public: + ParentsTree(const ParentsTree&) = delete; + ParentsTree(ParentsTree&&) = delete; + ParentsTree& operator=(const ParentsTree&) = delete; + ParentsTree& operator=(ParentsTree&&) = delete; + virtual ~ParentsTree() = default; + + virtual void GetAllLeavesFlat(std::set& out) const = 0; + + protected: + ParentsTree() = default; + }; + + class ParentsLeaf : public ParentsTree + { + public: + inline ParentsLeaf(Checkable::Ptr checkable) : m_Checkable(std::move(checkable)) + { + } + + void GetAllLeavesFlat(std::set& out) const override; + + private: + Checkable::Ptr m_Checkable; + }; + + class ParentsBranch : public ParentsTree + { + public: + inline ParentsBranch(std::vector> subTrees) : m_SubTrees(std::move(subTrees)) + { + } + + void GetAllLeavesFlat(std::set& out) const override; + + private: + std::vector> m_SubTrees; + }; + + class ParentsAll : public ParentsBranch + { + public: + using ParentsBranch::ParentsBranch; + }; + + class ParentsAny : public ParentsBranch + { + public: + using ParentsBranch::ParentsBranch; + }; + Checkable::Ptr m_Parent; Checkable::Ptr m_Child; + std::unique_ptr m_ParentsTree; + bool m_ParentsTreeValidated = false; static bool EvaluateApplyRuleInstance(const Checkable::Ptr& checkable, const String& name, ScriptFrame& frame, const ApplyRule& rule); static bool EvaluateApplyRule(const Checkable::Ptr& checkable, const ApplyRule& rule); void ValidateParentsRecursively(const Value& parents, std::vector& currentBranch); void BlameInvalidParents(const std::vector& currentBranch); - void RequireParents(const Value& parents); + std::unique_ptr RequireParents(const Value& parents); void BlameBadParents(String checkable); }; diff --git a/lib/icinga/dependency.ti b/lib/icinga/dependency.ti index 7ee988b76..cf3694f91 100644 --- a/lib/icinga/dependency.ti +++ b/lib/icinga/dependency.ti @@ -77,7 +77,7 @@ class Dependency : CustomVarObject < DependencyNameComposer }}} }; - [config] Value parents; + [config, virtual] Value parents; [config, navigation] name(TimePeriod) period (PeriodRaw) { navigate {{{ -- 2.40.0