diff --git a/src/main/java/net/imglib2/cache/img/AbstractReadWriteCachedCellImgFactory.java b/src/main/java/net/imglib2/cache/img/AbstractReadWriteCachedCellImgFactory.java
new file mode 100644
index 0000000..dd7f87a
--- /dev/null
+++ b/src/main/java/net/imglib2/cache/img/AbstractReadWriteCachedCellImgFactory.java
@@ -0,0 +1,190 @@
+/*
+ * #%L
+ * ImgLib2: a general-purpose, multidimensional image processing library.
+ * %%
+ * Copyright (C) 2009 - 2016 Tobias Pietzsch, Stephan Preibisch, Stephan Saalfeld,
+ * John Bogovic, Albert Cardona, Barry DeZonia, Christian Dietz, Jan Funke,
+ * Aivar Grislis, Jonathan Hale, Grant Harris, Stefan Helfrich, Mark Hiner,
+ * Martin Horn, Steffen Jaensch, Lee Kamentsky, Larry Lindsey, Melissa Linkert,
+ * Mark Longair, Brian Northan, Nick Perry, Curtis Rueden, Johannes Schindelin,
+ * Jean-Yves Tinevez and Michael Zinsmaier.
+ * %%
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * #L%
+ */
+
+package net.imglib2.cache.img;
+
+import net.imglib2.cache.Cache;
+import net.imglib2.cache.CacheLoader;
+import net.imglib2.cache.IoSync;
+import net.imglib2.cache.LoaderRemoverCache;
+import net.imglib2.cache.ref.GuardedStrongRefLoaderRemoverCache;
+import net.imglib2.cache.ref.SoftRefLoaderRemoverCache;
+import net.imglib2.img.NativeImgFactory;
+import net.imglib2.img.basictypeaccess.ArrayDataAccessFactory;
+import net.imglib2.img.basictypeaccess.array.ArrayDataAccess;
+import net.imglib2.img.cell.Cell;
+import net.imglib2.img.cell.CellGrid;
+import net.imglib2.type.NativeType;
+import net.imglib2.type.NativeTypeFactory;
+import net.imglib2.util.Fraction;
+
+/**
+ * Abstract factory for creating {@link CachedCellImg}s. Holds functionality shared by read-write-caches,
+ * but leaves the implementation of the cell writing to specialized implementations.
+ *
+ * See {@link DiskCachedCellImgFactory} for a specialized example.
+ *
+ * @param
+ * This is {@code true} by default.
+ *
+ * Because processing of removed entries is done whenever the cache is accessed,
+ * this may also block accesses to the cache. (This is a good thing, because it
+ * avoids running out of memory because entries cannot be cleared fast
+ * enough...)
+ *
+ * This is {@code false} by default.
+ *
+ * This option only has an effect for {@link DiskCachedCellImg} that are created
+ * with a {@link CellLoader}
+ * ({@link DiskCachedCellImgFactory#create(long[], net.imglib2.type.NativeType, CellLoader)}).
+ *
+ *
+ *
+ * @param cacheType which cache type to use (default is {@code SOFTREF}).
+ */
+ public abstract AbstractReadWriteCachedCellImgOptions cacheType(final CacheType cacheType);
+
+ /**
+ * Set the maximum number of values (cells) to keep in the cache. This is only
+ * used if {@link #cacheType(CacheType)} is {@link CacheType#BOUNDED}.
+ *
+ * @param maxCacheSize maximum number of values in the cache (default is 1000).
+ */
+ public abstract AbstractReadWriteCachedCellImgOptions maxCacheSize(final long maxCacheSize);
+
+ /**
+ * Set the dimensions of a cell. This is extended or truncated as necessary. For
+ * example if {@code cellDimensions=[64,32]} then for creating a 3D image it
+ * will be augmented to {@code [64,32,32]}. For creating a 1D image it will be
+ * truncated to {@code [64]}.
+ *
+ * @param cellDimensions dimensions of a cell (default is 10).
+ */
+ public abstract AbstractReadWriteCachedCellImgOptions cellDimensions(final int... cellDimensions);
+
+ /**
+ * Specify whether cells initialized by a {@link CellLoader} should be marked as
+ * dirty. It is useful to set this to {@code true} if initialization is a costly
+ * operation. By this, it is made sure that cells are initialized only once, and
+ * then written and retrieve from the disk cache when they are next required.
+ * ImgFactory imgFactory(final S type) throws IncompatibleTypeException {
+ if (NativeType.class.isInstance(type))
+ return new DiskCachedCellImgFactory(factoryOptions);
+ throw new IncompatibleTypeException(this,
+ type.getClass().getCanonicalName() + " does not implement NativeType.");
}
- private CellGrid createCellGrid( final long[] dimensions, final Fraction entitiesPerPixel, final DiskCachedCellImgOptions.Values options )
- {
- CellImgFactory.verifyDimensions( dimensions );
- final int n = dimensions.length;
- final int[] cellDimensions = CellImgFactory.getCellDimensions( options.cellDimensions(), n, entitiesPerPixel );
- return new CellGrid( dimensions, cellDimensions );
- }
-
- private Path createBlockCachePath( final DiskCachedCellImgOptions.Values options )
+ static Path createBlockCachePath( final DiskCachedCellImgOptions.Values options )
{
try
{
@@ -308,6 +215,46 @@ else if ( dir != null )
}
}
+ @Override
+ AbstractReadWriteCachedCellImgOptions mergeWithFactoryOptions(
+ AbstractReadWriteCachedCellImgOptions userProvidedOptions) {
+ return ( userProvidedOptions == null ) ? factoryOptions : factoryOptions.merge(userProvidedOptions);
+ }
+
+ @SuppressWarnings({"unchecked", "rawtypes"})
+ @Override
+ protected > ReadWriteCellCache createCellCache(
+ AbstractReadWriteCachedCellImgOptions options,
+ CellGrid grid,
+ CacheLoader
* This option only has an effect for {@link DiskCachedCellImg} that are - * created with a {@link CellLoader} - * ({@link DiskCachedCellImgFactory#create(long[], net.imglib2.type.NativeType, CellLoader)}). + * created with a {@link CellLoader} ({@link DiskCachedCellImgFactory#create(net.imglib2.Dimensions, CellLoader)}}) *
* * @param initializeAsDirty @@ -308,33 +284,20 @@ public DiskCachedCellImgOptions deleteCacheDirectoryOnExit( final boolean delete */ public DiskCachedCellImgOptions initializeCellsAsDirty( final boolean initializeAsDirty ) { - return new DiskCachedCellImgOptions( values.copy().setInitializeCellsAsDirty( initializeAsDirty ) ); + return new DiskCachedCellImgOptions(values.copy().setInitializeCellsAsDirty( initializeAsDirty )); } /** * Read-only {@link DiskCachedCellImgOptions} values. */ - public static class Values + protected static class Values extends AbstractReadWriteCachedCellImgOptions.Values { /** * Copy constructor. */ Values( final Values that ) { - this.dirtyAccesses = that.dirtyAccesses; - this.dirtyAccessesModified = that.dirtyAccessesModified; - this.volatileAccesses = that.volatileAccesses; - this.volatileAccessesModified = that.volatileAccessesModified; - this.numIoThreads = that.numIoThreads; - this.numIoThreadsModified = that.numIoThreadsModified; - this.maxIoQueueSize = that.maxIoQueueSize; - this.maxIoQueueSizeModified = that.maxIoQueueSizeModified; - this.cacheType = that.cacheType; - this.cacheTypeModified = that.cacheTypeModified; - this.maxCacheSize = that.maxCacheSize; - this.maxCacheSizeModified = that.maxCacheSizeModified; - this.cellDimensions = that.cellDimensions; - this.cellDimensionsModified = that.cellDimensionsModified; + super(that); this.cacheDirectory = that.cacheDirectory; this.cacheDirectoryModified = that.cacheDirectoryModified; this.tempDirectory = that.tempDirectory; @@ -343,8 +306,6 @@ public static class Values this.tempDirectoryPrefixModified = that.tempDirectoryPrefixModified; this.deleteCacheDirectoryOnExit = that.deleteCacheDirectoryOnExit; this.deleteCacheDirectoryOnExitModified = that.deleteCacheDirectoryOnExitModified; - this.initializeCellsAsDirty = that.initializeCellsAsDirty; - this.initializeCellsAsDirtyModified = that.initializeCellsAsDirtyModified; } Values() @@ -352,27 +313,7 @@ public static class Values Values( final Values base, final Values aug ) { - dirtyAccesses = aug.dirtyAccessesModified - ? aug.dirtyAccesses - : base.dirtyAccesses; - volatileAccesses = aug.volatileAccessesModified - ? aug.volatileAccesses - : base.volatileAccesses; - numIoThreads = aug.numIoThreadsModified - ? aug.numIoThreads - : base.numIoThreads; - maxIoQueueSize = aug.maxIoQueueSizeModified - ? aug.maxIoQueueSize - : base.maxIoQueueSize; - cacheType = aug.cacheTypeModified - ? aug.cacheType - : base.cacheType; - maxCacheSize = aug.maxCacheSizeModified - ? aug.maxCacheSize - : base.maxCacheSize; - cellDimensions = aug.cellDimensionsModified - ? aug.cellDimensions - : base.cellDimensions; + super(base, aug); cacheDirectory = aug.cacheDirectoryModified ? aug.cacheDirectory : base.cacheDirectory; @@ -385,30 +326,17 @@ public static class Values deleteCacheDirectoryOnExit = aug.deleteCacheDirectoryOnExitModified ? aug.deleteCacheDirectoryOnExit : base.deleteCacheDirectoryOnExit; - initializeCellsAsDirty = aug.initializeCellsAsDirtyModified - ? aug.initializeCellsAsDirty - : base.initializeCellsAsDirty; } - public DiskCachedCellImgOptions optionsFromValues() + Values( final Values base, final AbstractReadWriteCachedCellImgOptions.Values aug ) { - return new DiskCachedCellImgOptions( new Values( this ) ); + super(base, aug); + cacheDirectory = base.cacheDirectory; + tempDirectory = base.tempDirectory; + tempDirectoryPrefix = base.tempDirectoryPrefix; + deleteCacheDirectoryOnExit = base.deleteCacheDirectoryOnExit; } - private boolean dirtyAccesses = true; - - private boolean volatileAccesses = true; - - private int numIoThreads = 1; - - private int maxIoQueueSize = 10; - - private CacheType cacheType = CacheType.SOFTREF; - - private long maxCacheSize = 1000; - - private int[] cellDimensions = new int[] { 10 }; - private Path cacheDirectory = null; private Path tempDirectory = null; @@ -417,48 +345,6 @@ public DiskCachedCellImgOptions optionsFromValues() private boolean deleteCacheDirectoryOnExit = true; - private boolean initializeCellsAsDirty = false; - - public boolean dirtyAccesses() - { - return dirtyAccesses; - } - - public boolean volatileAccesses() - { - return volatileAccesses; - } - - public Set< AccessFlags > accessFlags() - { - return AccessFlags.fromBooleansDirtyVolatile( dirtyAccesses, volatileAccesses ); - } - - public int numIoThreads() - { - return numIoThreads; - } - - public int maxIoQueueSize() - { - return maxIoQueueSize; - } - - public CacheType cacheType() - { - return cacheType; - } - - public long maxCacheSize() - { - return maxCacheSize; - } - - public int[] cellDimensions() - { - return cellDimensions; - } - public Path cacheDirectory() { return cacheDirectory; @@ -479,25 +365,6 @@ public boolean deleteCacheDirectoryOnExit() return deleteCacheDirectoryOnExit; } - public boolean initializeCellsAsDirty() - { - return initializeCellsAsDirty; - } - - private boolean dirtyAccessesModified = false; - - private boolean volatileAccessesModified = false; - - private boolean numIoThreadsModified = false; - - private boolean maxIoQueueSizeModified = false; - - private boolean cacheTypeModified = false; - - private boolean maxCacheSizeModified = false; - - private boolean cellDimensionsModified = false; - private boolean cacheDirectoryModified = false; private boolean tempDirectoryModified = false; @@ -506,145 +373,93 @@ public boolean initializeCellsAsDirty() private boolean deleteCacheDirectoryOnExitModified = false; - private boolean initializeCellsAsDirtyModified = false; - - Values setDirtyAccesses( final boolean b ) + Values setCacheDirectory( final Path dir ) { - dirtyAccesses = b; - dirtyAccessesModified = true; + cacheDirectory = dir; + cacheDirectoryModified = true; return this; } - Values setVolatileAccesses( final boolean b ) + Values setTempDirectory( final Path dir ) { - volatileAccesses = b; - volatileAccessesModified = true; + tempDirectory = dir; + tempDirectoryModified = true; return this; } - Values setNumIoThreads( final int n ) + Values setTempDirectoryPrefix( final String prefix ) { - numIoThreads = n; - numIoThreadsModified = true; + tempDirectoryPrefix = prefix; + tempDirectoryPrefixModified = true; return this; } - Values setMaxIoQueueSize( final int n ) + Values setDeleteCacheDirectoryOnExit( final boolean b ) { - maxIoQueueSize = n; - maxIoQueueSizeModified = true; + deleteCacheDirectoryOnExit = b; + deleteCacheDirectoryOnExitModified = true; return this; } - Values setCacheType( final CacheType t ) + @Override + Values setDirtyAccesses( final boolean b ) { - cacheType = t; - cacheTypeModified = true; + super.setDirtyAccesses(b); return this; } - Values setMaxCacheSize( final long n ) + @Override + Values setVolatileAccesses( final boolean b ) { - maxCacheSize = n; - maxCacheSizeModified = true; + super.setVolatileAccesses(b); return this; } - Values setCellDimensions( final int[] dims ) + @Override + Values setCacheType( final CacheType t ) { - cellDimensions = dims; - cellDimensionsModified = true; + super.setCacheType(t); return this; } - Values setCacheDirectory( final Path dir ) + @Override + Values setMaxCacheSize( final long n ) { - cacheDirectory = dir; - cacheDirectoryModified = true; + super.setMaxCacheSize(n); return this; } - Values setTempDirectory( final Path dir ) + @Override + Values setCellDimensions( final int[] dims ) { - tempDirectory = dir; - tempDirectoryModified = true; + super.setCellDimensions(dims); return this; } - Values setTempDirectoryPrefix( final String prefix ) - { - tempDirectoryPrefix = prefix; - tempDirectoryPrefixModified = true; + @Override + Values setNumIoThreads(final int n) { + super.setNumIoThreads(n); return this; } - Values setDeleteCacheDirectoryOnExit( final boolean b ) - { - deleteCacheDirectoryOnExit = b; - deleteCacheDirectoryOnExitModified = true; + @Override + Values setMaxIoQueueSize(final int n) { + super.setMaxIoQueueSize(n); return this; } - Values setInitializeCellsAsDirty( final boolean b ) - { - initializeCellsAsDirty = b; - initializeCellsAsDirtyModified = true; + @Override + Values setInitializeCellsAsDirty(final boolean b) { + super.setInitializeCellsAsDirty(b); return this; } - Values copy() - { - return new Values( this ); - } - @Override public String toString() { final StringBuilder sb = new StringBuilder(); - - sb.append( "{" ); - - sb.append( "dirtyAccesses = " ); - sb.append( Boolean.toString( dirtyAccesses ) ); - if ( dirtyAccessesModified ) - sb.append( " [m]" ); - sb.append( ", " ); - - sb.append( "volatileAccesses = " ); - sb.append( Boolean.toString( volatileAccesses ) ); - if ( volatileAccessesModified ) - sb.append( " [m]" ); - sb.append( ", " ); - - sb.append( "numIoThreads = " ); - sb.append( numIoThreads ); - if ( numIoThreadsModified ) - sb.append( " [m]" ); - sb.append( ", " ); - - sb.append( "maxIoQueueSize = " ); - sb.append( maxIoQueueSize ); - if ( maxIoQueueSizeModified ) - sb.append( " [m]" ); - sb.append( ", " ); - - sb.append( "cacheType = " ); - sb.append( cacheType ); - if ( cacheTypeModified ) - sb.append( " [m]" ); - sb.append( ", " ); - - sb.append( "maxCacheSize = " ); - sb.append( maxCacheSize ); - if ( maxCacheSizeModified ) - sb.append( " [m]" ); - sb.append( ", " ); - - sb.append( "cellDimensions = " ); - sb.append( Util.printCoordinates( cellDimensions ) ); - if ( cellDimensionsModified ) - sb.append( " [m]" ); - sb.append( ", " ); + sb.append(super.toString()); + sb.append( "DiskCachedCellImgOptions = {" ); sb.append( "cacheDirectory = " ); sb.append( cacheDirectory ); @@ -669,14 +484,14 @@ public String toString() if ( deleteCacheDirectoryOnExitModified ) sb.append( " [m]" ); - sb.append( "initializeCellsAsDirty = " ); - sb.append( Boolean.toString( initializeCellsAsDirty ) ); - if ( initializeCellsAsDirtyModified ) - sb.append( " [m]" ); - sb.append( "}" ); return sb.toString(); } + + @Override + Values copy() { + return new Values(this); + } } } diff --git a/src/main/java/net/imglib2/cache/img/DiskCellCache.java b/src/main/java/net/imglib2/cache/img/DiskCellCache.java index f8b4de5..a82ac0e 100644 --- a/src/main/java/net/imglib2/cache/img/DiskCellCache.java +++ b/src/main/java/net/imglib2/cache/img/DiskCellCache.java @@ -40,8 +40,7 @@ * * @author Tobias Pietzsch */ -public class DiskCellCache< A > implements CacheRemover< Long, Cell< A > >, CacheLoader< Long, Cell< A > > -{ +public class DiskCellCache implements ReadWriteCellCache { private final Path blockcache; private final CellGrid grid; diff --git a/src/main/java/net/imglib2/cache/img/ReadOnlyCachedCellImgFactory.java b/src/main/java/net/imglib2/cache/img/ReadOnlyCachedCellImgFactory.java index cd7e9d3..ef5ce4e 100644 --- a/src/main/java/net/imglib2/cache/img/ReadOnlyCachedCellImgFactory.java +++ b/src/main/java/net/imglib2/cache/img/ReadOnlyCachedCellImgFactory.java @@ -123,12 +123,12 @@ public < T extends NativeType< T >, A > CachedCellImg< T, A > createWithCacheLoa final ReadOnlyCachedCellImgOptions additionalOptions ) { final ReadOnlyCachedCellImgOptions.Values options = ( additionalOptions == null ) - ? factoryOptions.values - : new ReadOnlyCachedCellImgOptions.Values( factoryOptions.values, additionalOptions.values ); + ? factoryOptions.values() + : factoryOptions.merge(additionalOptions).values(); final PrimitiveType primitiveType = type.getNativeTypeFactory().getPrimitiveType(); final Fraction entitiesPerPixel = type.getEntitiesPerPixel(); - final CellGrid grid = createCellGrid( dimensions, entitiesPerPixel, options ); + final CellGrid grid = createCellGrid( dimensions, options.cellDimensions(), entitiesPerPixel ); final A accessType = ArrayDataAccessFactory.get( primitiveType, options.accessFlags() ); @SuppressWarnings( "unchecked" ) @@ -152,11 +152,21 @@ public < T extends NativeType< T >, A > CachedCellImg< T, A > createWithCacheLoa return new CachedCellImg<>( grid, type, cache, accessType ); } - private CellGrid createCellGrid( final long[] dimensions, final Fraction entitiesPerPixel, final ReadOnlyCachedCellImgOptions.Values options ) + /** + * Create a {@link CellGrid} with the given image dimensions, desired cell dimensions, and entitiesPerPixel + * @param dimensions image dimensions + * @param defaultCellDimensions desired cell dimensions + * @param entitiesPerPixel + * @return + */ + static CellGrid createCellGrid( + final long[] dimensions, + final int[] defaultCellDimensions, + final Fraction entitiesPerPixel) { - CellImgFactory.verifyDimensions( dimensions ); + CellImgFactory.verifyDimensions(dimensions); final int n = dimensions.length; - final int[] cellDimensions = CellImgFactory.getCellDimensions( options.cellDimensions(), n, entitiesPerPixel ); - return new CellGrid( dimensions, cellDimensions ); + final int[] cellDimensions = CellImgFactory.getCellDimensions(defaultCellDimensions, n, entitiesPerPixel); + return new CellGrid(dimensions, cellDimensions); } } diff --git a/src/main/java/net/imglib2/cache/img/ReadOnlyCachedCellImgOptions.java b/src/main/java/net/imglib2/cache/img/ReadOnlyCachedCellImgOptions.java index d4b10bf..46e219e 100644 --- a/src/main/java/net/imglib2/cache/img/ReadOnlyCachedCellImgOptions.java +++ b/src/main/java/net/imglib2/cache/img/ReadOnlyCachedCellImgOptions.java @@ -32,7 +32,6 @@ import java.util.Set; import net.imglib2.Dirty; -import net.imglib2.cache.img.DiskCachedCellImgOptions.CacheType; import net.imglib2.img.basictypeaccess.AccessFlags; import net.imglib2.img.cell.CellImgFactory; import net.imglib2.util.Util; @@ -44,7 +43,7 @@ */ public class ReadOnlyCachedCellImgOptions { - public final Values values; + private final Values values; ReadOnlyCachedCellImgOptions( final Values values ) { @@ -66,6 +65,22 @@ public static ReadOnlyCachedCellImgOptions options() return new ReadOnlyCachedCellImgOptions(); } + /** + * @return The values of this options object + */ + public Values values() { + return values; + } + + /** + * @param other Options that should be merged with this option object + * @return New {@link ReadOnlyCachedCellImgOptions} containing the options of this object, + * overwritten by the non-default settings in the provided other options object + */ + public ReadOnlyCachedCellImgOptions merge(final ReadOnlyCachedCellImgOptions other) { + return new ReadOnlyCachedCellImgOptions(new Values(values, other.values)); + } + /** * Specify whether the image should use {@link Dirty} accesses. Dirty * accesses track whether cells were written to. @@ -86,6 +101,39 @@ public ReadOnlyCachedCellImgOptions volatileAccesses( final boolean volatil ) return new ReadOnlyCachedCellImgOptions( values.copy().setVolatileAccesses( volatil ) ); } + /** + * Rough in-memory cache types. + * + * @author Tobias Pietzsch + */ + public static enum CacheType + { + /** + * The cache keeps SoftReferences to values (cells), basically relying + * on GC for removal. The advantage of this is that many caches can be + * created without needing to put a limit on the size of any of them. GC + * will take care of balancing that. The downside is that + * {@link OutOfMemoryError} may occur because {@link SoftReference}s are + * cleared too slow. SoftReferences are not collected for a certain time + * after they have been used. If there is heavy thrashing with cells + * being constantly swapped in and out from disk then OutOfMemory may + * happen because of this. This sounds worse than it is in practice and + * should only happen in pathological situations. Tuning the + * {@code -XX:SoftRefLRUPolicyMSPerMB} JVM flag does often help. + */ + SOFTREF, + + /** + * The cache keeps strong references to a limited number of values + * (cells). The advantage is that there is never OutOfMemory because of + * the issues described above (fingers crossed). The downside is that + * the number of cells that should be cached needs to be specified + * beforehand. So {@link OutOfMemoryError} may occur if many caches are + * opened and consume too much memory in total. + */ + BOUNDED + } + /** * Which in-memory cache type to use. The options are *