[mapguide-commits] r5147 - in trunk/MgDev: Common/MapGuideCommon/System Server/src/Services/Resource Server/src/UnitTesting

svn_mapguide at osgeo.org svn_mapguide at osgeo.org
Fri Sep 17 16:23:27 EDT 2010


Author: brucedechant
Date: 2010-09-17 20:23:27 +0000 (Fri, 17 Sep 2010)
New Revision: 5147

Modified:
   trunk/MgDev/Common/MapGuideCommon/System/ConfigProperties.cpp
   trunk/MgDev/Common/MapGuideCommon/System/ConfigProperties.h
   trunk/MgDev/Server/src/Services/Resource/LibraryRepositoryManager.cpp
   trunk/MgDev/Server/src/Services/Resource/RepositoryManager.cpp
   trunk/MgDev/Server/src/Services/Resource/ServerResourceService.cpp
   trunk/MgDev/Server/src/UnitTesting/TestResourceService.cpp
   trunk/MgDev/Server/src/UnitTesting/TestResourceService.h
Log:
Fix for trac ticket 1440 - Repository retry mechanism not being used properly
http://trac.osgeo.org/mapguide/ticket/1440

Notes:
- Updated the repository retry mechanism


Modified: trunk/MgDev/Common/MapGuideCommon/System/ConfigProperties.cpp
===================================================================
--- trunk/MgDev/Common/MapGuideCommon/System/ConfigProperties.cpp	2010-09-17 20:19:39 UTC (rev 5146)
+++ trunk/MgDev/Common/MapGuideCommon/System/ConfigProperties.cpp	2010-09-17 20:23:27 UTC (rev 5147)
@@ -345,9 +345,9 @@
 const STRING MgConfigProperties::ResourceServicePropertyResourceValidationEnabled               = L"ResourceValidationEnabled"; // for internal use only
 const bool   MgConfigProperties::DefaultResourceServicePropertyResourceValidationEnabled        = true;
 const STRING MgConfigProperties::ResourceServicePropertyRetryAttempts                           = L"RetryAttempts";             // for internal use only
-const INT32  MgConfigProperties::DefaultResourceServicePropertyRetryAttempts                    = 10;
+const INT32  MgConfigProperties::DefaultResourceServicePropertyRetryAttempts                    = 50;
 const STRING MgConfigProperties::ResourceServicePropertyRetryInterval                           = L"RetryInterval";             // for internal use only
-const INT32  MgConfigProperties::DefaultResourceServicePropertyRetryInterval                    = 10;
+const INT32  MgConfigProperties::DefaultResourceServicePropertyRetryInterval                    = 25;
 
 // ******************************************************************
 // Site Service Properties

Modified: trunk/MgDev/Common/MapGuideCommon/System/ConfigProperties.h
===================================================================
--- trunk/MgDev/Common/MapGuideCommon/System/ConfigProperties.h	2010-09-17 20:19:39 UTC (rev 5146)
+++ trunk/MgDev/Common/MapGuideCommon/System/ConfigProperties.h	2010-09-17 20:23:27 UTC (rev 5147)
@@ -443,11 +443,11 @@
 
     /// Sets the number of retry attempts per operation
     static const STRING ResourceServicePropertyRetryAttempts;                   /// value("RetryAttempts")
-    static const INT32 DefaultResourceServicePropertyRetryAttempts;             /// value(10)
+    static const INT32 DefaultResourceServicePropertyRetryAttempts;             /// value(50)
 
     /// Sets the time duration (in milliseconds) between retry attempts
     static const STRING ResourceServicePropertyRetryInterval;                   /// value("RetryInterval")
-    static const INT32 DefaultResourceServicePropertyRetryInterval;             /// value(10)
+    static const INT32 DefaultResourceServicePropertyRetryInterval;             /// value(25)
 
 EXTERNAL_API:
 

