]> granicus.if.org Git - icinga2/commitdiff
Implement support for incremental IDO updates
authorGunnar Beutner <gunnar.beutner@netways.de>
Sun, 14 Aug 2016 20:24:51 +0000 (22:24 +0200)
committerGunnar Beutner <gunnar.beutner@netways.de>
Mon, 15 Aug 2016 12:43:11 +0000 (14:43 +0200)
fixes #12435

22 files changed:
lib/base/array.cpp
lib/base/array.hpp
lib/db_ido/dbconnection.cpp
lib/db_ido/dbconnection.hpp
lib/db_ido/dbobject.cpp
lib/db_ido/dbobject.hpp
lib/db_ido/hostdbobject.cpp
lib/db_ido/hostdbobject.hpp
lib/db_ido/servicedbobject.cpp
lib/db_ido/servicedbobject.hpp
lib/db_ido/timeperioddbobject.cpp
lib/db_ido/timeperioddbobject.hpp
lib/db_ido/userdbobject.cpp
lib/db_ido/userdbobject.hpp
lib/db_ido_mysql/idomysqlconnection.cpp
lib/db_ido_mysql/idomysqlconnection.hpp
lib/db_ido_mysql/schema/mysql.sql
lib/db_ido_mysql/schema/upgrade/2.5.0.sql
lib/db_ido_pgsql/idopgsqlconnection.cpp
lib/db_ido_pgsql/idopgsqlconnection.hpp
lib/db_ido_pgsql/schema/pgsql.sql
lib/db_ido_pgsql/schema/upgrade/2.5.0.sql

index 3152834b42ce53059311918427b87abb7096ee27..e849cc64a4a40127cada7bb45b1e116b325a1e3e 100644 (file)
@@ -204,6 +204,12 @@ Array::Ptr Array::Reverse(void) const
        return result;
 }
 
+void Array::Sort(void)
+{
+       ObjectLock olock(this);
+       std::sort(m_Data.begin(), m_Data.end());
+}
+
 String Array::ToString(void) const
 {
        std::ostringstream msgbuf;
index 0d50be8f2a818d90aeda326e2d198d7637352626..f6d75e4dcfb415c61ed6541fcc7d75d330f946d6 100644 (file)
@@ -131,6 +131,8 @@ public:
 
        Array::Ptr Reverse(void) const;
 
+       void Sort(void);
+
        virtual String ToString(void) const override;
 
        virtual Value GetFieldByName(const String& field, bool sandboxed, const DebugInfo& debugInfo) const override;
index 6f4af2da50bdd60c475e20163de6a873e03f20c2..bef8cd3d6e499c459eb47bb8e8a3a7b5e99a6e63 100644 (file)
@@ -285,6 +285,42 @@ void DbConnection::CleanUpExecuteQuery(const String&, const String&, double)
        /* Default handler does nothing. */
 }
 
+void DbConnection::SetConfigHash(const DbObject::Ptr& dbobj, const String& hash)
+{
+       SetConfigHash(dbobj->GetType(), GetObjectID(dbobj), hash);
+}
+
+void DbConnection::SetConfigHash(const DbType::Ptr& type, const DbReference& objid, const String& hash)
+{
+       if (!objid.IsValid())
+               return;
+
+       if (!hash.IsEmpty())
+               m_ConfigHashes[std::make_pair(type, objid)] = hash;
+       else
+               m_ConfigHashes.erase(std::make_pair(type, objid));
+}
+
+String DbConnection::GetConfigHash(const DbObject::Ptr& dbobj) const
+{
+       return GetConfigHash(dbobj->GetType(), GetObjectID(dbobj));
+}
+
+String DbConnection::GetConfigHash(const DbType::Ptr& type, const DbReference& objid) const
+{
+       if (!objid.IsValid())
+               return String();
+
+       std::map<std::pair<DbType::Ptr, DbReference>, String>::const_iterator it;
+
+       it = m_ConfigHashes.find(std::make_pair(type, objid));
+
+       if (it == m_ConfigHashes.end())
+               return String();
+
+       return it->second;
+}
+
 void DbConnection::SetObjectID(const DbObject::Ptr& dbobj, const DbReference& dbref)
 {
        if (dbref.IsValid())
@@ -363,6 +399,7 @@ void DbConnection::ClearIDCache(void)
        m_ActiveObjects.clear();
        m_ConfigUpdates.clear();
        m_StatusUpdates.clear();
+       m_ConfigHashes.clear();
 }
 
 void DbConnection::SetConfigUpdate(const DbObject::Ptr& dbobj, bool hasupdate)
@@ -406,8 +443,18 @@ void DbConnection::UpdateObject(const ConfigObject::Ptr& object)
                        if (!dbActive)
                                ActivateObject(dbobj);
 
-                       dbobj->SendConfigUpdate();
-                       dbobj->SendStatusUpdate();
+                       Dictionary::Ptr configFields = dbobj->GetConfigFields();
+                       String configHash = dbobj->CalculateConfigHash(configFields);
+                       configFields->Set("config_hash", configHash);
+
+                       String cachedHash = GetConfigHash(dbobj);
+
+                       if (cachedHash != configHash) {
+                               dbobj->SendConfigUpdateHeavy(configFields);
+                               dbobj->SendStatusUpdate();
+                       } else {
+                               dbobj->SendConfigUpdateLight();
+                       }
                } else if (!active) {
                        /* Deactivate the deleted object no matter
                         * which state it had in the database.
@@ -429,43 +476,6 @@ void DbConnection::UpdateAllObjects(void)
 
 void DbConnection::PrepareDatabase(void)
 {
-       /*
-        * only clear tables on reconnect which
-        * cannot be updated by their existing ids
-        * for details check https://dev.icinga.org/issues/5565
-        */
-
-       //ClearConfigTable("commands");
-       //ClearConfigTable("comments");
-       ClearConfigTable("contact_addresses");
-       ClearConfigTable("contact_notificationcommands");
-       //ClearConfigTable("contactgroup_members");
-       //ClearConfigTable("contactgroups");
-       //ClearConfigTable("contacts");
-       //ClearConfigTable("contactstatus");
-       //ClearConfigTable("customvariables");
-       //ClearConfigTable("customvariablestatus");
-       //ClearConfigTable("endpoints");
-       //ClearConfigTable("endpointstatus");
-       ClearConfigTable("host_contactgroups");
-       ClearConfigTable("host_contacts");
-       ClearConfigTable("host_parenthosts");
-       ClearConfigTable("hostdependencies");
-       //ClearConfigTable("hostgroup_members");
-       //ClearConfigTable("hostgroups");
-       //ClearConfigTable("hosts");
-       //ClearConfigTable("hoststatus");
-       //ClearConfigTable("scheduleddowntime");
-       ClearConfigTable("service_contactgroups");
-       ClearConfigTable("service_contacts");
-       ClearConfigTable("servicedependencies");
-       //ClearConfigTable("servicegroup_members");
-       //ClearConfigTable("servicegroups");
-       //ClearConfigTable("services");
-       //ClearConfigTable("servicestatus");
-       ClearConfigTable("timeperiod_timeranges");
-       //ClearConfigTable("timeperiods");
-
        BOOST_FOREACH(const DbType::Ptr& type, DbType::GetAllTypes()) {
                FillIDCache(type);
        }
index 74cc6b3e98dec1faf315c3b4ae90b4698bf2d188..0a5cad1e7d48b5e3a673aeb1b78c367febd52001 100644 (file)
@@ -49,6 +49,11 @@ public:
 
        static void InitializeDbTimer(void);
 
+       void SetConfigHash(const DbObject::Ptr& dbobj, const String& hash);
+       void SetConfigHash(const DbType::Ptr& type, const DbReference& objid, const String& hash);
+       String GetConfigHash(const DbObject::Ptr& dbobj) const;
+       String GetConfigHash(const DbType::Ptr& type, const DbReference& objid) const;
+
        void SetObjectID(const DbObject::Ptr& dbobj, const DbReference& dbref);
        DbReference GetObjectID(const DbObject::Ptr& dbobj) const;
 
@@ -106,6 +111,7 @@ protected:
 
 private:
        bool m_IDCacheValid;
+       std::map<std::pair<DbType::Ptr, DbReference>, String> m_ConfigHashes;
        std::map<DbObject::Ptr, DbReference> m_ObjectIDs;
        std::map<std::pair<DbType::Ptr, DbReference>, DbReference> m_InsertIDs;
        std::set<DbObject::Ptr> m_ActiveObjects;
@@ -115,8 +121,6 @@ private:
 
        void CleanUpHandler(void);
 
-       virtual void ClearConfigTable(const String& table) = 0;
-
        static Timer::Ptr m_ProgramStatusTimer;
        static boost::once_flag m_OnceFlag;
 
index 2f3974f7c4a9295f469b0dcda6ebca793f3f947e..4516a1054d00c045e80429d614d36cacab7426c5 100644 (file)
@@ -30,6 +30,8 @@
 #include "base/configobject.hpp"
 #include "base/configtype.hpp"
 #include "base/json.hpp"
+#include "base/serializer.hpp"
+#include "base/json.hpp"
 #include "base/convert.hpp"
 #include "base/objectlock.hpp"
 #include "base/utility.hpp"
@@ -83,35 +85,82 @@ DbType::Ptr DbObject::GetType(void) const
        return m_Type;
 }
 
