Skip to content

Commit

Permalink
#2 Memory cache added
Browse files Browse the repository at this point in the history
  • Loading branch information
kpietak committed Apr 23, 2013
1 parent 90d4c45 commit 3786d23
Show file tree
Hide file tree
Showing 11 changed files with 642 additions and 19 deletions.
6 changes: 6 additions & 0 deletions pl.edu.agh.cast.map/plugin.xml
Original file line number Diff line number Diff line change
Expand Up @@ -13,5 +13,11 @@
</property>
</product>
</extension>
<extension
point="org.eclipse.core.runtime.preferences">
<initializer
class="pl.edu.agh.cast.map.config.PreferencesMapConfigurator$DefualtValuesInitializer">
</initializer>
</extension>

</plugin>
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package pl.edu.agh.cast.map.cache;

import org.eclipse.swt.graphics.ImageData;

import pl.edu.agh.cast.common.IDisposable;

/**
* Map cache is one of the elements in map tile sources chain. Map cache has been distinguished from
* {@link pl.edu.agh.cast.map.editor.provider.IMapProvider} due to the fact that cache is operating on already loaded tiles (In fact
* definition of 'already loaded tiles' can vary in different {@link IMapCache} implementation) to enhance performance of obtaining tiles
* greatly.
*
*/
public interface IMapCache extends IDisposable {

/**
* Return tile described by 3 parameters - map's zoom level, tile's column number and tile's row number.<br/>
* Tiles can be requested synchronously in UI Thread or asynchronously from other thread, so <b>synchronization if needed should be
* considered</b>.
*
* @param zoom
* Map's zoom level.
* @param column
* Tile's column number.
* @param row
* Tile's row number.
*
* @return Image of requested tile or <code>null</code> otherwise.
*/
ImageData getTile(int zoom, int column, int row);

/**
* Saves tile (described by 3 parameters - map's zoom level, tile's column number and tile's row number) in cache. Tiles can be provided
* synchronously in UI Thread or asynchronously from other thread, so <b>synchronization if needed should be considered</b>.
*
* @param zoom
* Map's zoom level.
* @param column
* Tile's column number.
* @param row
* Tile's row number.
* @param tile
* Image of tile.
*/
void saveTile(int zoom, int column, int row, ImageData tile);

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
package pl.edu.agh.cast.map.cache;

import java.util.Collections;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map;

import org.apache.log4j.Logger;
import org.eclipse.swt.graphics.ImageData;

import pl.edu.agh.cast.map.config.IMapConfigurationProvider;

/**
* Caches map's tiles in memory.
*
*/
public class MemoryMapCache implements IMapCache {

/**
* Logger.
*/
private static Logger log = Logger.getLogger(MemoryMapCache.class);

/**
* Limit of operational memory (In megabytes).
*/
private int memoryLimit;

/**
* Size of allocated memory (in bytes).
*/
private long allocatedMemory;

/**
* Map of cached tiles.
*/
private Map<String, ImageData> cachedTiles = Collections
.synchronizedMap(new LinkedHashMap<String, ImageData>());

/**
* Constructor.
*
* @param memoryLimit
* Limit of memory that can be used for tiles storing (in
* megabytes).
*/
public MemoryMapCache(int memoryLimit) {
this.memoryLimit = memoryLimit;
allocatedMemory = 0;
}

// BEGIN API Methods

/**
* Creates instance of {@link MemoryMapCache}. Appropriate memory cache's
* configuration is obtained from given {@link IMapConfigurationProvider}.
* If memory cache is disabled in application's setting than
* <code>null</code> will be returned.
*
* @return Instance of {@link MemoryMapCache} or <code>null</code> is memory
* cache is disabled
*/
public static MemoryMapCache createMemoryMapCache(
IMapConfigurationProvider config) {
MemoryMapCache result = null;

if (config.memoryCacheEnabled()) {
result = new MemoryMapCache(config.memoryCacheLimit());
}

return result;
}

/**
* {@inheritDoc}
*
* @see pl.edu.agh.cast.map.editor.cache.IMapCache#getTile(int, int, int)
*/
@Override
public ImageData getTile(int zoom, int column, int row) {
return cachedTiles.get(getKey(zoom, column, row));
}

/**
* {@inheritDoc}
*
* @see pl.edu.agh.cast.map.editor.cache.IMapCache#saveTile(int, int, int,
* org.eclipse.swt.graphics.ImageData)
*/
@Override
public void saveTile(int zoom, int column, int row, ImageData tile) {
String key = getKey(zoom, column, row);
ImageData old = cachedTiles.put(key, tile);
if (old != null) {
if (log.isDebugEnabled()) {
log.debug(String.format(
"Tile under key %s has been overriden.", key)); //$NON-NLS-1$
}
}

long newSize = sizeOfImage(tile);
long oldSize = sizeOfImage(old);
allocatedMemory += newSize - oldSize;

while ((allocatedMemory / 1048576.0) > memoryLimit) {
synchronized (cachedTiles) {
Iterator<String> iterator = cachedTiles.keySet().iterator();
if (iterator.hasNext()) {
allocatedMemory -= sizeOfImage(cachedTiles.get(iterator
.next()));
iterator.remove();
}
}
}
}

/**
* {@inheritDoc}
*
* @see pl.edu.agh.cast.common.IDisposable#dispose()
*/
@Override
public void dispose() {
cachedTiles.clear();
allocatedMemory = 0;
}

// END API Methods

/**
* Returns key for specified attributes.
*
* @param zoom
* Tile zoom level.
* @param column
* Tile column.
* @param row
* Tile row.
* @return Key for specified attributes.
*/
private String getKey(int zoom, int column, int row) {
String separator = "/"; //$NON-NLS-1$
return zoom + separator + column + separator + row;
}

/**
* Returns size of image in memory.
*
* @param image
* Image to investigate.
* @return Size of image in memory.
*/
private long sizeOfImage(ImageData image) {
if (image == null) {
return 0;
}

return image.width * image.height * (image.depth / 8);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package pl.edu.agh.cast.map.config;

import java.util.List;

import pl.edu.agh.cast.map.provider.IMapProvider;

public interface IMapConfigurationProvider {

boolean discCacheEnabled();

boolean discCacheLimitEnabled();

int discCacheLimit();

boolean memoryCacheEnabled();

int memoryCacheLimit();

List<IMapProvider> mapProviders();

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package pl.edu.agh.cast.map.config;

import pl.edu.agh.cast.map.provider.IMapProvider;

public interface IMapConfigurator extends IMapConfigurationProvider {

// Disc cache

void enableDiscCache(boolean enabled);

void enableDiscCacheLimit(boolean enabled);

/**
*
* @param limit
* in MB
*/
void setDiscCacheLimit(int limit);

// Memory cache

void enableMemoryCache(boolean enabled);

/**
*
* @param limit
* in MB
*/
void setMemoryCacheLimit(int limit);

// Map providers

void addMapProvider(IMapProvider mapProvider);

void removeMapProvider(IMapProvider mapProvider);

}
Loading

0 comments on commit 3786d23

Please sign in to comment.