Modified: trunk/MgDev/Server/src/Services/Resource/LibraryRepositoryManager.cpp
===================================================================
--- trunk/MgDev/Server/src/Services/Resource/LibraryRepositoryManager.cpp	2010-09-17 20:19:39 UTC (rev 5146)
+++ trunk/MgDev/Server/src/Services/Resource/LibraryRepositoryManager.cpp	2010-09-17 20:23:27 UTC (rev 5147)
@@ -79,11 +79,18 @@
 
 void MgLibraryRepositoryManager::CommitTransaction()
 {
+    MG_RESOURCE_SERVICE_TRY()
+
+    // TODO: Updating the modified dates and doing the actual commit can cause DB_BUSY errors.
+    //       Ensure that only the Library updates the modified dates as the session does not need them. Check that this is true?
+    //       The root issue might be that 2 transactions are done here 1)Modified dates and 2)Repository Changes - can these be combined into a single transaction?
     m_resourceHeaderMan->UpdateResourceModifiedDates(m_dateModifiedResources);
 
     MgApplicationRepositoryManager::CommitTransaction();
 
     m_resourceHeaderMan->UpdatePermissionCache();
+
+    MG_RESOURCE_SERVICE_CATCH_AND_THROW(L"MgLibraryRepositoryManager.CommitTransaction")
 }
 
 ///----------------------------------------------------------------------------

Modified: trunk/MgDev/Server/src/Services/Resource/RepositoryManager.cpp
===================================================================
--- trunk/MgDev/Server/src/Services/Resource/RepositoryManager.cpp	2010-09-17 20:19:39 UTC (rev 5146)
+++ trunk/MgDev/Server/src/Services/Resource/RepositoryManager.cpp	2010-09-17 20:23:27 UTC (rev 5147)
@@ -468,6 +468,8 @@
 
 void MgRepositoryManager::CommitTransaction()
 {
+    MG_RESOURCE_SERVICE_TRY()
+
     if (NULL != m_dbTxn)
     {
         m_dbTxn->commit(0);
@@ -475,6 +477,8 @@
         m_xmlTxn.reset();
     }
 
+    MG_RESOURCE_SERVICE_CATCH_AND_THROW(L"MgRepositoryManager.CommitTransaction")
+
     m_transacted = false;
 }
 

Modified: trunk/MgDev/Server/src/Services/Resource/ServerResourceService.cpp
===================================================================
--- trunk/MgDev/Server/src/Services/Resource/ServerResourceService.cpp	2010-09-17 20:19:39 UTC (rev 5146)
+++ trunk/MgDev/Server/src/Services/Resource/ServerResourceService.cpp	2010-09-17 20:23:27 UTC (rev 5147)
@@ -28,7 +28,7 @@
 #include "UnmanagedDataManager.h"
 #include "LogDetail.h"
 
-INT32 MgServerResourceService::sm_retryAttempts = 10;
+INT32 MgServerResourceService::sm_retryAttempts = 50;
 ACE_Time_Value MgServerResourceService::sm_retryInterval;
 
 MgSiteRepository*    MgServerResourceService::sm_siteRepository    = NULL;
@@ -42,50 +42,61 @@
 
 ///////////////////////////////////////////////////////////////////////////////
 /// Server Resource Service retry macros.
-/// This pauses briefly (about 10 ms) before trying the operation again.
+/// This pauses briefly before trying the operation again.
 ///
 #define MG_RESOURCE_SERVICE_BEGIN_OPERATION(transacted)                       \
