[mapguide-commits] r1090 - in trunk/MgDev: Common/Foundation/System Common/MapGuideCommon/Resources Common/MapGuideCommon/System Server/src/Common/Manager Server/src/Services/Rendering Server/src/Services/Resource Server/src/Services/Tile Server/src/UnitTesting

svn_mapguide at osgeo.org svn_mapguide at osgeo.org
Fri Feb 2 20:06:40 EST 2007


Author: stevedang
Date: 2007-02-02 20:06:39 -0500 (Fri, 02 Feb 2007)
New Revision: 1090

Modified:
   trunk/MgDev/Common/Foundation/System/FileUtil.cpp
   trunk/MgDev/Common/MapGuideCommon/Resources/mapguide_en.res
   trunk/MgDev/Common/MapGuideCommon/System/ConfigProperties.cpp
   trunk/MgDev/Common/MapGuideCommon/System/ConfigProperties.h
   trunk/MgDev/Server/src/Common/Manager/FdoConnectionManager.cpp
   trunk/MgDev/Server/src/Services/Rendering/ServerRenderingService.cpp
   trunk/MgDev/Server/src/Services/Resource/ServerResourceService.cpp
   trunk/MgDev/Server/src/Services/Tile/ServerTileService.cpp
   trunk/MgDev/Server/src/Services/Tile/ServerTileService.h
   trunk/MgDev/Server/src/Services/Tile/TileCache.cpp
   trunk/MgDev/Server/src/Services/Tile/TileCache.h
   trunk/MgDev/Server/src/UnitTesting/TestTileService.cpp
Log:
Stability ?\226?\128?\147 Miscellaneous code cleanups and fixes:
- Fixed some threading problems in File Util.
- Fixed Tile Service unit tests (there were some codes previously commented out due to failures).
- Got rid of some compiling warnings in FDO Connection Manager.
- Implemented tile file locking mechanism to address some threading/file access problems.

Modified: trunk/MgDev/Common/Foundation/System/FileUtil.cpp
===================================================================
--- trunk/MgDev/Common/Foundation/System/FileUtil.cpp	2007-02-02 17:55:19 UTC (rev 1089)
+++ trunk/MgDev/Common/Foundation/System/FileUtil.cpp	2007-02-03 01:06:39 UTC (rev 1090)
@@ -219,13 +219,15 @@
 
     RemoveSlashFromEndOfPath(path); // This must be done.
 
