Skip to content
Permalink
Browse files

Remove oldest entries from svg cache if cache size is too large

  • Loading branch information
mhugent committed Jun 28, 2011
1 parent 166b3d2 commit 05b418317304df218fc3d8ad738a0c51db2db65a
Showing with 127 additions and 17 deletions.
  1. +102 −14 src/core/symbology-ng/qgssvgcache.cpp
  2. +25 −3 src/core/symbology-ng/qgssvgcache.h
@@ -48,6 +48,20 @@ bool QgsSvgCacheEntry::operator==( const QgsSvgCacheEntry& other ) const
&& other.rasterScaleFactor == rasterScaleFactor && other.fill == fill && other.outline == outline );
}

int QgsSvgCacheEntry::dataSize() const
{
int size = svgContent.size();
if ( picture )
{
size += picture->size();
}
if ( image )
{
size += ( image->width() * image->height() * 32 );
}
return size;
}

QString file;
double size;
double outlineWidth;
@@ -67,7 +81,7 @@ QgsSvgCache* QgsSvgCache::instance()
return mInstance;
}

QgsSvgCache::QgsSvgCache(): mTotalSize( 0 )
QgsSvgCache::QgsSvgCache(): mTotalSize( 0 ), mLeastRecentEntry( 0 ), mMostRecentEntry( 0 )
{
}

@@ -91,14 +105,9 @@ const QImage& QgsSvgCache::svgAsImage( const QString& file, double size, const Q
if ( !currentEntry->image )
{
cacheImage( currentEntry );
trimToMaximumSize();
}

//debug: display current cache usage
QgsDebugMsg( "cache size: " + QString::number( mTotalSize ) );

//set entry timestamp to current time
currentEntry->lastUsed = QDateTime::currentDateTime();

return *( currentEntry->image );
}

@@ -112,26 +121,38 @@ const QPicture& QgsSvgCache::svgAsPicture( const QString& file, double size, con
if ( !currentEntry->picture )
{
cachePicture( currentEntry );
trimToMaximumSize();
}

//debug: display current cache usage
QgsDebugMsg( "cache size: " + QString::number( mTotalSize ) );

//set entry timestamp to current time
currentEntry->lastUsed = QDateTime::currentDateTime();

return *( currentEntry->picture );
}

QgsSvgCacheEntry* QgsSvgCache::insertSVG( const QString& file, double size, const QColor& fill, const QColor& outline, double outlineWidth,
double widthScaleFactor, double rasterScaleFactor )
{
QgsSvgCacheEntry* entry = new QgsSvgCacheEntry( file, size, outlineWidth, widthScaleFactor, rasterScaleFactor, fill, outline );
entry->lastUsed = QDateTime::currentDateTime();

replaceParamsAndCacheSvg( entry );

mEntryLookup.insert( file, entry );

//insert to most recent place in entry list
if ( !mMostRecentEntry ) //inserting first entry
{
mLeastRecentEntry = entry;
mMostRecentEntry = entry;
entry->previousEntry = 0;
entry->nextEntry = 0;
}
else
{
entry->previousEntry = mMostRecentEntry;
entry->nextEntry = 0;
mMostRecentEntry->nextEntry = entry;
mMostRecentEntry = entry;
}

trimToMaximumSize();
return entry;
}

@@ -268,6 +289,18 @@ QgsSvgCacheEntry* QgsSvgCache::cacheEntry( const QString& file, double size, con
{
currentEntry = insertSVG( file, size, fill, outline, outlineWidth, widthScaleFactor, rasterScaleFactor );
}
else
{
takeEntryFromList( currentEntry );
mMostRecentEntry->nextEntry = currentEntry;
currentEntry->previousEntry = mMostRecentEntry;
currentEntry->nextEntry = 0;
mMostRecentEntry = currentEntry;
}

//debugging
//printEntryList();

return currentEntry;
}

@@ -350,3 +383,58 @@ void QgsSvgCache::removeCacheEntry( QString s, QgsSvgCacheEntry* entry )
mEntryLookup.remove( s , entry );
}