-void DbObject::SendConfigUpdate(void)
+String DbObject::CalculateConfigHash(const Dictionary::Ptr& configFields) const
+{
+       Dictionary::Ptr configFieldsDup = configFields->ShallowClone();
+
+       {
+               ObjectLock olock(configFieldsDup);
+
+               BOOST_FOREACH(const Dictionary::Pair& kv, configFieldsDup) {
+                       if (kv.second.IsObjectType<ConfigObject>()) {
+                               ConfigObject::Ptr obj = kv.second;
+                               configFieldsDup->Set(kv.first, obj->GetName());
+                       }
+               }
+       }
+
+       Array::Ptr data = new Array();
+       data->Add(configFieldsDup);
+
+       CustomVarObject::Ptr custom_var_object = dynamic_pointer_cast<CustomVarObject>(GetObject());
+
+       if (custom_var_object)
+               data->Add(custom_var_object->GetVars());
+
+       return HashValue(data);
+}
+
+String DbObject::HashValue(const Value& value)
+{
+       Value temp;
+
+       Type::Ptr type = value.GetReflectionType();
+
+       if (ConfigObject::TypeInstance->IsAssignableFrom(type))
+               temp = Serialize(value, FAConfig);
+       else
+               temp = value;
+
+       return SHA256(JsonEncode(temp));
+}
+
+void DbObject::SendConfigUpdateHeavy(const Dictionary::Ptr& configFields)
 {
        /* update custom var config and status */
-       SendVarsConfigUpdate();
+       SendVarsConfigUpdateHeavy();
        SendVarsStatusUpdate();
 
        /* config attributes */
-       Dictionary::Ptr fields = GetConfigFields();
-
-       if (!fields)
+       if (!configFields)
                return;
 
+       ASSERT(configFields->Contains("config_hash"));
+
+       ConfigObject::Ptr object = GetObject();
+
        DbQuery query;
        query.Table = GetType()->GetTable() + "s";
        query.Type = DbQueryInsert | DbQueryUpdate;
        query.Category = DbCatConfig;
-       query.Fields = fields;
-       query.Fields->Set(GetType()->GetIDColumn(), GetObject());
+       query.Fields = configFields;
+       query.Fields->Set(GetType()->GetIDColumn(), object);
        query.Fields->Set("instance_id", 0); /* DbConnection class fills in real ID */
        query.Fields->Set("config_type", 1);
        query.WhereCriteria = new Dictionary();
-       query.WhereCriteria->Set(GetType()->GetIDColumn(), GetObject());
+       query.WhereCriteria->Set(GetType()->GetIDColumn(), object);
        query.Object = this;
        query.ConfigUpdate = true;
        OnQuery(query);
 
        m_LastConfigUpdate = Utility::GetTime();
 
-       OnConfigUpdate();
+       OnConfigUpdateHeavy();
+}
+
+void DbObject::SendConfigUpdateLight(void)
+{
+       OnConfigUpdateLight();
 }
 
 void DbObject::SendStatusUpdate(void)
@@ -152,7 +201,7 @@ void DbObject::SendStatusUpdate(void)
        OnStatusUpdate();
 }
 
-void DbObject::SendVarsConfigUpdate(void)
+void DbObject::SendVarsConfigUpdateHeavy(void)
 {
        ConfigObject::Ptr obj = GetObject();
 
@@ -161,10 +210,29 @@ void DbObject::SendVarsConfigUpdate(void)
        if (!custom_var_object)
                return;
 
+       std::vector<DbQuery> queries;
+
+       DbQuery query1;
+       query1.Table = "customvariables";
+       query1.Type = DbQueryDelete;
+       query1.Category = DbCatConfig;
+       query1.WhereCriteria = new Dictionary();
+       query1.WhereCriteria->Set("object_id", obj);
+
+       queries.push_back(query1);
+
+       DbQuery query2;
+       query2.Table = "customvariablestatus";
+       query2.Type = DbQueryDelete;
+       query2.Category = DbCatConfig;
+       query2.WhereCriteria = new Dictionary();
+       query2.WhereCriteria->Set("object_id", obj);
+
+       queries.push_back(query2);
+
        Dictionary::Ptr vars = CompatUtility::GetCustomAttributeConfig(custom_var_object);
 
        if (vars) {
-               std::vector<DbQuery> queries;
                ObjectLock olock (vars);
 
                BOOST_FOREACH(const Dictionary::Pair& kv, vars) {
@@ -185,26 +253,25 @@ void DbObject::SendVarsConfigUpdate(void)
                        fields->Set("varvalue", value);
                        fields->Set("is_json", is_json);
                        fields->Set("config_type", 1);
-                       fields->Set("session_token", 0); /* DbConnection class fills in real ID */
                        fields->Set("object_id", obj);
                        fields->Set("instance_id", 0); /* DbConnection class fills in real ID */
 
-                       DbQuery query;
-                       query.Table = "customvariables";
-                       query.Type = DbQueryInsert | DbQueryUpdate;
-                       query.Category = DbCatConfig;
-                       query.Fields = fields;
+                       DbQuery query3;
+                       query3.Table = "customvariables";
+                       query3.Type = DbQueryInsert;
+                       query3.Category = DbCatConfig;
+                       query3.Fields = fields;
 
-                       query.WhereCriteria = new Dictionary();
-                       query.WhereCriteria->Set("object_id", obj);
-                       query.WhereCriteria->Set("varname", kv.first);
-                       query.Object = this;
+                       query3.WhereCriteria = new Dictionary();
+                       query3.WhereCriteria->Set("object_id", obj);
+                       query3.WhereCriteria->Set("varname", kv.first);
+                       query3.Object = this;
 
-                       queries.push_back(query);
+                       queries.push_back(query3);
                }
-
-               OnMultipleQueries(queries);
        }
+
+       OnMultipleQueries(queries);
 }
 
 void DbObject::SendVarsStatusUpdate(void)
@@ -240,7 +307,6 @@ void DbObject::SendVarsStatusUpdate(void)
                        fields->Set("varvalue", value);
                        fields->Set("is_json", is_json);
                        fields->Set("status_update_time", DbValue::FromTimestamp(Utility::GetTime()));
-                       fields->Set("session_token", 0); /* DbConnection class fills in real ID */
                        fields->Set("object_id", obj);
                        fields->Set("instance_id", 0); /* DbConnection class fills in real ID */
 
@@ -272,7 +338,12 @@ double DbObject::GetLastStatusUpdate(void) const
        return m_LastStatusUpdate;
 }
 
-void DbObject::OnConfigUpdate(void)
+void DbObject::OnConfigUpdateHeavy(void)
+{
+       /* Default handler does nothing. */
+}
+
+void DbObject::OnConfigUpdateLight(void)
 {
        /* Default handler does nothing. */
 }
@@ -350,7 +421,11 @@ void DbObject::VersionChangedHandler(const ConfigObject::Ptr& object)
        DbObject::Ptr dbobj = DbObject::GetOrCreateByObject(object);
 
        if (dbobj) {
-               dbobj->SendConfigUpdate();
+               Dictionary::Ptr configFields = dbobj->GetConfigFields();
+               String configHash = dbobj->CalculateConfigHash(configFields);
+               configFields->Set("config_hash", configHash);
+
+               dbobj->SendConfigUpdateHeavy(configFields);
                dbobj->SendStatusUpdate();
        }
 }
index f9ab0ec9a6d2a778daf824b7ce8e7c0757dbe8e3..87d80a9bce2e9f9e58c719e3b8122c9087a92b43 100644 (file)
@@ -81,20 +81,26 @@ public:
        static boost::signals2::signal<void (const DbQuery&)> OnQuery;
        static boost::signals2::signal<void (const std::vector<DbQuery>&)> OnMultipleQueries;
 
-       void SendConfigUpdate(void);
+       void SendConfigUpdateHeavy(const Dictionary::Ptr& configFields);
+       void SendConfigUpdateLight(void);
        void SendStatusUpdate(void);
-       void SendVarsConfigUpdate(void);
+       void SendVarsConfigUpdateHeavy(void);
        void SendVarsStatusUpdate(void);
 
        double GetLastConfigUpdate(void) const;
        double GetLastStatusUpdate(void) const;
 
+       virtual String CalculateConfigHash(const Dictionary::Ptr& configFields) const;
+
 protected:
        DbObject(const intrusive_ptr<DbType>& type, const String& name1, const String& name2);
 
-       virtual void OnConfigUpdate(void);
+       virtual void OnConfigUpdateHeavy(void);
+       virtual void OnConfigUpdateLight(void);
        virtual void OnStatusUpdate(void);
 
+       static String HashValue(const Value& value);
+
 private:
        String m_Name1;
        String m_Name2;
index ef69c6db292942186073637a88342994beda2915..7292338acd0d7ccff3a36f3f8c2312fe39e4d6ea 100644 (file)
@@ -177,36 +177,59 @@ Dictionary::Ptr HostDbObject::GetStatusFields(void) const
        return fields;
 }
 
