wiki:MapGuideRfc151

Version 2 (modified by zhanga, 9 years ago) ( diff )

--

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 Date20 Sep. 2015
Last Modified20 Sep. 2015
AuthorAndy Zhang
RFC Statusdraft
Implementation Statusunder development
Proposed Milestone3.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

Note: See TracWiki for help on using the wiki.