[mapguide-commits] r4403 - in trunk/MgDev: Common/MapGuideCommon/Services Common/MapGuideCommon/System Server/src/Core

svn_mapguide at osgeo.org svn_mapguide at osgeo.org
Wed Dec 9 16:13:55 EST 2009


Author: brucedechant
Date: 2009-12-09 16:13:53 -0500 (Wed, 09 Dec 2009)
New Revision: 4403

Modified:
   trunk/MgDev/Common/MapGuideCommon/Services/Command.cpp
   trunk/MgDev/Common/MapGuideCommon/Services/ServerConnection.cpp
   trunk/MgDev/Common/MapGuideCommon/Services/ServerConnection.h
   trunk/MgDev/Common/MapGuideCommon/Services/SiteConnection.cpp
   trunk/MgDev/Common/MapGuideCommon/Services/SiteManager.cpp
   trunk/MgDev/Common/MapGuideCommon/Services/SiteManager.h
   trunk/MgDev/Common/MapGuideCommon/System/ConfigProperties.cpp
   trunk/MgDev/Common/MapGuideCommon/System/ConfigProperties.h
   trunk/MgDev/Server/src/Core/serverconfig.ini
Log:
Fix for trac ticket 1131 - Load balancing doesn't support fail over
http://trac.osgeo.org/mapguide/ticket/1131

Notes:
- Updated load balancing algorithm to remove failed servers and periodically add them back in when they are up and running again

Modified: trunk/MgDev/Common/MapGuideCommon/Services/Command.cpp
===================================================================
--- trunk/MgDev/Common/MapGuideCommon/Services/Command.cpp	2009-12-09 21:05:09 UTC (rev 4402)
+++ trunk/MgDev/Common/MapGuideCommon/Services/Command.cpp	2009-12-09 21:13:53 UTC (rev 4403)
@@ -34,6 +34,8 @@
         //TODO:  Parse url and pull machine name into target
     }
 
+    MG_TRY()
+
     Ptr<MgUserInformation> userInfo = connProp->GetUserInfo();
     Ptr<MgServerConnection> serviceConn = MgServerConnection::Acquire(userInfo, connProp);
     Ptr<MgStream> stream = serviceConn->GetStream();
@@ -114,6 +116,29 @@
     stream->WriteStreamEnd();
 
     GetResponse(serviceConn, retType);
+
+    MG_CATCH(L"MgCommand.ExecuteCommand")
+
+    if (NULL != mgException)
+    {
+        if (mgException->IsOfClass(MapGuide_Exception_MgConnectionFailedException))
+        {
+            // The server didn't respond so it needs to be marked as unavailable in the list of servers.
+            // We will check to see if it can be made available later.
+            MgSiteManager* siteManager = MgSiteManager::GetInstance();
+            Ptr<MgSiteInfo> badSite = siteManager->GetSiteInfo(connProp->GetTarget(), connProp->GetPort());
+            if(NULL != badSite.p)
+            {
+                // Update the status of the failed server
+                badSite->SetStatus(MgSiteInfo::UnableToConnect);
+            }
+
+            // Need to remove the server connection from the pool
+            MgServerConnection::Remove(connProp);
+        }
+
+        MG_THROW();
+    }
 }
 
 //////////////////////////////////////////////////////////////////

Modified: trunk/MgDev/Common/MapGuideCommon/Services/ServerConnection.cpp
===================================================================
--- trunk/MgDev/Common/MapGuideCommon/Services/ServerConnection.cpp	2009-12-09 21:05:09 UTC (rev 4402)
+++ trunk/MgDev/Common/MapGuideCommon/Services/ServerConnection.cpp	2009-12-09 21:13:53 UTC (rev 4403)
@@ -275,10 +275,10 @@
 /// </summary>
 ///
 /// <param name="userInformation">
-/// User information to authenticate against
+/// User information to authenticate against.
 /// </param>
-/// <param name="target">
-/// Target server.  NULL or "" indicates local server
+/// <param name="connProp">
+/// Connection properties for the server to connect to.
 /// </param>
 /// <returns>
 /// Nothing
@@ -342,3 +342,28 @@
     return msc.Detach();
 }
 
