Skip to content

Commit 05b4183

Browse files
committed
Remove oldest entries from svg cache if cache size is too large
1 parent 166b3d2 commit 05b4183

File tree

2 files changed

+127
-17
lines changed

2 files changed

+127
-17
lines changed

src/core/symbology-ng/qgssvgcache.cpp

+102-14
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,20 @@ bool QgsSvgCacheEntry::operator==( const QgsSvgCacheEntry& other ) const
4848
&& other.rasterScaleFactor == rasterScaleFactor && other.fill == fill && other.outline == outline );
4949
}
5050

51+
int QgsSvgCacheEntry::dataSize() const
52+
{
53+
int size = svgContent.size();
54+
if ( picture )
55+
{
56+
size += picture->size();
57+
}
58+
if ( image )
59+
{
60+
size += ( image->width() * image->height() * 32 );
61+
}
62+
return size;
63+
}
64+
5165
QString file;
5266
double size;
5367
double outlineWidth;
@@ -67,7 +81,7 @@ QgsSvgCache* QgsSvgCache::instance()
6781
return mInstance;
6882
}
6983

70-
QgsSvgCache::QgsSvgCache(): mTotalSize( 0 )
84+
QgsSvgCache::QgsSvgCache(): mTotalSize( 0 ), mLeastRecentEntry( 0 ), mMostRecentEntry( 0 )
7185
{
7286
}
7387

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

96-
//debug: display current cache usage
97-
QgsDebugMsg( "cache size: " + QString::number( mTotalSize ) );
98-
99-
//set entry timestamp to current time
100-
currentEntry->lastUsed = QDateTime::currentDateTime();
101-
102111
return *( currentEntry->image );
103112
}
104113

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

117-
//debug: display current cache usage
118-
QgsDebugMsg( "cache size: " + QString::number( mTotalSize ) );
119-
120-
//set entry timestamp to current time
121-
currentEntry->lastUsed = QDateTime::currentDateTime();
122-
123127
return *( currentEntry->picture );
124128
}
125129

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

132135
replaceParamsAndCacheSvg( entry );
133136

134137
mEntryLookup.insert( file, entry );
138+
139+
//insert to most recent place in entry list
140+
if ( !mMostRecentEntry ) //inserting first entry
141+
{
142+
mLeastRecentEntry = entry;
143+
mMostRecentEntry = entry;
144+
entry->previousEntry = 0;
145+
entry->nextEntry = 0;
146+
}
147+
else
148+
{
149+
entry->previousEntry = mMostRecentEntry;
150+
entry->nextEntry = 0;
151+
mMostRecentEntry->nextEntry = entry;
152+
mMostRecentEntry = entry;
153+
}
154+
155+
trimToMaximumSize();
135156
return entry;
136157
}
137158

@@ -268,6 +289,18 @@ QgsSvgCacheEntry* QgsSvgCache::cacheEntry( const QString& file, double size, con
268289
{
269290
currentEntry = insertSVG( file, size, fill, outline, outlineWidth, widthScaleFactor, rasterScaleFactor );
270291
}
292+
else
293+
{
294+
takeEntryFromList( currentEntry );
295+
mMostRecentEntry->nextEntry = currentEntry;
296+
currentEntry->previousEntry = mMostRecentEntry;
297+
currentEntry->nextEntry = 0;
298+
mMostRecentEntry = currentEntry;
299+
}
300+
301+
//debugging
302+
//printEntryList();
303+
271304
return currentEntry;
272305
}
273306

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

