= !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 [wiki:MapGuideRfcs 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 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 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 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 cacheItem; MG_TRY() cacheItem = m_resourceServiceCache.GetLayerDefinition(resource); if (NULL == cacheItem.p) { // Get the Resource Service. Ptr resourceService = dynamic_cast( m_serviceManager->RequestService(MgServiceType::ResourceService)); ACE_ASSERT(NULL != resourceService.p); auto_ptr 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 layerid = mapLayer->GetLayerDefinition(); MgCacheManager* cacheManager = MgCacheManager::GetInstance(); Ptr cacheItem = cacheManager->GetResourceLayerDefinitionCacheItem(layerid); MdfModel::LayerDefinition* layerDefinition = cacheItem->Get(); ... MdfModel::VectorLayerDefinition* vl = dynamic_cast(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