Lookup apply rules faster by Type*, not String and by map instead of ==/!=

1. The lookup of apply rules per source type now implies
   no String(const char*) (no malloc()) and just pointer (uint64) comparisions
2. Apply rules are now also grouped by target type via a nested map, that obsoletes
   checking the target type while iterating over all rules per source type
This commit is contained in:
Alexander A. Klimov 2022-10-17 16:54:34 +02:00
parent 90fe4e5bea
commit d468d7993c
6 changed files with 45 additions and 39 deletions

View File

@ -75,7 +75,19 @@ void ApplyRule::AddRule(const String& sourceType, const String& targetType, cons
const Expression::Ptr& expression, const Expression::Ptr& filter, const String& package, const String& fkvar, const Expression::Ptr& expression, const Expression::Ptr& filter, const String& package, const String& fkvar,
const String& fvvar, const Expression::Ptr& fterm, bool ignoreOnError, const DebugInfo& di, const Dictionary::Ptr& scope) const String& fvvar, const Expression::Ptr& fterm, bool ignoreOnError, const DebugInfo& di, const Dictionary::Ptr& scope)
{ {
m_Rules[sourceType].push_back(ApplyRule(targetType, name, expression, filter, package, fkvar, fvvar, fterm, ignoreOnError, di, scope)); auto actualTargetType (&targetType);
if (*actualTargetType == "") {
auto& targetTypes (GetTargetTypes(sourceType));
if (targetTypes.size() == 1u) {
actualTargetType = &targetTypes[0];
}
}
m_Rules[Type::GetByName(sourceType).get()][Type::GetByName(*actualTargetType).get()].emplace_back(ApplyRule(
targetType, name, expression, filter, package, fkvar, fvvar, fterm, ignoreOnError, di, scope
));
} }
bool ApplyRule::EvaluateFilter(ScriptFrame& frame) const bool ApplyRule::EvaluateFilter(ScriptFrame& frame) const
@ -133,23 +145,33 @@ bool ApplyRule::HasMatches() const
return m_HasMatches; return m_HasMatches;
} }
std::vector<ApplyRule>& ApplyRule::GetRules(const String& type) std::vector<ApplyRule>& ApplyRule::GetRules(const Type::Ptr& sourceType, const Type::Ptr& targetType)
{ {
auto it = m_Rules.find(type); auto perSourceType (m_Rules.find(sourceType.get()));
if (it == m_Rules.end()) {
static std::vector<ApplyRule> emptyList; if (perSourceType != m_Rules.end()) {
return emptyList; auto perTargetType (perSourceType->second.find(targetType.get()));
if (perTargetType != perSourceType->second.end()) {
return perTargetType->second;
} }
return it->second; }
static std::vector<ApplyRule> noRules;
return noRules;
} }
void ApplyRule::CheckMatches(bool silent) void ApplyRule::CheckMatches(bool silent)
{ {
for (const RuleMap::value_type& kv : m_Rules) { for (auto& perSourceType : m_Rules) {
for (const ApplyRule& rule : kv.second) { for (auto& perTargetType : perSourceType.second) {
if (!rule.HasMatches() && !silent) for (auto& rule : perTargetType.second) {
if (!rule.HasMatches() && !silent) {
Log(LogWarning, "ApplyRule") Log(LogWarning, "ApplyRule")
<< "Apply rule '" << rule.GetName() << "' (" << rule.GetDebugInfo() << ") for type '" << kv.first << "' does not match anywhere!"; << "Apply rule '" << rule.GetName() << "' (" << rule.GetDebugInfo() << ") for type '"
<< perSourceType.first->GetName() << "' does not match anywhere!";
}
}
} }
} }
} }

View File