+//////////////////////////////////////////////////////////////////
+/// <summary>
+/// Removes a connection to a Mg server
+/// </summary>
+///
+/// <param name="connProp">
+/// Connection properties of the server to remove.
+/// </param>
+/// <returns>
+/// Nothing
+/// </returns>
+/// EXCEPTIONS:
+/// AuthorizationFailed
+/// TargetNotFound
+void MgServerConnection::Remove(MgConnectionProperties* connProp)
+{
+    CHECKNULL((MgConnectionProperties*)connProp, L"MgServerConnection.Remove");
+
+    {
+        ACE_MT(ACE_GUARD(ACE_Recursive_Thread_Mutex, ace_mon, sm_mutex));
+
+        wstring hash = connProp->Hash();
+        g_connectionPool->pool.erase(hash);
+    }
+}

Modified: trunk/MgDev/Common/MapGuideCommon/Services/ServerConnection.h
===================================================================
--- trunk/MgDev/Common/MapGuideCommon/Services/ServerConnection.h	2009-12-09 21:05:09 UTC (rev 4402)
+++ trunk/MgDev/Common/MapGuideCommon/Services/ServerConnection.h	2009-12-09 21:13:53 UTC (rev 4403)
@@ -105,6 +105,19 @@
 
     //////////////////////////////////////////////////////////////////
     /// \brief
+    /// Removes the TCP/IP connection to a MapGuide server from the
+    /// internal connection pool.
+    ///
+    /// \param connProp
+    /// Connection properties for target server
+    ///
+    /// \return
+    /// Nothing
+    ///
+    static void Remove(MgConnectionProperties* connProp);
+
+    //////////////////////////////////////////////////////////////////
+    /// \brief
     /// Internal method used for getting stream helper
     /// which will then be used in serialize/deserialize
     ///

Modified: trunk/MgDev/Common/MapGuideCommon/Services/SiteConnection.cpp
===================================================================
--- trunk/MgDev/Common/MapGuideCommon/Services/SiteConnection.cpp	2009-12-09 21:05:09 UTC (rev 4402)
+++ trunk/MgDev/Common/MapGuideCommon/Services/SiteConnection.cpp	2009-12-09 21:13:53 UTC (rev 4403)
@@ -129,7 +129,8 @@
 
     if (m_connProp == NULL)
     {
-        throw new MgLogicException(L"MgSiteConnection.Open",
+        // There might not be any MapGuide servers running for the site
+        throw new MgConnectionFailedException(L"MgSiteConnection.Open",
             __LINE__, __WFILE__, NULL, L"", NULL);
     }
 

Modified: trunk/MgDev/Common/MapGuideCommon/Services/SiteManager.cpp
===================================================================
--- trunk/MgDev/Common/MapGuideCommon/Services/SiteManager.cpp	2009-12-09 21:05:09 UTC (rev 4402)
+++ trunk/MgDev/Common/MapGuideCommon/Services/SiteManager.cpp	2009-12-09 21:13:53 UTC (rev 4403)
@@ -19,6 +19,94 @@
 // Process-wide MgSiteManager
 Ptr<MgSiteManager> MgSiteManager::sm_siteManager = (MgSiteManager*)NULL;
 
+// Background thread function
+ACE_THR_FUNC_RETURN CheckServers(void* param)
+{
+    SMThreadData* threadData = (SMThreadData*)param;
+    // Store our unique thread ID
+    threadData->threadId = ACE_Thread::self();
+
+    MgSiteManager* siteManager = MgSiteManager::GetInstance();
+
+    bool bDone = false;
+    while(!bDone)
+    {
+        INT32 sleepTime = threadData->failoverRetryTime;
+
+        MgSiteVector* sites = siteManager->GetSites();
+        if(sites)
+        {
+            for(size_t i=0;i<sites->size();i++)
+            {
+                MgSiteInfo* siteInfo = sites->at(i);
+
+                // Check the server status
+                if (MgSiteInfo::Ok != siteInfo->GetStatus())
+                {
+                    // This is an unavailable server so we need to check if it is now available
+                    MG_TRY()
+
+                    // Send a simple request to the server to see if it can respond
+                    Ptr<MgUserInformation> userInformation = new MgUserInformation(L"", L"");
+                    Ptr<MgConnectionProperties> connProp = siteManager->GetConnectionProperties(userInformation, siteInfo, MgSiteInfo::Admin);
+
+                    // Use GetSiteStatus because it doesn't require authentication
+                    MgCommand cmd;
+                    cmd.ExecuteCommand(connProp,                               // Connection
+                                       MgCommand::knObject,                    // Return type expected
+                                       MgServerAdminServiceOpId::GetSiteStatus, // Command Code
+                                       0,                                      // No of arguments
+                                       ServerAdmin_Service,                    // Service Id
+                                       BUILD_VERSION(2,2,0),                   // Operation version
+                                       MgCommand::knNone);
+
+                    // The server responded so update the status if the server is online
+                    Ptr<MgPropertyCollection> properties = (MgPropertyCollection*)cmd.GetReturnValue().val.m_obj;
+                    if(properties.p)
+                    {
+                        // Check the status of the server
+                        Ptr<MgBooleanProperty> boolProp = (MgBooleanProperty*)properties->GetItem(MgServerInformationProperties::Status);
+                        if(boolProp->GetValue())
+                        {
+                            // Server is there and "Online"
+                            ACE_MT(ACE_GUARD_RETURN(ACE_Recursive_Thread_Mutex, ace_mon, siteManager->m_mutex, NULL));
+                            siteInfo->SetStatus(MgSiteInfo::Ok);
+                        }
+                    }
+
+                    MG_CATCH_AND_RELEASE()
+                    if(NULL != mgException.p)
+                    {
+                        // Exception was thrown
+                        STRING message = mgException->GetMessage();
+                    }
+                }
+            }
+
+            // Does this site only contain 1 server?
+            if(sites->size() == 1)
+            {
+                MgSiteInfo* siteInfo = sites->at(0);
+
+                // Check the server status in case it was just updated
+                if (MgSiteInfo::Ok != siteInfo->GetStatus())
+                {
+                    // There is only 1 server in the site and it is not in a "Good" state yet so reduce the sleep time
+                    sleepTime = 1;
+                }
+            }
+        }
+
+        // Sleep the thread as thread resume/suspend is not supported on all platforms
+        ACE_OS::sleep(sleepTime);
+
+        // Update whether we are done or not
+        bDone = siteManager->GetCheckServersThreadDone();
+    }
+
+    return 0;
+}
+
 ///----------------------------------------------------------------------------
 /// <summary>
 /// Constructs the object.
@@ -43,6 +131,10 @@
 
     ClearSiteInfo();
 
+    // Block any threads as we are updating the thread done
+    ACE_MT(ACE_GUARD(ACE_Recursive_Thread_Mutex, ace_mon, m_mutex));
+    m_bCheckServersThreadDone = true;
+
     MG_CATCH(L"MgSiteManager.~MgSiteManager")
 }
 