386+
void QgsSvgCache::printEntryList()
387+
{
388+
QgsDebugMsg( "****************svg cache entry list*************************" );
389+
QgsDebugMsg( "Cache size: " + QString::number( mTotalSize ) );
390+
QgsSvgCacheEntry* entry = mLeastRecentEntry;
391+
while ( entry )
392+
{
393+
QgsDebugMsg( "***Entry:" );
394+
QgsDebugMsg( "File:" + entry->file );
395+
QgsDebugMsg( "Size:" + QString::number( entry->size ) );
396+
QgsDebugMsg( "Width scale factor" + QString::number( entry->widthScaleFactor ) );
397+
QgsDebugMsg( "Raster scale factor" + QString::number( entry->rasterScaleFactor ) );
398+
entry = entry->nextEntry;
399+
}
400+
}
401+
402+
void QgsSvgCache::trimToMaximumSize()
403+
{
404+
QgsSvgCacheEntry* entry = mLeastRecentEntry;
405+
while ( entry && ( mTotalSize > mMaximumSize ) )
406+
{
407+
QgsSvgCacheEntry* bkEntry = entry;
408+
entry = entry->nextEntry;
409+
410+
takeEntryFromList( bkEntry );
411+
mTotalSize -= bkEntry->dataSize();
412+
delete bkEntry;
413+
}
414+
}
415+
416+
void QgsSvgCache::takeEntryFromList( QgsSvgCacheEntry* entry )
417+
{
418+
if ( !entry )
419+
{
420+
return;
421+
}
422+
423+
if ( entry->previousEntry )
424+
{
425+
entry->previousEntry->nextEntry = entry->nextEntry;
426+
}
427+
else
428+
{
429+
mLeastRecentEntry = entry->nextEntry;
430+
}
431+
if ( entry->nextEntry )
432+
{
433+
entry->nextEntry->previousEntry = entry->previousEntry;
434+
}
435+
else
436+
{
437+
mMostRecentEntry = entry->previousEntry;
438+
}
439+
}
440+

src/core/symbology-ng/qgssvgcache.h

+25-3
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@
1919
#define QGSSVGCACHE_H
2020

2121
#include <QColor>
22-
#include <QDateTime>
2322
#include <QMap>
2423
#include <QMultiHash>
2524
#include <QString>
@@ -43,12 +42,17 @@ struct QgsSvgCacheEntry
4342
QColor outline;
4443
QImage* image;
4544
QPicture* picture;
46-
QDateTime lastUsed;
4745
//content (with params replaced)
4846
QByteArray svgContent;
4947

48+
//keep entries on a least, sorted by last access
49+
QgsSvgCacheEntry* nextEntry;
50+
QgsSvgCacheEntry* previousEntry;
51+
5052
/**Don't consider image, picture, last used timestamp for comparison*/
5153
bool operator==( const QgsSvgCacheEntry& other ) const;
54+
/**Return memory usage in bytes*/
55+
int dataSize() const;
5256
};
5357

5458
/**A cache for images / pictures derived from svg files. This class supports parameter replacement in svg files
@@ -81,7 +85,13 @@ class QgsSvgCache
8185
void cachePicture( QgsSvgCacheEntry* entry );
8286
/**Returns entry from cache or creates a new entry if it does not exist already*/
8387
QgsSvgCacheEntry* cacheEntry( const QString& file, double size, const QColor& fill, const QColor& outline, double outlineWidth,
84-
double widthScaleFactor, double rasterScaleFactor );
88+
double widthScaleFactor, double rasterScaleFactor );
89+
90+
/**Removes the least used items until the maximum size is under the limit*/
91+
void trimToMaximumSize();
92+
93+
//Removes entry from the ordered list (but does not delete the entry itself)
94+
void takeEntryFromList( QgsSvgCacheEntry* entry );
8595

8696
private:
8797
static QgsSvgCache* mInstance;
@@ -90,11 +100,23 @@ class QgsSvgCache
90100
QMultiHash< QString, QgsSvgCacheEntry* > mEntryLookup;
91101
/**Estimated total size of all images, pictures and svgContent*/
92102
long mTotalSize;
103+
104+
//The svg cache keeps the entries on a double connected list, moving the current entry to the front.
105+
//That way, removing entries for more space can start with the least used objects.
106+
QgsSvgCacheEntry* mLeastRecentEntry;
107+
QgsSvgCacheEntry* mMostRecentEntry;
108+
109+
//Maximum cache size
110+
static const long mMaximumSize = 20000000;
111+
93112
/**Replaces parameters in elements of a dom node and calls method for all child nodes*/
94113
void replaceElemParams( QDomElement& elem, const QColor& fill, const QColor& outline, double outlineWidth );
95114

96115
/**Release memory and remove cache entry from mEntryLookup*/
97116
void removeCacheEntry( QString s, QgsSvgCacheEntry* entry );
117+
118+
/**For debugging*/
119+
void printEntryList();
98120
};
99121

100122
#endif // QGSSVGCACHE_H

0 commit comments

Comments
 (0)