IDO: use per-instance notification_id in history

When there are multiple active IDO instances on the same node, before this
commit, all of them would share a single DbValue object for the notification_id
column of the icinga_contactnotifications table. This resulted in the issue
that one database references the notification_id in another database.

This commit fixes this by using a separate DbValue value for each IDO instance.
This needs a new signal as the existing OnQuery and OnMultipleQueries signals
perform the same queries on all IDO instances, but different queries are needed
here per instance (they only differ in the referenced DbValue). Therefore, a
new signal OnMakeQueries is added that takes a std::function which is called
once per IDO instance and can access callbacks to perform one or multiple
queries only on this specific IDO instance.
This commit is contained in:
Julian Brost 2022-02-10 16:08:30 +01:00
parent 8016b013ac
commit 7c9d0fff01
4 changed files with 79 additions and 54 deletions

View File

@ -45,8 +45,19 @@ void DbConnection::Start(bool runtimeCreated)
Log(LogInformation, "DbConnection") Log(LogInformation, "DbConnection")
<< "'" << GetName() << "' started."; << "'" << GetName() << "' started.";
DbObject::OnQuery.connect([this](const DbQuery& query) { ExecuteQuery(query); }); auto onQuery = [this](const DbQuery& query) { ExecuteQuery(query); };
DbObject::OnMultipleQueries.connect([this](const std::vector<DbQuery>& multiQueries) { ExecuteMultipleQueries(multiQueries); }); DbObject::OnQuery.connect(onQuery);
auto onMultipleQueries = [this](const std::vector<DbQuery>& multiQueries) { ExecuteMultipleQueries(multiQueries); };
DbObject::OnMultipleQueries.connect(onMultipleQueries);
DbObject::QueryCallbacks queryCallbacks;
queryCallbacks.Query = onQuery;
queryCallbacks.MultipleQueries = onMultipleQueries;
DbObject::OnMakeQueries.connect([queryCallbacks](const std::function<void (const DbObject::QueryCallbacks&)>& queryFunc) {
queryFunc(queryCallbacks);
});
} }
void DbConnection::Stop(bool runtimeRemoved) void DbConnection::Stop(bool runtimeRemoved)

View File

@ -837,6 +837,12 @@ void DbEvents::AddAcknowledgementInternal(const Checkable::Ptr& checkable, Ackno
void DbEvents::AddNotificationHistory(const Notification::Ptr& notification, const Checkable::Ptr& checkable, const std::set<User::Ptr>& users, NotificationType type, void DbEvents::AddNotificationHistory(const Notification::Ptr& notification, const Checkable::Ptr& checkable, const std::set<User::Ptr>& users, NotificationType type,
const CheckResult::Ptr& cr, const String& author, const String& text) const CheckResult::Ptr& cr, const String& author, const String& text)
{ {
/* NotificationInsertID has to be tracked per IDO instance, therefore the OnQuery and OnMultipleQueries signals
* cannot be called directly as all IDO instances would insert rows with the same ID which is (most likely) only
* correct in one database. Instead, pass a lambda which generates the queries with new DbValue for
* NotificationInsertID each IDO instance.
*/
DbObject::OnMakeQueries([&checkable, &users, &type, &cr](const DbObject::QueryCallbacks& callbacks) {
/* start and end happen at the same time */ /* start and end happen at the same time */
std::pair<unsigned long, unsigned long> timeBag = ConvertTimestamp(Utility::GetTime()); std::pair<unsigned long, unsigned long> timeBag = ConvertTimestamp(Utility::GetTime());
@ -879,7 +885,7 @@ void DbEvents::AddNotificationHistory(const Notification::Ptr& notification, con
fields1->Set("endpoint_object_id", endpoint); fields1->Set("endpoint_object_id", endpoint);
query1.Fields = fields1; query1.Fields = fields1;
DbObject::OnQuery(query1); callbacks.Query(query1);
std::vector<DbQuery> queries; std::vector<DbQuery> queries;
@ -902,7 +908,8 @@ void DbEvents::AddNotificationHistory(const Notification::Ptr& notification, con
queries.emplace_back(std::move(query2)); queries.emplace_back(std::move(query2));
} }
DbObject::OnMultipleQueries(queries); callbacks.MultipleQueries(queries);
});
} }
/* statehistory */ /* statehistory */

View File

@ -25,6 +25,7 @@ using namespace icinga;
boost::signals2::signal<void (const DbQuery&)> DbObject::OnQuery; boost::signals2::signal<void (const DbQuery&)> DbObject::OnQuery;
boost::signals2::signal<void (const std::vector<DbQuery>&)> DbObject::OnMultipleQueries; boost::signals2::signal<void (const std::vector<DbQuery>&)> DbObject::OnMultipleQueries;
boost::signals2::signal<void (const std::function<void (const DbObject::QueryCallbacks&)>&)> DbObject::OnMakeQueries;
INITIALIZE_ONCE(&DbObject::StaticInitialize); INITIALIZE_ONCE(&DbObject::StaticInitialize);

View File

@ -61,8 +61,14 @@ public:
static DbObject::Ptr GetOrCreateByObject(const ConfigObject::Ptr& object); static DbObject::Ptr GetOrCreateByObject(const ConfigObject::Ptr& object);
struct QueryCallbacks {
std::function<void(const DbQuery&)> Query;
std::function<void(const std::vector<DbQuery>&)> MultipleQueries;
};
static boost::signals2::signal<void (const DbQuery&)> OnQuery; static boost::signals2::signal<void (const DbQuery&)> OnQuery;
static boost::signals2::signal<void (const std::vector<DbQuery>&)> OnMultipleQueries; static boost::signals2::signal<void (const std::vector<DbQuery>&)> OnMultipleQueries;
static boost::signals2::signal<void (const std::function<void (const QueryCallbacks&)>&)> OnMakeQueries;
void SendConfigUpdateHeavy(const Dictionary::Ptr& configFields); void SendConfigUpdateHeavy(const Dictionary::Ptr& configFields);
void SendConfigUpdateLight(); void SendConfigUpdateLight();