-    ACE_MT(ACE_GUARD_RETURN(ACE_Recursive_Thread_Mutex, ace_mon, sm_mutex, false));
+    { // Begin guarding.
+        ACE_MT(ACE_GUARD_RETURN(ACE_Recursive_Thread_Mutex, ace_mon, sm_mutex, false));
 
 #ifdef _WIN32
-    success = ::_wstat(path.c_str(), &statInfo) == 0;
+        success = ::_wstat(path.c_str(), &statInfo) == 0;
 #else
-    success = ::stat(MgUtil::WideCharToMultiByte(path).c_str(), &statInfo) == 0;
+        success = ::stat(MgUtil::WideCharToMultiByte(path).c_str(), &statInfo) == 0;
 #endif
+    } // End guarding.
 
     if (!success && strict)
     {
@@ -297,6 +299,8 @@
 {
     MG_TRY()
 
+    ACE_MT(ACE_GUARD(ACE_Recursive_Thread_Mutex, ace_mon, sm_mutex));
+
     if (PathnameExists(path))
     {
         if (strict)
@@ -311,7 +315,6 @@
         return;
     }
 
-    ACE_MT(ACE_GUARD(ACE_Recursive_Thread_Mutex, ace_mon, sm_mutex));
     int errCode = ACE_OS::mkdir(MG_WCHAR_TO_TCHAR(path));
 
     if (0 != errCode)
@@ -400,6 +403,8 @@
 
     MG_TRY()
 
+    ACE_MT(ACE_GUARD_RETURN(ACE_Recursive_Thread_Mutex, ace_mon, sm_mutex, false));
+
     if (!PathnameExists(path))
     {
         if (strict)
@@ -414,7 +419,6 @@
         return false;
     }
 
-    ACE_MT(ACE_GUARD_RETURN(ACE_Recursive_Thread_Mutex, ace_mon, sm_mutex, false));
     numEntries = ACE_OS::scandir(MG_WCHAR_TO_TCHAR(path), &dirEntries,
         MgDirEntrySelector, MgDirEntryComparator);
 
@@ -487,11 +491,11 @@
 
 STRING MgFileUtil::ChangeDirectory(CREFSTRING path)
 {
-    ACE_MT(ACE_GUARD_RETURN(ACE_Recursive_Thread_Mutex, ace_mon, sm_mutex, L""));
-
     STRING currDir;
     ACE_TCHAR buffer[MAXPATHLEN];
 
+    ACE_MT(ACE_GUARD_RETURN(ACE_Recursive_Thread_Mutex, ace_mon, sm_mutex, L""));
+
     if (ACE_OS::getcwd(buffer, MAXPATHLEN) == NULL)
     {
         MgStringCollection arguments;
@@ -550,6 +554,8 @@
 {
     MG_TRY()
 
+    ACE_MT(ACE_GUARD(ACE_Recursive_Thread_Mutex, ace_mon, sm_mutex));
+
     if (!PathnameExists(pathname))
     {
         if (strict)
@@ -564,7 +570,6 @@
         return;
     }
 
-    ACE_MT(ACE_GUARD(ACE_Recursive_Thread_Mutex, ace_mon, sm_mutex));
     int errCode = ACE_OS::unlink(MG_WCHAR_TO_TCHAR(pathname));
 
     if (0 != errCode)
@@ -711,6 +716,8 @@
             __LINE__, __WFILE__, &arguments, L"", NULL);
     }
 
+    ACE_MT(ACE_GUARD(ACE_Recursive_Thread_Mutex, ace_mon, sm_mutex));
+
     if (overwrite)
     {
         DeleteFile(newPathname);
@@ -724,8 +731,6 @@
             __LINE__, __WFILE__, &arguments, L"", NULL);
     }
 
-    ACE_MT(ACE_GUARD(ACE_Recursive_Thread_Mutex, ace_mon, sm_mutex));
-
 #ifdef WIN32
     int errCode = ::_wrename(oldPathname.c_str(), newPathname.c_str());
 #else
@@ -992,9 +997,9 @@
 {
     bool bResult = true;
 
+#ifndef WIN32
     ACE_MT(ACE_GUARD_RETURN(ACE_Recursive_Thread_Mutex, ace_mon, sm_mutex, false));
 
-#ifndef WIN32
     FILE* file = ACE_OS::fopen(MG_WCHAR_TO_TCHAR(pathname), ACE_TEXT("r+"));
     if (file)
     {

Modified: trunk/MgDev/Common/MapGuideCommon/Resources/mapguide_en.res
===================================================================
--- trunk/MgDev/Common/MapGuideCommon/Resources/mapguide_en.res	2007-02-02 17:55:19 UTC (rev 1089)
+++ trunk/MgDev/Common/MapGuideCommon/Resources/mapguide_en.res	2007-02-03 01:06:39 UTC (rev 1090)
@@ -210,6 +210,7 @@
 MgInvalidPropertyType                                 = The property type is invalid because it is not recognized.
 MgInvalidPropertyTypeForCommand                       = The property type is invalid for the command because it was of a different type then expected.
 MgInvalidResourceCannotBeRoot                         = The resource is invalid because it cannot be the root.
+MgInvalidScaleIndex                                   = Scale index is out of range.
 MgInvalidSecond                                       = The second is invalid because it must be between 0 and 59.
 MgInvalidServiceType                                  = The service type is invalid because it is not recognized.
 MgInvalidSessionsId                                   = The session ID is invalid because the session separator character was not found.
@@ -225,6 +226,7 @@
 MgInvalidWebWidgetType                                = The web widget type is invalid because it is not recognized.
 MgInvalidXmlDateTime                                  = The Xml date time is invalid because not all of the fields were found.
 MgInvalidYear                                         = The year is invalid because it must be between 1 and 9999.
+MgMapCacheCleared                                     = The Tile Service map cache has been cleared.  Please increase TiledMapCacheSize in serverconfig.ini.
 MgMapLayerGroupNameNotFound                           = The map layer group name was not found.
 MgMissingClassDef                                     = No class definition specified.
 MgMissingSchema                                       = No schema specified.
@@ -244,6 +246,8 @@
 MgStringEmpty                                         = The string cannot be empty. 
 MgStringTooLong                                       = The string is too long.
 MgTagFieldNotFound                                    = The tag contained no fields.
+MgUnableToLockTileFile                                = Unable to lock the tile file.
+MgUnableToOpenTileFile                                = Unable to open the tile file.
 MgUnsupportedService                                  = The site/resource services cannot be enabled/disabled.
 MgUserAndGroupNotEmpty                                = Both the user and group are not empty.
 MgUserAndRoleNotEmpty                                 = Both the user and role are not empty.

Modified: trunk/MgDev/Common/MapGuideCommon/System/ConfigProperties.cpp
===================================================================
--- trunk/MgDev/Common/MapGuideCommon/System/ConfigProperties.cpp	2007-02-02 17:55:19 UTC (rev 1089)
+++ trunk/MgDev/Common/MapGuideCommon/System/ConfigProperties.cpp	2007-02-03 01:06:39 UTC (rev 1090)
@@ -308,10 +308,16 @@
 const STRING MgConfigProperties::TileServicePropertiesSection                               = L"TileServiceProperties";
 const STRING MgConfigProperties::TileServicePropertyTileCachePath                           = L"TileCachePath";
 const STRING MgConfigProperties::DefaultTileServicePropertyTileCachePath                    = L"Repositories/TileCache/";
+const STRING MgConfigProperties::TileServicePropertyCreationCutoffTime                      = L"CreationCutoffTime";
+const INT32  MgConfigProperties::DefaultTileServicePropertyCreationCutoffTime               = 120;
+const STRING MgConfigProperties::TileServicePropertyLockFolderName                          = L"LockFolderName";
+const STRING MgConfigProperties::DefaultTileServicePropertyLockFolderName                   = L"Lock";
+const STRING MgConfigProperties::TileServicePropertyPollingInterval                         = L"PollingInterval";
+const INT32  MgConfigProperties::DefaultTileServicePropertyPollingInterval                  = 1;
+const STRING MgConfigProperties::TileServicePropertyRenderOnly                              = L"RenderOnly";
+const bool   MgConfigProperties::DefaultTileServicePropertyRenderOnly                       = false;
 const STRING MgConfigProperties::TileServicePropertyTiledMapCacheSize                       = L"TiledMapCacheSize";
 const INT32  MgConfigProperties::DefaultTileServicePropertyTiledMapCacheSize                = 10;
-const STRING MgConfigProperties::TileServicePropertyRenderOnly                              = L"RenderOnly";
-const bool   MgConfigProperties::DefaultTileServicePropertyRenderOnly                       = false;
 
 // ******************************************************************
 // Access Log Properties
@@ -541,8 +547,11 @@
 const MgConfigValidationInfo MgConfigProperties::sm_cviTileServiceProperties[] =
 {
     { MgConfigProperties::TileServicePropertyTileCachePath                          , MgPropertyType::String    , MG_CONFIG_MIN_PATH_LENGTH             , MG_CONFIG_MAX_PATH_LENGTH             , MG_CONFIG_PATH_RESERVED_CHARACTERS        },
+    { MgConfigProperties::TileServicePropertyCreationCutoffTime                     , MgPropertyType::Int32     , 1                                     , 600                                   , L""                                       },
+    { MgConfigProperties::TileServicePropertyLockFolderName                         , MgPropertyType::String    , MG_CONFIG_MIN_FOLDER_NAME_LENGTH      , MG_CONFIG_MAX_FOLDER_NAME_LENGTH      , MG_CONFIG_FOLDER_NAME_RESERVED_CHARACTERS },
+    { MgConfigProperties::TileServicePropertyPollingInterval                        , MgPropertyType::Int32     , 1                                     , 60                                    , L""                                       },
+    { MgConfigProperties::TileServicePropertyRenderOnly                             , MgPropertyType::Boolean   , 0                                     , 1                                     , L""                                       },
     { MgConfigProperties::TileServicePropertyTiledMapCacheSize                      , MgPropertyType::Int32     , MG_CONFIG_MIN_CACHE_SIZE              , MG_CONFIG_MAX_CACHE_SIZE              , L""                                       },
-    { MgConfigProperties::TileServicePropertyRenderOnly                             , MgPropertyType::Boolean   , 0                                     , 1                                     , L""                                       },
     { L""                                                                           , 0                         , 0.0                                   , 0.0                                   , L""                                       }
 };
 

Modified: trunk/MgDev/Common/MapGuideCommon/System/ConfigProperties.h
===================================================================
--- trunk/MgDev/Common/MapGuideCommon/System/ConfigProperties.h	2007-02-02 17:55:19 UTC (rev 1089)
+++ trunk/MgDev/Common/MapGuideCommon/System/ConfigProperties.h	2007-02-03 01:06:39 UTC (rev 1090)
@@ -396,12 +396,29 @@
     static const STRING TileServicePropertyTileCachePath;               /// value("TileCachePath")
     static const STRING DefaultTileServicePropertyTileCachePath;        /// value("Repositories/TileCache/")
 
+INTERNAL_API:
+
+    /// Sets the maximum amount of time (in seconds) to create a tile
+    static const STRING TileServicePropertyCreationCutoffTime;          /// value("CreationCutoffTime")
+    static const INT32 DefaultTileServicePropertyCreationCutoffTime;    /// value(120)
+
+    /// Sets the folder name for locks
+    static const STRING TileServicePropertyLockFolderName;              /// value("LockFolderName")
+    static const STRING DefaultTileServicePropertyLockFolderName;       /// value("Lock")
+
+    /// Sets the time duration (in seconds) between lock checks
+    static const STRING TileServicePropertyPollingInterval;             /// value("PollingInterval")
+    static const INT32 DefaultTileServicePropertyPollingInterval;       /// value(1)
+
+    /// Specifies whether the tile is only rendered
+    static const STRING TileServicePropertyRenderOnly;                  /// value("RenderOnly")
+    static const bool DefaultTileServicePropertyRenderOnly;             /// value(true)
+
     /// Sets the limit on the number of cached MgMap objects used for tile generation
     static const STRING TileServicePropertyTiledMapCacheSize;           /// value("TiledMapCacheSize")
     static const INT32 DefaultTileServicePropertyTiledMapCacheSize;     /// value(10)
-    static const STRING TileServicePropertyRenderOnly;                  /// value("RenderOnly")
-    static const bool DefaultTileServicePropertyRenderOnly;             /// value(true)
 
+EXTERNAL_API:
 
     //////////////////////////////////////////////////////////////////
     /// \brief

Modified: trunk/MgDev/Server/src/Common/Manager/FdoConnectionManager.cpp
===================================================================
--- trunk/MgDev/Server/src/Common/Manager/FdoConnectionManager.cpp	2007-02-02 17:55:19 UTC (rev 1089)
+++ trunk/MgDev/Server/src/Common/Manager/FdoConnectionManager.cpp	2007-02-03 01:06:39 UTC (rev 1090)
@@ -1234,7 +1234,8 @@
     RetrieveFeatureSource(resId, featureSourceXmlContent);
 
     MdfParser::FSDSAX2Parser parser;
-    parser.ParseString(featureSourceXmlContent.c_str(), featureSourceXmlContent.length()*sizeof(char));
+    parser.ParseString(featureSourceXmlContent.c_str(),
+        (unsigned int)(featureSourceXmlContent.length()*sizeof(char)));
 
     assert(parser.GetSucceeded());
 

Modified: trunk/MgDev/Server/src/Services/Rendering/ServerRenderingService.cpp
===================================================================
--- trunk/MgDev/Server/src/Services/Rendering/ServerRenderingService.cpp	2007-02-02 17:55:19 UTC (rev 1089)
+++ trunk/MgDev/Server/src/Services/Rendering/ServerRenderingService.cpp	2007-02-03 01:06:39 UTC (rev 1090)
@@ -140,7 +140,7 @@
 
     MG_CATCH_AND_THROW(L"MgServerRenderingService.RenderTile")
 
-    return SAFE_ADDREF(ret.p);
+    return ret.Detach();
 }
 
 
@@ -208,7 +208,7 @@
 
     MG_CATCH_AND_THROW(L"MgServerRenderingService.RenderTile")
 
-    return SAFE_ADDREF(ret.p);
+    return ret.Detach();
 }
 
 
@@ -272,7 +272,7 @@
 
     MG_CATCH_AND_THROW(L"MgServerRenderingService.RenderDynamicOverlay")
 
-    return SAFE_ADDREF(ret.p);
+    return ret.Detach();
 }
 
 
@@ -301,7 +301,7 @@
 
     MG_CATCH_AND_THROW(L"MgServerRenderingService.RenderMap")
 
-    return SAFE_ADDREF(ret.p);
+    return ret.Detach();
 }
 
 