-    int numRetries = 0;                                                       \
+    MG_RESOURCE_SERVICE_BEGIN_RETRY()                                         \
+    repositoryMan->Initialize(transacted);                                    \
+
+#define MG_RESOURCE_SERVICE_END_OPERATION(maxRetries)                         \
+    MG_RESOURCE_SERVICE_END_RETRY(maxRetries)                                 \
+    MG_RESOURCE_SERVICE_BEGIN_RETRY()                                         \
+        repositoryMan->Terminate();                                           \
+    MG_RESOURCE_SERVICE_END_RETRY(maxRetries)                                 \
+
+#define MG_RESOURCE_SERVICE_BEGIN_RETRY()                                     \
+    {                                                                         \
+        int numRetries = 0;                                                   \
                                                                               \
-    while (true)                                                              \
-    {                                                                         \
-        try                                                                   \
+        while (true)                                                          \
         {                                                                     \
-            repositoryMan->Initialize(transacted);                            \
+            try                                                               \
+            {                                                                 \
 
-#define MG_RESOURCE_SERVICE_END_OPERATION(maxRetries)                         \
-            break;                                                            \
-        }                                                                     \
-        catch (MgException* e)                                                \
-        {                                                                     \
-            ++numRetries;                                                     \
+#define MG_RESOURCE_SERVICE_END_RETRY(maxRetries)                             \
+                break;                                                        \
+            }                                                                 \
+            catch (MgException* e)                                            \
+            {                                                                 \
+                ++numRetries;                                                 \
                                                                               \
-            if ((e->IsOfClass(MapGuide_Exception_MgDbXmlException) || e->IsOfClass(MapGuide_Exception_MgDbException)) \
-             && (DB_LOCK_DEADLOCK == (static_cast<MgThirdPartyException*>(e))->GetErrorCode())) \
-            {                                                                 \
-                if (numRetries < maxRetries)                                  \
+                if ((e->IsOfClass(MapGuide_Exception_MgDbXmlException) || e->IsOfClass(MapGuide_Exception_MgDbException)) \
+                 && (DB_LOCK_DEADLOCK == (static_cast<MgThirdPartyException*>(e))->GetErrorCode())) \
                 {                                                             \
-                    SAFE_RELEASE(e);                                          \
+                    if (numRetries < maxRetries)                              \
+                    {                                                         \
+                        SAFE_RELEASE(e);                                      \
+                    }                                                         \
+                    else                                                      \
+                    {                                                         \
+                        throw e;                                              \
+                    }                                                         \
                 }                                                             \
                 else                                                          \
                 {                                                             \
                     throw e;                                                  \
                 }                                                             \
             }                                                                 \
-            else                                                              \
+            catch (...)                                                       \
             {                                                                 \
-                throw e;                                                      \
+                throw;                                                        \
             }                                                                 \
+                                                                              \
+            ACE_Time_Value sleepTime;                                         \
+            sleepTime.msec((long)(sm_retryInterval.msec() + ((ACE_OS::rand()%10)+1))); \
+            ACE_OS::sleep(sleepTime);                                         \
         }                                                                     \
-        catch (...)                                                           \
-        {                                                                     \
-            throw;                                                            \
-        }                                                                     \
-                                                                              \
-        ACE_OS::sleep(sm_retryInterval);                                      \
-    }                                                                         \
-                                                                              \
-    repositoryMan->Terminate();                                               \
+    }
 
 ///----------------------------------------------------------------------------
 /// <summary>
@@ -123,7 +134,7 @@
 
     // Initialize performance tuning settings.
 
-    INT32 retryInterval = 10; // in milliseconds
+    INT32 retryInterval = 25; // in milliseconds
     MgConfiguration* configuration = MgConfiguration::GetInstance();
     assert(NULL != configuration);
 
@@ -729,6 +740,7 @@
         maxRetries = 0;
     }
 
+    set<STRING> changedResources;
     MG_RESOURCE_SERVICE_BEGIN_OPERATION(true)
 
     if (NULL != content && content->IsRewindable())
@@ -743,10 +755,11 @@
 
     repositoryMan->SetResource(resource, content, header);
 
+    changedResources = repositoryMan->GetChangedResources();
     MG_RESOURCE_SERVICE_END_OPERATION(maxRetries)
 
     // Update the current set of changed resources.
-    UpdateChangedResources(repositoryMan->GetChangedResources());
+    UpdateChangedResources(changedResources);
 
     MG_RESOURCE_SERVICE_CATCH_AND_THROW(L"MgServerResourceService.SetResource")
 }

Modified: trunk/MgDev/Server/src/UnitTesting/TestResourceService.cpp
===================================================================
--- trunk/MgDev/Server/src/UnitTesting/TestResourceService.cpp	2010-09-17 20:19:39 UTC (rev 5146)
+++ trunk/MgDev/Server/src/UnitTesting/TestResourceService.cpp	2010-09-17 20:23:27 UTC (rev 5147)
@@ -25,6 +25,13 @@
 
 CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(TestResourceService, "TestResourceService");
 