@@ -179,6 +271,24 @@
         m_sites.push_back(siteInfo.Detach());
     }
 
+    // Create background thread that will check any unavailable servers to see if their status has changed
+    INT32 failoverRetryTime = MgConfigProperties::DefaultGeneralPropertyFailoverRetryTime;
+    configuration->GetIntValue(
+        MgConfigProperties::GeneralPropertiesSection,
+        MgConfigProperties::GeneralPropertyFailoverRetryTime,
+        failoverRetryTime,
+        MgConfigProperties::DefaultGeneralPropertyFailoverRetryTime);
+
+    m_threadData.failoverRetryTime = failoverRetryTime;
+
+    m_bCheckServersThreadDone = false;
+
+    // Need a thread manager
+    ACE_Thread_Manager* manager = ACE_Thread_Manager::instance();
+    
+    // Create the background thread
+    manager->spawn(ACE_THR_FUNC(CheckServers), &m_threadData);
+
     MG_CATCH_AND_THROW(L"MgSiteManager.Initialize")
 }
 
@@ -213,12 +323,19 @@
         {
             STRING siteHexString = sessionId.substr(
                 length - MgSiteInfo::HexStringLength, MgSiteInfo::HexStringLength);
-            Ptr<MgSiteInfo> siteInfo = new MgSiteInfo(siteHexString);
+            Ptr<MgSiteInfo> siteInfo = GetSiteInfo(siteHexString);
 
             if (MgSiteInfo::Ok == siteInfo->GetStatus())
             {
                 connProps = GetConnectionProperties(userInfo, siteInfo, portType);
             }
+            else
+            {
+                // This site is not currently working
+
+                // We have a session, but it will not exist on any other machine so we force the session exception
+                throw new MgSessionExpiredException(L"MgSiteManager.GetConnectionProperties",__LINE__,__WFILE__, NULL, L"", NULL);
+            }
         }
     }
     else