@@ -394,7 +394,7 @@
 
     MG_CATCH_AND_THROW(L"MgServerRenderingService.RenderMap")
 
-    return SAFE_ADDREF(ret.p);
+    return ret.Detach();
 }
 
 
@@ -448,7 +448,7 @@
 
     MG_CATCH_AND_THROW(L"MgServerRenderingService.RenderMap")
 
-    return SAFE_ADDREF(ret.p);
+    return ret.Detach();
 }
 
 
@@ -488,7 +488,7 @@
 
     MG_CATCH_AND_THROW(L"MgServerRenderingService.QueryFeatures")
 
-    return SAFE_ADDREF(ret.p);
+    return ret.Detach();
 }
 
 
@@ -516,7 +516,7 @@
 
     MG_CATCH_AND_THROW(L"MgServerRenderingService.QueryFeatures")
 
-    return SAFE_ADDREF(ret.p);
+    return ret.Detach();
 }
 
 
@@ -638,7 +638,7 @@
     dr->ProcessPolyline(&lb, ls);
     //-------------------------------------------------------
 */
-    MgByteReader* ret = NULL;
+    Ptr<MgByteReader> ret;
 
     // get a byte representation of the image
     RS_ByteData* data = dr->Save(format, saveWidth, saveHeight);
@@ -663,7 +663,7 @@
         data->Dispose();
     }
 
-    return ret;
+    return ret.Detach();
 }
 
 
@@ -743,7 +743,7 @@
 
     MG_CATCH_AND_THROW(L"MgServerRenderingService.RenderMapLegend")
 
-    return SAFE_ADDREF(ret.p);
+    return ret.Detach();
 }
 
 

Modified: trunk/MgDev/Server/src/Services/Resource/ServerResourceService.cpp
===================================================================
--- trunk/MgDev/Server/src/Services/Resource/ServerResourceService.cpp	2007-02-02 17:55:19 UTC (rev 1089)
+++ trunk/MgDev/Server/src/Services/Resource/ServerResourceService.cpp	2007-02-03 01:06:39 UTC (rev 1090)
@@ -2035,7 +2035,7 @@
 bool MgServerResourceService::HasPermission(MgResourceIdentifier* resource, 
     CREFSTRING permission)
 {
-    bool retVal = false;
+    bool permitted = false;
 
     MG_RESOURCE_SERVICE_TRY()
 
@@ -2056,13 +2056,20 @@
 
     MG_RESOURCE_SERVICE_BEGIN_OPERATION(false)
 
-    retVal = resourceContentMan->CheckPermission(*resource, permission);
+    permitted = resourceContentMan->CheckPermission(*resource, permission);
 
     MG_RESOURCE_SERVICE_END_OPERATION(sm_maxOpRetries)
 
-    MG_RESOURCE_SERVICE_CATCH_AND_THROW(L"MgServerResourceService.HasPermission")
+    MG_RESOURCE_SERVICE_CATCH(L"MgServerResourceService.HasPermission")
 
-    return retVal;
+    if (mgException != NULL
+        && !mgException->IsOfClass(MapGuide_Exception_MgPermissionDeniedException)
+        && !mgException->IsOfClass(MapGuide_Exception_MgUnauthorizedAccessException))
+    {
+        MG_RESOURCE_SERVICE_THROW()
+    }
+
+    return permitted;
 }
 
 ///----------------------------------------------------------------------------

Modified: trunk/MgDev/Server/src/Services/Tile/ServerTileService.cpp
===================================================================
--- trunk/MgDev/Server/src/Services/Tile/ServerTileService.cpp	2007-02-02 17:55:19 UTC (rev 1089)
+++ trunk/MgDev/Server/src/Services/Tile/ServerTileService.cpp	2007-02-03 01:06:39 UTC (rev 1090)
@@ -22,25 +22,43 @@
 
 ACE_Recursive_Thread_Mutex MgServerTileService::sm_mutex;
 MgServerTileService::MapCache MgServerTileService::sm_mapCache;
+INT32 MgServerTileService::sm_creationCutoffTime = 120;     // in seconds
+INT32 MgServerTileService::sm_pollingInterval = 1;          // in seconds
+bool MgServerTileService::sm_renderOnly = false;
 INT32 MgServerTileService::sm_mapCacheSize = -1;