void QgsSvgCache::printEntryList()
{
QgsDebugMsg( "****************svg cache entry list*************************" );
QgsDebugMsg( "Cache size: " + QString::number( mTotalSize ) );
QgsSvgCacheEntry* entry = mLeastRecentEntry;
while ( entry )
{
QgsDebugMsg( "***Entry:" );
QgsDebugMsg( "File:" + entry->file );
QgsDebugMsg( "Size:" + QString::number( entry->size ) );
QgsDebugMsg( "Width scale factor" + QString::number( entry->widthScaleFactor ) );
QgsDebugMsg( "Raster scale factor" + QString::number( entry->rasterScaleFactor ) );
entry = entry->nextEntry;
}
}

void QgsSvgCache::trimToMaximumSize()
{
QgsSvgCacheEntry* entry = mLeastRecentEntry;
while ( entry && ( mTotalSize > mMaximumSize ) )
{
QgsSvgCacheEntry* bkEntry = entry;
entry = entry->nextEntry;

takeEntryFromList( bkEntry );
mTotalSize -= bkEntry->dataSize();
delete bkEntry;
}
}

void QgsSvgCache::takeEntryFromList( QgsSvgCacheEntry* entry )
{
if ( !entry )
{
return;
}

if ( entry->previousEntry )
{
entry->previousEntry->nextEntry = entry->nextEntry;
}
else
{
mLeastRecentEntry = entry->nextEntry;
}
if ( entry->nextEntry )
{
entry->nextEntry->previousEntry = entry->previousEntry;
}
else
{
mMostRecentEntry = entry->previousEntry;
}
}

@@ -19,7 +19,6 @@
#define QGSSVGCACHE_H

#include <QColor>
#include <QDateTime>
#include <QMap>
#include <QMultiHash>
#include <QString>
@@ -43,12 +42,17 @@ struct QgsSvgCacheEntry
QColor outline;
QImage* image;
QPicture* picture;
QDateTime lastUsed;
//content (with params replaced)
QByteArray svgContent;

//keep entries on a least, sorted by last access
QgsSvgCacheEntry* nextEntry;
QgsSvgCacheEntry* previousEntry;

/**Don't consider image, picture, last used timestamp for comparison*/
bool operator==( const QgsSvgCacheEntry& other ) const;
/**Return memory usage in bytes*/
int dataSize() const;
};

/**A cache for images / pictures derived from svg files. This class supports parameter replacement in svg files
@@ -81,7 +85,13 @@ class QgsSvgCache
void cachePicture( QgsSvgCacheEntry* entry );
/**Returns entry from cache or creates a new entry if it does not exist already*/
QgsSvgCacheEntry* cacheEntry( const QString& file, double size, const QColor& fill, const QColor& outline, double outlineWidth,
double widthScaleFactor, double rasterScaleFactor );
double widthScaleFactor, double rasterScaleFactor );

/**Removes the least used items until the maximum size is under the limit*/
void trimToMaximumSize();

//Removes entry from the ordered list (but does not delete the entry itself)
void takeEntryFromList( QgsSvgCacheEntry* entry );

private:
static QgsSvgCache* mInstance;
@@ -90,11 +100,23 @@ class QgsSvgCache
QMultiHash< QString, QgsSvgCacheEntry* > mEntryLookup;
/**Estimated total size of all images, pictures and svgContent*/
long mTotalSize;

//The svg cache keeps the entries on a double connected list, moving the current entry to the front.
//That way, removing entries for more space can start with the least used objects.
QgsSvgCacheEntry* mLeastRecentEntry;
QgsSvgCacheEntry* mMostRecentEntry;

//Maximum cache size
static const long mMaximumSize = 20000000;

/**Replaces parameters in elements of a dom node and calls method for all child nodes*/
void replaceElemParams( QDomElement& elem, const QColor& fill, const QColor& outline, double outlineWidth );

/**Release memory and remove cache entry from mEntryLookup*/
void removeCacheEntry( QString s, QgsSvgCacheEntry* entry );

/**For debugging*/
void printEntryList();
};

#endif // QGSSVGCACHE_H

0 comments on commit 05b4183

Please sign in to comment.
You can’t perform that action at this time.