@@ -233,7 +350,8 @@
 
     if (NULL == connProps.p)
     {
-        throw new MgLogicException(
+        // There might not be any MapGuide servers running for the site
+        throw new MgConnectionFailedException(
             L"MgSiteManager.GetConnectionProperties",
             __LINE__, __WFILE__, NULL, L"", NULL);
     }
@@ -371,3 +489,64 @@
 
     return SAFE_ADDREF(matchingSiteInfo);
 }
+
+///----------------------------------------------------------------------------
+/// <summary>
+/// Retrieves site info for the site server matching the specified target and port
+/// contained within the specifed hex string.
+/// </summary>
+///----------------------------------------------------------------------------
+MgSiteInfo* MgSiteManager::GetSiteInfo(CREFSTRING hexString)
+{
+    MgSiteInfo* matchingSiteInfo = NULL;
+
+    if(hexString.length() >= MgSiteInfo::HexStringLength)
+    {
+        UINT32 n1, n2, n3, n4;
+        INT32 sitePort, clientPort, adminPort;
+        STRING target;
+
+        // Read the IP parts into their variables
+        if(::swscanf(hexString.c_str(), L"%2X%2X%2X%2X%4X%4X%4X", &n1, &n2, &n3, &n4, &sitePort, &clientPort, &adminPort) == 7)
+        {
+            // Write the 4 'n' values into an IP string
+            wchar_t buffer[20];
+            swprintf(buffer, 20, L"%u.%u.%u.%u", n1, n2, n3, n4);
+            target = buffer;
+        }
+
+        ACE_MT(ACE_GUARD_RETURN(ACE_Recursive_Thread_Mutex, ace_mon, m_mutex, NULL));
+
+        for (INT32 i = 0; i < (INT32)m_sites.size(); i++)
+        {
+            MgSiteInfo* siteInfo = m_sites.at(i);
+
+            if (siteInfo->GetTarget() == target
+                && (siteInfo->GetPort(MgSiteInfo::Site)   == sitePort ||
+                    siteInfo->GetPort(MgSiteInfo::Client) == clientPort ||
+                    siteInfo->GetPort(MgSiteInfo::Admin)  == adminPort))
+            {
+                matchingSiteInfo = siteInfo;
+                break;
+            }
+        }
+    }
+
+    return SAFE_ADDREF(matchingSiteInfo);
+}
+
+MgSiteVector* MgSiteManager::GetSites()
+{
+    return &m_sites;
+}
+
+bool MgSiteManager::GetCheckServersThreadDone()
+{
+    return m_bCheckServersThreadDone;
+}
+
+void MgSiteManager::SetCheckServersThreadDone(bool bDone)
+{
+    ACE_MT(ACE_GUARD(ACE_Recursive_Thread_Mutex, ace_mon, m_mutex));
+    m_bCheckServersThreadDone = bDone;
+}

Modified: trunk/MgDev/Common/MapGuideCommon/Services/SiteManager.h
===================================================================
--- trunk/MgDev/Common/MapGuideCommon/Services/SiteManager.h	2009-12-09 21:05:09 UTC (rev 4402)
+++ trunk/MgDev/Common/MapGuideCommon/Services/SiteManager.h	2009-12-09 21:13:53 UTC (rev 4403)
@@ -21,6 +21,13 @@
 class MgSiteInfo;
 typedef std::vector<MgSiteInfo*> MgSiteVector;
 
+// Data structure which is passed to thread
+struct SMThreadData
+{
+    ACE_thread_t threadId;
+    INT32 failoverRetryTime;
+};
+
 class MG_MAPGUIDE_API MgSiteManager : public MgGuardDisposable
 {
 DECLARE_CLASSNAME(MgSiteManager)
@@ -63,9 +70,16 @@
 
     MgSiteInfo* GetSiteInfo(INT32 index);
     MgSiteInfo* GetSiteInfo(CREFSTRING target, INT32 port);
+    MgSiteInfo* GetSiteInfo(CREFSTRING hexString);
 
     INT32 GetSiteCount();
 
+    MgSiteVector* GetSites();
+    ACE_Recursive_Thread_Mutex m_mutex;
+
+    bool GetCheckServersThreadDone();
+    void SetCheckServersThreadDone(bool bDone);
+
 private:
 
     void Initialize();
@@ -79,9 +93,10 @@
 
     static Ptr<MgSiteManager> sm_siteManager;
 
-    ACE_Recursive_Thread_Mutex m_mutex;
     INT32 m_index;
     MgSiteVector m_sites;
+    SMThreadData m_threadData;
+    bool m_bCheckServersThreadDone;
 };
 
 #endif // MG_SITEMANAGER_H_