-void HostDbObject::OnConfigUpdate(void)
+void HostDbObject::OnConfigUpdateHeavy(void)
 {
        Host::Ptr host = static_pointer_cast<Host>(GetObject());
 
        /* groups */
        Array::Ptr groups = host->GetGroups();
 
+       std::vector<DbQuery> queries;
+
+       DbQuery query1;
+       query1.Table = DbType::GetByName("HostGroup")->GetTable() + "_members";
+       query1.Type = DbQueryDelete;
+       query1.Category = DbCatConfig;
+       query1.WhereCriteria = new Dictionary();
+       query1.WhereCriteria->Set("host_object_id", host);
+
+       queries.push_back(query1);
+
        if (groups) {
                ObjectLock olock(groups);
                BOOST_FOREACH(const String& groupName, groups) {
                        HostGroup::Ptr group = HostGroup::GetByName(groupName);
 
-                       DbQuery query1;
-                       query1.Table = DbType::GetByName("HostGroup")->GetTable() + "_members";
-                       query1.Type = DbQueryInsert | DbQueryUpdate;
-                       query1.Category = DbCatConfig;
-                       query1.Fields = new Dictionary();
-                       query1.Fields->Set("instance_id", 0); /* DbConnection class fills in real ID */
-                       query1.Fields->Set("hostgroup_id", DbValue::FromObjectInsertID(group));
-                       query1.Fields->Set("host_object_id", host);
-                       query1.Fields->Set("session_token", 0); /* DbConnection class fills in real ID */
-                       query1.WhereCriteria = new Dictionary();
-                       query1.WhereCriteria->Set("instance_id", 0); /* DbConnection class fills in real ID */
-                       query1.WhereCriteria->Set("hostgroup_id", DbValue::FromObjectInsertID(group));
-                       query1.WhereCriteria->Set("host_object_id", host);
-
-                       DbObject::OnQuery(query1);
+                       DbQuery query2;
+                       query2.Table = DbType::GetByName("HostGroup")->GetTable() + "_members";
+                       query2.Type = DbQueryInsert;
+                       query2.Category = DbCatConfig;
+                       query2.Fields = new Dictionary();
+                       query2.Fields->Set("instance_id", 0); /* DbConnection class fills in real ID */
+                       query2.Fields->Set("hostgroup_id", DbValue::FromObjectInsertID(group));
+                       query2.Fields->Set("host_object_id", host);
+                       query2.WhereCriteria = new Dictionary();
+                       query2.WhereCriteria->Set("instance_id", 0); /* DbConnection class fills in real ID */
+                       query2.WhereCriteria->Set("hostgroup_id", DbValue::FromObjectInsertID(group));
+                       query2.WhereCriteria->Set("host_object_id", host);
+
+                       queries.push_back(query2);
                }
        }
 
+       DbObject::OnMultipleQueries(queries);
+
+       queries.clear();
+
+       DbQuery query2;
+       query2.Table = GetType()->GetTable() + "_parenthosts";
+       query2.Type = DbQueryDelete;
+       query2.Category = DbCatConfig;
+       query2.WhereCriteria = new Dictionary();
+       query2.WhereCriteria->Set(GetType()->GetTable() + "_id", DbValue::FromObjectInsertID(GetObject()));
+
+       queries.push_back(query2);
+
        /* parents */
        BOOST_FOREACH(const Checkable::Ptr& checkable, host->GetParents()) {
                Host::Ptr parent = dynamic_pointer_cast<Host>(checkable);
@@ -228,13 +251,27 @@ void HostDbObject::OnConfigUpdate(void)
                query1.Type = DbQueryInsert;
                query1.Category = DbCatConfig;
                query1.Fields = fields1;
-               OnQuery(query1);
+
+               queries.push_back(query1);
        }
 
+       DbObject::OnMultipleQueries(queries);
+
        /* host dependencies */
        Log(LogDebug, "HostDbObject")
            << "host dependencies for '" << host->GetName() << "'";
 
+       queries.clear();
+
+       DbQuery query3;
+       query3.Table = GetType()->GetTable() + "dependencies";
+       query3.Type = DbQueryDelete;
+       query3.Category = DbCatConfig;
+       query3.WhereCriteria = new Dictionary();
+       query3.WhereCriteria->Set("dependent_host_object_id", host);
+
+       queries.push_back(query3);
+
        BOOST_FOREACH(const Dependency::Ptr& dep, host->GetDependencies()) {
                Checkable::Ptr parent = dep->GetParent();
 
@@ -263,12 +300,26 @@ void HostDbObject::OnConfigUpdate(void)
                query2.Type = DbQueryInsert;
                query2.Category = DbCatConfig;
                query2.Fields = fields2;
-               OnQuery(query2);
+
+               queries.push_back(query2);
        }
 
+       DbObject::OnMultipleQueries(queries);
+
        Log(LogDebug, "HostDbObject")
            << "host contacts: " << host->GetName();
 
+       queries.clear();
+
+       DbQuery query4;
+       query4.Table = GetType()->GetTable() + "_contacts";
+       query4.Type = DbQueryDelete;
+       query4.Category = DbCatConfig;
+       query4.WhereCriteria = new Dictionary();
+       query4.WhereCriteria->Set("host_id", DbValue::FromObjectInsertID(host));
+
+       queries.push_back(query4);
+
        BOOST_FOREACH(const User::Ptr& user, CompatUtility::GetCheckableNotificationUsers(host)) {
                Log(LogDebug, "HostDbObject")
                    << "host contacts: " << user->GetName();
@@ -283,12 +334,26 @@ void HostDbObject::OnConfigUpdate(void)
                query_contact.Type = DbQueryInsert;
                query_contact.Category = DbCatConfig;
                query_contact.Fields = fields_contact;
-               OnQuery(query_contact);
+
+               queries.push_back(query_contact);
        }
 
+       DbObject::OnMultipleQueries(queries);
+
        Log(LogDebug, "HostDbObject")
            << "host contactgroups: " << host->GetName();
 
+       queries.clear();
+
+       DbQuery query5;
+       query5.Table = GetType()->GetTable() + "_contactgroups";
+       query5.Type = DbQueryDelete;
+       query5.Category = DbCatConfig;
+       query5.WhereCriteria = new Dictionary();
+       query5.WhereCriteria->Set("host_id", DbValue::FromObjectInsertID(host));
+
+       queries.push_back(query5);
+
        BOOST_FOREACH(const UserGroup::Ptr& usergroup, CompatUtility::GetCheckableNotificationUserGroups(host)) {
                Log(LogDebug, "HostDbObject")
                    << "host contactgroups: " << usergroup->GetName();
@@ -303,14 +368,93 @@ void HostDbObject::OnConfigUpdate(void)
                query_contact.Type = DbQueryInsert;
                query_contact.Category = DbCatConfig;
                query_contact.Fields = fields_contact;
-               OnQuery(query_contact);
+
+               queries.push_back(query_contact);
        }
 
+       DbObject::OnMultipleQueries(queries);
+
+       DoCommonConfigUpdate();
+}
+
+void HostDbObject::OnConfigUpdateLight(void)
+{
+       DoCommonConfigUpdate();
+}
+
+void HostDbObject::DoCommonConfigUpdate(void)
+{
+       Host::Ptr host = static_pointer_cast<Host>(GetObject());
+
        /* update comments and downtimes on config change */
        DbEvents::AddComments(host);
        DbEvents::AddDowntimes(host);
 }
 
-void HostDbObject::OnStatusUpdate(void)
+String HostDbObject::CalculateConfigHash(const Dictionary::Ptr& configFields) const
 {
+       String hashData = DbObject::CalculateConfigHash(configFields);
+
+       Host::Ptr host = static_pointer_cast<Host>(GetObject());
+
+       Array::Ptr parents = new Array();
+
+       /* parents */
+       BOOST_FOREACH(const Checkable::Ptr& checkable, host->GetParents()) {
+               Host::Ptr parent = dynamic_pointer_cast<Host>(checkable);
+
+               if (!parent)
+                       continue;
+
+               parents->Add(parent->GetName());
+       }
+
+       parents->Sort();
+
+       hashData += DbObject::HashValue(parents);
+
+       Array::Ptr dependencies = new Array();
+
+       /* dependencies */
+       BOOST_FOREACH(const Dependency::Ptr& dep, host->GetDependencies()) {
+               Checkable::Ptr parent = dep->GetParent();
+
+               if (!parent)
+                       continue;
+
+               int state_filter = dep->GetStateFilter();
+
+               Array::Ptr depInfo = new Array();
+               depInfo->Add(parent->GetName());
+               depInfo->Add(dep->GetStateFilter());
+               depInfo->Add(dep->GetPeriodRaw());
+
+               dependencies->Add(depInfo);
+       }
+
+       dependencies->Sort();
+
+       hashData += DbObject::HashValue(dependencies);
+
+       Array::Ptr users = new Array();
+
+       BOOST_FOREACH(const User::Ptr& user, CompatUtility::GetCheckableNotificationUsers(host)) {
+               users->Add(user->GetName());
+       }
+
+       users->Sort();
+
+       hashData += DbObject::HashValue(users);
+
+       Array::Ptr userGroups = new Array();
+
+       BOOST_FOREACH(const UserGroup::Ptr& usergroup, CompatUtility::GetCheckableNotificationUserGroups(host)) {
+               userGroups->Add(usergroup->GetName());
+       }
+
+       userGroups->Sort();
+
+       hashData += DbObject::HashValue(userGroups);
+
+       return SHA256(hashData);
 }
