]> granicus.if.org Git - icinga2/commitdiff
ido_mysql: Automatically reconnect when necessary.
authorGunnar Beutner <gunnar.beutner@netways.de>
Fri, 19 Jul 2013 08:18:47 +0000 (10:18 +0200)
committerGunnar Beutner <gunnar.beutner@netways.de>
Fri, 19 Jul 2013 08:18:47 +0000 (10:18 +0200)
components/ido_mysql/Makefile.am
components/ido_mysql/mysqldbconnection.cpp
components/ido_mysql/mysqldbconnection.h
m4/ax_lib_mysql.m4

index 43a84e033892761e12aa9531007e69fe0f047106..998474f411f11b5c1bc937383a6315f3134b4499 100644 (file)
@@ -23,7 +23,7 @@ libido_mysql_la_CPPFLAGS = \
 
 libido_mysql_la_LDFLAGS = \
        $(BOOST_LDFLAGS) \
-       $(MYSQL_LDFLAGS) \
+       $(MYSQLR_LDFLAGS) \
        -module \
        -no-undefined \
        @RELEASE_INFO@ \
index 40d413e391824f482cb6948e9a8c29c2050a667d..e4e71a092687e0ac164e7f11747df52dc28bca13 100644 (file)
@@ -31,7 +31,7 @@ using namespace icinga;
 REGISTER_TYPE(MysqlDbConnection);
 
 MysqlDbConnection::MysqlDbConnection(const Dictionary::Ptr& serializedUpdate)