Modified: trunk/MgDev/Common/MapGuideCommon/System/ConfigProperties.cpp
===================================================================
--- trunk/MgDev/Common/MapGuideCommon/System/ConfigProperties.cpp	2009-12-09 21:05:09 UTC (rev 4402)
+++ trunk/MgDev/Common/MapGuideCommon/System/ConfigProperties.cpp	2009-12-09 21:13:53 UTC (rev 4403)
@@ -161,6 +161,8 @@
 const INT32  MgConfigProperties::DefaultGeneralPropertyWorkerThreadPoolSize                 = 1;
 const STRING MgConfigProperties::GeneralPropertyRenderer                                    = L"Renderer";
 const STRING MgConfigProperties::DefaultGeneralPropertyRenderer                             = L"GD";
+const STRING MgConfigProperties::GeneralPropertyFailoverRetryTime                           = L"FailoverRetryTime"; // for internal use only
+const INT32  MgConfigProperties::DefaultGeneralPropertyFailoverRetryTime                    = 60;
 
 // ******************************************************************
 // Administrative Connection Properties
@@ -505,6 +507,7 @@
     { MgConfigProperties::GeneralPropertyWfsDocumentPath                            , MgPropertyType::String    , MG_CONFIG_MIN_PATH_LENGTH             , MG_CONFIG_MAX_PATH_LENGTH             , MG_CONFIG_PATH_RESERVED_CHARACTERS        },
     { MgConfigProperties::GeneralPropertyWmsDocumentPath                            , MgPropertyType::String    , MG_CONFIG_MIN_PATH_LENGTH             , MG_CONFIG_MAX_PATH_LENGTH             , MG_CONFIG_PATH_RESERVED_CHARACTERS        },
     { MgConfigProperties::GeneralPropertyWorkerThreadPoolSize                       , MgPropertyType::Int32     , MG_CONFIG_MIN_THREAD_POOL_SIZE        , MG_CONFIG_MAX_THREAD_POOL_SIZE        , L""                                       },
+    { MgConfigProperties::GeneralPropertyFailoverRetryTime                          , MgPropertyType::Int32     , MG_CONFIG_MIN_TIMER_INTERVAL          , MG_CONFIG_MAX_TIMER_INTERVAL          , L""                                       },
     { L""                                                                           , 0                         , 0.0                                   , 0.0                                   , L""                                       }
 };
 

Modified: trunk/MgDev/Common/MapGuideCommon/System/ConfigProperties.h
===================================================================
--- trunk/MgDev/Common/MapGuideCommon/System/ConfigProperties.h	2009-12-09 21:05:09 UTC (rev 4402)
+++ trunk/MgDev/Common/MapGuideCommon/System/ConfigProperties.h	2009-12-09 21:13:53 UTC (rev 4403)
@@ -135,6 +135,10 @@
     static const STRING GeneralPropertyWorkerThreadPoolSize;            /// value("WorkerThreadPoolSize")
     static const INT32 DefaultGeneralPropertyWorkerThreadPoolSize;      /// value(1)
 
+    /// Sets the failover retry time
+    static const STRING GeneralPropertyFailoverRetryTime;               /// value("FailoverRetryTime")
+    static const INT32 DefaultGeneralPropertyFailoverRetryTime;         /// value(60)
+
 EXTERNAL_API:
 
     /// ADMINISTRATIVE CONNECTION PROPERTIES SECTION ---------------------------------------------------------------------

Modified: trunk/MgDev/Server/src/Core/serverconfig.ini
===================================================================
--- trunk/MgDev/Server/src/Core/serverconfig.ini	2009-12-09 21:05:09 UTC (rev 4402)
+++ trunk/MgDev/Server/src/Core/serverconfig.ini	2009-12-09 21:13:53 UTC (rev 4403)
@@ -1,4 +1,4 @@
-# *****************************************************************************
+# *****************************************************************************
 # MapGuide Server Configuration File
 #
 # The following configuration is based on a single CPU with a single core.
@@ -83,6 +83,7 @@
 ConnectionTimerInterval            = 60
 DefaultMessageLocale               = en
 DisplayName                        =
+FailoverRetryTime                  = 60
 FdoPath                            = FDO/
 LicenseServerPath                  = @localhost
 Locale                             =



More information about the mapguide-commits mailing list