-bool MgServerTileService::sm_renderOnly = false;
 
 MgServerTileService::MgServerTileService() : MgTileService()
 {
+    //TODO: It is possible to get a double write on sm_mapCacheSize here.  We need
+    //to investigate general mutex use in this class.
     if (sm_mapCacheSize < 0)
     {
         // initialize the tile cache size
         MgConfiguration* pConf = MgConfiguration::GetInstance();
 
-        pConf->GetIntValue(MgConfigProperties::TileServicePropertiesSection,
-            MgConfigProperties::TileServicePropertyTiledMapCacheSize,
-            sm_mapCacheSize,
-            MgConfigProperties::DefaultTileServicePropertyTiledMapCacheSize);
+        pConf->GetIntValue(
+            MgConfigProperties::TileServicePropertiesSection,
+            MgConfigProperties::TileServicePropertyCreationCutoffTime,
+            sm_creationCutoffTime,
+            MgConfigProperties::DefaultTileServicePropertyCreationCutoffTime);
 
-        pConf->GetBoolValue(MgConfigProperties::TileServicePropertiesSection,
+        pConf->GetIntValue(
+            MgConfigProperties::TileServicePropertiesSection,
+            MgConfigProperties::TileServicePropertyPollingInterval,
+            sm_pollingInterval,
+            MgConfigProperties::DefaultTileServicePropertyPollingInterval);
+
+        pConf->GetBoolValue(
+            MgConfigProperties::TileServicePropertiesSection,
             MgConfigProperties::TileServicePropertyRenderOnly,
             sm_renderOnly,
             MgConfigProperties::DefaultTileServicePropertyRenderOnly);
+
+        pConf->GetIntValue(
+            MgConfigProperties::TileServicePropertiesSection,
+            MgConfigProperties::TileServicePropertyTiledMapCacheSize,
+            sm_mapCacheSize,
+            MgConfigProperties::DefaultTileServicePropertyTiledMapCacheSize);
     }
 
     m_tileCache = new MgTileCache();
@@ -51,6 +69,36 @@
 {
 }
 
+///////////////////////////////////////////////////////////////////////////////
+/// \brief
+/// Detect if the tile file has been locked by another thread or process.
+///
+bool MgServerTileService::DetectTileLockFile(CREFSTRING lockPathname)
+{
+    bool found = false;
+    struct _stat lockFileInfo;
+
+    // Check the lock file to see if another thread/process is writing the tile file.
+    while (MgFileUtil::GetFileStatus(lockPathname, lockFileInfo))
+    {
+        time_t currTime;
+        ACE_OS::time(&currTime);
+        INT32 diffTime = (INT32)(currTime - lockFileInfo.st_mtime);
+
+        if (diffTime < sm_creationCutoffTime)
+        {
+            ACE_OS::sleep(sm_pollingInterval);
+        }
+        else
+        {
+            found = true;
+            break;
+        }
+    }
+
+    return found;
+}
+
 MgByteReader* MgServerTileService::GetTile(
     MgResourceIdentifier* mapDefinition,
     CREFSTRING baseMapLayerGroupName,
@@ -59,26 +107,39 @@
     INT32 scaleIndex)
 {
     Ptr<MgByteReader> ret;
+    FILE* lockFile = NULL;
+    STRING tilePathname, lockPathname;
 
     MG_TRY()
 
     if (NULL == mapDefinition || baseMapLayerGroupName.empty())
     {
-        throw new MgNullArgumentException(
-            L"MgServerTileService.GetTile", __LINE__, __WFILE__, NULL, L"", NULL);
+        throw new MgNullArgumentException(L"MgServerTileService.GetTile",
+            __LINE__, __WFILE__, NULL, L"", NULL);
     }
 
+    if (scaleIndex < 0)
+    {
+        STRING buffer;
+        MgUtil::Int32ToString(scaleIndex, buffer);
+
+        MgStringCollection arguments;
+        arguments.Add(L"5");
+        arguments.Add(buffer);
+
+        throw new MgInvalidArgumentException(L"MgServerTileService.GetTile",
+            __LINE__, __WFILE__, &arguments, L"MgInvalidScaleIndex", NULL);
+    }
+
     MgServiceManager* serviceMan = MgServiceManager::GetInstance();
     assert(NULL != serviceMan);
 
     // Get the service from service manager
     Ptr<MgResourceService> resourceService = dynamic_cast<MgResourceService*>(
         serviceMan->RequestService(MgServiceType::ResourceService));
-    assert(resourceService != NULL);
+    assert(NULL != resourceService);
 
-    bool bAllowed = resourceService->HasPermission(mapDefinition, MgResourcePermission::ReadOnly);
-
-    if (!bAllowed)
+    if (!resourceService->HasPermission(mapDefinition, MgResourcePermission::ReadOnly))
     {
         MG_LOG_AUTHENTICATION_ENTRY(MgResources::PermissionDenied.c_str());
 
@@ -89,24 +150,72 @@
             L"MgServerTileService.GetTile",
             __LINE__, __WFILE__, &arguments, L"", NULL);
     }
-    
-    ret = m_tileCache->Get(mapDefinition, scaleIndex, baseMapLayerGroupName, tileColumn, tileRow);
 
-    if (!ret)
+    // Generate tile and lock pathnames.
+    m_tileCache->GeneratePathnames(mapDefinition, scaleIndex, baseMapLayerGroupName,
+        tileColumn, tileRow, tilePathname, lockPathname, false);
+
+    // If there is a dangling lock file, then attempt to remove it.
+    if (DetectTileLockFile(lockPathname))
     {
+        // TODO: Handle the exception by displaying a tile with an error message?
+        MgFileUtil::DeleteFile(lockPathname, true);
+    }
 
+    // try getting the tile from the cache
+    ret = m_tileCache->Get(tilePathname);
+
+    // if the reader is NULL then the tile wasn't in the cache and we
+    // need to generate it
+    while (NULL == ret)
+    {
         // Attempt use a cached & serialized MgMap object
         Ptr<MgMemoryStreamHelper> cachedMap;
-
         STRING mapString = mapDefinition->ToString();
-
         Ptr<MgMap> map;
 
         // Protect the serialized MgMap cache with a mutex.  Stream reading is not
         // thread safe so we need to deserialize the map within the mutex to ensure
         // that a Rewind() is not called in the middle of a Deserialize()
         {
+            // Attemp to lock the tile file.
             ACE_MT(ACE_GUARD_RETURN(ACE_Recursive_Thread_Mutex, ace_mon, sm_mutex, NULL));
+
+            // Bail out if the tile file has been locked for so long.
+            if (DetectTileLockFile(lockPathname))
+            {
+                MgStringCollection arguments;
+                arguments.Add(lockPathname);
+
+                throw new MgFileIoException(L"MgServerTileService.GetTile",
+                    __LINE__, __WFILE__, &arguments, L"MgUnableToLockTileFile", NULL);
+            }
+
+            // try getting the tile from the cache
+            ret = m_tileCache->Get(tilePathname);
+
+            if (NULL != ret)
+            {
+                break;
+            }
+
+            // Create the lock file and close it right away.
+            m_tileCache->CreateFullPath(mapDefinition, scaleIndex, baseMapLayerGroupName);
+            lockFile = ACE_OS::fopen(MG_WCHAR_TO_TCHAR(lockPathname), ACE_TEXT("wb"));
+
+            if (NULL == lockFile)
+            {
+                MgStringCollection arguments;
+                arguments.Add(lockPathname);
+
+                throw new MgFileIoException(L"MgServerTileService.GetTile",
+                    __LINE__, __WFILE__, &arguments, L"MgUnableToOpenTileFile", NULL);
+            }
+            else
+            {
+                ACE_OS::fclose(lockFile);
+            }
+
             MapCache::const_iterator iter = sm_mapCache.find(mapString);
             if (sm_mapCache.end() != iter)
             {
@@ -138,11 +247,21 @@
 
         double scale = map->GetFiniteDisplayScaleAt(scaleIndex);
         map->SetViewScale(scale);
-        ret = GetTile(map, baseMapLayerGroupName, tileColumn, tileRow);
+
+        // Render the tile and cache it.
+        ret = GetTile(tilePathname, map, scaleIndex, baseMapLayerGroupName, tileColumn, tileRow);
+        break;
     }
 
-    MG_CATCH_AND_THROW(L"MgServerTileService.GetTile")
+    MG_CATCH(L"MgServerTileService.GetTile")
 
+    if (NULL != lockFile)
+    {
+        MgFileUtil::DeleteFile(lockPathname, false);
+    }
+
+    MG_THROW()
+
     return ret.Detach();
 }
 
@@ -153,11 +272,16 @@
                                            INT32 tileRow)
 {
     Ptr<MgByteReader> ret;
+    FILE* lockFile = NULL;
+    STRING tilePathname, lockPathname;
 
     MG_TRY()
 
     if (NULL == map || baseMapLayerGroupName.empty())
-        throw new MgNullArgumentException(L"MgServerTileService.GetTile", __LINE__, __WFILE__, NULL, L"", NULL);
+    {
+        throw new MgNullArgumentException(L"MgServerTileService.GetTile",
+            __LINE__, __WFILE__, NULL, L"", NULL);
+    }
 
     // find the finite display scale closest to the requested map scale
     double scale = map->GetViewScale();
@@ -165,44 +289,119 @@
 
     // if we don't find a nearest scale then something is wrong with the map
     if (scaleIndex < 0)
-        throw new MgInvalidMapDefinitionException(L"MgServerTileService.GetTile", __LINE__, __WFILE__, NULL, L"", NULL);
+    {
+        throw new MgInvalidMapDefinitionException(L"MgServerTileService.GetTile",
+            __LINE__, __WFILE__, NULL, L"", NULL);
+    }
 
+    // Detect the lock file to see if another thread is creating the tile file.
+    m_tileCache->GeneratePathnames(map, scaleIndex, baseMapLayerGroupName,
+        tileColumn, tileRow, tilePathname, lockPathname, false);
+
+    // If there is a dangling lock file, then attempt to remove it.
+    if (DetectTileLockFile(lockPathname))
+    {
+        // TODO: Handle the exception by displaying a tile with an error message?
+        MgFileUtil::DeleteFile(lockPathname, true);
+    }
+
     // try getting the tile from the cache
-    ret = m_tileCache->Get(map, scaleIndex, baseMapLayerGroupName, tileColumn, tileRow);
+    ret = m_tileCache->Get(tilePathname);
 
     // if the reader is NULL then the tile wasn't in the cache and we
     // need to generate it
-    if (ret == NULL)
+    while (NULL == ret)
     {
-        // get a rendering service instance
-        MgServiceManager* serviceMan = MgServiceManager::GetInstance();
-        assert(NULL != serviceMan);
-        Ptr<MgRenderingService> svcRendering = dynamic_cast<MgRenderingService*>(
-            serviceMan->RequestService(MgServiceType::RenderingService));
-
-        if (svcRendering != NULL)
         {
-            // generate the tile
-            ret = svcRendering->RenderTile(map, baseMapLayerGroupName, tileColumn, tileRow);
+            // Attemp to lock the tile file.
+            ACE_MT(ACE_GUARD_RETURN(ACE_Recursive_Thread_Mutex, ace_mon, sm_mutex, NULL));
 
-            // cache the tile
-            if (!sm_renderOnly)
+            // Bail out if the tile file has been locked for so long.
+            if (DetectTileLockFile(lockPathname))
             {
-                SetTile(ret, map, scaleIndex, baseMapLayerGroupName, tileColumn, tileRow);
+                MgStringCollection arguments;
+                arguments.Add(lockPathname);
 
-                // rewind the reader since setting the tile advances it to the end
-                if (ret)
-                    ret->Rewind();
+                throw new MgFileIoException(L"MgServerTileService.GetTile",
+                    __LINE__, __WFILE__, &arguments, L"MgUnableToLockTileFile", NULL);
             }
+
+            // try getting the tile from the cache
+            ret = m_tileCache->Get(tilePathname);
+
+            if (NULL != ret)
+            {
+                break;
+            }
+
+            // Create the lock file and close it right away.
+            m_tileCache->CreateFullPath(map, scaleIndex, baseMapLayerGroupName);
+            lockFile = ACE_OS::fopen(MG_WCHAR_TO_TCHAR(lockPathname), ACE_TEXT("wb"));
+
+            if (NULL == lockFile)
+            {
+                MgStringCollection arguments;
+                arguments.Add(lockPathname);
+
+                throw new MgFileIoException(L"MgServerTileService.GetTile",
+                    __LINE__, __WFILE__, &arguments, L"MgUnableToOpenTileFile", NULL);
+            }
+            else
+            {
+                ACE_OS::fclose(lockFile);
+            }
         }
+
+        // Render the tile and cache it.
+        ret = GetTile(tilePathname, map, scaleIndex, baseMapLayerGroupName, tileColumn, tileRow);
+        break;
     }
 
-    MG_CATCH_AND_THROW(L"MgServerTileService.GetTile")
+    MG_CATCH(L"MgServerTileService.GetTile")
 
-    return SAFE_ADDREF(ret.p);
+    if (NULL != lockFile)
+    {
+        MgFileUtil::DeleteFile(lockPathname, false);
+    }
+
+    MG_THROW()
+
+    return ret.Detach();
 }
 
+MgByteReader* MgServerTileService::GetTile(CREFSTRING tilePathname, MgMap* map, INT32 scaleIndex,
+    CREFSTRING baseMapLayerGroupName, INT32 tileColumn, INT32 tileRow)
+{
+    Ptr<MgByteReader> img;
 
+    // get a rendering service instance
+    MgServiceManager* serviceMan = MgServiceManager::GetInstance();
+    assert(NULL != serviceMan);
+    Ptr<MgRenderingService> svcRendering = dynamic_cast<MgRenderingService*>(
+        serviceMan->RequestService(MgServiceType::RenderingService));
+    assert(NULL != svcRendering);
+
+    if (svcRendering != NULL)
+    {
+        // generate the tile
+        img = svcRendering->RenderTile(map, baseMapLayerGroupName, tileColumn, tileRow);
+
+        // cache the tile
+        if (!sm_renderOnly)
+        {
+            m_tileCache->Set(img, tilePathname);
+
+            // rewind the reader since setting the tile advances it to the end
+            if (img)
+            {
+                img->Rewind();
+            }
+        }
+    }
+
+    return img.Detach();
+}
+
 void MgServerTileService::SetTile(MgByteReader* img,
                                   MgMap* map,
                                   INT32 scaleIndex,
@@ -210,10 +409,16 @@
                                   INT32 tileColumn,
                                   INT32 tileRow)
 {
+    FILE* lockFile = NULL;
+    STRING tilePathname, lockPathname;
+
     MG_TRY()
 
     if (NULL == img || NULL == map || baseMapLayerGroupName.empty())
-        throw new MgNullArgumentException(L"MgServerTileService.SetTile", __LINE__, __WFILE__, NULL, L"", NULL);
+    {
+        throw new MgNullArgumentException(L"MgServerTileService.SetTile",
+            __LINE__, __WFILE__, NULL, L"", NULL);
+    }
 
     if (scaleIndex < 0)
     {
@@ -228,10 +433,48 @@
             __LINE__, __WFILE__, &arguments, L"MgInvalidScaleIndex", NULL);
     }
 
+    // Generate tile and lock pathnames.
+    m_tileCache->GeneratePathnames(map, scaleIndex, baseMapLayerGroupName,
+        tileColumn, tileRow, tilePathname, lockPathname, true);
+
+    {
+        // Attemp to lock the tile file.
+        ACE_MT(ACE_GUARD(ACE_Recursive_Thread_Mutex, ace_mon, sm_mutex));
+
+        if (DetectTileLockFile(lockPathname))
+        {
+            // Attemp to remove a dangling lock file.
+            MgFileUtil::DeleteFile(lockPathname, true);
+        }
+
+        // Create the lock file and close it right away.
+        lockFile = ACE_OS::fopen(MG_WCHAR_TO_TCHAR(lockPathname), ACE_TEXT("wb"));
+
+        if (NULL == lockFile)
+        {
+            MgStringCollection arguments;
+            arguments.Add(lockPathname);
+
+            throw new MgFileIoException(L"MgServerTileService.SetTile",
+                __LINE__, __WFILE__, &arguments, L"MgUnableToOpenTileFile", NULL);
+        }
+        else
+        {
+            ACE_OS::fclose(lockFile);
+        }
+    }
+
     // cache the tile
-    m_tileCache->Set(img, map, scaleIndex, baseMapLayerGroupName, tileColumn, tileRow);
+    m_tileCache->Set(img, tilePathname);
 
-    MG_CATCH_AND_THROW(L"MgServerTileService.SetTile")
+    MG_CATCH(L"MgServerTileService.SetTile")
+
+    if (NULL != lockFile)
+    {
+        MgFileUtil::DeleteFile(lockPathname, false);
+    }
+
+    MG_THROW()
 }
 
 

Modified: trunk/MgDev/Server/src/Services/Tile/ServerTileService.h
===================================================================
--- trunk/MgDev/Server/src/Services/Tile/ServerTileService.h	2007-02-02 17:55:19 UTC (rev 1089)
+++ trunk/MgDev/Server/src/Services/Tile/ServerTileService.h	2007-02-03 01:06:39 UTC (rev 1090)
@@ -56,17 +56,24 @@
 
 private:
 
+    bool DetectTileLockFile(CREFSTRING lockPathname);
+
+    MgByteReader* GetTile(CREFSTRING tilePathname, MgMap* map, INT32 scaleIndex,
+        CREFSTRING baseMapLayerGroupName, INT32 tileColumn, INT32 tileRow);
+
     void ClearMapCache(CREFSTRING mapName);
 
     // member data
     Ptr<MgTileCache> m_tileCache;
 
     typedef std::map<STRING, MgMemoryStreamHelper*> MapCache;
+
+    static ACE_Recursive_Thread_Mutex sm_mutex;
     static MapCache sm_mapCache;
-    static ACE_Recursive_Thread_Mutex sm_mutex;
+    static INT32 sm_creationCutoffTime;
+    static INT32 sm_pollingInterval;
+    static bool sm_renderOnly;
     static INT32 sm_mapCacheSize;
-    static bool sm_renderOnly;
-
 };
 
 #endif

