diff --git a/components/ido_mysql/mysqldbconnection.cpp b/components/ido_mysql/mysqldbconnection.cpp index 8cc12dcbd..40d413e39 100644 --- a/components/ido_mysql/mysqldbconnection.cpp +++ b/components/ido_mysql/mysqldbconnection.cpp @@ -19,6 +19,7 @@ #include "base/logger_fwd.h" #include "base/objectlock.h" +#include "base/convert.h" #include "ido/dbtype.h" #include "ido_mysql/mysqldbconnection.h" #include @@ -41,6 +42,11 @@ MysqlDbConnection::MysqlDbConnection(const Dictionary::Ptr& serializedUpdate) RegisterAttribute("instance_name", Attribute_Config, &m_InstanceName); RegisterAttribute("instance_description", Attribute_Config, &m_InstanceDescription); + m_TxTimer = boost::make_shared(); + m_TxTimer->SetInterval(5); + m_TxTimer->OnTimerExpired.connect(boost::bind(&MysqlDbConnection::TxTimerHandler, this)); + m_TxTimer->Start(); + /* TODO: move this to a timer so we can periodically check if we're still connected - and reconnect if necessary */ String ihost, iuser, ipasswd, idb; const char *host, *user , *passwd, *db; @@ -75,7 +81,7 @@ MysqlDbConnection::MysqlDbConnection(const Dictionary::Ptr& serializedUpdate) if (rows->GetLength() == 0) { Query("INSERT INTO icinga_instances (instance_name, instance_description) VALUES ('" + Escape(instanceName) + "', '" + m_InstanceDescription + "')"); - m_InstanceID = GetInsertId(); + m_InstanceID = GetInsertID(); } else { Dictionary::Ptr row = rows->Get(0); m_InstanceID = DbReference(row->Get("instance_id")); @@ -88,20 +94,23 @@ MysqlDbConnection::MysqlDbConnection(const Dictionary::Ptr& serializedUpdate) Query("UPDATE icinga_objects SET is_active = 0"); std::ostringstream qbuf; - qbuf << "SELECT objecttype_id, name1, name2 FROM icinga_objects WHERE instance_id = " << static_cast(m_InstanceID); + qbuf << "SELECT object_id, objecttype_id, name1, name2 FROM icinga_objects WHERE instance_id = " << static_cast(m_InstanceID); rows = Query(qbuf.str()); ObjectLock olock(rows); BOOST_FOREACH(const Dictionary::Ptr& row, rows) { - DbType::Ptr dbtype = DbType::GetById(row->Get("objecttype_id")); + DbType::Ptr dbtype = DbType::GetByID(row->Get("objecttype_id")); if (!dbtype) continue; - dbtype->GetOrCreateObjectByName(row->Get("name1"), row->Get("name2")); + DbObject::Ptr dbobj = dbtype->GetOrCreateObjectByName(row->Get("name1"), row->Get("name2")); + SetReference(dbobj, DbReference(row->Get("object_id"))); } } + Query("BEGIN"); + UpdateAllObjects(); } @@ -111,8 +120,17 @@ void MysqlDbConnection::Stop(void) mysql_close(&m_Connection); } +void MysqlDbConnection::TxTimerHandler(void) +{ + boost::mutex::scoped_lock lock(m_ConnectionMutex); + Query("COMMIT"); + Query("BEGIN"); +} + Array::Ptr MysqlDbConnection::Query(const String& query) { + Log(LogDebug, "ido_mysql", "Query: " + query); + if (mysql_query(&m_Connection, query.CStr()) != 0) BOOST_THROW_EXCEPTION(std::runtime_error(mysql_error(&m_Connection))); @@ -141,7 +159,7 @@ Array::Ptr MysqlDbConnection::Query(const String& query) return rows; } -DbReference MysqlDbConnection::GetInsertId(void) +DbReference MysqlDbConnection::GetInsertID(void) { return DbReference(mysql_insert_id(&m_Connection)); } @@ -189,6 +207,8 @@ Dictionary::Ptr MysqlDbConnection::FetchRow(MYSQL_RES *result) } void MysqlDbConnection::UpdateObject(const DbObject::Ptr& dbobj, DbUpdateType kind) { + boost::mutex::scoped_lock lock(m_ConnectionMutex); + DbReference dbref = GetReference(dbobj); if (kind == DbObjectRemoved) { @@ -200,56 +220,69 @@ void MysqlDbConnection::UpdateObject(const DbObject::Ptr& dbobj, DbUpdateType ki Log(LogWarning, "ido_mysql", "Query: " + qbuf.str()); } - std::ostringstream q1buf; + if (kind == DbObjectCreated) { + std::ostringstream q1buf; - if (!dbref.IsValid()) { - q1buf << "INSERT INTO icinga_objects (instance_id, objecttype_id, name1, name2, is_active) VALUES ("; - } else { - q1buf << "UPDATE icinga_objects SET is_active = 1 WHERE object_id = " << static_cast(dbref); - } - - Dictionary::Ptr cols = boost::make_shared(); - - Dictionary::Ptr fields = dbobj->GetFields(); - - if (!fields) - return; - - ObjectLock olock(fields); - - String key; - Value value; - BOOST_FOREACH(boost::tie(key, value), fields) { - if (value.IsObjectType()) { - DbObject::Ptr dbobjcol = DbObject::GetOrCreateByObject(value); - - if (!dbobjcol) - return; - - DbReference dbrefcol = GetReference(dbobjcol); - - if (!dbrefcol.IsValid()) { - UpdateObject(dbobjcol, DbObjectCreated); - - dbrefcol = GetReference(dbobjcol); - - if (!dbrefcol.IsValid()) - return; - } - - value = static_cast(dbrefcol); + if (!dbref.IsValid()) { + q1buf << "INSERT INTO icinga_objects (instance_id, objecttype_id, name1, name2, is_active) VALUES (" + << static_cast(m_InstanceID) << ", " << dbobj->GetType()->GetTypeID() << ", " + << "'" << Escape(dbobj->GetName1()) << "', '" << Escape(dbobj->GetName2()) << "', 1)"; + Query(q1buf.str()); + dbref = GetInsertID(); + } else if (kind == DbObjectCreated) { + q1buf << "UPDATE icinga_objects SET is_active = 1 WHERE object_id = " << static_cast(dbref); + Query(q1buf.str()); } - cols->Set(key, value); + //Dictionary::Ptr cols = boost::make_shared(); + + Dictionary::Ptr fields = dbobj->GetFields(); + + if (!fields) + return; + + String cols; + String values; + + ObjectLock olock(fields); + + String key; + Value value; + BOOST_FOREACH(boost::tie(key, value), fields) { + if (value.IsObjectType()) { + DbObject::Ptr dbobjcol = DbObject::GetOrCreateByObject(value); + + if (!dbobjcol) + return; + + DbReference dbrefcol = GetReference(dbobjcol); + + if (!dbrefcol.IsValid()) { + UpdateObject(dbobjcol, DbObjectCreated); + + dbrefcol = GetReference(dbobjcol); + + if (!dbrefcol.IsValid()) + return; + } + + value = static_cast(dbrefcol); + } + + cols += ", " + key; + values += ", '" + Convert::ToString(value) + "'"; + } + + std::ostringstream q2buf; + q2buf << "DELETE FROM icinga_" << dbobj->GetType()->GetTable() << "s WHERE " << dbobj->GetType()->GetTable() << "_object_id = " << static_cast(dbref); + Query(q2buf.str()); + + std::ostringstream q3buf; + q3buf << "INSERT INTO icinga_" << dbobj->GetType()->GetTable() + << "s (instance_id, " << dbobj->GetType()->GetTable() << "_object_id" << cols << ") VALUES (" + << static_cast(m_InstanceID) << ", " << static_cast(dbref) << values << ")"; + Query(q3buf.str()); } - std::ostringstream q2buf; - - if (dbref.IsValid()) { - q2buf << "UPDATE icinga_" << dbobj->GetType()->GetTable() << "s SET xxx WHERE id = " << static_cast(dbref); - } else { - q2buf << "INSERT INTO icinga_" << dbobj->GetType()->GetTable() << "s xxx"; - } - - Log(LogWarning, "ido_mysql", "Query: " + q2buf.str()); + // TODO: Object and status updates } diff --git a/components/ido_mysql/mysqldbconnection.h b/components/ido_mysql/mysqldbconnection.h index bf3467b1b..610505077 100644 --- a/components/ido_mysql/mysqldbconnection.h +++ b/components/ido_mysql/mysqldbconnection.h @@ -22,6 +22,7 @@ #include "base/array.h" #include "base/dynamictype.h" +#include "base/timer.h" #include "ido/dbconnection.h" #include @@ -58,10 +59,14 @@ private: boost::mutex m_ConnectionMutex; MYSQL m_Connection; + Timer::Ptr m_TxTimer; + Array::Ptr Query(const String& query); - DbReference GetInsertId(void); + DbReference GetInsertID(void); String Escape(const String& s); Dictionary::Ptr FetchRow(MYSQL_RES *result); + + void TxTimerHandler(void); }; } diff --git a/lib/ido/Makefile.am b/lib/ido/Makefile.am index 85e27e1b5..211dc4d0f 100644 --- a/lib/ido/Makefile.am +++ b/lib/ido/Makefile.am @@ -20,7 +20,9 @@ libido_la_SOURCES = \ dbtype.h \ hostdbobject.cpp \ hostdbobject.h \ - ido-type.cpp + ido-type.cpp \ + servicedbobject.cpp \ + servicedbobject.h libido_la_CPPFLAGS = \ $(LTDLINCL) \ diff --git a/lib/ido/dbconnection.cpp b/lib/ido/dbconnection.cpp index 987c08f88..1a155f91b 100644 --- a/lib/ido/dbconnection.cpp +++ b/lib/ido/dbconnection.cpp @@ -27,7 +27,7 @@ DbConnection::DbConnection(const Dictionary::Ptr& serializedUpdate) : DynamicObject(serializedUpdate) { } -void DbConnection::Initialize(void) +void DbConnection::Start(void) { DbObject::OnObjectUpdated.connect(boost::bind(&DbConnection::InternalUpdateObject, this, _1, _2)); } diff --git a/lib/ido/dbconnection.h b/lib/ido/dbconnection.h index 33efc0e7b..804527f52 100644 --- a/lib/ido/dbconnection.h +++ b/lib/ido/dbconnection.h @@ -42,12 +42,13 @@ public: DbReference GetReference(const DbObject::Ptr& dbobj) const; protected: + virtual void Start(void); + virtual void UpdateObject(const DbObject::Ptr& dbobj, DbUpdateType kind) = 0; void UpdateAllObjects(void); private: - void Initialize(void); void InternalUpdateObject(const DbObject::Ptr& dbobj, DbUpdateType kind); std::map m_References; diff --git a/lib/ido/dbtype.cpp b/lib/ido/dbtype.cpp index 9f6d2ead2..60806a62b 100644 --- a/lib/ido/dbtype.cpp +++ b/lib/ido/dbtype.cpp @@ -28,7 +28,7 @@ using namespace icinga; boost::mutex DbType::m_StaticMutex; DbType::DbType(const String& name, const String& table, long tid, const DbType::ObjectFactory& factory) - : m_Name(name), m_Table(table), m_TypeId(tid), m_ObjectFactory(factory) + : m_Name(name), m_Table(table), m_TypeID(tid), m_ObjectFactory(factory) { static boost::once_flag initializeOnce = BOOST_ONCE_INIT; boost::call_once(initializeOnce, &DbObject::StaticInitialize); @@ -44,9 +44,9 @@ String DbType::GetTable(void) const return m_Table; } -long DbType::GetTypeId(void) const +long DbType::GetTypeID(void) const { - return m_TypeId; + return m_TypeID; } void DbType::RegisterType(const DbType::Ptr& type) @@ -66,12 +66,12 @@ DbType::Ptr DbType::GetByName(const String& name) return it->second; } -DbType::Ptr DbType::GetById(long tid) +DbType::Ptr DbType::GetByID(long tid) { String name; DbType::Ptr type; BOOST_FOREACH(boost::tie(name, type), GetTypes()) { - if (type->GetTypeId() == tid) + if (type->GetTypeID() == tid) return type; } diff --git a/lib/ido/dbtype.h b/lib/ido/dbtype.h index 2d9343838..ebf0bd3bd 100644 --- a/lib/ido/dbtype.h +++ b/lib/ido/dbtype.h @@ -45,19 +45,19 @@ public: String GetName(void) const; String GetTable(void) const; - long GetTypeId(void) const; + long GetTypeID(void) const; static void RegisterType(const DbType::Ptr& type); static DbType::Ptr GetByName(const String& name); - static DbType::Ptr GetById(long tid); + static DbType::Ptr GetByID(long tid); DbObject::Ptr GetOrCreateObjectByName(const String& name1, const String& name2); private: String m_Name; String m_Table; - long m_TypeId; + long m_TypeID; ObjectFactory m_ObjectFactory; static boost::mutex m_StaticMutex; diff --git a/lib/ido/servicedbobject.cpp b/lib/ido/servicedbobject.cpp new file mode 100644 index 000000000..2d9651f99 --- /dev/null +++ b/lib/ido/servicedbobject.cpp @@ -0,0 +1,40 @@ +/****************************************************************************** + * Icinga 2 * + * Copyright (C) 2012 Icinga Development Team (http://www.icinga.org/) * + * * + * This program is free software; you can redistribute it and/or * + * modify it under the terms of the GNU General Public License * + * as published by the Free Software Foundation; either version 2 * + * of the License, or (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the Free Software Foundation * + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * + ******************************************************************************/ + +#include "ido/servicedbobject.h" +#include "ido/dbtype.h" +#include "icinga/service.h" + +using namespace icinga; + +REGISTER_DBTYPE("Service", "service", 2, ServiceDbObject); + +ServiceDbObject::ServiceDbObject(const String& name1, const String& name2) + : DbObject(DbType::GetByName("Service"), name1, name2) +{ } + +Dictionary::Ptr ServiceDbObject::GetFields(void) const +{ + Dictionary::Ptr fields = boost::make_shared(); + Service::Ptr service = static_pointer_cast(GetObject()); + + fields->Set("display_name", service->GetDisplayName()); + + return fields; +} diff --git a/lib/ido/servicedbobject.h b/lib/ido/servicedbobject.h new file mode 100644 index 000000000..1dff03c9d --- /dev/null +++ b/lib/ido/servicedbobject.h @@ -0,0 +1,46 @@ +/****************************************************************************** + * Icinga 2 * + * Copyright (C) 2012 Icinga Development Team (http://www.icinga.org/) * + * * + * This program is free software; you can redistribute it and/or * + * modify it under the terms of the GNU General Public License * + * as published by the Free Software Foundation; either version 2 * + * of the License, or (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the Free Software Foundation * + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * + ******************************************************************************/ + +#ifndef SERVICEDBOBJECT_H +#define SERVICEDBOBJECT_H + +#include "ido/dbobject.h" +#include "base/dynamicobject.h" + +namespace icinga +{ + +/** + * A Service database object. + * + * @ingroup ido + */ +class ServiceDbObject : public DbObject +{ +public: + DECLARE_PTR_TYPEDEFS(ServiceDbObject); + + ServiceDbObject(const String& name1, const String& name2); + + virtual Dictionary::Ptr GetFields(void) const; +}; + +} + +#endif /* SERVICEDBOBJECT_H */