MapGuide RFC # 151 - Add Layer Definition Cache
This page contains a change request (RFC) for the MapGuide Open Source project. More MapGuide RFCs can be found on the RFCs page.
Status
RFC Template Version | (1.0) |
Submission Date | 20 Sep. 2015 |
Last Modified | 20 Sep. 2015 |
Author | Andy Zhang |
RFC Status | draft |
Implementation Status | under development |
Proposed Milestone | 3.1 |
Assigned PSC guide(s) | (when determined) |
Voting History | (vote date) |
+1 | |
+0 | |
-0 | |
-1 | |
no vote |
Overview
This RFC proposed to add layer definition cache. The performance of rendering map can be improved a lot by caching layer definitions.
Motivation
When stylizing layers, MapGuide Server gets the XML document of the layer from XML database and converts the XML document to MdfModel::LayerDefinition for each layer. It is an expensive operation especially for complicate layers. For a map which has a lot of complicate layers, this operation accounts for about 5~10% of total time of stylizing layers. If we can cache the layer definitions, the performance of rendering map can be improved a lot.
Proposed Solution
The solution is similar as current feature service cache. New classes MgResourceServiceCache, MgResourceServiceCacheEntry, MgResourceLayerDefinitionCacheItem and MgResourceServiceCacheTimeLimitEventHandler are added.
class MG_SERVER_CACHE_API MgResourceServiceCache : public MgServerCache { DECLARE_CLASSNAME(MgResourceServiceCache) /// Constructors/Destructor public: MgResourceServiceCache(void); ~MgResourceServiceCache(void); private: // Unimplemented copy constructor and assignment operator. MgResourceServiceCache(const MgResourceServiceCache&); MgResourceServiceCache& operator=(const MgResourceServiceCache&); /// Methods public: virtual void Clear(); void RemoveEntry(CREFSTRING resource); void RemoveEntry(MgResourceIdentifier* resource); void RemoveExpiredEntries(); // gets/sets layer definitions void SetLayerDefinition(MgResourceIdentifier* resource, MgResourceLayerDefinitionCacheItem* layerDefinition); MgResourceLayerDefinitionCacheItem* GetLayerDefinition(MgResourceIdentifier* source); INT32 GetCacheSize(); INT32 GetDroppedEntriesCount(); protected: void Compact(); MgResourceServiceCacheEntry* SetEntry(MgResourceIdentifier* resource); MgResourceServiceCacheEntry* GetEntry(MgResourceIdentifier* resource); void RemoveOldEntry(); /// Data Members private: friend class MgCacheManager; typedef std::map<STRING, MgResourceServiceCacheEntry*> MgResourceServiceCacheEntries; MgResourceServiceCacheEntries m_resourceServiceCacheEntries; INT32 m_nDroppedEntries; };
class MG_SERVER_CACHE_API MgResourceServiceCacheEntry : public MgServerCacheEntry { /// Constructors/Destructor public: MgResourceServiceCacheEntry(void); virtual ~MgResourceServiceCacheEntry(void); private: // Unimplemented copy constructor and assignment operator. MgResourceServiceCacheEntry(const MgResourceServiceCacheEntry&); MgResourceServiceCacheEntry& operator=(const MgResourceServiceCacheEntry&); /// Methods public: void SetLayerDefinition(MgResourceLayerDefinitionCacheItem* layerDefinition); MgResourceLayerDefinitionCacheItem* GetLayerDefinition(); private: Ptr<MgResourceLayerDefinitionCacheItem> m_layerDefinition; };
class MG_SERVER_CACHE_API MgResourceLayerDefinitionCacheItem : public MgServerCacheItem { /// Constructors/Destructor public: MgResourceLayerDefinitionCacheItem(void); explicit MgResourceLayerDefinitionCacheItem(MdfModel::LayerDefinition* LayerDefinition); virtual ~MgResourceLayerDefinitionCacheItem(void); private: // Unimplemented copy constructor and assignment operator. MgResourceLayerDefinitionCacheItem(const MgResourceLayerDefinitionCacheItem&); MgResourceLayerDefinitionCacheItem& operator=(const MgResourceLayerDefinitionCacheItem&); /// Methods public: MdfModel::LayerDefinition* Get(); void Set(MdfModel::LayerDefinition* layerDefinition); /// Data Members private: auto_ptr<MdfModel::LayerDefinition> m_layerDefinition; };
/////////////////////////////////////////////////////////////////////////////// /// \brief /// Derived Event Handler class to clean up inactive resource service cache items. /// class MgResourceServiceCacheTimeLimitEventHandler : public MgTimedEventHandler { /// Constructors/Destructor public: MgResourceServiceCacheTimeLimitEventHandler(MgEventTimer& timer); virtual ~MgResourceServiceCacheTimeLimitEventHandler(); private: // Unimplemented Constructors/Methods MgResourceServiceCacheTimeLimitEventHandler(); MgResourceServiceCacheTimeLimitEventHandler(const MgResourceServiceCacheTimeLimitEventHandler&); MgResourceServiceCacheTimeLimitEventHandler& operator=(const MgResourceServiceCacheTimeLimitEventHandler&); /// Methods protected: virtual void HandleEvent(long eventId); /// Data Members private: };
3 new configuration entries are added to ResourceServiceProperties section.
# CacheSize Max # of internal data objects (layer definitions) to cache # 0 < Value <= 5000 # CacheTimeLimit Time duration in seconds for how long to # cache the internal data objects # 0 < Value <= 2147483647 # CacheTimerInterval Time interval in seconds for when the server # checks for expired cache entries # 0 < Value <= 2147483647 [ResourceServiceProperties] CacheSize = 1000 CacheTimeLimit = 86400 CacheTimerInterval = 3600
There are also some changes in MgCacheManager. A private variable m_resourceServerCache and 2 methods are added.
class MG_SERVER_MANAGER_API MgCacheManager : public MgGuardDisposable { ... public: // get resource service cache MgResourceServiceCache* GetResourceServiceCache(); MgResourceLayerDefinitionCacheItem* GetResourceLayerDefinitionCacheItem(MgResourceIdentifier* resource); ... private: ... MgResourceServiceCache m_resourceServiceCache; };
We get layer definition from the cache first. If it is not found, get the layer definition from XML database.
MgResourceLayerDefinitionCacheItem* MgCacheManager::GetResourceLayerDefinitionCacheItem(MgResourceIdentifier* resource) { Ptr<MgResourceLayerDefinitionCacheItem> cacheItem; MG_TRY() cacheItem = m_resourceServiceCache.GetLayerDefinition(resource); if (NULL == cacheItem.p) { // Get the Resource Service. Ptr<MgResourceService> resourceService = dynamic_cast<MgResourceService*>( m_serviceManager->RequestService(MgServiceType::ResourceService)); ACE_ASSERT(NULL != resourceService.p); auto_ptr<MdfModel::LayerDefinition> layerDefinition; layerDefinition.reset(MgLayerBase::GetLayerDefinition(resourceService, resource)); if (NULL == layerDefinition.get()) { MgResources* resources = MgResources::GetInstance(); ACE_ASSERT(NULL != resources); STRING message = resources->GetResourceMessage(MgResources::ResourceService, L"MgInvalidLayerDefinition", NULL); MgStringCollection arguments; arguments.Add(message); throw new MgInvalidFeatureSourceException( L"MgCacheManager.GetResourceLayerDefinitionCacheItem", __LINE__, __WFILE__, &arguments, L"", NULL); } cacheItem = new MgResourceLayerDefinitionCacheItem(layerDefinition.release()); m_resourceServiceCache.SetLayerDefinition(resource, cacheItem.p); } else { CheckPermission(resource, MgResourcePermission::ReadOnly); } MG_CATCH_AND_THROW(L"MgCacheManager.GetResourceLayerDefinitionCacheItem") return cacheItem.Detach(); }
If the resource is changed, remove the entry from the cache.
void MgCacheManager::NotifyResourceChanged(CREFSTRING resource) { ...... if (STRING::npos != resource.rfind(MgResourceType::LayerDefinition)) { ACE_MT(ACE_GUARD(ACE_Recursive_Thread_Mutex, ace_mon, m_resourceServiceCache.m_mutex)); m_resourceServiceCache.RemoveEntry(resource); } }
Now, we get the MdfModel::LayerDefinition of a layer from the cache manager:
//get layer definition Ptr<MgResourceIdentifier> layerid = mapLayer->GetLayerDefinition(); MgCacheManager* cacheManager = MgCacheManager::GetInstance(); Ptr<MgResourceLayerDefinitionCacheItem> cacheItem = cacheManager->GetResourceLayerDefinitionCacheItem(layerid); MdfModel::LayerDefinition* layerDefinition = cacheItem->Get(); ... MdfModel::VectorLayerDefinition* vl = dynamic_cast<MdfModel::VectorLayerDefinition*>(layerDefinition); ...
Implications
Now implications are intended as it is an internal implementation change. We just get better performance when rendering maps.
Test Plan
So far I don’t plan to add new unit tests for this change.
Funding / Resources
Autodesk