Modified: trunk/MgDev/Server/src/Services/Tile/TileCache.cpp
===================================================================
--- trunk/MgDev/Server/src/Services/Tile/TileCache.cpp	2007-02-02 17:55:19 UTC (rev 1089)
+++ trunk/MgDev/Server/src/Services/Tile/TileCache.cpp	2007-02-03 01:06:39 UTC (rev 1090)
@@ -18,124 +18,133 @@
 #include "MapGuideCommon.h"
 #include "TileCache.h"
 
-#define PATH_LEN 512
+STRING MgTileCache::sm_lockFolderName = L"Lock";    // name of file folder for locks
+STRING MgTileCache::sm_path = L"";
 
-STRING MgTileCache::m_path = L"";
-
 // default constructor
 MgTileCache::MgTileCache()
 {
-    //TODO: It is possible to get a double write on m_path here.  We need
+    //TODO: It is possible to get a double write on sm_path here.  We need
     //to investigate general mutex use in this class.
-    if (m_path.empty())
+    if (sm_path.empty())
     {
         // initialize the tile cache path
         MgConfiguration* pConf = MgConfiguration::GetInstance();
 
-        pConf->GetStringValue(MgConfigProperties::TileServicePropertiesSection,
-                              MgConfigProperties::TileServicePropertyTileCachePath,
-                              m_path,
-                              MgConfigProperties::DefaultTileServicePropertyTileCachePath);
+        pConf->GetStringValue(
+            MgConfigProperties::TileServicePropertiesSection,
+            MgConfigProperties::TileServicePropertyLockFolderName,
+            sm_lockFolderName,
+            MgConfigProperties::DefaultTileServicePropertyLockFolderName);
 
+        pConf->GetStringValue(
+            MgConfigProperties::TileServicePropertiesSection,
+            MgConfigProperties::TileServicePropertyTileCachePath,
+            sm_path,
+            MgConfigProperties::DefaultTileServicePropertyTileCachePath);
+
         // generate directory location for tile cache
-        MgFileUtil::AppendSlashToEndOfPath(m_path);
+        MgFileUtil::AppendSlashToEndOfPath(sm_path);
 
         // create directory if it is not already there
-        if (!MgFileUtil::PathnameExists(m_path))
-            MgFileUtil::CreateDirectory(m_path, false);
+        if (!MgFileUtil::PathnameExists(sm_path))
+            MgFileUtil::CreateDirectory(sm_path, false);
     }
 }
 
