Icinga DB: use one Redis connection per config object type

This commit is contained in:
Alexander A. Klimov 2021-03-23 12:37:32 +01:00
parent 8b516f0c08
commit d1e15a220c
5 changed files with 69 additions and 33 deletions

View File

@ -55,6 +55,27 @@ return id
INITIALIZE_ONCE(&IcingaDB::ConfigStaticInitialize); INITIALIZE_ONCE(&IcingaDB::ConfigStaticInitialize);
std::vector<Type::Ptr> IcingaDB::GetTypes()
{
return {
CheckCommand::TypeInstance,
Comment::TypeInstance,
Downtime::TypeInstance,
Endpoint::TypeInstance,
EventCommand::TypeInstance,
Host::TypeInstance,
HostGroup::TypeInstance,
Notification::TypeInstance,
NotificationCommand::TypeInstance,
Service::TypeInstance,
ServiceGroup::TypeInstance,
TimePeriod::TypeInstance,
User::TypeInstance,
UserGroup::TypeInstance,
Zone::TypeInstance
};
}
void IcingaDB::ConfigStaticInitialize() void IcingaDB::ConfigStaticInitialize()
{ {
/* triggered in ProcessCheckResult(), requires UpdateNextCheck() to be called before */ /* triggered in ProcessCheckResult(), requires UpdateNextCheck() to be called before */
@ -125,23 +146,7 @@ void IcingaDB::UpdateAllConfigObjects()
WorkQueue upq(25000, Configuration::Concurrency); WorkQueue upq(25000, Configuration::Concurrency);
upq.SetName("IcingaDB:ConfigDump"); upq.SetName("IcingaDB:ConfigDump");
std::vector<Type::Ptr> types = { std::vector<Type::Ptr> types = GetTypes();
CheckCommand::TypeInstance,
Comment::TypeInstance,
Downtime::TypeInstance,
Endpoint::TypeInstance,
EventCommand::TypeInstance,
Host::TypeInstance,
HostGroup::TypeInstance,
Notification::TypeInstance,
NotificationCommand::TypeInstance,
Service::TypeInstance,
ServiceGroup::TypeInstance,
TimePeriod::TypeInstance,
User::TypeInstance,
UserGroup::TypeInstance,
Zone::TypeInstance
};
m_Rcon->SuppressQueryKind(Prio::CheckResult); m_Rcon->SuppressQueryKind(Prio::CheckResult);
m_Rcon->SuppressQueryKind(Prio::State); m_Rcon->SuppressQueryKind(Prio::State);
@ -159,8 +164,9 @@ void IcingaDB::UpdateAllConfigObjects()
m_PrefixConfigObject + "notes:url", m_PrefixConfigObject + "notes:url",
m_PrefixConfigObject + "icon:image", m_PrefixConfigObject + "icon:image",
}; };
DeleteKeys(globalKeys, Prio::Config); DeleteKeys(m_Rcon, globalKeys, Prio::Config);
DeleteKeys({"icinga:nextupdate:host", "icinga:nextupdate:service"}, Prio::CheckResult); DeleteKeys(m_Rcon, {"icinga:nextupdate:host", "icinga:nextupdate:service"}, Prio::CheckResult);
m_Rcon->Sync();
Defer resetDumpedGlobals ([this]() { Defer resetDumpedGlobals ([this]() {
m_DumpedGlobals.CustomVar.Reset(); m_DumpedGlobals.CustomVar.Reset();
@ -175,8 +181,10 @@ void IcingaDB::UpdateAllConfigObjects()
if (!ctype) if (!ctype)
return; return;
auto& rcon (m_Rcons.at(ctype));
std::vector<String> keys = GetTypeOverwriteKeys(lcType); std::vector<String> keys = GetTypeOverwriteKeys(lcType);
DeleteKeys(keys, Prio::Config); DeleteKeys(rcon, keys, Prio::Config);
WorkQueue upqObjectType(25000, Configuration::Concurrency); WorkQueue upqObjectType(25000, Configuration::Concurrency);
upqObjectType.SetName("IcingaDB:ConfigDump:" + lcType); upqObjectType.SetName("IcingaDB:ConfigDump:" + lcType);
@ -184,11 +192,11 @@ void IcingaDB::UpdateAllConfigObjects()
std::map<String, String> redisCheckSums; std::map<String, String> redisCheckSums;
String configCheckSum = m_PrefixConfigCheckSum + lcType; String configCheckSum = m_PrefixConfigCheckSum + lcType;
upqObjectType.Enqueue([this, &configCheckSum, &redisCheckSums]() { upqObjectType.Enqueue([&]() {
String cursor = "0"; String cursor = "0";
do { do {
Array::Ptr res = m_Rcon->GetResultOfQuery({ Array::Ptr res = rcon->GetResultOfQuery({
"HSCAN", configCheckSum, cursor, "COUNT", "1000" "HSCAN", configCheckSum, cursor, "COUNT", "1000"
}, Prio::Config); }, Prio::Config);
@ -282,7 +290,7 @@ void IcingaDB::UpdateAllConfigObjects()
if (transaction.size() > 1) { if (transaction.size() > 1) {
transaction.push_back({"EXEC"}); transaction.push_back({"EXEC"});
m_Rcon->FireAndForgetQueries(std::move(transaction), Prio::Config); rcon->FireAndForgetQueries(std::move(transaction), Prio::Config);
transaction = {{"MULTI"}}; transaction = {{"MULTI"}};
} }
} }
@ -298,7 +306,7 @@ void IcingaDB::UpdateAllConfigObjects()
if (zAdds->size() >= 102u) { if (zAdds->size() >= 102u) {
std::vector<String> header (zAdds->begin(), zAdds->begin() + 2u); std::vector<String> header (zAdds->begin(), zAdds->begin() + 2u);
m_Rcon->FireAndForgetQuery(std::move(*zAdds), Prio::CheckResult); rcon->FireAndForgetQuery(std::move(*zAdds), Prio::CheckResult);
*zAdds = std::move(header); *zAdds = std::move(header);
} }
@ -319,12 +327,12 @@ void IcingaDB::UpdateAllConfigObjects()
if (transaction.size() > 1) { if (transaction.size() > 1) {
transaction.push_back({"EXEC"}); transaction.push_back({"EXEC"});
m_Rcon->FireAndForgetQueries(std::move(transaction), Prio::Config); rcon->FireAndForgetQueries(std::move(transaction), Prio::Config);
} }
for (auto zAdds : {&hostZAdds, &serviceZAdds}) { for (auto zAdds : {&hostZAdds, &serviceZAdds}) {
if (zAdds->size() > 2u) { if (zAdds->size() > 2u) {
m_Rcon->FireAndForgetQuery(std::move(*zAdds), Prio::CheckResult); rcon->FireAndForgetQuery(std::move(*zAdds), Prio::CheckResult);
} }
} }
@ -386,7 +394,7 @@ void IcingaDB::UpdateAllConfigObjects()
setChecksum.clear(); setChecksum.clear();
setObject.clear(); setObject.clear();
m_Rcon->FireAndForgetQueries(std::move(transaction), Prio::Config); rcon->FireAndForgetQueries(std::move(transaction), Prio::Config);
}); });
auto flushDels ([&]() { auto flushDels ([&]() {
@ -403,7 +411,7 @@ void IcingaDB::UpdateAllConfigObjects()
delChecksum.clear(); delChecksum.clear();
delObject.clear(); delObject.clear();
m_Rcon->FireAndForgetQueries(std::move(transaction), Prio::Config); rcon->FireAndForgetQueries(std::move(transaction), Prio::Config);
}); });
auto setOne ([&]() { auto setOne ([&]() {
@ -464,8 +472,9 @@ void IcingaDB::UpdateAllConfigObjects()
} }
for (auto& key : GetTypeDumpSignalKeys(type)) { for (auto& key : GetTypeDumpSignalKeys(type)) {
m_Rcon->FireAndForgetQuery({"XADD", "icinga:dump", "*", "key", key, "state", "done"}, Prio::Config); rcon->FireAndForgetQuery({"XADD", "icinga:dump", "*", "key", key, "state", "done"}, Prio::Config);
} }
rcon->Sync();
}); });
upq.Join(); upq.Join();
@ -518,13 +527,13 @@ std::vector<std::vector<intrusive_ptr<ConfigObject>>> IcingaDB::ChunkObjects(std
return std::move(chunks); return std::move(chunks);
} }
void IcingaDB::DeleteKeys(const std::vector<String>& keys, RedisConnection::QueryPriority priority) { void IcingaDB::DeleteKeys(const RedisConnection::Ptr& conn, const std::vector<String>& keys, RedisConnection::QueryPriority priority) {
std::vector<String> query = {"DEL"}; std::vector<String> query = {"DEL"};
for (auto& key : keys) { for (auto& key : keys) {
query.emplace_back(key); query.emplace_back(key);
} }
m_Rcon->FireAndForgetQuery(std::move(query), priority); conn->FireAndForgetQuery(std::move(query), priority);
} }
std::vector<String> IcingaDB::GetTypeOverwriteKeys(const String& type) std::vector<String> IcingaDB::GetTypeOverwriteKeys(const String& type)

View File

@ -77,6 +77,16 @@ void IcingaDB::Start(bool runtimeCreated)
}); });
m_Rcon->Start(); m_Rcon->Start();
for (const Type::Ptr& type : GetTypes()) {
auto ctype (dynamic_cast<ConfigType*>(type.get()));
if (!ctype)
continue;
RedisConnection::Ptr rCon (new RedisConnection(GetHost(), GetPort(), GetPath(), GetPassword(), GetDbIndex()));
rCon->Start();
m_Rcons[ctype] = std::move(rCon);
}
m_StatsTimer = new Timer(); m_StatsTimer = new Timer();
m_StatsTimer->SetInterval(1); m_StatsTimer->SetInterval(1);
m_StatsTimer->OnTimerExpired.connect([this](const Timer * const&) { PublishStatsTimerHandler(); }); m_StatsTimer->OnTimerExpired.connect([this](const Timer * const&) { PublishStatsTimerHandler(); });