index 082b45b7a5dec1252caca0a8c8c4f3f8cedf2af3..679bea66d4019ad6b52f34cd44fb7afc9aed07a4 100644 (file)
@@ -41,9 +41,13 @@ public:
        virtual Dictionary::Ptr GetConfigFields(void) const override;
        virtual Dictionary::Ptr GetStatusFields(void) const override;
 
+       virtual void OnConfigUpdateHeavy(void) override;
+       virtual void OnConfigUpdateLight(void) override;
+
+       virtual String CalculateConfigHash(const Dictionary::Ptr& configFields) const;
+
 private:
-       virtual void OnConfigUpdate(void) override;
-       virtual void OnStatusUpdate(void) override;
+       void DoCommonConfigUpdate(void);
 };
 
 }
index 81ca8a30f69cc452a86196e964331a5362b77fd3..921e159609ddf6df0080bb897c08dfc82aa03655 100644 (file)
@@ -171,40 +171,63 @@ Dictionary::Ptr ServiceDbObject::GetStatusFields(void) const
        return fields;
 }
 
-void ServiceDbObject::OnConfigUpdate(void)
+void ServiceDbObject::OnConfigUpdateHeavy(void)
 {
        Service::Ptr service = static_pointer_cast<Service>(GetObject());
 
        /* groups */
        Array::Ptr groups = service->GetGroups();
 
+       std::vector<DbQuery> queries;
+
+       DbQuery query1;
+       query1.Table = DbType::GetByName("ServiceGroup")->GetTable() + "_members";
+       query1.Type = DbQueryDelete;
+       query1.Category = DbCatConfig;
+       query1.WhereCriteria = new Dictionary();
+       query1.WhereCriteria->Set("service_object_id", service);
+
+       queries.push_back(query1);
+
        if (groups) {
                ObjectLock olock(groups);
                BOOST_FOREACH(const String& groupName, groups) {
                        ServiceGroup::Ptr group = ServiceGroup::GetByName(groupName);
 
-                       DbQuery query1;
-                       query1.Table = DbType::GetByName("ServiceGroup")->GetTable() + "_members";
-                       query1.Type = DbQueryInsert | DbQueryUpdate;
-                       query1.Category = DbCatConfig;
-                       query1.Fields = new Dictionary();
-                       query1.Fields->Set("instance_id", 0); /* DbConnection class fills in real ID */
-                       query1.Fields->Set("servicegroup_id", DbValue::FromObjectInsertID(group));
-                       query1.Fields->Set("service_object_id", service);
-                       query1.Fields->Set("session_token", 0); /* DbConnection class fills in real ID */
-                       query1.WhereCriteria = new Dictionary();
-                       query1.WhereCriteria->Set("instance_id", 0); /* DbConnection class fills in real ID */
-                       query1.WhereCriteria->Set("servicegroup_id", DbValue::FromObjectInsertID(group));
-                       query1.WhereCriteria->Set("service_object_id", service);
-
-                       DbObject::OnQuery(query1);
+                       DbQuery query2;
+                       query2.Table = DbType::GetByName("ServiceGroup")->GetTable() + "_members";
+                       query2.Type = DbQueryInsert;
+                       query2.Category = DbCatConfig;
+                       query2.Fields = new Dictionary();
+                       query2.Fields->Set("instance_id", 0); /* DbConnection class fills in real ID */
+                       query2.Fields->Set("servicegroup_id", DbValue::FromObjectInsertID(group));
+                       query2.Fields->Set("service_object_id", service);
+                       query2.WhereCriteria = new Dictionary();
+                       query2.WhereCriteria->Set("instance_id", 0); /* DbConnection class fills in real ID */
+                       query2.WhereCriteria->Set("servicegroup_id", DbValue::FromObjectInsertID(group));
+                       query2.WhereCriteria->Set("service_object_id", service);
+
+                       queries.push_back(query2);
                }
        }
 
+       DbObject::OnMultipleQueries(queries);
+
        /* service dependencies */
        Log(LogDebug, "ServiceDbObject")
            << "service dependencies for '" << service->GetName() << "'";
 
+       queries.clear();
+
+       DbQuery query2;
+       query2.Table = GetType()->GetTable() + "dependencies";
+       query2.Type = DbQueryDelete;
+       query2.Category = DbCatConfig;
+       query2.WhereCriteria = new Dictionary();
+       query2.WhereCriteria->Set("dependent_service_object_id", service);
+
+       queries.push_back(query2);
+
        BOOST_FOREACH(const Dependency::Ptr& dep, service->GetDependencies()) {
                Checkable::Ptr parent = dep->GetParent();
 
@@ -236,13 +259,27 @@ void ServiceDbObject::OnConfigUpdate(void)
                query1.Type = DbQueryInsert;
                query1.Category = DbCatConfig;
                query1.Fields = fields1;
-               OnQuery(query1);
+
+               queries.push_back(query1);
        }
 
+       DbObject::OnMultipleQueries(queries);
+
        /* service contacts, contactgroups */
        Log(LogDebug, "ServiceDbObject")
            << "service contacts: " << service->GetName();
 
+       queries.clear();
+
+       DbQuery query3;
+       query3.Table = GetType()->GetTable() + "_contacts";
+       query3.Type = DbQueryDelete;
+       query3.Category = DbCatConfig;
+       query3.WhereCriteria = new Dictionary();
+       query3.WhereCriteria->Set("service_id", DbValue::FromObjectInsertID(service));
+
+       queries.push_back(query3);
+
        BOOST_FOREACH(const User::Ptr& user, CompatUtility::GetCheckableNotificationUsers(service)) {
                Log(LogDebug, "ServiceDbObject")
                    << "service contacts: " << user->GetName();
@@ -257,12 +294,26 @@ void ServiceDbObject::OnConfigUpdate(void)
                query_contact.Type = DbQueryInsert;
                query_contact.Category = DbCatConfig;
                query_contact.Fields = fields_contact;
-               OnQuery(query_contact);
+
+               queries.push_back(query_contact);
        }
 
+       DbObject::OnMultipleQueries(queries);
+
        Log(LogDebug, "ServiceDbObject")
            << "service contactgroups: " << service->GetName();
 
+       queries.clear();
+
+       DbQuery query4;
+       query4.Table = GetType()->GetTable() + "_contactgroups";
+       query4.Type = DbQueryDelete;
+       query4.Category = DbCatConfig;
+       query4.WhereCriteria = new Dictionary();
+       query4.WhereCriteria->Set("service_id", DbValue::FromObjectInsertID(service));
+
+       queries.push_back(query4);
+
        BOOST_FOREACH(const UserGroup::Ptr& usergroup, CompatUtility::GetCheckableNotificationUserGroups(service)) {
                Log(LogDebug, "ServiceDbObject")
                    << "service contactgroups: " << usergroup->GetName();
@@ -277,14 +328,77 @@ void ServiceDbObject::OnConfigUpdate(void)
                query_contact.Type = DbQueryInsert;
                query_contact.Category = DbCatConfig;
                query_contact.Fields = fields_contact;
-               OnQuery(query_contact);
+
+               queries.push_back(query_contact);
        }
 
+       DbObject::OnMultipleQueries(queries);
+
+       DoCommonConfigUpdate();
+}
+
+void ServiceDbObject::OnConfigUpdateLight(void)
+{
+       DoCommonConfigUpdate();
+}
+
+void ServiceDbObject::DoCommonConfigUpdate(void)
+{
+       Service::Ptr service = static_pointer_cast<Service>(GetObject());
+
        /* update comments and downtimes on config change */
        DbEvents::AddComments(service);
        DbEvents::AddDowntimes(service);
 }
 
-void ServiceDbObject::OnStatusUpdate(void)
+String ServiceDbObject::CalculateConfigHash(const Dictionary::Ptr& configFields) const
 {
+       String hashData = DbObject::CalculateConfigHash(configFields);
+
+       Service::Ptr service = static_pointer_cast<Service>(GetObject());
+
+       Array::Ptr dependencies = new Array();
+
+       /* dependencies */
+       BOOST_FOREACH(const Dependency::Ptr& dep, service->GetDependencies()) {
+               Checkable::Ptr parent = dep->GetParent();
+
+               if (!parent)
+                       continue;
+
+               int state_filter = dep->GetStateFilter();
+
+               Array::Ptr depInfo = new Array();
+               depInfo->Add(parent->GetName());
+               depInfo->Add(dep->GetStateFilter());
+               depInfo->Add(dep->GetPeriodRaw());
+
+               dependencies->Add(depInfo);
+       }
+
+       dependencies->Sort();
+
+       hashData += DbObject::HashValue(dependencies);
+
+       Array::Ptr users = new Array();
+
+       BOOST_FOREACH(const User::Ptr& user, CompatUtility::GetCheckableNotificationUsers(service)) {
+               users->Add(user->GetName());
+       }
+
+       users->Sort();
+
+       hashData += DbObject::HashValue(users);
+
+       Array::Ptr userGroups = new Array();
+
+       BOOST_FOREACH(const UserGroup::Ptr& usergroup, CompatUtility::GetCheckableNotificationUserGroups(service)) {
+               userGroups->Add(usergroup->GetName());
+       }
+
+       userGroups->Sort();
+
+       hashData += DbObject::HashValue(userGroups);
+
+       return SHA256(hashData);
 }