-
-// returns any cached tile for the given map / scale index / group / i / j
-MgByteReader* MgTileCache::Get(MgMap* map, int scaleIndex, CREFSTRING group, int i, int j)
+///////////////////////////////////////////////////////////////////////////////
+/// \brief
+/// Generate tile and lock pathnames.
+///
+void MgTileCache::GeneratePathnames(MgResourceIdentifier* mapDef, int scaleIndex,
+    CREFSTRING group, int tileColumn, int tileRow,
+    STRING& tilePathname, STRING& lockPathname, bool createFullPath)
 {
-    // acquire a read lock - this blocks if a writer holds the lock
-    ACE_Read_Guard<ACE_RW_Thread_Mutex> ace_mon(m_mutexRW);
+    wchar_t fileName[MAXPATHLEN] = { 0 };
+    ::swprintf(fileName, MAXPATHLEN, L"/%d_%d.", tileRow, tileColumn);
 
-    Ptr<MgByteReader> ret;
+    lockPathname = GetBasePath(mapDef);
+    tilePathname;
 
-    if (map != NULL)
+    if (createFullPath)
     {
-        STRING tilePath = MgTileCache::GetFullPath(map, scaleIndex, group);
+        tilePathname = CreateFullPath(lockPathname, scaleIndex, group);
+    }
+    else
+    {
+        tilePathname = GetFullPath(lockPathname, scaleIndex, group);
+    }
 
-        // generate full path to tile file using <row,column> format
-        // TODO: handle case where path is > PATH_LEN
-        wchar_t tmp[PATH_LEN] = { 0 };
-        swprintf(tmp, PATH_LEN, L"%ls/%d_%d.png", tilePath.c_str(), j, i);
+    // Generate the tile pathname using format "%ls/%d_%d.png":
+    //     <tilePathname> = <fullPath>/<row>_<column>.png
+    tilePathname += fileName;
+    tilePathname += L"png";
 
-        // check if the tile exists
-        if (MgFileUtil::PathnameExists(tmp))
-        {
-            Ptr<MgByteSource> bs = new MgByteSource(tmp, false);
-            bs->SetMimeType(MgMimeType::Png);
-            ret = bs->GetReader();
-        }
-    }
+    // Generate the lock pathname using format "%ls/%d_%d.lck":
+    //     <lockPathname> = <basePath>/<row>_<column>.lck
+    lockPathname += L"/";
+    lockPathname += sm_lockFolderName;
+    lockPathname += fileName;
+    lockPathname += L"lck";
+}
 
-    return SAFE_ADDREF(ret.p);
+void MgTileCache::GeneratePathnames(MgMap* map, int scaleIndex,
+    CREFSTRING group, int tileColumn, int tileRow,
+    STRING& tilePathname, STRING& lockPathname, bool createFullPath)
+{
+    assert(NULL != map);
+    Ptr<MgResourceIdentifier> mapDef = map->GetMapDefinition();
+
+    GeneratePathnames(mapDef, scaleIndex, group, tileColumn, tileRow,
+        tilePathname, lockPathname, createFullPath);
 }
 
-MgByteReader* MgTileCache::Get(MgResourceIdentifier* mapDef, int scaleIndex, CREFSTRING group, int i, int j)
+// returns any cached tile for the given pathname
+MgByteReader* MgTileCache::Get(CREFSTRING tilePathname)
 {
     // acquire a read lock - this blocks if a writer holds the lock
-    ACE_Read_Guard<ACE_RW_Thread_Mutex> ace_mon(m_mutexRW);
+    ACE_Read_Guard<ACE_RW_Thread_Mutex> ace_mon(m_rwMutex);
 
     Ptr<MgByteReader> ret;
 
-    if (mapDef != NULL)
+    MG_TRY()
+
+    if (MgFileUtil::PathnameExists(tilePathname))
     {
-        STRING tilePath = MgTileCache::GetFullPath(mapDef, scaleIndex, group);
+        Ptr<MgByteSource> byteSource = new MgByteSource(tilePathname, false);
 
-        // generate full path to tile file using <row,column> format
-        // TODO: handle case where path is > PATH_LEN
-        wchar_t tmp[PATH_LEN] = { 0 };
-        swprintf(tmp, PATH_LEN, L"%ls/%d_%d.png", tilePath.c_str(), j, i);
+        byteSource->SetMimeType(MgMimeType::Png);
+        ret = byteSource->GetReader();
+    }
 
-        MG_TRY()
+    MG_CATCH_AND_RELEASE()
 
-        Ptr<MgByteSource> bs = new MgByteSource(tmp, false);
-        bs->SetMimeType(MgMimeType::Png);
-        ret = bs->GetReader();
-
-        MG_CATCH_AND_RELEASE()
-    }
-
-    return SAFE_ADDREF(ret.p);
+    return ret.Detach();
 }
 