+// define thread group for tiling tests
+#define THREAD_GROUP 65530
+
+#define TESTREQUESTS 500
+
+static const INT32 MG_TEST_THREADS = 8; // Adjust this to get failures!
+
 const STRING adminName = L"Administrator";
 const STRING adminPass = L"admin";
 const STRING userLocale = L"en";
@@ -1635,3 +1642,182 @@
         CPPUNIT_FAIL(MG_WCHAR_TO_CHAR(message.c_str()));
     }
 }
+
+// data structure which is passed to each thread
+struct ThreadData
+{
+    INT32 threadId;
+    INT32 command;
+    bool success;
+    bool done;
+};
+
+// the method which gets executed by the ACE worker thread
+ACE_THR_FUNC_RETURN RepositoryWorker(void* param)
+{
+    // get the data for this thread
+    ThreadData* threadData = (ThreadData*)param;
+    INT32 threadId = threadData->threadId;
+    INT32 command = threadData->command;
+    ACE_DEBUG((LM_INFO, ACE_TEXT("> thread %d started\n"), threadId));
+
+    try
+    {
+        // set user info
+        Ptr<MgUserInformation> userInfo = new MgUserInformation(L"Administrator", L"admin");
+        userInfo->SetLocale(TEST_LOCALE);
+        MgUserInformation::SetCurrentUserInfo(userInfo);
+
+        // get the tile service instance
+        MgServiceManager* serviceManager = MgServiceManager::GetInstance();
+        Ptr<MgResourceService> svcResource = dynamic_cast<MgResourceService*>(
+            serviceManager->RequestService(MgServiceType::ResourceService));
+        assert(svcResource != NULL);
+
+        switch (command)
+        {
+        case 0:
+            {
+            //Set the resource
+            Ptr<MgResourceIdentifier> resId = new MgResourceIdentifier(L"Library://UnitTests/Data/test-1.FeatureSource");
+            Ptr<MgByteSource> contentSource = new MgByteSource(resourceContentFileName);
+            Ptr<MgByteReader> contentReader = contentSource->GetReader();
+            svcResource->SetResource(resId, contentReader, NULL);
+            }
+        case 1:
+            {
+            //Set the resource data
+            Ptr<MgResourceIdentifier> resId = new MgResourceIdentifier(L"Library://UnitTests/Data/test-1.FeatureSource");
+            Ptr<MgByteSource> dataSource = new MgByteSource(dataFileName);
+            Ptr<MgByteReader> dataReader = dataSource->GetReader();
+            svcResource->SetResourceData(resId, resourceDataName, L"File", dataReader);
+            }
+            // Need to add a case that updates the session with runtime map
+        }
+
+        MgUserInformation::SetCurrentUserInfo(NULL);
+        threadData->success = true;
+    }
+    catch (MgException* e)
+    {
+        STRING message = e->GetDetails(TEST_LOCALE);
+        message += L"\n";
+        message += e->GetStackTrace(TEST_LOCALE);
+        SAFE_RELEASE(e);
+        ACE_DEBUG((LM_INFO, ACE_TEXT("RepositoryWorker - Exception:\n%W\n"), message.c_str()));
+    }
+    catch (...)
+    {
+        throw;
+    }
+
+    // clear the user info to prevent leaks - if an exception happens and this is not called it leaks about 500 bytes!
+    MgUserInformation::SetCurrentUserInfo(NULL);
+
+    ACE_DEBUG((LM_INFO, ACE_TEXT("> thread %d done\n"), threadId));
+
+    threadData->done = true;
+    return 0;
+}
+
+void TestResourceService::TestCase_RepositoryBusy()
+{
+    // specify the number of threads to use
+    const INT32 numThreads = MG_TEST_THREADS;
+    ThreadData threadData[numThreads];
+
+    try
+    {
+        long lStart = GetTickCount();
+
+        // get the tile service instance
+        MgServiceManager* serviceManager = MgServiceManager::GetInstance();
+        Ptr<MgResourceService> svcResource = dynamic_cast<MgResourceService*>(
+            serviceManager->RequestService(MgServiceType::ResourceService));
+        assert(svcResource != NULL);
+
+        // set user info
+        Ptr<MgUserInformation> userInfo = new MgUserInformation(L"Administrator", L"admin");
+        userInfo->SetLocale(TEST_LOCALE);
+        MgUserInformation::SetCurrentUserInfo(userInfo);
+
+        // Initialize the resource
+        Ptr<MgResourceIdentifier> resId = new MgResourceIdentifier(L"Library://UnitTests/Data/test-1.FeatureSource");
+        Ptr<MgByteSource> contentSource = new MgByteSource(resourceContentFileName);
+        Ptr<MgByteReader> contentReader = contentSource->GetReader();
+        svcResource->SetResource(resId, contentReader, NULL);
+
+        // need a thread manager
+        ACE_Thread_Manager* manager = ACE_Thread_Manager::instance();
+
+        // initialize the thread data
+        for (INT32 i=0; i<numThreads; i++)
+        {
+            threadData[i].threadId = i;
+            threadData[i].success  = false;
+            threadData[i].done     = true;
+        }
+
+        ACE_DEBUG((LM_INFO, ACE_TEXT("\nTestCase_RepositoryBusy\nThreads: %d  Requests: %d\n\n"), numThreads, TESTREQUESTS));
+
+        INT32 nRequest = 0;
+        INT32 nSuccessful = 0;
+        bool bExceptionOcurred = false;
+        for (;;)
+        {
+            INT32 dc = 0;
+            for (INT32 i=0; i<numThreads; i++)
+            {
+                // check if the thread is available
+                if (threadData[i].done)
+                {
+                    if(threadData[i].success)
+                        nSuccessful++;
+
+                    threadData[i].success = false;
+                    threadData[i].done    = false;
+                    threadData[i].command = i%2;
+
+                    // spawn a new thread using a specific group id
+                    int thid = manager->spawn(ACE_THR_FUNC(RepositoryWorker), &threadData[i], 0, NULL, NULL, 0, THREAD_GROUP);
+                    nRequest++;
+                }
+            }
+
+            // move on if all threads are done
+            if ((nRequest > TESTREQUESTS) || (bExceptionOcurred))
+                break;
+
+            // under Linux we get a deadlock if we don't call this every once in a while
+            if (nRequest % 25 == 0)
+                manager->wait_grp(THREAD_GROUP);
+            else
+            {
+                // pause briefly (10ms) before checking again
+                ACE_Time_Value t(0, 10000);
+                ACE_OS::sleep(t);
+            }
+        }
+
+        // make sure all threads in the group have completed
+        manager->wait_grp(THREAD_GROUP);
+
+        for (INT32 i=0; i<numThreads; i++)
+        {
+            if(threadData[i].success)
+                nSuccessful++;
+        }
+
+        ACE_DEBUG((LM_INFO, ACE_TEXT("\nRequests: %d/%d - Execution Time: = %6.4f (s)\n"), nSuccessful, nRequest, ((GetTickCount()-lStart)/1000.0)));
+    }
+    catch (MgException* e)
+    {
+        STRING message = e->GetDetails(TEST_LOCALE);
+        SAFE_RELEASE(e);
+        CPPUNIT_FAIL(MG_WCHAR_TO_CHAR(message.c_str()));
+    }
+    catch (...)
+    {
+        throw;
+    }
+}

Modified: trunk/MgDev/Server/src/UnitTesting/TestResourceService.h
===================================================================
--- trunk/MgDev/Server/src/UnitTesting/TestResourceService.h	2010-09-17 20:19:39 UTC (rev 5146)
+++ trunk/MgDev/Server/src/UnitTesting/TestResourceService.h	2010-09-17 20:23:27 UTC (rev 5147)
@@ -54,6 +54,7 @@
     CPPUNIT_TEST(TestCase_DeleteResource);
 
     CPPUNIT_TEST(TestCase_EnumerateUnmanagedData);
+    CPPUNIT_TEST(TestCase_RepositoryBusy);
 
     CPPUNIT_TEST(TestEnd); // This must be the very last unit test
     CPPUNIT_TEST_SUITE_END();
@@ -96,6 +97,7 @@
     void TestCase_DeleteResource();
 
     void TestCase_EnumerateUnmanagedData();
+    void TestCase_RepositoryBusy();
 };
 
 #endif // TESTRESOURCESERVICE_H_



More information about the mapguide-commits mailing list