@ -6,6 +6,8 @@
#include "config/i2-config.hpp" #include "config/i2-config.hpp"
#include "config/expression.hpp" #include "config/expression.hpp"
#include "base/debuginfo.hpp" #include "base/debuginfo.hpp"
#include "base/type.hpp"
#include <unordered_map>
namespace icinga namespace icinga
{ {
@ -17,7 +19,7 @@ class ApplyRule
{ {
public: public:
typedef std::map<String, std::vector<String> > TypeMap; typedef std::map<String, std::vector<String> > TypeMap;
typedef std::map<String, std::vector<ApplyRule> > RuleMap; typedef std::unordered_map<Type*, std::unordered_map<Type*, std::vector<ApplyRule>>> RuleMap;
String GetTargetType() const; String GetTargetType() const;
String GetName() const; String GetName() const;
@ -38,7 +40,7 @@ public:
static void AddRule(const String& sourceType, const String& targetType, const String& name, const Expression::Ptr& expression, static void AddRule(const String& sourceType, const String& targetType, const String& name, const Expression::Ptr& expression,
const Expression::Ptr& filter, const String& package, const String& fkvar, const String& fvvar, const Expression::Ptr& fterm, const Expression::Ptr& filter, const String& package, const String& fkvar, const String& fvvar, const Expression::Ptr& fterm,
bool ignoreOnError, const DebugInfo& di, const Dictionary::Ptr& scope); bool ignoreOnError, const DebugInfo& di, const Dictionary::Ptr& scope);
static std::vector<ApplyRule>& GetRules(const String& type); static std::vector<ApplyRule>& GetRules(const Type::Ptr& sourceType, const Type::Ptr& targetType);
static void RegisterType(const String& sourceType, const std::vector<String>& targetTypes); static void RegisterType(const String& sourceType, const std::vector<String>& targetTypes);
static bool IsValidSourceType(const String& sourceType); static bool IsValidSourceType(const String& sourceType);

View File

@ -136,10 +136,7 @@ void Dependency::EvaluateApplyRules(const Host::Ptr& host)
{ {
CONTEXT("Evaluating 'apply' rules for host '" + host->GetName() + "'"); CONTEXT("Evaluating 'apply' rules for host '" + host->GetName() + "'");
for (ApplyRule& rule : ApplyRule::GetRules("Dependency")) { for (auto& rule : ApplyRule::GetRules(Dependency::TypeInstance, Host::TypeInstance)) {
if (rule.GetTargetType() != "Host")
continue;
if (EvaluateApplyRule(host, rule)) if (EvaluateApplyRule(host, rule))
rule.AddMatch(); rule.AddMatch();
} }
@ -149,10 +146,7 @@ void Dependency::EvaluateApplyRules(const Service::Ptr& service)
{ {
CONTEXT("Evaluating 'apply' rules for service '" + service->GetName() + "'"); CONTEXT("Evaluating 'apply' rules for service '" + service->GetName() + "'");
for (ApplyRule& rule : ApplyRule::GetRules("Dependency")) { for (auto& rule : ApplyRule::GetRules(Dependency::TypeInstance, Service::TypeInstance)) {
if (rule.GetTargetType() != "Service")
continue;
if (EvaluateApplyRule(service, rule)) if (EvaluateApplyRule(service, rule))
rule.AddMatch(); rule.AddMatch();
} }

View File

@ -135,11 +135,8 @@ void Notification::EvaluateApplyRules(const Host::Ptr& host)
{ {
CONTEXT("Evaluating 'apply' rules for host '" + host->GetName() + "'"); CONTEXT("Evaluating 'apply' rules for host '" + host->GetName() + "'");
for (ApplyRule& rule : ApplyRule::GetRules("Notification")) for (auto& rule : ApplyRule::GetRules(Notification::TypeInstance, Host::TypeInstance))
{ {
if (rule.GetTargetType() != "Host")
continue;
if (EvaluateApplyRule(host, rule)) if (EvaluateApplyRule(host, rule))
rule.AddMatch(); rule.AddMatch();
} }
@ -149,10 +146,7 @@ void Notification::EvaluateApplyRules(const Service::Ptr& service)
{ {
CONTEXT("Evaluating 'apply' rules for service '" + service->GetName() + "'"); CONTEXT("Evaluating 'apply' rules for service '" + service->GetName() + "'");
for (ApplyRule& rule : ApplyRule::GetRules("Notification")) { for (auto& rule : ApplyRule::GetRules(Notification::TypeInstance, Service::TypeInstance)) {
if (rule.GetTargetType() != "Service")
continue;
if (EvaluateApplyRule(service, rule)) if (EvaluateApplyRule(service, rule))
rule.AddMatch(); rule.AddMatch();
} }

View File

@ -134,10 +134,7 @@ void ScheduledDowntime::EvaluateApplyRules(const Host::Ptr& host)
{ {
CONTEXT("Evaluating 'apply' rules for host '" + host->GetName() + "'"); CONTEXT("Evaluating 'apply' rules for host '" + host->GetName() + "'");
for (ApplyRule& rule : ApplyRule::GetRules("ScheduledDowntime")) { for (auto& rule : ApplyRule::GetRules(ScheduledDowntime::TypeInstance, Host::TypeInstance)) {
if (rule.GetTargetType() != "Host")
continue;
if (EvaluateApplyRule(host, rule)) if (EvaluateApplyRule(host, rule))
rule.AddMatch(); rule.AddMatch();
} }
@ -147,10 +144,7 @@ void ScheduledDowntime::EvaluateApplyRules(const Service::Ptr& service)
{ {
CONTEXT("Evaluating 'apply' rules for service '" + service->GetName() + "'"); CONTEXT("Evaluating 'apply' rules for service '" + service->GetName() + "'");
for (ApplyRule& rule : ApplyRule::GetRules("ScheduledDowntime")) { for (auto& rule : ApplyRule::GetRules(ScheduledDowntime::TypeInstance, Service::TypeInstance)) {
if (rule.GetTargetType() != "Service")
continue;
if (EvaluateApplyRule(service, rule)) if (EvaluateApplyRule(service, rule))
rule.AddMatch(); rule.AddMatch();
} }

View File

@ -123,7 +123,7 @@ void Service::EvaluateApplyRules(const Host::Ptr& host)
{ {
CONTEXT("Evaluating 'apply' rules for host '" + host->GetName() + "'"); CONTEXT("Evaluating 'apply' rules for host '" + host->GetName() + "'");
for (ApplyRule& rule : ApplyRule::GetRules("Service")) { for (auto& rule : ApplyRule::GetRules(Service::TypeInstance, Host::TypeInstance)) {
if (EvaluateApplyRule(host, rule)) if (EvaluateApplyRule(host, rule))
rule.AddMatch(); rule.AddMatch();
} }