-
-// caches a tile for the given map / scale index / group / i / j
-void MgTileCache::Set(MgByteReader* img, MgMap* map, int scaleIndex, CREFSTRING group, int i, int j)
+// caches a tile for the given pathname
+void MgTileCache::Set(MgByteReader* img, CREFSTRING tilePathname)
 {
     // acquire a write lock - this blocks if any readers or a writer hold the lock
-    ACE_Write_Guard<ACE_RW_Thread_Mutex> ace_mon(m_mutexRW);
+    ACE_Write_Guard<ACE_RW_Thread_Mutex> ace_mon(m_rwMutex);
 
-    if (map != NULL && img != NULL)
+    if (img != NULL)
     {
-        // ensure the necessary directories are created
-        STRING tilePath = MgTileCache::CreateFullPath(map, scaleIndex, group);
+        Ptr<MgByteSink> byteSink = new MgByteSink(img);
 
-        // generate full path to tile file using <row,column> format
-        // TODO: handle case where path is > PATH_LEN
-        wchar_t tmp[PATH_LEN] = { 0 };
-        swprintf(tmp, PATH_LEN, L"%ls/%d_%d.png", tilePath.c_str(), j, i);
-
-        // save the file
-        (MgByteSink(img)).ToFile(tmp);
+        byteSink->ToFile(tilePathname);
     }
 }
 
-
 // clears the tile cache for the given map
 void MgTileCache::Clear(MgMap* map)
 {
     // acquire a write lock - this blocks if any readers or a writer hold the lock
-    ACE_Write_Guard<ACE_RW_Thread_Mutex> ace_mon(m_mutexRW);
+    ACE_Write_Guard<ACE_RW_Thread_Mutex> ace_mon(m_rwMutex);
 
     if (map != NULL)
     {
-        STRING basePath = MgTileCache::GetBasePath(map);
+        STRING basePath = GetBasePath(map);
 
         // delete main map directory
         if (!basePath.empty())
@@ -143,17 +152,16 @@
     }
 }
 
-
 // clears the tile cache for the given map
-void MgTileCache::Clear(MgResourceIdentifier* resId)
+void MgTileCache::Clear(MgResourceIdentifier* mapDef)
 {
     // acquire a write lock - this blocks if any readers or a writer hold the lock
-    ACE_Write_Guard<ACE_RW_Thread_Mutex> ace_mon(m_mutexRW);
+    ACE_Write_Guard<ACE_RW_Thread_Mutex> ace_mon(m_rwMutex);
 
     // the resource must be a map definition
-    if (resId != NULL && resId->GetResourceType() == MgResourceType::MapDefinition)
+    if (mapDef != NULL && mapDef->GetResourceType() == MgResourceType::MapDefinition)
     {
-        STRING basePath = MgTileCache::GetBasePath(resId);
+        STRING basePath = GetBasePath(mapDef);
 
         // delete main map directory
         if (!basePath.empty())
@@ -161,41 +169,35 @@
     }
 }
 
-
-// gets the base path to use with the tile cache for the given map
-STRING MgTileCache::GetBasePath(MgMap* map)
-{
-    Ptr<MgResourceIdentifier> resId = map->GetMapDefinition();
-    return GetBasePath(resId);
-}
-
-
 // gets the base path to use with the tile cache for the given map definition resource