index 69958d6b3b33ba8602408fcd7ffe52d30d2ebf6b..64ffca2da63e5a1aaf1a926d83c7abfb63e9260d 100644 (file)
@@ -44,9 +44,13 @@ public:
        virtual Dictionary::Ptr GetConfigFields(void) const override;
        virtual Dictionary::Ptr GetStatusFields(void) const override;
 
-protected:
-       virtual void OnConfigUpdate(void) override;
-       virtual void OnStatusUpdate(void) override;
+       virtual void OnConfigUpdateHeavy(void) override;
+       virtual void OnConfigUpdateLight(void) override;
+
+       virtual String CalculateConfigHash(const Dictionary::Ptr& configFields) const;
+
+private:
+       void DoCommonConfigUpdate(void);
 };
 
 }
index badca9dd185bbc73e6a0123b37df40d24b34940b..290a2bff41b7f658330c41db5da6f8182813340b 100644 (file)
@@ -50,7 +50,7 @@ Dictionary::Ptr TimePeriodDbObject::GetStatusFields(void) const
        return Empty;
 }
 
-void TimePeriodDbObject::OnConfigUpdate(void)
+void TimePeriodDbObject::OnConfigUpdateHeavy(void)
 {
        TimePeriod::Ptr tp = static_pointer_cast<TimePeriod>(GetObject());
 
index eca79c5c70fe8bd870d57c8bd717af013cdf741b..00004a6fcd461403c79180688b87c96cd6fbba2d 100644 (file)
@@ -38,9 +38,11 @@ public:
 
        TimePeriodDbObject(const DbType::Ptr& type, const String& name1, const String& name2);
 
+protected:
        virtual Dictionary::Ptr GetConfigFields(void) const override;
        virtual Dictionary::Ptr GetStatusFields(void) const override;
-       virtual void OnConfigUpdate(void) override;
+
+       virtual void OnConfigUpdateHeavy(void) override;
 };
 
 }
index ce0a89ec6d0df290dc2abc7f9da94ce5c560e685..60fe460e647746d1ded7a1af9cf51692888fd1c0 100644 (file)
@@ -80,45 +80,65 @@ Dictionary::Ptr UserDbObject::GetStatusFields(void) const
        return fields;
 }
 
-void UserDbObject::OnConfigUpdate(void)
+void UserDbObject::OnConfigUpdateHeavy(void)
 {
-       Dictionary::Ptr fields = new Dictionary();
        User::Ptr user = static_pointer_cast<User>(GetObject());
 
        /* groups */
        Array::Ptr groups = user->GetGroups();
 
+       std::vector<DbQuery> queries;
+
+       DbQuery query1;
+       query1.Table = DbType::GetByName("UserGroup")->GetTable() + "_members";
+       query1.Type = DbQueryDelete;
+       query1.Category = DbCatConfig;
+       query1.WhereCriteria = new Dictionary();
+       query1.WhereCriteria->Set("contact_object_id", user);
+
+       queries.push_back(query1);
+
        if (groups) {
                ObjectLock olock(groups);
                BOOST_FOREACH(const String& groupName, groups) {
                        UserGroup::Ptr group = UserGroup::GetByName(groupName);
 
-                       DbQuery query1;
-                       query1.Table = DbType::GetByName("UserGroup")->GetTable() + "_members";
-                       query1.Type = DbQueryInsert | DbQueryUpdate;
-                       query1.Category = DbCatConfig;
-                       query1.Fields = new Dictionary();
-                       query1.Fields->Set("instance_id", 0); /* DbConnection class fills in real ID */
-                       query1.Fields->Set("contactgroup_id", DbValue::FromObjectInsertID(group));
-                       query1.Fields->Set("contact_object_id", user);
-                       query1.Fields->Set("session_token", 0); /* DbConnection class fills in real ID */
-                       query1.WhereCriteria = new Dictionary();
-                       query1.WhereCriteria->Set("instance_id", 0); /* DbConnection class fills in real ID */
-                       query1.WhereCriteria->Set("contactgroup_id", DbValue::FromObjectInsertID(group));
-                       query1.WhereCriteria->Set("contact_object_id", user);
-
-                       OnQuery(query1);
+                       DbQuery query2;
+                       query2.Table = DbType::GetByName("UserGroup")->GetTable() + "_members";
+                       query2.Type = DbQueryInsert | DbQueryUpdate;
+                       query2.Category = DbCatConfig;
+                       query2.Fields = new Dictionary();
+                       query2.Fields->Set("instance_id", 0); /* DbConnection class fills in real ID */
+                       query2.Fields->Set("contactgroup_id", DbValue::FromObjectInsertID(group));
+                       query2.Fields->Set("contact_object_id", user);
+                       query2.WhereCriteria = new Dictionary();
+                       query2.WhereCriteria->Set("instance_id", 0); /* DbConnection class fills in real ID */
+                       query2.WhereCriteria->Set("contactgroup_id", DbValue::FromObjectInsertID(group));
+                       query2.WhereCriteria->Set("contact_object_id", user);
+
+                       queries.push_back(query2);
                }
        }
 
-       /* contact addresses */
-       Log(LogDebug, "UserDbObject")
-           << "contact addresses for '" << user->GetName() << "'";
+       DbObject::OnMultipleQueries(queries);
+
+       queries.clear();
+
+       DbQuery query2;
+       query2.Table = "contact_addresses";
+       query2.Type = DbQueryDelete;
+       query2.Category = DbCatConfig;
+       query2.WhereCriteria = new Dictionary();
+       query2.WhereCriteria->Set("contact_id", DbValue::FromObjectInsertID(user));
+
+       queries.push_back(query2);
 
        Dictionary::Ptr vars = user->GetVars();
 
        if (vars) { /* This is sparta. */
                for (int i = 1; i <= 6; i++) {
+                       Dictionary::Ptr fields = new Dictionary();
+
                        String key = "address" + Convert::ToString(i);
 
                        if (!vars->Contains(key))
@@ -136,7 +156,10 @@ void UserDbObject::OnConfigUpdate(void)
                        query.Table = "contact_addresses";
                        query.Category = DbCatConfig;
                        query.Fields = fields;
-                       OnQuery(query);
+
+                       queries.push_back(query);
                }
        }
+
+       DbObject::OnMultipleQueries(queries);
 }
index df78299dfab162058832b53c134e30270adb311f..20f18fa213c44c763e83194d769be6618e225998 100644 (file)
@@ -38,10 +38,11 @@ public:
 
        UserDbObject(const DbType::Ptr& type, const String& name1, const String& name2);
 
+protected:
        virtual Dictionary::Ptr GetConfigFields(void) const override;
        virtual Dictionary::Ptr GetStatusFields(void) const override;
 
-       virtual void OnConfigUpdate(void) override;
+       virtual void OnConfigUpdateHeavy(void) override;
 };
 
 }
index 3bc8e89bcc2cae7acf9dffa0e3671025d7524cdc..f46bbabfe01339b633880e15ed773f1605acfe3c 100644 (file)
@@ -436,12 +436,7 @@ void IdoMysqlConnection::FinishConnect(double startTime)
 
 void IdoMysqlConnection::ClearTablesBySession(void)
 {
-       /* delete all customvariables and group members without current session token */
-       ClearTableBySession("customvariables");
-       ClearTableBySession("customvariablestatus");
-       ClearTableBySession("hostgroup_members");
-       ClearTableBySession("servicegroup_members");
-       ClearTableBySession("contactgroup_members");
+       /* delete all comments and downtimes without current session token */
        ClearTableBySession("comments");
        ClearTableBySession("scheduleddowntime");
 }
@@ -453,11 +448,6 @@ void IdoMysqlConnection::ClearTableBySession(const String& table)
            Convert::ToString(GetSessionToken()));
 }
 