View File

@ -16,6 +16,7 @@
#include <memory> #include <memory>
#include <mutex> #include <mutex>
#include <set> #include <set>
#include <unordered_map>
#include <utility> #include <utility>
namespace icinga namespace icinga
@ -57,7 +58,7 @@ private:
/* config & status dump */ /* config & status dump */
void UpdateAllConfigObjects(); void UpdateAllConfigObjects();
std::vector<std::vector<intrusive_ptr<ConfigObject>>> ChunkObjects(std::vector<intrusive_ptr<ConfigObject>> objects, size_t chunkSize); std::vector<std::vector<intrusive_ptr<ConfigObject>>> ChunkObjects(std::vector<intrusive_ptr<ConfigObject>> objects, size_t chunkSize);
void DeleteKeys(const std::vector<String>& keys, RedisConnection::QueryPriority priority); void DeleteKeys(const RedisConnection::Ptr& conn, const std::vector<String>& keys, RedisConnection::QueryPriority priority);
std::vector<String> GetTypeOverwriteKeys(const String& type); std::vector<String> GetTypeOverwriteKeys(const String& type);
std::vector<String> GetTypeDumpSignalKeys(const Type::Ptr& type); std::vector<String> GetTypeDumpSignalKeys(const Type::Ptr& type);
void InsertObjectDependencies(const ConfigObject::Ptr& object, const String typeName, std::map<String, std::vector<String>>& hMSets, void InsertObjectDependencies(const ConfigObject::Ptr& object, const String typeName, std::map<String, std::vector<String>>& hMSets,
@ -150,6 +151,8 @@ private:
return std::move(haystack); return std::move(haystack);
} }
static std::vector<Type::Ptr> GetTypes();
Timer::Ptr m_StatsTimer; Timer::Ptr m_StatsTimer;
WorkQueue m_WorkQueue; WorkQueue m_WorkQueue;
@ -160,6 +163,7 @@ private:
bool m_ConfigDumpDone; bool m_ConfigDumpDone;
RedisConnection::Ptr m_Rcon; RedisConnection::Ptr m_Rcon;
std::unordered_map<ConfigType*, RedisConnection::Ptr> m_Rcons;
struct { struct {
DumpedGlobals CustomVar, ActionUrl, NotesUrl, IconImage; DumpedGlobals CustomVar, ActionUrl, NotesUrl, IconImage;

View File

@ -187,6 +187,17 @@ void RedisConnection::EnqueueCallback(const std::function<void(boost::asio::yiel
}); });
} }
/**
* Puts a no-op command with a result at the end of the queue and wait for the result,
* i.e. for everything enqueued to be processed by the server.
*
* @ingroup icingadb
*/
void RedisConnection::Sync()
{
GetResultOfQuery({"PING"}, RedisConnection::QueryPriority::SyncConnection);
}
/** /**
* Mark kind as kind of queries not to actually send yet * Mark kind as kind of queries not to actually send yet
* *

View File

@ -63,7 +63,8 @@ namespace icinga
Config, Config,
State, State,
History, History,
CheckResult CheckResult,
SyncConnection = 255
}; };
RedisConnection(const String& host, const int port, const String& path, RedisConnection(const String& host, const int port, const String& path,
@ -80,6 +81,7 @@ namespace icinga
Replies GetResultsOfQueries(Queries queries, QueryPriority priority); Replies GetResultsOfQueries(Queries queries, QueryPriority priority);
void EnqueueCallback(const std::function<void(boost::asio::yield_context&)>& callback, QueryPriority priority); void EnqueueCallback(const std::function<void(boost::asio::yield_context&)>& callback, QueryPriority priority);
void Sync();
void SuppressQueryKind(QueryPriority kind); void SuppressQueryKind(QueryPriority kind);
void UnsuppressQueryKind(QueryPriority kind); void UnsuppressQueryKind(QueryPriority kind);