-STRING MgTileCache::GetBasePath(MgResourceIdentifier* resId)
+STRING MgTileCache::GetBasePath(MgResourceIdentifier* mapDef)
 {
+    assert(mapDef != NULL);
+    assert(mapDef->GetResourceType() == MgResourceType::MapDefinition);
     STRING mapPath;
 
-    // safety check
-    assert(resId != NULL);
-    if (resId == NULL)
-        return mapPath;
-
-    // we should only be dealing with map definitions
-    assert(resId->GetResourceType() == MgResourceType::MapDefinition);
-
-    if (resId->GetRepositoryType() == MgRepositoryType::Library)
+    if (mapDef->GetRepositoryType() == MgRepositoryType::Library)
     {
         // for maps in the library repository the path+name is unique
-        mapPath  = resId->GetPath();
+        mapPath  = mapDef->GetPath();
         mapPath += L"_";
-        mapPath += resId->GetName();
+        mapPath += mapDef->GetName();
     }
-    else if (resId->GetRepositoryType() == MgRepositoryType::Session)
+    else if (mapDef->GetRepositoryType() == MgRepositoryType::Session)
     {
-        // for maps in the session repository we use the session name + map name
-        mapPath  = resId->GetRepositoryName();
+        // for maps in the session repository we use the session + path + map name
+        mapPath  = mapDef->GetRepositoryName();
         mapPath += L"_";
-        mapPath += resId->GetName();
+
+        STRING resourcePath  = mapDef->GetPath();
+
+        if (!resourcePath.empty())
+        {
+            mapPath += resourcePath;
+            mapPath += L"_";
+        }
+
+        mapPath += mapDef->GetName();
     }
     else
     {
@@ -208,56 +210,90 @@
     mapPath = MgUtil::ReplaceString(mapPath, L"/", L"_");
     mapPath = MgUtil::ReplaceString(mapPath, L":", L"_");
 
-    // build the base path
-    wchar_t tmp[PATH_LEN] = { 0 };
-    swprintf(tmp, PATH_LEN, L"%ls%ls", m_path.c_str(), mapPath.c_str());
+    // Build the base path using format "%ls%ls":
+    //     <basePath> = <tileCachePath><mapPath>
+    STRING basePath = sm_path;
+    basePath += mapPath;
 
-    return STRING(tmp);
+    return basePath;
 }
 
+// gets the base path to use with the tile cache for the given map
+STRING MgTileCache::GetBasePath(MgMap* map)
+{
+    assert(NULL != map);
+    Ptr<MgResourceIdentifier> mapDef = map->GetMapDefinition();
+    return GetBasePath(mapDef);
+}
 
-// gets the full path to use with the tile cache for the given map / scale index / group
-STRING MgTileCache::GetFullPath(MgMap* map, int scaleIndex, CREFSTRING group)
+// gets the full path to use with the tile cache for the given base path / scale index / group
+STRING MgTileCache::GetFullPath(CREFSTRING basePath, int scaleIndex, CREFSTRING group)
 {
-    STRING basePath = MgTileCache::GetBasePath(map);
+    // Build full path using format "%ls/%d/%ls":
+    //     <fullPath> = <basePath>/<scaleIndex>/<group>
+    assert(!basePath.empty());
+    STRING fullPath = basePath;
+    STRING buffer;
+    MgUtil::Int32ToString(scaleIndex, buffer);
 
-    wchar_t tmp[PATH_LEN] = { 0 };
-    swprintf(tmp, PATH_LEN, L"%ls/%d/%ls", basePath.c_str(), scaleIndex, group.c_str());
+    fullPath += L"/";
+    fullPath += buffer;
+    fullPath += L"/";
+    fullPath += group;
 
-    return STRING(tmp);
+    return fullPath;
 }
 
-// gets the full path to use with the tile cache for the given map / scale index / group
+// gets the full path to use with the tile cache for the given map definition / scale index / group
 STRING MgTileCache::GetFullPath(MgResourceIdentifier* mapDef, int scaleIndex, CREFSTRING group)
 {
-    STRING basePath = MgTileCache::GetBasePath(mapDef);
+    return GetFullPath(GetBasePath(mapDef), scaleIndex, group);
+}
 
-    wchar_t tmp[PATH_LEN] = { 0 };
-    swprintf(tmp, PATH_LEN, L"%ls/%d/%ls", basePath.c_str(), scaleIndex, group.c_str());
-
-    return STRING(tmp);
+// gets the full path to use with the tile cache for the given map / scale index / group
+STRING MgTileCache::GetFullPath(MgMap* map, int scaleIndex, CREFSTRING group)
+{
+    assert(NULL != map);
+    Ptr<MgResourceIdentifier> mapDef = map->GetMapDefinition();
+    return GetFullPath(mapDef, scaleIndex, group);
 }
 
-
-STRING MgTileCache::CreateFullPath(MgMap* map, int scaleIndex, CREFSTRING group)
+STRING MgTileCache::CreateFullPath(CREFSTRING basePath, int scaleIndex, CREFSTRING group)
 {
-    wchar_t tmp[PATH_LEN] = { 0 };
+    assert(!basePath.empty());
+    STRING fullPath = basePath;
 
-    if (map != NULL)
-    {
-        STRING basePath = MgTileCache::GetBasePath(map);
+    // Create base directory if it does not exist.
+    MgFileUtil::CreateDirectory(fullPath, false);
+    fullPath += L"/";
 
-        // check main map directory
-        MgFileUtil::CreateDirectory(basePath, false);
+    // Create lock directory if it does not exist.
+    STRING lockPath = fullPath;
 
-        // check scale directory
-        swprintf(tmp, PATH_LEN, L"%ls/%d", basePath.c_str(), scaleIndex);
-        MgFileUtil::CreateDirectory(tmp, false);
+    lockPath += sm_lockFolderName;
+    MgFileUtil::CreateDirectory(lockPath, false);
 
-        // check group directory
-        swprintf(tmp, PATH_LEN, L"%ls/%d/%ls", basePath.c_str(), scaleIndex, group.c_str());
-        MgFileUtil::CreateDirectory(tmp, false);
-    }
+    // Create scale directory if it does not exist.
+    STRING buffer;
+    MgUtil::Int32ToString(scaleIndex, buffer);
 
-    return STRING(tmp);
+    fullPath += buffer;
+    MgFileUtil::CreateDirectory(fullPath, false);
+
+    // Create group directory if it does not exist.
+    fullPath += L"/";
+    fullPath += group;
+    MgFileUtil::CreateDirectory(fullPath, false);
+
+    return fullPath;
 }
+
+STRING MgTileCache::CreateFullPath(MgResourceIdentifier* mapDef, int scaleIndex, CREFSTRING group)
+{
+    return CreateFullPath(GetBasePath(mapDef), scaleIndex, group); 
+}
+
+STRING MgTileCache::CreateFullPath(MgMap* map, int scaleIndex, CREFSTRING group)
+{
+    return CreateFullPath(GetBasePath(map), scaleIndex, group); 
+}

Modified: trunk/MgDev/Server/src/Services/Tile/TileCache.h
===================================================================
--- trunk/MgDev/Server/src/Services/Tile/TileCache.h	2007-02-02 17:55:19 UTC (rev 1089)
+++ trunk/MgDev/Server/src/Services/Tile/TileCache.h	2007-02-03 01:06:39 UTC (rev 1090)
@@ -26,11 +26,21 @@
 public:
     MgTileCache();
 
-    MgByteReader* Get(MgMap* map, int scaleIndex, CREFSTRING group, int i, int j);
-    MgByteReader* Get(MgResourceIdentifier* mapDef, int scaleIndex, CREFSTRING group, int i, int j);
-    void Set(MgByteReader* img, MgMap* map, int scaleIndex, CREFSTRING group, int i, int j);
+    void GeneratePathnames(MgResourceIdentifier* mapDef, int scaleIndex,
+        CREFSTRING group, int tileColumn, int tileRow,
+        STRING& tilePathname, STRING& lockPathname, bool createFullPath);
+    void GeneratePathnames(MgMap* map, int scaleIndex,
+        CREFSTRING group, int tileColumn, int tileRow,
+        STRING& tilePathname, STRING& lockPathname, bool createFullPath);
+
+    STRING CreateFullPath(MgResourceIdentifier* mapDef, int scaleIndex, CREFSTRING group);
+    STRING CreateFullPath(MgMap* map, int scaleIndex, CREFSTRING group);
+
+    MgByteReader* Get(CREFSTRING tilePathname);
+    void Set(MgByteReader* img, CREFSTRING tilePathname);
+
     void Clear(MgMap* map);
-    void Clear(MgResourceIdentifier* resId);
+    void Clear(MgResourceIdentifier* mapDef);
 
 protected:
     virtual void Dispose()
@@ -39,17 +49,22 @@
     }
 
 private:
+    // Unimplemented Constructors/Methods
+    MgTileCache(const MgTileCache&);
+    MgTileCache& operator=(const MgTileCache&);
+
+    STRING GetBasePath(MgResourceIdentifier* mapDef);
     STRING GetBasePath(MgMap* map);
-    STRING GetBasePath(MgResourceIdentifier* resId);
+
+    STRING GetFullPath(CREFSTRING basePath, int scaleIndex, CREFSTRING group);
+    STRING GetFullPath(MgResourceIdentifier* mapDef, int scaleIndex, CREFSTRING group);
     STRING GetFullPath(MgMap* map, int scaleIndex, CREFSTRING group);
-    STRING GetFullPath(MgResourceIdentifier* mapDef, int scaleIndex, CREFSTRING group);
-    STRING CreateFullPath(MgMap* map, int scaleIndex, CREFSTRING group);
 
-    // TODO: Investigate this mutex.  It may fail if
-    // we have more than one tile service and could reduce
-    // multi-threaded performance.  File locks would be better.
-    ACE_RW_Thread_Mutex m_mutexRW;
-    static STRING m_path;
+    STRING CreateFullPath(CREFSTRING basePath, int scaleIndex, CREFSTRING group);
+
+    ACE_RW_Thread_Mutex m_rwMutex;
+    static STRING sm_path;
+    static STRING sm_lockFolderName;
 };
 
 #endif

Modified: trunk/MgDev/Server/src/UnitTesting/TestTileService.cpp
===================================================================
--- trunk/MgDev/Server/src/UnitTesting/TestTileService.cpp	2007-02-02 17:55:19 UTC (rev 1089)
+++ trunk/MgDev/Server/src/UnitTesting/TestTileService.cpp	2007-02-03 01:06:39 UTC (rev 1090)
@@ -280,6 +280,7 @@
     {
         STRING message = e->GetDetails(TEST_LOCALE);
         SAFE_RELEASE(e);
+        CPPUNIT_FAIL(MG_WCHAR_TO_CHAR(message.c_str()));
     }
     catch (...)
     {
@@ -702,14 +703,7 @@
 void TestTileService::TestCase_GetSetTile()
 {
     // specify the number of threads to use
-#ifdef _WIN32
-    // TODO: Investigate threading problem on Windows 2003 (dual core CPU).
-    //       There may be some issue with ByteSourceFileImpl::LoadFile (i.e. Is errno thread safe?).
-    const INT32 numThreads = 1;
-#else
     const INT32 numThreads = MG_TEST_THREADS;
-#endif
-
     ThreadData threadData[numThreads];
 
     // define the range of tiles to get and set



More information about the mapguide-commits mailing list