-void IdoMysqlConnection::ClearConfigTable(const String& table)
-{
-       Query("DELETE FROM " + GetTablePrefix() + table + " WHERE instance_id = " + Convert::ToString(static_cast<long>(m_InstanceID)));
-}
-
 void IdoMysqlConnection::AsyncQuery(const String& query, const boost::function<void (const IdoMysqlResult&)>& callback)
 {
        AssertOnWorkQueue();
@@ -1058,13 +1048,15 @@ void IdoMysqlConnection::InternalCleanUpExecuteQuery(const String& table, const
 
 void IdoMysqlConnection::FillIDCache(const DbType::Ptr& type)
 {
-       String query = "SELECT " + type->GetIDColumn() + " AS object_id, " + type->GetTable() + "_id FROM " + GetTablePrefix() + type->GetTable() + "s";
+       String query = "SELECT " + type->GetIDColumn() + " AS object_id, " + type->GetTable() + "_id, config_hash FROM " + GetTablePrefix() + type->GetTable() + "s";
        IdoMysqlResult result = Query(query);
 
        Dictionary::Ptr row;
 
        while ((row = FetchRow(result))) {
-               SetInsertID(type, DbReference(row->Get("object_id")), DbReference(row->Get(type->GetTable() + "_id")));
+               DbReference dbref(row->Get("object_id"));
+               SetInsertID(type, dbref, DbReference(row->Get(type->GetTable() + "_id")));
+               SetConfigHash(type, dbref, row->Get("config_hash"));
        }
 }
 
index 816c34ebb27d273d2cd1e38c89c8a20f3011f860..53209cd8bd558b0ae95a160f55ad44dab36af418 100644 (file)
@@ -114,7 +114,6 @@ private:
        void InternalCleanUpExecuteQuery(const String& table, const String& time_key, double time_value);
        void InternalNewTransaction(void);
 
-       virtual void ClearConfigTable(const String& table) override;
        void ClearTableBySession(const String& table);
        void ClearTablesBySession(void);
 
index 114ee6c92a51fe131bacbfa96cfa0fbaf076d3bb..c4671478ba9124dfd8e6b2483727b1da738227e8 100644 (file)
@@ -54,6 +54,7 @@ CREATE TABLE IF NOT EXISTS icinga_commands (
   config_type smallint default 0,
   object_id bigint unsigned default 0,
   command_line TEXT character set latin1  default '',
+  config_hash varchar(64) DEFAULT NULL,
   PRIMARY KEY  (command_id),
   UNIQUE KEY instance_id (instance_id,object_id,config_type)
 ) ENGINE=InnoDB  COMMENT='Command definitions';
@@ -182,6 +183,7 @@ CREATE TABLE IF NOT EXISTS icinga_contactgroups (
   config_type smallint default 0,
   contactgroup_object_id bigint unsigned default 0,
   alias varchar(255) character set latin1  default '',
+  config_hash varchar(64) DEFAULT NULL,
   PRIMARY KEY  (contactgroup_id),
   UNIQUE KEY instance_id (instance_id,config_type,contactgroup_object_id)
 ) ENGINE=InnoDB  COMMENT='Contactgroup definitions';
@@ -197,7 +199,6 @@ CREATE TABLE IF NOT EXISTS icinga_contactgroup_members (
   instance_id bigint unsigned default 0,
   contactgroup_id bigint unsigned default 0,
   contact_object_id bigint unsigned default 0,
-  session_token int default NULL,
   PRIMARY KEY  (contactgroup_member_id)
 ) ENGINE=InnoDB  COMMENT='Contactgroup members';
 
@@ -270,6 +271,7 @@ CREATE TABLE IF NOT EXISTS icinga_contacts (
   notify_host_unreachable smallint default 0,
   notify_host_flapping smallint default 0,
   notify_host_downtime smallint default 0,
+  config_hash varchar(64) DEFAULT NULL,
   PRIMARY KEY  (contact_id),
   UNIQUE KEY instance_id (instance_id,config_type,contact_object_id)
 ) ENGINE=InnoDB  COMMENT='Contact definitions';
@@ -344,7 +346,6 @@ CREATE TABLE IF NOT EXISTS icinga_customvariables (
   varname varchar(255) character set latin1 collate latin1_general_cs default NULL,
   varvalue TEXT character set latin1  default '',
   is_json smallint default 0,
-  session_token int default NULL,
   PRIMARY KEY  (customvariable_id),
   UNIQUE KEY object_id_2 (object_id,config_type,varname),
   KEY varname (varname)
@@ -365,7 +366,6 @@ CREATE TABLE IF NOT EXISTS icinga_customvariablestatus (
   varname varchar(255) character set latin1 collate latin1_general_cs default NULL,
   varvalue TEXT character set latin1  default '',
   is_json smallint default 0,
-  session_token int default NULL,
   PRIMARY KEY  (customvariablestatus_id),
   UNIQUE KEY object_id_2 (object_id,varname),
   KEY varname (varname)
@@ -612,6 +612,7 @@ CREATE TABLE IF NOT EXISTS icinga_hostgroups (
   notes TEXT character set latin1  default NULL,
   notes_url TEXT character set latin1  default NULL,
   action_url TEXT character set latin1  default NULL,
+  config_hash varchar(64) DEFAULT NULL,
   PRIMARY KEY  (hostgroup_id),
   UNIQUE KEY instance_id (instance_id,hostgroup_object_id)
 ) ENGINE=InnoDB  COMMENT='Hostgroup definitions';
@@ -627,7 +628,6 @@ CREATE TABLE IF NOT EXISTS icinga_hostgroup_members (
   instance_id bigint unsigned default 0,
   hostgroup_id bigint unsigned default 0,
   host_object_id bigint unsigned default 0,
-  session_token int default NULL,
   PRIMARY KEY  (hostgroup_member_id)
 ) ENGINE=InnoDB  COMMENT='Hostgroup members';
 
@@ -697,6 +697,7 @@ CREATE TABLE IF NOT EXISTS icinga_hosts (
   x_3d double  default '0',
   y_3d double  default '0',
   z_3d double  default '0',
+  config_hash varchar(64) DEFAULT NULL,
   PRIMARY KEY  (host_id),
   UNIQUE KEY instance_id (instance_id,config_type,host_object_id),
   KEY host_object_id (host_object_id)
@@ -1108,6 +1109,7 @@ CREATE TABLE IF NOT EXISTS icinga_servicegroups (
   notes TEXT character set latin1  default NULL,
   notes_url TEXT character set latin1  default NULL,
   action_url TEXT character set latin1  default NULL,
+  config_hash varchar(64) DEFAULT NULL,
   PRIMARY KEY  (servicegroup_id),
   UNIQUE KEY instance_id (instance_id,config_type,servicegroup_object_id)
 ) ENGINE=InnoDB  COMMENT='Servicegroup definitions';
@@ -1123,7 +1125,6 @@ CREATE TABLE IF NOT EXISTS icinga_servicegroup_members (
   instance_id bigint unsigned default 0,
   servicegroup_id bigint unsigned default 0,
   service_object_id bigint unsigned default 0,
-  session_token int default NULL,
   PRIMARY KEY  (servicegroup_member_id)
 ) ENGINE=InnoDB  COMMENT='Servicegroup members';
 
@@ -1186,6 +1187,7 @@ CREATE TABLE IF NOT EXISTS icinga_services (
   action_url TEXT character set latin1  default '',
   icon_image TEXT character set latin1  default '',
   icon_image_alt TEXT character set latin1  default '',
+  config_hash varchar(64) DEFAULT NULL,
   PRIMARY KEY  (service_id),
   UNIQUE KEY instance_id (instance_id,config_type,service_object_id),
   KEY service_object_id (service_object_id)
@@ -1342,6 +1344,7 @@ CREATE TABLE IF NOT EXISTS icinga_timeperiods (
   config_type smallint default 0,
   timeperiod_object_id bigint unsigned default 0,
   alias varchar(255) character set latin1  default '',
+  config_hash varchar(64) DEFAULT NULL,
   PRIMARY KEY  (timeperiod_id),
   UNIQUE KEY instance_id (instance_id,config_type,timeperiod_object_id)
 ) ENGINE=InnoDB  COMMENT='Timeperiod definitions';
@@ -1379,6 +1382,7 @@ CREATE TABLE IF NOT EXISTS icinga_endpoints (
   config_type smallint(6) DEFAULT '0',
   identity varchar(255) DEFAULT NULL,
   node varchar(255) DEFAULT NULL,
+  config_hash varchar(64) DEFAULT NULL,
   PRIMARY KEY  (endpoint_id)
 ) ENGINE=InnoDB COMMENT='Endpoint configuration';
 
@@ -1411,6 +1415,7 @@ CREATE TABLE IF NOT EXISTS icinga_zones (
   config_type smallint(6) DEFAULT '0',
   parent_zone_object_id bigint(20) unsigned DEFAULT '0',
   is_global smallint(6),
+  config_hash varchar(64) DEFAULT NULL,
   PRIMARY KEY  (zone_id)
 ) ENGINE=InnoDB COMMENT='Zone configuration';
 
@@ -1664,19 +1669,22 @@ CREATE INDEX idx_zones_parent_object_id on icinga_zones(parent_zone_object_id);
 CREATE INDEX idx_zonestatus_parent_object_id on icinga_zonestatus(parent_zone_object_id);
 
 -- #12210
-CREATE INDEX idx_hg_session_del ON icinga_hostgroup_members (instance_id, session_token);
-CREATE INDEX idx_sg_session_del ON icinga_servicegroup_members (instance_id, session_token);
-CREATE INDEX idx_cg_session_del ON icinga_contactgroup_members (instance_id, session_token);
-
-CREATE INDEX idx_cv_session_del ON icinga_customvariables (instance_id, session_token);
-CREATE INDEX idx_cvs_session_del ON icinga_customvariablestatus (instance_id, session_token);
-
 CREATE INDEX idx_comments_session_del ON icinga_comments (instance_id, session_token);
 CREATE INDEX idx_downtimes_session_del ON icinga_scheduleddowntime (instance_id, session_token);
 
 -- #12107
 CREATE INDEX idx_statehistory_cleanup on icinga_statehistory(instance_id, state_time);
 
+-- #12435
+CREATE INDEX idx_customvariables_object_id on icinga_customvariables(object_id);
+CREATE INDEX idx_contactgroup_members_object_id on icinga_contactgroup_members(contact_object_id);
+CREATE INDEX idx_hostgroup_members_object_id on icinga_hostgroup_members(host_object_id);
+CREATE INDEX idx_servicegroup_members_object_id on icinga_servicegroup_members(service_object_id);
+CREATE INDEX idx_servicedependencies_dependent_service_object_id on icinga_servicedependencies(dependent_service_object_id);
+CREATE INDEX idx_hostdependencies_dependent_host_object_id on icinga_hostdependencies(dependent_host_object_id);
+CREATE INDEX idx_service_contacts_service_id on icinga_service_contacts(service_id);
+CREATE INDEX idx_host_contacts_host_id on icinga_host_contacts(host_id);
+
 -- -----------------------------------------
 -- set dbversion
 -- -----------------------------------------
index d1ee47bd49814a858d22ab94851c867a6ae98889..2aae0ba8aebaebca591e29dd804a3b2087203ae5 100644 (file)
@@ -60,24 +60,6 @@ CREATE INDEX idx_zonestatus_parent_object_id on icinga_zonestatus(parent_zone_ob
 -- -----------------------------------------
 CREATE INDEX idx_statehistory_cleanup on icinga_statehistory(instance_id, state_time);
 
--- -----------------------------------------
--- #12210
--- -----------------------------------------
-
-ALTER TABLE icinga_hostgroup_members ADD COLUMN session_token int default NULL;
-ALTER TABLE icinga_servicegroup_members ADD COLUMN session_token int default NULL;
-ALTER TABLE icinga_contactgroup_members ADD COLUMN session_token int default NULL;
-
-CREATE INDEX idx_hg_session_del ON icinga_hostgroup_members (instance_id, session_token);
-CREATE INDEX idx_sg_session_del ON icinga_servicegroup_members (instance_id, session_token);
-CREATE INDEX idx_cg_session_del ON icinga_contactgroup_members (instance_id, session_token);
-
-DROP INDEX cv_session_del_idx ON icinga_customvariables;
-DROP INDEX cvs_session_del_idx ON icinga_customvariablestatus;
-
-CREATE INDEX idx_cv_session_del ON icinga_customvariables (instance_id, session_token);
-CREATE INDEX idx_cvs_session_del ON icinga_customvariablestatus (instance_id, session_token);
-
 -- -----------------------------------------
 -- #12258
 -- -----------------------------------------
@@ -87,6 +69,32 @@ ALTER TABLE icinga_scheduleddowntime ADD COLUMN session_token INTEGER default NU
 CREATE INDEX idx_comments_session_del ON icinga_comments (instance_id, session_token);
 CREATE INDEX idx_downtimes_session_del ON icinga_scheduleddowntime (instance_id, session_token);
 
+-- -----------------------------------------
+-- #12435
+-- -----------------------------------------
+ALTER TABLE icinga_commands ADD config_hash VARCHAR(64) DEFAULT NULL;
+ALTER TABLE icinga_contactgroups ADD config_hash VARCHAR(64) DEFAULT NULL;
+ALTER TABLE icinga_contacts ADD config_hash VARCHAR(64) DEFAULT NULL;
+ALTER TABLE icinga_hostgroups ADD config_hash VARCHAR(64) DEFAULT NULL;
+ALTER TABLE icinga_hosts ADD config_hash VARCHAR(64) DEFAULT NULL;
+ALTER TABLE icinga_servicegroups ADD config_hash VARCHAR(64) DEFAULT NULL;
+ALTER TABLE icinga_services ADD config_hash VARCHAR(64) DEFAULT NULL;
+ALTER TABLE icinga_timeperiods ADD config_hash VARCHAR(64) DEFAULT NULL;
+ALTER TABLE icinga_endpoints ADD config_hash VARCHAR(64) DEFAULT NULL;
+ALTER TABLE icinga_zones ADD config_hash VARCHAR(64) DEFAULT NULL;
+
+ALTER TABLE icinga_customvariables DROP session_token;
+ALTER TABLE icinga_customvariablestatus DROP session_token;
+
+CREATE INDEX idx_customvariables_object_id on icinga_customvariables(object_id);
+CREATE INDEX idx_contactgroup_members_object_id on icinga_contactgroup_members(contact_object_id);
+CREATE INDEX idx_hostgroup_members_object_id on icinga_hostgroup_members(host_object_id);
+CREATE INDEX idx_servicegroup_members_object_id on icinga_servicegroup_members(service_object_id);
+CREATE INDEX idx_servicedependencies_dependent_service_object_id on icinga_servicedependencies(dependent_service_object_id);
+CREATE INDEX idx_hostdependencies_dependent_host_object_id on icinga_hostdependencies(dependent_host_object_id);
+CREATE INDEX idx_service_contacts_service_id on icinga_service_contacts(service_id);
+CREATE INDEX idx_host_contacts_host_id on icinga_host_contacts(host_id);
+
 -- -----------------------------------------
 -- set dbversion
 -- -----------------------------------------
index 9cc124232ec3cf58b988e3d0b2db0e08362ffbd9..2a9ec50c2c1da659d3d1aa9f80a5bc4bfb41224e 100644 (file)
@@ -407,12 +407,7 @@ void IdoPgsqlConnection::FinishConnect(double startTime)
 
 void IdoPgsqlConnection::ClearTablesBySession(void)
 {
-       /* delete all customvariables and group members without current session token */
-       ClearTableBySession("customvariables");
-       ClearTableBySession("customvariablestatus");
-       ClearTableBySession("hostgroup_members");
-       ClearTableBySession("servicegroup_members");
-       ClearTableBySession("contactgroup_members");
+       /* delete all comments and downtimes without current session token */
        ClearTableBySession("comments");
        ClearTableBySession("scheduleddowntime");
 }
@@ -424,11 +419,6 @@ void IdoPgsqlConnection::ClearTableBySession(const String& table)
            Convert::ToString(GetSessionToken()));
 }
 
-void IdoPgsqlConnection::ClearConfigTable(const String& table)
-{
-       Query("DELETE FROM " + GetTablePrefix() + table + " WHERE instance_id = " + Convert::ToString(static_cast<long>(m_InstanceID)));
-}
-
 IdoPgsqlResult IdoPgsqlConnection::Query(const String& query)
 {
        AssertOnWorkQueue();
@@ -919,7 +909,7 @@ void IdoPgsqlConnection::InternalCleanUpExecuteQuery(const String& table, const
 
 void IdoPgsqlConnection::FillIDCache(const DbType::Ptr& type)
 {
-       String query = "SELECT " + type->GetIDColumn() + " AS object_id, " + type->GetTable() + "_id FROM " + GetTablePrefix() + type->GetTable() + "s";
+       String query = "SELECT " + type->GetIDColumn() + " AS object_id, " + type->GetTable() + "_id, config_hash FROM " + GetTablePrefix() + type->GetTable() + "s";
        IdoPgsqlResult result = Query(query);
 
        Dictionary::Ptr row;
@@ -927,7 +917,9 @@ void IdoPgsqlConnection::FillIDCache(const DbType::Ptr& type)
        int index = 0;
        while ((row = FetchRow(result, index))) {
                index++;
-               SetInsertID(type, DbReference(row->Get("object_id")), DbReference(row->Get(type->GetTable() + "_id")));
+               DbReference dbref(row->Get("object_id"));
+               SetInsertID(type, dbref, DbReference(row->Get(type->GetTable() + "_id")));
+               SetConfigHash(type, dbref, row->Get("config_hash"));
        }
 }
 
index 06858e33606b8baa492c273c3ee2af875e5c84d3..2c4c46547e5c3d1883f37344d4802a33716eeab5 100644 (file)
@@ -99,7 +99,6 @@ private:
        void InternalExecuteMultipleQueries(const std::vector<DbQuery>& queries);
        void InternalCleanUpExecuteQuery(const String& table, const String& time_key, double time_value);
 
-       virtual void ClearConfigTable(const String& table) override;
        void ClearTableBySession(const String& table);
        void ClearTablesBySession(void);
 
index afbdbe0cca3fd51d81949a0ee88e38128a0b9132..e9791c0dc6e4dbf9eb5b7f4d77bf629701452fce 100644 (file)
@@ -80,6 +80,7 @@ CREATE TABLE  icinga_commands (
   config_type INTEGER  default 0,
   object_id bigint default 0,
   command_line TEXT  default '',
+  config_hash varchar(64) DEFAULT NULL,
   CONSTRAINT PK_command_id PRIMARY KEY (command_id) ,
   CONSTRAINT UQ_commands UNIQUE (instance_id,object_id,config_type)
 ) ;
@@ -208,6 +209,7 @@ CREATE TABLE  icinga_contactgroups (
   config_type INTEGER  default 0,
   contactgroup_object_id bigint default 0,
   alias TEXT  default '',
+  config_hash varchar(64) DEFAULT NULL,
   CONSTRAINT PK_contactgroup_id PRIMARY KEY (contactgroup_id) ,
   CONSTRAINT UQ_contactgroups UNIQUE (instance_id,config_type,contactgroup_object_id)
 );
@@ -296,6 +298,7 @@ CREATE TABLE  icinga_contacts (
   notify_host_unreachable INTEGER  default 0,
   notify_host_flapping INTEGER  default 0,
   notify_host_downtime INTEGER  default 0,
+  config_hash varchar(64) DEFAULT NULL,
   CONSTRAINT PK_contact_id PRIMARY KEY (contact_id) ,
   CONSTRAINT UQ_contacts UNIQUE (instance_id,config_type,contact_object_id)
 ) ;
@@ -639,6 +642,7 @@ CREATE TABLE  icinga_hostgroups (
   notes TEXT  default NULL,
   notes_url TEXT  default NULL,
   action_url TEXT  default NULL,
+  config_hash varchar(64) DEFAULT NULL,
   CONSTRAINT PK_hostgroup_id PRIMARY KEY (hostgroup_id) ,
   CONSTRAINT UQ_hostgroups UNIQUE (instance_id,hostgroup_object_id)
 ) ;
@@ -724,6 +728,7 @@ CREATE TABLE  icinga_hosts (
   x_3d double precision  default 0,
   y_3d double precision  default 0,
   z_3d double precision  default 0,
+  config_hash varchar(64) DEFAULT NULL,
   CONSTRAINT PK_host_id PRIMARY KEY (host_id) ,
   CONSTRAINT UQ_hosts UNIQUE (instance_id,config_type,host_object_id)
 ) ;
@@ -1135,6 +1140,7 @@ CREATE TABLE  icinga_servicegroups (
   notes TEXT  default NULL,
   notes_url TEXT  default NULL,
   action_url TEXT  default NULL,
+  config_hash varchar(64) DEFAULT NULL,
   CONSTRAINT PK_servicegroup_id PRIMARY KEY (servicegroup_id) ,
   CONSTRAINT UQ_servicegroups UNIQUE (instance_id,config_type,servicegroup_object_id)
 ) ;
@@ -1213,6 +1219,7 @@ CREATE TABLE  icinga_services (
   action_url TEXT  default '',
   icon_image TEXT  default '',
   icon_image_alt TEXT  default '',
+  config_hash varchar(64) DEFAULT NULL,
   CONSTRAINT PK_service_id PRIMARY KEY (service_id) ,
   CONSTRAINT UQ_services UNIQUE (instance_id,config_type,service_object_id)
 ) ;
@@ -1368,6 +1375,7 @@ CREATE TABLE  icinga_timeperiods (
   config_type INTEGER  default 0,
   timeperiod_object_id bigint default 0,
   alias TEXT  default '',
+  config_hash varchar(64) DEFAULT NULL,
   CONSTRAINT PK_timeperiod_id PRIMARY KEY (timeperiod_id) ,
   CONSTRAINT UQ_timeperiods UNIQUE (instance_id,config_type,timeperiod_object_id)
 ) ;
@@ -1405,6 +1413,7 @@ CREATE TABLE  icinga_endpoints (
   config_type integer default 0,
   identity text DEFAULT NULL,
   node text DEFAULT NULL,
+  config_hash varchar(64) DEFAULT NULL,
   CONSTRAINT PK_endpoint_id PRIMARY KEY (endpoint_id) ,
   CONSTRAINT UQ_endpoints UNIQUE (instance_id,config_type,endpoint_object_id)
 ) ;
@@ -1439,6 +1448,7 @@ CREATE TABLE  icinga_zones (
   parent_zone_object_id bigint default 0,
   config_type integer default 0,
   is_global integer default 0,
+  config_hash varchar(64) DEFAULT NULL,
   CONSTRAINT PK_zone_id PRIMARY KEY (zone_id) ,
   CONSTRAINT UQ_zones UNIQUE (instance_id,config_type,zone_object_id)
 ) ;
@@ -1693,19 +1703,22 @@ CREATE INDEX idx_zones_parent_object_id on icinga_zones(parent_zone_object_id);
 CREATE INDEX idx_zonestatus_parent_object_id on icinga_zonestatus(parent_zone_object_id);
 
 -- #12210
-CREATE INDEX idx_hg_session_del ON icinga_hostgroup_members (instance_id, session_token);
-CREATE INDEX idx_sg_session_del ON icinga_servicegroup_members (instance_id, session_token);
-CREATE INDEX idx_cg_session_del ON icinga_contactgroup_members (instance_id, session_token);
-
 CREATE INDEX idx_comments_session_del ON icinga_comments (instance_id, session_token);
 CREATE INDEX idx_downtimes_session_del ON icinga_scheduleddowntime (instance_id, session_token);
 
-CREATE INDEX idx_cv_session_del ON icinga_customvariables (instance_id, session_token);
-CREATE INDEX idx_cvs_session_del ON icinga_customvariablestatus (instance_id, session_token);
-
 -- #12107
 CREATE INDEX idx_statehistory_cleanup on icinga_statehistory(instance_id, state_time);
 
+-- #12435
+CREATE INDEX idx_customvariables_object_id on icinga_customvariables(object_id);
+CREATE INDEX idx_contactgroup_members_object_id on icinga_contactgroup_members(contact_object_id);
+CREATE INDEX idx_hostgroup_members_object_id on icinga_hostgroup_members(host_object_id);
+CREATE INDEX idx_servicegroup_members_object_id on icinga_servicegroup_members(service_object_id);
+CREATE INDEX idx_servicedependencies_dependent_service_object_id on icinga_servicedependencies(dependent_service_object_id);
+CREATE INDEX idx_hostdependencies_dependent_host_object_id on icinga_hostdependencies(dependent_host_object_id);
+CREATE INDEX idx_service_contacts_service_id on icinga_service_contacts(service_id);
+CREATE INDEX idx_host_contacts_host_id on icinga_host_contacts(host_id);
+
 -- -----------------------------------------
 -- set dbversion
 -- -----------------------------------------
index a5c2b5859a3e35b87a31bc5d92be984ec55734b7..9161b8d33d28c8b4943b25c38c5bfe7773806114 100644 (file)
@@ -38,24 +38,6 @@ CREATE INDEX idx_zonestatus_object_id on icinga_zonestatus(zone_object_id);
 CREATE INDEX idx_zones_parent_object_id on icinga_zones(parent_zone_object_id);
 CREATE INDEX idx_zonestatus_parent_object_id on icinga_zonestatus(parent_zone_object_id);
 
--- -----------------------------------------
--- #12210
--- -----------------------------------------
-
-ALTER TABLE icinga_hostgroup_members ADD COLUMN session_token INTEGER default NULL;
-ALTER TABLE icinga_servicegroup_members ADD COLUMN session_token INTEGER default NULL;
-ALTER TABLE icinga_contactgroup_members ADD COLUMN session_token INTEGER default NULL;
-
-CREATE INDEX idx_hg_session_del ON icinga_hostgroup_members (instance_id, session_token);
-CREATE INDEX idx_sg_session_del ON icinga_servicegroup_members (instance_id, session_token);
-CREATE INDEX idx_cg_session_del ON icinga_contactgroup_members (instance_id, session_token);
-
-DROP INDEX cv_session_del_idx;
-DROP INDEX cvs_session_del_idx;
-
-CREATE INDEX idx_cv_session_del ON icinga_customvariables (instance_id, session_token);
-CREATE INDEX idx_cvs_session_del ON icinga_customvariablestatus (instance_id, session_token);
-
 -- -----------------------------------------
 -- #12258
 -- -----------------------------------------
@@ -70,6 +52,32 @@ CREATE INDEX idx_downtimes_session_del ON icinga_scheduleddowntime (instance_id,
 -- -----------------------------------------
 CREATE INDEX idx_statehistory_cleanup on icinga_statehistory(instance_id, state_time);
 
+-- -----------------------------------------
+-- #12435
+-- -----------------------------------------
+ALTER TABLE icinga_commands ADD config_hash VARCHAR(64) DEFAULT NULL;
+ALTER TABLE icinga_contactgroups ADD config_hash VARCHAR(64) DEFAULT NULL;
+ALTER TABLE icinga_contacts ADD config_hash VARCHAR(64) DEFAULT NULL;
+ALTER TABLE icinga_hostgroups ADD config_hash VARCHAR(64) DEFAULT NULL;
+ALTER TABLE icinga_hosts ADD config_hash VARCHAR(64) DEFAULT NULL;
+ALTER TABLE icinga_servicegroups ADD config_hash VARCHAR(64) DEFAULT NULL;
+ALTER TABLE icinga_services ADD config_hash VARCHAR(64) DEFAULT NULL;
+ALTER TABLE icinga_timeperiods ADD config_hash VARCHAR(64) DEFAULT NULL;
+ALTER TABLE icinga_endpoints ADD config_hash VARCHAR(64) DEFAULT NULL;
+ALTER TABLE icinga_zones ADD config_hash VARCHAR(64) DEFAULT NULL;
+
+ALTER TABLE icinga_customvariables DROP session_token;
+ALTER TABLE icinga_customvariablestatus DROP session_token;
+
+CREATE INDEX idx_customvariables_object_id on icinga_customvariables(object_id);
+CREATE INDEX idx_contactgroup_members_object_id on icinga_contactgroup_members(contact_object_id);
+CREATE INDEX idx_hostgroup_members_object_id on icinga_hostgroup_members(host_object_id);
+CREATE INDEX idx_servicegroup_members_object_id on icinga_servicegroup_members(service_object_id);
+CREATE INDEX idx_servicedependencies_dependent_service_object_id on icinga_servicedependencies(dependent_service_object_id);
+CREATE INDEX idx_hostdependencies_dependent_host_object_id on icinga_hostdependencies(dependent_host_object_id);
+CREATE INDEX idx_service_contacts_service_id on icinga_service_contacts(service_id);
+CREATE INDEX idx_host_contacts_host_id on icinga_host_contacts(host_id);
+
 -- -----------------------------------------
 -- set dbversion
 -- -----------------------------------------