-       : DbConnection(serializedUpdate)
+       : DbConnection(serializedUpdate), m_Connected(false)
 {
        RegisterAttribute("host", Attribute_Config, &m_Host);
        RegisterAttribute("port", Attribute_Config, &m_Port);
@@ -47,7 +47,44 @@ MysqlDbConnection::MysqlDbConnection(const Dictionary::Ptr& serializedUpdate)
        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 */
+       m_ReconnectTimer = boost::make_shared<Timer>();
+       m_ReconnectTimer->SetInterval(10);
+       m_ReconnectTimer->OnTimerExpired.connect(boost::bind(&MysqlDbConnection::ReconnectTimerHandler, this));
+       m_ReconnectTimer->Start();
+
+       ASSERT(mysql_thread_safe());
+}
+
+void MysqlDbConnection::Stop(void)
+{
+       boost::mutex::scoped_lock lock(m_ConnectionMutex);
+       mysql_close(&m_Connection);
+}
+
+void MysqlDbConnection::TxTimerHandler(void)
+{
+       boost::mutex::scoped_lock lock(m_ConnectionMutex);
+
+       if (!m_Connected)
+               return;
+
+       Query("COMMIT");
+       Query("BEGIN");
+}
+
+void MysqlDbConnection::ReconnectTimerHandler(void)
+{
+       boost::mutex::scoped_lock lock(m_ConnectionMutex);
+
+       if (m_Connected) {
+               /* Check if we're really still connected */
+               if (mysql_ping(&m_Connection) == 0)
+                       return;
+
+               mysql_close(&m_Connection);
+               m_Connected = false;
+       }
+
        String ihost, iuser, ipasswd, idb;
        const char *host, *user , *passwd, *db;
        long port;
@@ -63,50 +100,48 @@ MysqlDbConnection::MysqlDbConnection(const Dictionary::Ptr& serializedUpdate)
        passwd = (!ipasswd.IsEmpty()) ? ipasswd.CStr() : NULL;
        db = (!idb.IsEmpty()) ? idb.CStr() : NULL;
 
-       {
-               boost::mutex::scoped_lock lock(m_ConnectionMutex);
+       if (!mysql_init(&m_Connection))
+               BOOST_THROW_EXCEPTION(std::bad_alloc());
 
-               if (!mysql_init(&m_Connection))
-                       BOOST_THROW_EXCEPTION(std::bad_alloc());
+       if (!mysql_real_connect(&m_Connection, host, user, passwd, db, port, NULL, 0))
+               BOOST_THROW_EXCEPTION(std::runtime_error(mysql_error(&m_Connection)));
 
-               if (!mysql_real_connect(&m_Connection, host, user, passwd, db, port, NULL, 0))
-                       BOOST_THROW_EXCEPTION(std::runtime_error(mysql_error(&m_Connection)));
+       m_Connected = true;
 
-               String instanceName = "default";
+       String instanceName = "default";
 
-               if (!m_InstanceName.IsEmpty())
-                       instanceName = m_InstanceName;
+       if (!m_InstanceName.IsEmpty())
+               instanceName = m_InstanceName;
 
-               Array::Ptr rows = Query("SELECT instance_id FROM icinga_instances WHERE instance_name = '" + Escape(instanceName) + "'");
+       Array::Ptr rows = Query("SELECT instance_id FROM icinga_instances WHERE instance_name = '" + Escape(instanceName) + "'");
 
-               if (rows->GetLength() == 0) {
-                       Query("INSERT INTO icinga_instances (instance_name, instance_description) VALUES ('" + Escape(instanceName) + "', '" + m_InstanceDescription + "')");
-                       m_InstanceID = GetInsertID();
-               } else {
-                       Dictionary::Ptr row = rows->Get(0);
-                       m_InstanceID = DbReference(row->Get("instance_id"));
-               }
+       if (rows->GetLength() == 0) {
+               Query("INSERT INTO icinga_instances (instance_name, instance_description) VALUES ('" + Escape(instanceName) + "', '" + m_InstanceDescription + "')");
+               m_InstanceID = GetInsertID();
+       } else {
+               Dictionary::Ptr row = rows->Get(0);
+               m_InstanceID = DbReference(row->Get("instance_id"));
+       }
 
-               std::ostringstream msgbuf;
-               msgbuf << "MySQL IDO instance id: " << static_cast<long>(m_InstanceID);
-               Log(LogInformation, "ido_mysql", msgbuf.str());
+       std::ostringstream msgbuf;
+       msgbuf << "MySQL IDO instance id: " << static_cast<long>(m_InstanceID);
+       Log(LogInformation, "ido_mysql", msgbuf.str());
 
-               Query("UPDATE icinga_objects SET is_active = 0");
+       Query("UPDATE icinga_objects SET is_active = 0");
 
-               std::ostringstream qbuf;
-               qbuf << "SELECT object_id, objecttype_id, name1, name2 FROM icinga_objects WHERE instance_id = " << static_cast<long>(m_InstanceID);
-               rows = Query(qbuf.str());
+       std::ostringstream qbuf;
+       qbuf << "SELECT object_id, objecttype_id, name1, name2 FROM icinga_objects WHERE instance_id = " << static_cast<long>(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"));
+       ObjectLock olock(rows);
+       BOOST_FOREACH(const Dictionary::Ptr& row, rows) {
+               DbType::Ptr dbtype = DbType::GetByID(row->Get("objecttype_id"));
 
-                       if (!dbtype)
-                               continue;
+               if (!dbtype)
+                       continue;
 
-                       DbObject::Ptr dbobj = dbtype->GetOrCreateObjectByName(row->Get("name1"), row->Get("name2"));
-                       SetReference(dbobj, DbReference(row->Get("object_id")));
-               }
+               DbObject::Ptr dbobj = dbtype->GetOrCreateObjectByName(row->Get("name1"), row->Get("name2"));
+               SetReference(dbobj, DbReference(row->Get("object_id")));
        }
 
        Query("BEGIN");
@@ -114,19 +149,6 @@ MysqlDbConnection::MysqlDbConnection(const Dictionary::Ptr& serializedUpdate)
        UpdateAllObjects();
 }
 
-void MysqlDbConnection::Stop(void)
-{
-       boost::mutex::scoped_lock lock(m_ConnectionMutex);
-       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);
@@ -209,6 +231,10 @@ Dictionary::Ptr MysqlDbConnection::FetchRow(MYSQL_RES *result)
 void MysqlDbConnection::UpdateObject(const DbObject::Ptr& dbobj, DbUpdateType kind) {
        boost::mutex::scoped_lock lock(m_ConnectionMutex);
 
+       /* Check if we can handle updates right now */
+       if (!m_Connected)
+               return;
+
        DbReference dbref = GetReference(dbobj);
 
        if (kind == DbObjectRemoved) {
@@ -234,8 +260,6 @@ void MysqlDbConnection::UpdateObject(const DbObject::Ptr& dbobj, DbUpdateType ki
                        Query(q1buf.str());
                }
 
-               //Dictionary::Ptr cols = boost::make_shared<Dictionary>();
-
                Dictionary::Ptr fields = dbobj->GetFields();
 
                if (!fields)
index 610505077a13f9aaffab9ffce397a41b9ea2afcf..224b00f4804297a738599ebd7ca4b4d0cfe8ed13 100644 (file)
@@ -57,8 +57,10 @@ private:
        DbReference m_InstanceID;
 
        boost::mutex m_ConnectionMutex;
+       bool m_Connected;
        MYSQL m_Connection;
 
+       Timer::Ptr m_ReconnectTimer;
        Timer::Ptr m_TxTimer;
 
        Array::Ptr Query(const String& query);
@@ -67,6 +69,7 @@ private:
        Dictionary::Ptr FetchRow(MYSQL_RES *result);
 
        void TxTimerHandler(void);
+       void ReconnectTimerHandler(void);
 };
 
 }
index e27d755db427bb07994487ca329f4eea02423486..fbf6a3dc50e9f8b800473e91364259b75f97a576 100644 (file)
@@ -28,6 +28,7 @@
 #
 #     AC_SUBST(MYSQL_CFLAGS)
 #     AC_SUBST(MYSQL_LDFLAGS)
+#     AC_SUBST(MYSQLR_LDFLAGS)
 #     AC_SUBST(MYSQL_VERSION)
 #
 #   And sets:
@@ -82,6 +83,7 @@ AC_DEFUN([AX_LIB_MYSQL],
         if test "$MYSQL_CONFIG" != "no"; then
             MYSQL_CFLAGS="`$MYSQL_CONFIG --cflags`"
             MYSQL_LDFLAGS="`$MYSQL_CONFIG --libs`"
+            MYSQLR_LDFLAGS="`$MYSQL_CONFIG --libs_r`"
 
             MYSQL_VERSION=`$MYSQL_CONFIG --version`
 
@@ -144,4 +146,5 @@ AC_DEFUN([AX_LIB_MYSQL],
     AC_SUBST([MYSQL_VERSION])
     AC_SUBST([MYSQL_CFLAGS])
     AC_SUBST([MYSQL_LDFLAGS])
+    AC_SUBST([MYSQLR_LDFLAGS])
 ])