IDO: Ensure that the notification insert id is passed to contactnotification inserts

We cannot add the notification insert id directly
to the following contactnotifications queries. Instead
we need to pass a DbValue reference which gets set after
the notification insert id is calculated.
The contactnotifications insert queries are fired as query
group calling CanExecuteQuery() and FieldToEscapedString().
If the notification id does not exist yet, the queries are
moved to the end of the queue.
Once the contactnotifications queries are fired the DbValue
reference is destroyed.

This patch also removes the old notification insert id cache
which was broken in many ways.

fixes #11387
This commit is contained in:
Michael Friedrich 2016-03-21 13:37:32 +01:00 committed by Gunnar Beutner
parent 45786e2b81
commit 0cbedf495a
9 changed files with 46 additions and 65 deletions

View File

@ -323,26 +323,6 @@ DbReference DbConnection::GetInsertID(const DbType::Ptr& type, const DbReference
return it->second;
}
void DbConnection::SetNotificationInsertID(const CustomVarObject::Ptr& obj, const DbReference& dbref)
{
if (dbref.IsValid())
m_NotificationInsertIDs[obj] = dbref;
else
m_NotificationInsertIDs.erase(obj);
}
DbReference DbConnection::GetNotificationInsertID(const CustomVarObject::Ptr& obj) const
{
std::map<CustomVarObject::Ptr, DbReference>::const_iterator it;
it = m_NotificationInsertIDs.find(obj);
if (it == m_NotificationInsertIDs.end())
return DbReference();
return it->second;
}
void DbConnection::SetObjectActive(const DbObject::Ptr& dbobj, bool active)
{
if (active)
@ -360,7 +340,6 @@ void DbConnection::ClearIDCache(void)
{
m_ObjectIDs.clear();
m_InsertIDs.clear();
m_NotificationInsertIDs.clear();
m_ActiveObjects.clear();
m_ConfigUpdates.clear();
m_StatusUpdates.clear();

View File

@ -57,9 +57,6 @@ public:
DbReference GetInsertID(const DbObject::Ptr& dbobj) const;
DbReference GetInsertID(const DbType::Ptr& type, const DbReference& objid) const;
void SetNotificationInsertID(const CustomVarObject::Ptr& obj, const DbReference& dbref);
DbReference GetNotificationInsertID(const CustomVarObject::Ptr& obj) const;
void SetObjectActive(const DbObject::Ptr& dbobj, bool active);
bool GetObjectActive(const DbObject::Ptr& dbobj) const;
@ -101,7 +98,6 @@ protected:
private:
std::map<DbObject::Ptr, DbReference> m_ObjectIDs;
std::map<std::pair<DbType::Ptr, DbReference>, DbReference> m_InsertIDs;
std::map<CustomVarObject::Ptr, DbReference> m_NotificationInsertIDs;
std::set<DbObject::Ptr> m_ActiveObjects;
std::set<DbObject::Ptr> m_ConfigUpdates;
std::set<DbObject::Ptr> m_StatusUpdates;

View File

@ -833,8 +833,7 @@ void DbEvents::AddNotificationHistory(const Notification::Ptr& notification, con
query1.Table = "notifications";
query1.Type = DbQueryInsert;
query1.Category = DbCatNotification;
/* store the object ptr for caching the insert id for this object */
query1.NotificationObject = notification;
query1.NotificationInsertID = new DbValue(DbValueObjectInsertID, -1);
Host::Ptr host;
Service::Ptr service;
@ -868,16 +867,17 @@ void DbEvents::AddNotificationHistory(const Notification::Ptr& notification, con
query1.Fields = fields1;
DbObject::OnQuery(query1);
DbQuery query2;
query2.Table = "contactnotifications";
query2.Type = DbQueryInsert;
query2.Category = DbCatNotification;
std::vector<DbQuery> queries;
/* filtered users */
BOOST_FOREACH(const User::Ptr& user, users) {
Log(LogDebug, "DbEvents")
<< "add contact notification history for service '" << checkable->GetName() << "' and user '" << user->GetName() << "'.";
DbQuery query2;
query2.Table = "contactnotifications";
query2.Type = DbQueryInsert;
query2.Category = DbCatNotification;
Dictionary::Ptr fields2 = new Dictionary();
fields2->Set("contact_object_id", user);
fields2->Set("start_time", DbValue::FromTimestamp(time_bag.first));
@ -885,12 +885,14 @@ void DbEvents::AddNotificationHistory(const Notification::Ptr& notification, con
fields2->Set("end_time", DbValue::FromTimestamp(time_bag.first));
fields2->Set("end_time_usec", time_bag.second);
fields2->Set("notification_id", notification); /* DbConnection class fills in real ID from notification insert id cache */
fields2->Set("notification_id", query1.NotificationInsertID);
fields2->Set("instance_id", 0); /* DbConnection class fills in real ID */
query2.Fields = fields2;
DbObject::OnQuery(query2);
queries.push_back(query2);
}
DbObject::OnMultipleQueries(queries);
}
/* statehistory */

View File

@ -21,6 +21,7 @@
#define DBQUERY_H
#include "db_ido/i2-db_ido.hpp"
#include "db_ido/dbvalue.hpp"
#include "icinga/customvarobject.hpp"
#include "base/dictionary.hpp"
#include "base/configobject.hpp"
@ -67,7 +68,7 @@ struct I2_DB_IDO_API DbQuery
Dictionary::Ptr Fields;
Dictionary::Ptr WhereCriteria;
intrusive_ptr<DbObject> Object;
intrusive_ptr<CustomVarObject> NotificationObject;
DbValue::Ptr NotificationInsertID;
bool ConfigUpdate;
bool StatusUpdate;
WorkQueuePriority Priority;

View File

@ -93,3 +93,8 @@ Value DbValue::GetValue(void) const
{
return m_Value;
}
void DbValue::SetValue(const Value& value)
{
m_Value = value;
}

View File

@ -31,7 +31,7 @@ enum DbValueType
{
DbValueTimestamp,
DbValueTimestampNow,
DbValueObjectInsertID,
DbValueObjectInsertID
};
/**
@ -58,7 +58,9 @@ public:
static Value ExtractValue(const Value& value);
DbValueType GetType(void) const;
Value GetValue(void) const;
void SetValue(const Value& value);
private:
DbValueType m_Type;

View File

@ -704,14 +704,6 @@ bool IdoMysqlConnection::FieldToEscapedString(const String& key, const Value& va
} else if (key == "session_token") {
*result = m_SessionToken;
return true;
} else if (key == "notification_id") {
DbReference ref = GetNotificationInsertID(value);
if (!ref.IsValid())
return false;
*result = static_cast<long>(ref);
return true;
}
Value rawvalue = DbValue::ExtractValue(value);
@ -752,6 +744,14 @@ bool IdoMysqlConnection::FieldToEscapedString(const String& key, const Value& va
*result = Value(msgbuf.str());
} else if (DbValue::IsTimestampNow(value)) {
*result = "NOW()";
} else if (DbValue::IsObjectInsertID(value)) {
long id = static_cast<long>(rawvalue);
if (id <= 0)
return false;
*result = id;
return true;
} else {
Value fvalue;
@ -969,11 +969,8 @@ void IdoMysqlConnection::FinishExecuteQuery(const DbQuery& query, int type, bool
SetStatusUpdate(query.Object, true);
}
if (type == DbQueryInsert && query.Table == "notifications" && query.NotificationObject) { // FIXME remove hardcoded table name
SetNotificationInsertID(query.NotificationObject, GetLastInsertID());
Log(LogDebug, "IdoMysqlConnection")
<< "saving contactnotification notification_id=" << static_cast<long>(GetLastInsertID());
}
if (type == DbQueryInsert && query.Table == "notifications" && query.NotificationInsertID)
query.NotificationInsertID->SetValue(static_cast<long>(GetLastInsertID()));
}
void IdoMysqlConnection::CleanUpExecuteQuery(const String& table, const String& time_column, double max_age)

View File

@ -583,14 +583,6 @@ bool IdoPgsqlConnection::FieldToEscapedString(const String& key, const Value& va
} else if (key == "session_token") {
*result = m_SessionToken;
return true;
} else if (key == "notification_id") {
DbReference ref = GetNotificationInsertID(value);
if (!ref.IsValid())
return false;
*result = static_cast<long>(ref);
return true;
}
Value rawvalue = DbValue::ExtractValue(value);
@ -630,6 +622,14 @@ bool IdoPgsqlConnection::FieldToEscapedString(const String& key, const Value& va
*result = Value(msgbuf.str());
} else if (DbValue::IsTimestampNow(value)) {
*result = "NOW()";
} else if (DbValue::IsObjectInsertID(value)) {
long id = static_cast<long>(rawvalue);
if (id <= 0)
return false;
*result = id;
return true;
} else {
Value fvalue;
@ -849,12 +849,9 @@ void IdoPgsqlConnection::InternalExecuteQuery(const DbQuery& query, DbQueryType
SetStatusUpdate(query.Object, true);
}
if (type == DbQueryInsert && query.Table == "notifications" && query.NotificationObject) { // FIXME remove hardcoded table name
String idField = "notification_id";
DbReference seqval = GetSequenceValue(GetTablePrefix() + query.Table, idField);
SetNotificationInsertID(query.NotificationObject, seqval);
Log(LogDebug, "IdoPgsqlConnection")
<< "saving contactnotification notification_id=" << Convert::ToString(seqval);
if (type == DbQueryInsert && query.Table == "notifications" && query.NotificationInsertID) {
DbReference seqval = GetSequenceValue(GetTablePrefix() + query.Table, "notification_id");
query.NotificationInsertID->SetValue(static_cast<long>(seqval));
}
}

View File

@ -466,7 +466,7 @@ void Notification::ExecuteNotificationHelper(NotificationType type, const User::
if (!command) {
Log(LogDebug, "Notification")
<< "No notification_command found for notification '" << GetName() << "'. Skipping execution.";
<< "No command found for notification '" << GetName() << "'. Skipping execution.";
return;
}
@ -482,7 +482,9 @@ void Notification::ExecuteNotificationHelper(NotificationType type, const User::
Service::OnNotificationSentToUser(this, GetCheckable(), user, type, cr, author, text, command->GetName());
Log(LogInformation, "Notification")
<< "Completed sending notification '" << GetName() << "' for checkable '" << GetCheckable()->GetName() << "'";
<< "Completed sending notification '" << GetName()
<< "' for checkable '" << GetCheckable()->GetName()
<< "' and user '" << user->GetName() << "'.";
} catch (const std::exception& ex) {
Log(LogWarning, "Notification")
<< "Exception occured during notification for checkable '"