You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by tv...@apache.org on 2015/04/06 17:28:11 UTC

svn commit: r1671552 [1/2] - in /commons/proper/jcs/trunk: commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/disk/ commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/disk/behavior/ commons-jcs-core/src/main/java/org/apache/co...

Author: tv
Date: Mon Apr  6 15:28:10 2015
New Revision: 1671552

URL: http://svn.apache.org/r1671552
Log:
JCS-147: Provide file size limitation for Block Disk Cache and Indexed Disk Cache

Added:
    commons/proper/jcs/trunk/commons-jcs-core/src/main/java/org/apache/commons/jcs/utils/struct/AbstractLRUMap.java   (with props)
    commons/proper/jcs/trunk/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/disk/block/BlockDiskCacheUnitTestCount.java   (with props)
    commons/proper/jcs/trunk/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/disk/block/BlockDiskCacheUnitTestSize.java   (with props)
    commons/proper/jcs/trunk/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/disk/indexed/IndexDiskCacheUnitTestCount.java   (with props)
    commons/proper/jcs/trunk/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/disk/indexed/IndexDiskCacheUnitTestSize.java   (with props)
    commons/proper/jcs/trunk/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/disk/indexed/LRUMapSizeVsCount.java   (with props)
Modified:
    commons/proper/jcs/trunk/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/disk/AbstractDiskCacheAttributes.java
    commons/proper/jcs/trunk/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/disk/behavior/IDiskCacheAttributes.java
    commons/proper/jcs/trunk/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/disk/block/BlockDiskCache.java
    commons/proper/jcs/trunk/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/disk/block/BlockDiskCacheAttributes.java
    commons/proper/jcs/trunk/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/disk/block/BlockDiskKeyStore.java
    commons/proper/jcs/trunk/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/disk/indexed/IndexedDiskCache.java
    commons/proper/jcs/trunk/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/disk/indexed/IndexedDiskCacheAttributes.java
    commons/proper/jcs/trunk/commons-jcs-core/src/main/java/org/apache/commons/jcs/utils/struct/LRUMap.java
    commons/proper/jcs/trunk/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/disk/DiskTestObject.java
    commons/proper/jcs/trunk/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/disk/LRUMapJCSUnitTest.java
    commons/proper/jcs/trunk/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/disk/block/BlockDiskCacheKeyStoreUnitTest.java
    commons/proper/jcs/trunk/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/disk/block/BlockDiskCacheUnitTest.java
    commons/proper/jcs/trunk/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/disk/indexed/IndexDiskCacheUnitTest.java
    commons/proper/jcs/trunk/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/disk/indexed/IndexedDiskCacheSameRegionConcurrentUnitTest.java
    commons/proper/jcs/trunk/commons-jcs-core/src/test/java/org/apache/commons/jcs/utils/struct/JCSvsCommonsLRUMapPerformanceTest.java
    commons/proper/jcs/trunk/commons-jcs-core/src/test/java/org/apache/commons/jcs/utils/struct/LRUMapPerformanceTest.java
    commons/proper/jcs/trunk/src/changes/changes.xml
    commons/proper/jcs/trunk/xdocs/BlockDiskCache.xml
    commons/proper/jcs/trunk/xdocs/IndexedDiskAuxCache.xml

Modified: commons/proper/jcs/trunk/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/disk/AbstractDiskCacheAttributes.java
URL: http://svn.apache.org/viewvc/commons/proper/jcs/trunk/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/disk/AbstractDiskCacheAttributes.java?rev=1671552&r1=1671551&r2=1671552&view=diff
==============================================================================
--- commons/proper/jcs/trunk/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/disk/AbstractDiskCacheAttributes.java (original)
+++ commons/proper/jcs/trunk/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/disk/AbstractDiskCacheAttributes.java Mon Apr  6 15:28:10 2015
@@ -58,6 +58,10 @@ public abstract class AbstractDiskCacheA
      */
     private int shutdownSpoolTimeLimit = DEFAULT_shutdownSpoolTimeLimit;
 
+    private DiskLimitType diskLimitType = DiskLimitType.COUNT;
+
+    private int chunkSize;
+
     /**
      * Sets the diskPath attribute of the DiskCacheAttributes object
      * <p>
@@ -203,4 +207,27 @@ public abstract class AbstractDiskCacheA
         str.append( "\n ShutdownSpoolTimeLimit   = " + getShutdownSpoolTimeLimit() );
         return str.toString();
     }
+    @Override
+    public void setDiskLimitType(DiskLimitType diskLimitType) {
+        this.diskLimitType = diskLimitType;
+
+    }
+
+    @Override
+    public void setDiskLimitTypeName(String diskLimitTypeName) {
+        if (diskLimitTypeName != null) {
+            String name = diskLimitTypeName.trim();
+            if ("COUNT".equals(name)) {
+                diskLimitType = DiskLimitType.COUNT;
+            } else if ("SIZE".equals(name)) {
+                diskLimitType = DiskLimitType.SIZE;
+            }
+        }
+
+    }
+
+    @Override
+    public DiskLimitType getDiskLimitType() {
+        return diskLimitType;
+    }
 }

Modified: commons/proper/jcs/trunk/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/disk/behavior/IDiskCacheAttributes.java
URL: http://svn.apache.org/viewvc/commons/proper/jcs/trunk/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/disk/behavior/IDiskCacheAttributes.java?rev=1671552&r1=1671551&r2=1671552&view=diff
==============================================================================
--- commons/proper/jcs/trunk/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/disk/behavior/IDiskCacheAttributes.java (original)
+++ commons/proper/jcs/trunk/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/disk/behavior/IDiskCacheAttributes.java Mon Apr  6 15:28:10 2015
@@ -29,6 +29,12 @@ import java.io.File;
 public interface IDiskCacheAttributes
     extends AuxiliaryCacheAttributes
 {
+    enum DiskLimitType {
+        /** limit elements by count (default) */
+        COUNT,
+        /** limit elements by their size */
+        SIZE
+    }
     /**
      * This is the default purgatory size limit. Purgatory is the area where
      * items to be spooled are temporarily stored. It basically provides access
@@ -102,4 +108,24 @@ public interface IDiskCacheAttributes
      * @param allowRemoveAll
      */
     void setAllowRemoveAll( boolean allowRemoveAll );
+
+    /**
+     * set the type of the limit of the cache size
+     * @param diskLimitType COUNT - limit by count of the elements, SIZE, limit by sum of element's size
+     */
+    void setDiskLimitType(DiskLimitType diskLimitType);
+
+    /**
+     * Translates and stores String values  of DiskLimitType
+     *
+     * Allowed values: "COUNT" and "SIZE"
+     * @param diskLimitTypeName
+     */
+    void setDiskLimitTypeName(String diskLimitTypeName);
+
+    /**
+     *
+     * @return active DiskLimitType
+     */
+    DiskLimitType getDiskLimitType();
 }

Modified: commons/proper/jcs/trunk/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/disk/block/BlockDiskCache.java
URL: http://svn.apache.org/viewvc/commons/proper/jcs/trunk/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/disk/block/BlockDiskCache.java?rev=1671552&r1=1671551&r2=1671552&view=diff
==============================================================================
--- commons/proper/jcs/trunk/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/disk/block/BlockDiskCache.java (original)
+++ commons/proper/jcs/trunk/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/disk/block/BlockDiskCache.java Mon Apr  6 15:28:10 2015
@@ -21,6 +21,7 @@ package org.apache.commons.jcs.auxiliary
 
 import org.apache.commons.jcs.auxiliary.AuxiliaryCacheAttributes;
 import org.apache.commons.jcs.auxiliary.disk.AbstractDiskCache;
+import org.apache.commons.jcs.auxiliary.disk.behavior.IDiskCacheAttributes.DiskLimitType;
 import org.apache.commons.jcs.engine.CacheConstants;
 import org.apache.commons.jcs.engine.behavior.ICacheElement;
 import org.apache.commons.jcs.engine.behavior.IElementSerializer;

Modified: commons/proper/jcs/trunk/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/disk/block/BlockDiskCacheAttributes.java
URL: http://svn.apache.org/viewvc/commons/proper/jcs/trunk/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/disk/block/BlockDiskCacheAttributes.java?rev=1671552&r1=1671551&r2=1671552&view=diff
==============================================================================
--- commons/proper/jcs/trunk/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/disk/block/BlockDiskCacheAttributes.java (original)
+++ commons/proper/jcs/trunk/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/disk/block/BlockDiskCacheAttributes.java Mon Apr  6 15:28:10 2015
@@ -112,6 +112,7 @@ public class BlockDiskCacheAttributes
         str.append( "\n MaxPurgatorySize [" + this.getMaxPurgatorySize() + "]" );
         str.append( "\n BlockSizeBytes [" + this.getBlockSizeBytes() + "]" );
         str.append( "\n KeyPersistenceIntervalSeconds [" + this.getKeyPersistenceIntervalSeconds() + "]" );
+        str.append( "\n DiskLimitType [" + this.getDiskLimitType() + "]" );
         return str.toString();
     }
 }

Modified: commons/proper/jcs/trunk/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/disk/block/BlockDiskKeyStore.java
URL: http://svn.apache.org/viewvc/commons/proper/jcs/trunk/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/disk/block/BlockDiskKeyStore.java?rev=1671552&r1=1671551&r2=1671552&view=diff
==============================================================================
--- commons/proper/jcs/trunk/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/disk/block/BlockDiskKeyStore.java (original)
+++ commons/proper/jcs/trunk/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/disk/block/BlockDiskKeyStore.java Mon Apr  6 15:28:10 2015
@@ -20,7 +20,11 @@ package org.apache.commons.jcs.auxiliary
  */
 
 import org.apache.commons.jcs.auxiliary.disk.LRUMapJCS;
+import org.apache.commons.jcs.auxiliary.disk.behavior.IDiskCacheAttributes.DiskLimitType;
+import org.apache.commons.jcs.auxiliary.disk.indexed.IndexedDiskElementDescriptor;
 import org.apache.commons.jcs.io.ObjectInputStreamClassLoaderAware;
+import org.apache.commons.jcs.utils.struct.AbstractLRUMap;
+import org.apache.commons.jcs.utils.struct.LRUMap;
 import org.apache.commons.jcs.utils.timing.ElapsedTimer;
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
@@ -37,6 +41,7 @@ import java.io.ObjectOutputStream;
 import java.util.HashMap;
 import java.util.Map;
 import java.util.Set;
+import java.util.concurrent.atomic.AtomicInteger;
 
 /**
  * This is responsible for storing the keys.
@@ -69,6 +74,10 @@ public class BlockDiskKeyStore<K>
     /** we need this so we can communicate free blocks to the data store when keys fall off the LRU */
     protected final BlockDiskCache<K, ?> blockDiskCache;
 
+    private DiskLimitType diskLimitType = DiskLimitType.COUNT;
+
+    private int blockSize;
+
     /**
      * Set the configuration options.
      * <p>
@@ -83,6 +92,8 @@ public class BlockDiskKeyStore<K>
         this.fileName = this.blockDiskCacheAttributes.getCacheName();
         this.maxKeySize = cacheAttributes.getMaxKeySize();
         this.blockDiskCache = blockDiskCache;
+        this.diskLimitType  = cacheAttributes.getDiskLimitType();
+        this.blockSize = cacheAttributes.getBlockSizeBytes();
 
         File rootDirectory = cacheAttributes.getDiskPath();
 
@@ -190,7 +201,11 @@ public class BlockDiskKeyStore<K>
         keyHash = null;
         if ( maxKeySize >= 0 )
         {
-            keyHash = new LRUMap( maxKeySize );
+            if (this.diskLimitType.equals(DiskLimitType.SIZE)) {
+                keyHash = new LRUMapSizeLimited(maxKeySize);
+            } else {
+                keyHash = new LRUMapCountLimited( maxKeySize );
+            }
             if ( log.isInfoEnabled() )
             {
                 log.info( logCacheName + "Set maxKeySize to: '" + maxKeySize + "'" );
@@ -338,22 +353,27 @@ public class BlockDiskKeyStore<K>
         return this.keyHash.remove( key );
     }
 
+
     /**
-     * Class for recycling and lru. This implements the LRU overflow callback, so we can mark the
+     * Class for recycling and lru. This implements the LRU size overflow callback, so we can mark the
      * blocks as free.
      */
-    public class LRUMap
-        extends LRUMapJCS<K, int[]>
+
+    public class LRUMapSizeLimited
+    	extends AbstractLRUMap<K, int[]>
+
     {
         /**
          * <code>tag</code> tells us which map we are working on.
          */
-        public String tag = "orig";
-
+        public String tag = "orig-lru-size";
+        // size of the content in kB
+        private AtomicInteger contentSize = new AtomicInteger();
+        private int maxSize = -1;
         /**
          * Default
          */
-        public LRUMap()
+        public LRUMapSizeLimited()
         {
             super();
         }
@@ -361,11 +381,76 @@ public class BlockDiskKeyStore<K>
         /**
          * @param maxKeySize
          */
-        public LRUMap( int maxKeySize )
+        public LRUMapSizeLimited( int maxKeySize )
         {
-            super( maxKeySize );
+            super();
+            this.maxSize = maxKeySize;
         }
 
+        @Override
+        public int[] put(K key, int[] value) {
+            try {
+                return super.put(key, value);
+            } finally {
+                // keep the content size in kB, so 2^31 kB is reasonable value
+                contentSize.addAndGet((int) Math.ceil(value.length * blockSize / 1024.0));
+            }
+        }
+
+        @Override
+        public int[] remove(Object key ) {
+            int[] value = null;
+
+            try {
+                value = super.remove(key);
+                return value;
+            } finally {
+                if (value != null) {
+                    // keep the content size in kB, so 2^31 kB is reasonable value
+                    contentSize.addAndGet((int) ((Math.ceil(value.length * blockSize / 1024.0)) * -1));
+                }
+            }
+        }
+
+        /**
+         * This is called when the may key size is reached. The least recently used item will be
+         * passed here. We will store the position and size of the spot on disk in the recycle bin.
+         * <p>
+         * @param key
+         * @param value
+         */
+        protected void processRemovedLRU( K key, int[] value )
+        {
+            blockDiskCache.freeBlocks( value );
+            if ( log.isDebugEnabled() )
+            {
+                log.debug( logCacheName + "Removing key: [" + key + "] from key store." );
+                log.debug( logCacheName + "Key store size: [" + super.size() + "]." );
+            }
+        }
+        @Override
+        protected boolean shouldRemove() {
+            return maxSize > 0 && contentSize.intValue() > maxSize && this.size() > 1;
+        }
+    }
+    /**
+     * Class for recycling and lru. This implements the LRU overflow callback, so we can mark the
+     * blocks as free.
+     */
+    public class LRUMapCountLimited
+    extends LRUMap<K, int[]>
+    // implements Serializable
+    {
+        /**
+         * <code>tag</code> tells us which map we are working on.
+         */
+        public String tag = "orig-lru-count";
+
+        public LRUMapCountLimited(int maxKeySize) {
+            super(maxKeySize);
+        }
+
+
         /**
          * This is called when the may key size is reached. The least recently used item will be
          * passed here. We will store the position and size of the spot on disk in the recycle bin.

Modified: commons/proper/jcs/trunk/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/disk/indexed/IndexedDiskCache.java
URL: http://svn.apache.org/viewvc/commons/proper/jcs/trunk/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/disk/indexed/IndexedDiskCache.java?rev=1671552&r1=1671551&r2=1671552&view=diff
==============================================================================
--- commons/proper/jcs/trunk/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/disk/indexed/IndexedDiskCache.java (original)
+++ commons/proper/jcs/trunk/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/disk/indexed/IndexedDiskCache.java Mon Apr  6 15:28:10 2015
@@ -21,7 +21,7 @@ package org.apache.commons.jcs.auxiliary
 
 import org.apache.commons.jcs.auxiliary.AuxiliaryCacheAttributes;
 import org.apache.commons.jcs.auxiliary.disk.AbstractDiskCache;
-import org.apache.commons.jcs.auxiliary.disk.LRUMapJCS;
+import org.apache.commons.jcs.auxiliary.disk.behavior.IDiskCacheAttributes.DiskLimitType;
 import org.apache.commons.jcs.engine.CacheConstants;
 import org.apache.commons.jcs.engine.behavior.ICacheElement;
 import org.apache.commons.jcs.engine.behavior.IElementSerializer;
@@ -33,6 +33,8 @@ import org.apache.commons.jcs.engine.sta
 import org.apache.commons.jcs.engine.stats.Stats;
 import org.apache.commons.jcs.engine.stats.behavior.IStatElement;
 import org.apache.commons.jcs.engine.stats.behavior.IStats;
+import org.apache.commons.jcs.utils.struct.AbstractLRUMap;
+import org.apache.commons.jcs.utils.struct.LRUMap;
 import org.apache.commons.jcs.utils.struct.SortedPreferentialArray;
 import org.apache.commons.jcs.utils.timing.ElapsedTimer;
 import org.apache.commons.logging.Log;
@@ -131,6 +133,9 @@ public class IndexedDiskCache<K, V>
     /** the number of bytes free on disk. */
     private long bytesFree = 0;
 
+    /** mode we are working on (size or count limited **/
+    private DiskLimitType diskLimitType = DiskLimitType.COUNT;
+
     /** simple stat */
     private AtomicInteger hitCount = new AtomicInteger(0);
 
@@ -166,6 +171,7 @@ public class IndexedDiskCache<K, V>
         this.isRealTimeOptimizationEnabled = cattr.getOptimizeAtRemoveCount() > 0;
         this.isShutdownOptimizationEnabled = cattr.isOptimizeOnShutdown();
         this.logCacheName = "Region [" + getCacheName() + "] ";
+        this.diskLimitType = cattr.getDiskLimitType();
         // Make a clean file name
         this.fileName = getCacheName().replaceAll("[^a-zA-Z0-9-_\\.]", "_");
 
@@ -1017,7 +1023,12 @@ public class IndexedDiskCache<K, V>
         keyHash = null;
         if ( maxKeySize >= 0 )
         {
-            keyHash = new LRUMap( maxKeySize );
+            if (this.diskLimitType.equals(DiskLimitType.COUNT)) {
+                keyHash = new LRUMapCountLimited( maxKeySize );
+            } else {
+                keyHash = new LRUMapSizeLimited(maxKeySize);
+            }
+
             if ( log.isInfoEnabled() )
             {
                 log.info( logCacheName + "Set maxKeySize to: '" + maxKeySize + "'" );
@@ -1566,6 +1577,7 @@ public class IndexedDiskCache<K, V>
         {
             log.error( e );
         }
+        elems.add(new StatElement<Integer>( "Max Key Size", this.maxKeySize));
         elems.add(new StatElement<Integer>( "Hit Count", Integer.valueOf(this.hitCount.get()) ) );
         elems.add(new StatElement<Long>( "Bytes Free", Long.valueOf(this.bytesFree) ) );
         elems.add(new StatElement<Integer>( "Optimize Operation Count", Integer.valueOf(this.removeCount) ) );
@@ -1642,21 +1654,22 @@ public class IndexedDiskCache<K, V>
 
     /**
      * Class for recycling and lru. This implements the LRU overflow callback, so we can add items
-     * to the recycle bin.
+     * to the recycle bin. This class counts the size element to decide, when to throw away an element
      */
-    public class LRUMap
-        extends LRUMapJCS<K, IndexedDiskElementDescriptor>
-        // implements Serializable
+    public class LRUMapSizeLimited
+        extends AbstractLRUMap<K, IndexedDiskElementDescriptor>
     {
         /**
          * <code>tag</code> tells us which map we are working on.
          */
         public String tag = "orig";
-
+        // size of the content in kB
+        private AtomicInteger contentSize = new AtomicInteger();
+        private int maxSize = -1;
         /**
          * Default
          */
-        public LRUMap()
+        public LRUMapSizeLimited()
         {
             super();
         }
@@ -1664,11 +1677,79 @@ public class IndexedDiskCache<K, V>
         /**
          * @param maxKeySize
          */
-        public LRUMap( int maxKeySize )
+        public LRUMapSizeLimited( int maxKeySize )
+        {
+            super();
+            this.maxSize = maxKeySize;
+        }
+
+        @Override
+        public IndexedDiskElementDescriptor put(K key, IndexedDiskElementDescriptor value) {
+            try {
+                return super.put(key, value);
+            } finally {
+                // keep the content size in kB, so 2^31 kB is reasonable value
+                contentSize.addAndGet((int) Math.ceil((value.len + IndexedDisk.HEADER_SIZE_BYTES) / 1024.0));
+            }
+        }
+
+        @Override
+        public IndexedDiskElementDescriptor remove(Object key ) {
+            IndexedDiskElementDescriptor value = null;
+
+            try {
+                value = super.remove(key);
+                return value;
+            } finally {
+                if (value != null) {
+                    // keep the content size in kB, so 2^31 kB is reasonable value
+                    contentSize.addAndGet((int) ((Math.ceil((value.len + IndexedDisk.HEADER_SIZE_BYTES) / 1024.0)) * -1));
+                }
+            }
+        }
+
+        /**
+         * This is called when the may key size is reached. The least recently used item will be
+         * passed here. We will store the position and size of the spot on disk in the recycle bin.
+         * <p>
+         * @param key
+         * @param value
+         */
+        @Override
+        protected void processRemovedLRU(K key, IndexedDiskElementDescriptor value )
         {
-            super( maxKeySize );
+            if (value != null) {
+                // keep the content size in kB, so 2^31 kB is reasonable value
+                contentSize.addAndGet((int) ((Math.ceil(value.len / 1024.0)) * -1));
+            }
+            addToRecycleBin( value );
+            if ( log.isDebugEnabled() )
+            {
+                log.debug( logCacheName + "Removing key: [" + key + "] from key store." );
+                log.debug( logCacheName + "Key store size: [" + this.size() + "]." );
+            }
+
+            doOptimizeRealTime();
         }
 
+        @Override
+        protected boolean shouldRemove() {
+            return maxSize > 0 && contentSize.intValue() > maxSize && this.size() > 0;
+        }
+    }
+
+    /**
+     * Class for recycling and lru. This implements the LRU overflow callback, so we can add items
+     * to the recycle bin. This class counts the elements to decide, when to throw away an element
+     */
+
+    public class LRUMapCountLimited
+    extends LRUMap<K, IndexedDiskElementDescriptor>
+    // implements Serializable
+    {
+        public LRUMapCountLimited(int maxKeySize) {
+            super(maxKeySize);
+        }
         /**
          * This is called when the may key size is reached. The least recently used item will be
          * passed here. We will store the position and size of the spot on disk in the recycle bin.

Modified: commons/proper/jcs/trunk/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/disk/indexed/IndexedDiskCacheAttributes.java
URL: http://svn.apache.org/viewvc/commons/proper/jcs/trunk/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/disk/indexed/IndexedDiskCacheAttributes.java?rev=1671552&r1=1671551&r2=1671552&view=diff
==============================================================================
--- commons/proper/jcs/trunk/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/disk/indexed/IndexedDiskCacheAttributes.java (original)
+++ commons/proper/jcs/trunk/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/disk/indexed/IndexedDiskCacheAttributes.java Mon Apr  6 15:28:10 2015
@@ -60,6 +60,8 @@ public class IndexedDiskCacheAttributes
     /** Should we clear the disk on startup. If true the congtents of disk are cleared. */
     private boolean clearDiskOnStartup = DEFAULT_CLEAR_DISK_ON_STARTUP;
 
+    private DiskLimitType diskLimitType = DiskLimitType.COUNT;
+
     /**
      * Constructor for the DiskCacheAttributes object
      */

Added: commons/proper/jcs/trunk/commons-jcs-core/src/main/java/org/apache/commons/jcs/utils/struct/AbstractLRUMap.java
URL: http://svn.apache.org/viewvc/commons/proper/jcs/trunk/commons-jcs-core/src/main/java/org/apache/commons/jcs/utils/struct/AbstractLRUMap.java?rev=1671552&view=auto
==============================================================================
--- commons/proper/jcs/trunk/commons-jcs-core/src/main/java/org/apache/commons/jcs/utils/struct/AbstractLRUMap.java (added)
+++ commons/proper/jcs/trunk/commons-jcs-core/src/main/java/org/apache/commons/jcs/utils/struct/AbstractLRUMap.java Mon Apr  6 15:28:10 2015
@@ -0,0 +1,671 @@
+package org.apache.commons.jcs.utils.struct;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.NoSuchElementException;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantLock;
+
+import org.apache.commons.jcs.engine.control.group.GroupAttrName;
+import org.apache.commons.jcs.engine.stats.StatElement;
+import org.apache.commons.jcs.engine.stats.Stats;
+import org.apache.commons.jcs.engine.stats.behavior.IStatElement;
+import org.apache.commons.jcs.engine.stats.behavior.IStats;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * This is a simple LRUMap. It implements most of the map methods. It is not recommended that you
+ * use any but put, get, remove, and clear.
+ * <p>
+ * Children can implement the processRemovedLRU method if they want to handle the removal of the
+ * lest recently used item.
+ * <p>
+ * This class was abstracted out of the LRU Memory cache. Put, remove, and get should be thread
+ * safe. It uses a hashtable and our own double linked list.
+ * <p>
+ * Locking is done on the instance.
+ * <p>
+ * @author aaron smuts
+ */
+public abstract class AbstractLRUMap<K, V>
+    implements Map<K, V>
+{
+    /** The logger */
+    private static final Log log = LogFactory.getLog( AbstractLRUMap.class );
+
+    /** double linked list for lru */
+    private final DoubleLinkedList<LRUElementDescriptor<K, V>> list;
+
+    /** Map where items are stored by key. */
+    private Map<K, LRUElementDescriptor<K, V>> map;
+
+    /** stats */
+    int hitCnt = 0;
+
+    /** stats */
+    int missCnt = 0;
+
+    /** stats */
+    int putCnt = 0;
+
+    /** make configurable */
+    private int chunkSize = 1;
+
+    private final Lock lock = new ReentrantLock();
+
+    /**
+     * This creates an unbounded version. Setting the max objects will result in spooling on
+     * subsequent puts.
+     */
+    public AbstractLRUMap()
+    {
+        list = new DoubleLinkedList<LRUElementDescriptor<K, V>>();
+
+        // normal hshtable is faster for
+        // sequential keys.
+        map = new ConcurrentHashMap<K, LRUElementDescriptor<K, V>>();
+        // map = new ConcurrentHashMap();
+    }
+
+
+    /**
+     * This simply returned the number of elements in the map.
+     * <p>
+     * @see java.util.Map#size()
+     */
+    @Override
+    public int size()
+    {
+        return map.size();
+    }
+
+    /**
+     * This removes all the items. It clears the map and the double linked list.
+     * <p>
+     * @see java.util.Map#clear()
+     */
+    @Override
+    public void clear()
+    {
+        lock.lock();
+        try
+        {
+            map.clear();
+            list.removeAll();
+        }
+        finally
+        {
+            lock.unlock();
+        }
+    }
+
+    /**
+     * Returns true if the map is empty.
+     * <p>
+     * @see java.util.Map#isEmpty()
+     */
+    @Override
+    public boolean isEmpty()
+    {
+        return map.size() == 0;
+    }
+
+    /**
+     * Returns true if the map contains an element for the supplied key.
+     * <p>
+     * @see java.util.Map#containsKey(java.lang.Object)
+     */
+    @Override
+    public boolean containsKey( Object key )
+    {
+        return map.containsKey( key );
+    }
+
+    /**
+     * This is an expensive operation that determines if the object supplied is mapped to any key.
+     * <p>
+     * @see java.util.Map#containsValue(java.lang.Object)
+     */
+    @Override
+    public boolean containsValue( Object value )
+    {
+        return map.containsValue( value );
+    }
+
+    /**
+     * @return map.values();
+     */
+    @Override
+    public Collection<V> values()
+    {
+        List<V> valueList = new ArrayList<V>(map.size());
+
+        for (LRUElementDescriptor<K, V> value : map.values())
+        {
+            valueList.add(value.getPayload());
+        }
+
+        return valueList;
+    }
+
+    /**
+     * @param source
+     */
+    @Override
+    public void putAll( Map<? extends K, ? extends V> source )
+    {
+        if ( source != null )
+        {
+            for (Map.Entry<? extends K, ? extends V> entry : source.entrySet())
+            {
+                this.put( entry.getKey(), entry.getValue() );
+            }
+        }
+    }
+
+    /**
+     * @param key
+     * @return Object
+     */
+    @Override
+    public V get( Object key )
+    {
+        V retVal = null;
+
+        if ( log.isDebugEnabled() )
+        {
+            log.debug( "getting item  for key " + key );
+        }
+
+        LRUElementDescriptor<K, V> me = map.get( key );
+
+        if ( me != null )
+        {
+            hitCnt++;
+            if ( log.isDebugEnabled() )
+            {
+                log.debug( "LRUMap hit for " + key );
+            }
+
+            retVal = me.getPayload();
+
+            list.makeFirst( me );
+        }
+        else
+        {
+            missCnt++;
+            log.debug( "LRUMap miss for " + key );
+        }
+
+        // verifyCache();
+        return retVal;
+    }
+
+    /**
+     * This gets an element out of the map without adjusting it's posisiton in the LRU. In other
+     * words, this does not count as being used. If the element is the last item in the list, it
+     * will still be the last itme in the list.
+     * <p>
+     * @param key
+     * @return Object
+     */
+    public V getQuiet( Object key )
+    {
+        V ce = null;
+
+        LRUElementDescriptor<K, V> me = map.get( key );
+        if ( me != null )
+        {
+            if ( log.isDebugEnabled() )
+            {
+                log.debug( "LRUMap quiet hit for " + key );
+            }
+
+            ce = me.getPayload();
+        }
+        else if ( log.isDebugEnabled() )
+        {
+            log.debug( "LRUMap quiet miss for " + key );
+        }
+
+        return ce;
+    }
+
+    /**
+     * @param key
+     * @return Object removed
+     */
+    @Override
+    public V remove( Object key )
+    {
+        if ( log.isDebugEnabled() )
+        {
+            log.debug( "removing item for key: " + key );
+        }
+
+        // remove single item.
+        lock.lock();
+        try
+        {
+            LRUElementDescriptor<K, V> me = map.remove(key);
+
+            if (me != null)
+            {
+                list.remove(me);
+                return me.getPayload();
+            }
+        }
+        finally
+        {
+            lock.unlock();
+        }
+
+        return null;
+    }
+
+    /**
+     * @param key
+     * @param value
+     * @return Object
+     */
+    @Override
+    public V put(K key, V value)
+    {
+        putCnt++;
+
+        LRUElementDescriptor<K, V> old = null;
+        lock.lock();
+        try
+        {
+            // TODO address double synchronization of addFirst, use write lock
+            addFirst( key, value );
+            // this must be synchronized
+            LRUElementDescriptor<K, V> first = list.getFirst();
+            old = map.put(first.getKey(), first);
+
+            // If the node was the same as an existing node, remove it.
+            if ( old != null && first.getKey().equals(old.getKey()))
+            {
+                list.remove( old );
+            }
+        }
+        finally
+        {
+            lock.unlock();
+        }
+
+        // If the element limit is reached, we need to spool
+
+        if (shouldRemove())
+        {
+            final boolean debugEnabled = log.isDebugEnabled();
+            if (debugEnabled)
+            {
+                log.debug( "In memory limit reached, removing least recently used." );
+            }
+
+            // The spool will put them in a disk event queue, so there is no
+            // need to pre-queue the queuing. This would be a bit wasteful
+            // and wouldn't save much time in this synchronous call.
+
+            while ( shouldRemove() )
+            {
+                lock.lock();
+                try
+                {
+                    LRUElementDescriptor<K, V> last = list.getLast();
+                    if (last != null)
+                    {
+                        processRemovedLRU(last.getKey(), last.getPayload());
+                        if (map.remove(last.getKey()) == null)
+                        {
+                            log.warn("update: remove failed for key: "
+                                    + last.getKey());
+                            verifyCache();
+                        }
+                        list.removeLast();
+                    }
+                    else
+                    {
+                        verifyCache();
+                        throw new Error("update: last is null!");
+                    }
+                }
+                finally
+                {
+                    lock.unlock();
+                }
+            }
+
+            if ( log.isDebugEnabled() )
+            {
+                log.debug( "update: After spool map size: " + map.size() );
+            }
+            if ( map.size() != dumpCacheSize() )
+            {
+                log.error("update: After spool, size mismatch: map.size() = " + map.size() + ", linked list size = "
+                        + dumpCacheSize());
+            }
+        }
+
+        if ( old != null )
+        {
+            return old.getPayload();
+        }
+        return null;
+    }
+
+    protected abstract boolean shouldRemove();
+
+
+    /**
+     * Adds a new node to the start of the link list.
+     * <p>
+     * @param key
+     * @param val The feature to be added to the First
+     */
+    private void addFirst(K key, V val)
+    {
+        lock.lock();
+        try
+        {
+            LRUElementDescriptor<K, V> me = new LRUElementDescriptor<K, V>(key, val);
+            list.addFirst( me );
+        }
+        finally
+        {
+            lock.unlock();
+        }
+    }
+
+    /**
+     * Returns the size of the list.
+     * <p>
+     * @return int
+     */
+    private int dumpCacheSize()
+    {
+        return list.size();
+    }
+
+    /**
+     * Dump the cache entries from first to list for debugging.
+     */
+    @SuppressWarnings("unchecked") // No generics for public fields
+    public void dumpCacheEntries()
+    {
+        log.debug( "dumpingCacheEntries" );
+        for ( LRUElementDescriptor<K, V> me = list.getFirst(); me != null; me = (LRUElementDescriptor<K, V>) me.next )
+        {
+            if ( log.isDebugEnabled() )
+            {
+                log.debug( "dumpCacheEntries> key=" + me.getKey() + ", val=" + me.getPayload() );
+            }
+        }
+    }
+
+    /**
+     * Dump the cache map for debugging.
+     */
+    public void dumpMap()
+    {
+        log.debug( "dumpingMap" );
+        for (Map.Entry<K, LRUElementDescriptor<K, V>> e : map.entrySet())
+        {
+            LRUElementDescriptor<K, V> me = e.getValue();
+            if ( log.isDebugEnabled() )
+            {
+                log.debug( "dumpMap> key=" + e.getKey() + ", val=" + me.getPayload() );
+            }
+        }
+    }
+
+    /**
+     * Checks to see if all the items that should be in the cache are. Checks consistency between
+     * List and map.
+     */
+    @SuppressWarnings("unchecked") // No generics for public fields
+    protected void verifyCache()
+    {
+        if ( !log.isDebugEnabled() )
+        {
+            return;
+        }
+
+        boolean found = false;
+        log.debug( "verifycache: mapContains " + map.size() + " elements, linked list contains " + dumpCacheSize()
+            + " elements" );
+        log.debug( "verifycache: checking linked list by key " );
+        for (LRUElementDescriptor<K, V> li = list.getFirst(); li != null; li = (LRUElementDescriptor<K, V>) li.next )
+        {
+            K key = li.getKey();
+            if ( !map.containsKey( key ) )
+            {
+                log.error( "verifycache: map does not contain key : " + li.getKey() );
+                log.error( "li.hashcode=" + li.getKey().hashCode() );
+                log.error( "key class=" + key.getClass() );
+                log.error( "key hashcode=" + key.hashCode() );
+                log.error( "key toString=" + key.toString() );
+                if ( key instanceof GroupAttrName )
+                {
+                    GroupAttrName<?> name = (GroupAttrName<?>) key;
+                    log.error( "GroupID hashcode=" + name.groupId.hashCode() );
+                    log.error( "GroupID.class=" + name.groupId.getClass() );
+                    log.error( "AttrName hashcode=" + name.attrName.hashCode() );
+                    log.error( "AttrName.class=" + name.attrName.getClass() );
+                }
+                dumpMap();
+            }
+            else if ( map.get( li.getKey() ) == null )
+            {
+                log.error( "verifycache: linked list retrieval returned null for key: " + li.getKey() );
+            }
+        }
+
+        log.debug( "verifycache: checking linked list by value " );
+        for (LRUElementDescriptor<K, V> li3 = list.getFirst(); li3 != null; li3 = (LRUElementDescriptor<K, V>) li3.next )
+        {
+            if ( map.containsValue( li3 ) == false )
+            {
+                log.error( "verifycache: map does not contain value : " + li3 );
+                dumpMap();
+            }
+        }
+
+        log.debug( "verifycache: checking via keysets!" );
+        for (Iterator<K> itr2 = map.keySet().iterator(); itr2.hasNext(); )
+        {
+            found = false;
+            Serializable val = null;
+            try
+            {
+                val = (Serializable) itr2.next();
+            }
+            catch ( NoSuchElementException nse )
+            {
+                log.error( "verifycache: no such element exception" );
+                continue;
+            }
+
+            for (LRUElementDescriptor<K, V> li2 = list.getFirst(); li2 != null; li2 = (LRUElementDescriptor<K, V>) li2.next )
+            {
+                if ( val.equals( li2.getKey() ) )
+                {
+                    found = true;
+                    break;
+                }
+            }
+            if ( !found )
+            {
+                log.error( "verifycache: key not found in list : " + val );
+                dumpCacheEntries();
+                if ( map.containsKey( val ) )
+                {
+                    log.error( "verifycache: map contains key" );
+                }
+                else
+                {
+                    log.error( "verifycache: map does NOT contain key, what the HECK!" );
+                }
+            }
+        }
+    }
+
+    /**
+     * Logs an error is an element that should be in the cache is not.
+     * <p>
+     * @param key
+     */
+    @SuppressWarnings("unchecked") // No generics for public fields
+    protected void verifyCache( Object key )
+    {
+        if ( !log.isDebugEnabled() )
+        {
+            return;
+        }
+
+        boolean found = false;
+
+        // go through the linked list looking for the key
+        for (LRUElementDescriptor<K, V> li = list.getFirst(); li != null; li = (LRUElementDescriptor<K, V>) li.next )
+        {
+            if ( li.getKey() == key )
+            {
+                found = true;
+                log.debug( "verifycache(key) key match: " + key );
+                break;
+            }
+        }
+        if ( !found )
+        {
+            log.error( "verifycache(key), couldn't find key! : " + key );
+        }
+    }
+
+    /**
+     * This is called when an item is removed from the LRU. We just log some information.
+     * <p>
+     * Children can implement this method for special behavior.
+     * @param key
+     * @param value
+     */
+    protected void processRemovedLRU(K key, V value )
+    {
+        if ( log.isDebugEnabled() )
+        {
+            log.debug( "Removing key: [" + key + "] from LRUMap store, value = [" + value + "]" );
+            log.debug( "LRUMap store size: '" + this.size() + "'." );
+        }
+    }
+
+    /**
+     * The chunk size is the number of items to remove when the max is reached. By default it is 1.
+     * <p>
+     * @param chunkSize The chunkSize to set.
+     */
+    public void setChunkSize( int chunkSize )
+    {
+        this.chunkSize = chunkSize;
+    }
+
+    /**
+     * @return Returns the chunkSize.
+     */
+    public int getChunkSize()
+    {
+        return chunkSize;
+    }
+
+    /**
+     * @return IStats
+     */
+    public IStats getStatistics()
+    {
+        IStats stats = new Stats();
+        stats.setTypeName( "LRUMap" );
+
+        ArrayList<IStatElement<?>> elems = new ArrayList<IStatElement<?>>();
+
+        elems.add(new StatElement<Integer>( "List Size", Integer.valueOf(list.size()) ) );
+        elems.add(new StatElement<Integer>( "Map Size", Integer.valueOf(map.size()) ) );
+        elems.add(new StatElement<Integer>( "Put Count", Integer.valueOf(putCnt) ) );
+        elems.add(new StatElement<Integer>( "Hit Count", Integer.valueOf(hitCnt) ) );
+        elems.add(new StatElement<Integer>( "Miss Count", Integer.valueOf(missCnt) ) );
+
+        stats.setStatElements( elems );
+
+        return stats;
+    }
+
+    /**
+     * This returns a set of entries. Our LRUMapEntry is used since the value stored in the
+     * underlying map is a node in the double linked list. We wouldn't want to return this to the
+     * client, so we construct a new entry with the payload of the node.
+     * <p>
+     * TODO we should return out own set wrapper, so we can avoid the extra object creation if it
+     * isn't necessary.
+     * <p>
+     * @see java.util.Map#entrySet()
+     */
+    @Override
+    public Set<Map.Entry<K, V>> entrySet()
+    {
+        lock.lock();
+        try
+        {
+            // todo, we should return a defensive copy
+            Set<Map.Entry<K, LRUElementDescriptor<K, V>>> entries = map.entrySet();
+
+            Set<Map.Entry<K, V>> unWrapped = new HashSet<Map.Entry<K, V>>();
+
+            for (Map.Entry<K, LRUElementDescriptor<K, V>> pre : entries) {
+                Map.Entry<K, V> post = new LRUMapEntry<K, V>(pre.getKey(), pre.getValue().getPayload());
+                unWrapped.add(post);
+            }
+
+            return unWrapped;
+        }
+        finally
+        {
+            lock.unlock();
+        }
+    }
+
+    /**
+     * @return map.keySet();
+     */
+    @Override
+    public Set<K> keySet()
+    {
+        // TODO fix this, it needs to return the keys inside the wrappers.
+        return map.keySet();
+    }
+
+}

Propchange: commons/proper/jcs/trunk/commons-jcs-core/src/main/java/org/apache/commons/jcs/utils/struct/AbstractLRUMap.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Modified: commons/proper/jcs/trunk/commons-jcs-core/src/main/java/org/apache/commons/jcs/utils/struct/LRUMap.java
URL: http://svn.apache.org/viewvc/commons/proper/jcs/trunk/commons-jcs-core/src/main/java/org/apache/commons/jcs/utils/struct/LRUMap.java?rev=1671552&r1=1671551&r2=1671552&view=diff
==============================================================================
--- commons/proper/jcs/trunk/commons-jcs-core/src/main/java/org/apache/commons/jcs/utils/struct/LRUMap.java (original)
+++ commons/proper/jcs/trunk/commons-jcs-core/src/main/java/org/apache/commons/jcs/utils/struct/LRUMap.java Mon Apr  6 15:28:10 2015
@@ -19,680 +19,42 @@ package org.apache.commons.jcs.utils.str
  * under the License.
  */
 
-import org.apache.commons.jcs.engine.control.group.GroupAttrName;
-import org.apache.commons.jcs.engine.stats.StatElement;
-import org.apache.commons.jcs.engine.stats.Stats;
-import org.apache.commons.jcs.engine.stats.behavior.IStatElement;
-import org.apache.commons.jcs.engine.stats.behavior.IStats;
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-
-import java.io.Serializable;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-import java.util.NoSuchElementException;
-import java.util.Set;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.locks.Lock;
-import java.util.concurrent.locks.ReentrantLock;
+import java.util.concurrent.atomic.AtomicInteger;
 
 /**
- * This is a simple LRUMap. It implements most of the map methods. It is not recommended that you
- * use any but put, get, remove, and clear.
- * <p>
- * Children can implement the processRemovedLRU method if they want to handle the removal of the
- * lest recently used item.
- * <p>
- * This class was abstracted out of the LRU Memory cache. Put, remove, and get should be thread
- * safe. It uses a hashtable and our own double linked list.
- * <p>
- * Locking is done on the instance.
- * <p>
- * @author aaron smuts
+ *
+ * @author Wiktor Niesiobędzki
+ *
+ * Simple LRUMap implementation that keeps the number of the objects below or equal maxObjects
+ *
+ * @param <K>
+ * @param <V>
  */
-public class LRUMap<K, V>
-    implements Map<K, V>
-{
-    /** The logger */
-    private static final Log log = LogFactory.getLog( LRUMap.class );
-
-    /** double linked list for lru */
-    private final DoubleLinkedList<LRUElementDescriptor<K, V>> list;
-
-    /** Map where items are stored by key. */
-    private Map<K, LRUElementDescriptor<K, V>> map;
-
-    /** stats */
-    int hitCnt = 0;
-
-    /** stats */
-    int missCnt = 0;
-
-    /** stats */
-    int putCnt = 0;
+public class LRUMap<K, V> extends AbstractLRUMap<K, V> {
 
     /** if the max is less than 0, there is no limit! */
     int maxObjects = -1;
+    AtomicInteger counter = new AtomicInteger(0);
 
-    /** make configurable */
-    private int chunkSize = 1;
-
-    private final Lock lock = new ReentrantLock();
-
-    /**
-     * This creates an unbounded version. Setting the max objects will result in spooling on
-     * subsequent puts.
-     */
-    public LRUMap()
-    {
-        list = new DoubleLinkedList<LRUElementDescriptor<K, V>>();
-
-        // normal hshtable is faster for
-        // sequential keys.
-        map = new ConcurrentHashMap<K, LRUElementDescriptor<K, V>>();
-        // map = new ConcurrentHashMap();
+    public LRUMap() {
+        super();
     }
 
     /**
-     * This sets the size limit.
-     * <p>
-     * @param maxObjects
+     *
+     * @param maxObjects maximum number to keep in the map
      */
-    public LRUMap( int maxObjects )
-    {
-        this();
+    public LRUMap(int maxObjects) {
+        super();
         this.maxObjects = maxObjects;
     }
 
-    /**
-     * This simply returned the number of elements in the map.
-     * <p>
-     * @see java.util.Map#size()
-     */
-    @Override
-    public int size()
-    {
-        return map.size();
-    }
-
-    /**
-     * This removes all the items. It clears the map and the double linked list.
-     * <p>
-     * @see java.util.Map#clear()
-     */
-    @Override
-    public void clear()
-    {
-        lock.lock();
-        try
-        {
-            map.clear();
-            list.removeAll();
-        }
-        finally
-        {
-            lock.unlock();
-        }
-    }
-
-    /**
-     * Returns true if the map is empty.
-     * <p>
-     * @see java.util.Map#isEmpty()
-     */
-    @Override
-    public boolean isEmpty()
-    {
-        return map.size() == 0;
-    }
-
-    /**
-     * Returns true if the map contains an element for the supplied key.
-     * <p>
-     * @see java.util.Map#containsKey(java.lang.Object)
-     */
-    @Override
-    public boolean containsKey( Object key )
-    {
-        return map.containsKey( key );
-    }
-
-    /**
-     * This is an expensive operation that determines if the object supplied is mapped to any key.
-     * <p>
-     * @see java.util.Map#containsValue(java.lang.Object)
-     */
-    @Override
-    public boolean containsValue( Object value )
-    {
-        return map.containsValue( value );
-    }
-
-    /**
-     * @return map.values();
-     */
-    @Override
-    public Collection<V> values()
-    {
-        List<V> valueList = new ArrayList<V>(map.size());
-
-        for (LRUElementDescriptor<K, V> value : map.values())
-        {
-            valueList.add(value.getPayload());
-        }
-
-        return valueList;
-    }
-
-    /**
-     * @param source
-     */
-    @Override
-    public void putAll( Map<? extends K, ? extends V> source )
-    {
-        if ( source != null )
-        {
-            for (Map.Entry<? extends K, ? extends V> entry : source.entrySet())
-            {
-                this.put( entry.getKey(), entry.getValue() );
-            }
-        }
-    }
-
-    /**
-     * @param key
-     * @return Object
-     */
-    @Override
-    public V get( Object key )
-    {
-        V retVal = null;
-
-        if ( log.isDebugEnabled() )
-        {
-            log.debug( "getting item  for key " + key );
-        }
-
-        LRUElementDescriptor<K, V> me = map.get( key );
-
-        if ( me != null )
-        {
-            hitCnt++;
-            if ( log.isDebugEnabled() )
-            {
-                log.debug( "LRUMap hit for " + key );
-            }
-
-            retVal = me.getPayload();
-
-            list.makeFirst( me );
-        }
-        else
-        {
-            missCnt++;
-            log.debug( "LRUMap miss for " + key );
-        }
-
-        // verifyCache();
-        return retVal;
-    }
-
-    /**
-     * This gets an element out of the map without adjusting it's posisiton in the LRU. In other
-     * words, this does not count as being used. If the element is the last item in the list, it
-     * will still be the last itme in the list.
-     * <p>
-     * @param key
-     * @return Object
-     */
-    public V getQuiet( Object key )
-    {
-        V ce = null;
-
-        LRUElementDescriptor<K, V> me = map.get( key );
-        if ( me != null )
-        {
-            if ( log.isDebugEnabled() )
-            {
-                log.debug( "LRUMap quiet hit for " + key );
-            }
-
-            ce = me.getPayload();
-        }
-        else if ( log.isDebugEnabled() )
-        {
-            log.debug( "LRUMap quiet miss for " + key );
-        }
-
-        return ce;
-    }
-
-    /**
-     * @param key
-     * @return Object removed
-     */
-    @Override
-    public V remove( Object key )
-    {
-        if ( log.isDebugEnabled() )
-        {
-            log.debug( "removing item for key: " + key );
-        }
-
-        // remove single item.
-        lock.lock();
-        try
-        {
-            LRUElementDescriptor<K, V> me = map.remove(key);
-
-            if (me != null)
-            {
-                list.remove(me);
-                return me.getPayload();
-            }
-        }
-        finally
-        {
-            lock.unlock();
-        }
-
-        return null;
-    }
-
-    /**
-     * @param key
-     * @param value
-     * @return Object
-     */
-    @Override
-    public V put(K key, V value)
-    {
-        putCnt++;
-
-        LRUElementDescriptor<K, V> old = null;
-        lock.lock();
-        try
-        {
-            // TODO address double synchronization of addFirst, use write lock
-            addFirst( key, value );
-            // this must be synchronized
-            LRUElementDescriptor<K, V> first = list.getFirst();
-            old = map.put(first.getKey(), first);
-
-            // If the node was the same as an existing node, remove it.
-            if ( old != null && first.getKey().equals(old.getKey()))
-            {
-                list.remove( old );
-            }
-        }
-        finally
-        {
-            lock.unlock();
-        }
-
-        int size = map.size();
-        // If the element limit is reached, we need to spool
-
-        if ( this.maxObjects >= 0 && size > this.maxObjects )
-        {
-            final boolean debugEnabled = log.isDebugEnabled();
-            if (debugEnabled)
-            {
-                log.debug( "In memory limit reached, removing least recently used." );
-            }
-
-            // Write the last 'chunkSize' items to disk.
-            int chunkSizeCorrected = Math.min( size, getChunkSize() );
-
-            if (debugEnabled)
-            {
-                log.debug( "About to remove the least recently used. map size: " + size + ", max objects: "
-                    + this.maxObjects + ", items to spool: " + chunkSizeCorrected );
-            }
-
-            // The spool will put them in a disk event queue, so there is no
-            // need to pre-queue the queuing. This would be a bit wasteful
-            // and wouldn't save much time in this synchronous call.
-
-            for ( int i = 0; i < chunkSizeCorrected; i++ )
-            {
-                lock.lock();
-                try
-                {
-                    LRUElementDescriptor<K, V> last = list.getLast();
-                    if (last != null)
-                    {
-                        processRemovedLRU(last.getKey(), last.getPayload());
-                        if (map.remove(last.getKey()) == null)
-                        {
-                            log.warn("update: remove failed for key: "
-                                    + last.getKey());
-                            verifyCache();
-                        }
-                        list.removeLast();
-                    }
-                    else
-                    {
-                        verifyCache();
-                        throw new Error("update: last is null!");
-                    }
-                }
-                finally
-                {
-                    lock.unlock();
-                }
-            }
-
-            if ( log.isDebugEnabled() )
-            {
-                log.debug( "update: After spool map size: " + map.size() );
-            }
-            if ( map.size() != dumpCacheSize() )
-            {
-                log.error("update: After spool, size mismatch: map.size() = " + map.size() + ", linked list size = "
-                        + dumpCacheSize());
-            }
-        }
-
-        if ( old != null )
-        {
-            return old.getPayload();
-        }
-        return null;
-    }
-
-    /**
-     * Adds a new node to the start of the link list.
-     * <p>
-     * @param key
-     * @param val The feature to be added to the First
-     */
-    private void addFirst(K key, V val)
-    {
-        lock.lock();
-        try
-        {
-            LRUElementDescriptor<K, V> me = new LRUElementDescriptor<K, V>(key, val);
-            list.addFirst( me );
-        }
-        finally
-        {
-            lock.unlock();
-        }
-    }
-
-    /**
-     * Returns the size of the list.
-     * <p>
-     * @return int
-     */
-    private int dumpCacheSize()
-    {
-        return list.size();
-    }
-
-    /**
-     * Dump the cache entries from first to list for debugging.
-     */
-    @SuppressWarnings("unchecked") // No generics for public fields
-    public void dumpCacheEntries()
-    {
-        log.debug( "dumpingCacheEntries" );
-        for ( LRUElementDescriptor<K, V> me = list.getFirst(); me != null; me = (LRUElementDescriptor<K, V>) me.next )
-        {
-            if ( log.isDebugEnabled() )
-            {
-                log.debug( "dumpCacheEntries> key=" + me.getKey() + ", val=" + me.getPayload() );
-            }
-        }
-    }
-
-    /**
-     * Dump the cache map for debugging.
-     */
-    public void dumpMap()
-    {
-        log.debug( "dumpingMap" );
-        for (Map.Entry<K, LRUElementDescriptor<K, V>> e : map.entrySet())
-        {
-            LRUElementDescriptor<K, V> me = e.getValue();
-            if ( log.isDebugEnabled() )
-            {
-                log.debug( "dumpMap> key=" + e.getKey() + ", val=" + me.getPayload() );
-            }
-        }
-    }
-
-    /**
-     * Checks to see if all the items that should be in the cache are. Checks consistency between
-     * List and map.
-     */
-    @SuppressWarnings("unchecked") // No generics for public fields
-    protected void verifyCache()
-    {
-        if ( !log.isDebugEnabled() )
-        {
-            return;
-        }
-
-        boolean found = false;
-        log.debug( "verifycache: mapContains " + map.size() + " elements, linked list contains " + dumpCacheSize()
-            + " elements" );
-        log.debug( "verifycache: checking linked list by key " );
-        for (LRUElementDescriptor<K, V> li = list.getFirst(); li != null; li = (LRUElementDescriptor<K, V>) li.next )
-        {
-            K key = li.getKey();
-            if ( !map.containsKey( key ) )
-            {
-                log.error( "verifycache: map does not contain key : " + li.getKey() );
-                log.error( "li.hashcode=" + li.getKey().hashCode() );
-                log.error( "key class=" + key.getClass() );
-                log.error( "key hashcode=" + key.hashCode() );
-                log.error( "key toString=" + key.toString() );
-                if ( key instanceof GroupAttrName )
-                {
-                    GroupAttrName<?> name = (GroupAttrName<?>) key;
-                    log.error( "GroupID hashcode=" + name.groupId.hashCode() );
-                    log.error( "GroupID.class=" + name.groupId.getClass() );
-                    log.error( "AttrName hashcode=" + name.attrName.hashCode() );
-                    log.error( "AttrName.class=" + name.attrName.getClass() );
-                }
-                dumpMap();
-            }
-            else if ( map.get( li.getKey() ) == null )
-            {
-                log.error( "verifycache: linked list retrieval returned null for key: " + li.getKey() );
-            }
-        }
-
-        log.debug( "verifycache: checking linked list by value " );
-        for (LRUElementDescriptor<K, V> li3 = list.getFirst(); li3 != null; li3 = (LRUElementDescriptor<K, V>) li3.next )
-        {
-            if ( map.containsValue( li3 ) == false )
-            {
-                log.error( "verifycache: map does not contain value : " + li3 );
-                dumpMap();
-            }
-        }
-
-        log.debug( "verifycache: checking via keysets!" );
-        for (Iterator<K> itr2 = map.keySet().iterator(); itr2.hasNext(); )
-        {
-            found = false;
-            Serializable val = null;
-            try
-            {
-                val = (Serializable) itr2.next();
-            }
-            catch ( NoSuchElementException nse )
-            {
-                log.error( "verifycache: no such element exception" );
-                continue;
-            }
-
-            for (LRUElementDescriptor<K, V> li2 = list.getFirst(); li2 != null; li2 = (LRUElementDescriptor<K, V>) li2.next )
-            {
-                if ( val.equals( li2.getKey() ) )
-                {
-                    found = true;
-                    break;
-                }
-            }
-            if ( !found )
-            {
-                log.error( "verifycache: key not found in list : " + val );
-                dumpCacheEntries();
-                if ( map.containsKey( val ) )
-                {
-                    log.error( "verifycache: map contains key" );
-                }
-                else
-                {
-                    log.error( "verifycache: map does NOT contain key, what the HECK!" );
-                }
-            }
-        }
-    }
-
-    /**
-     * Logs an error is an element that should be in the cache is not.
-     * <p>
-     * @param key
-     */
-    @SuppressWarnings("unchecked") // No generics for public fields
-    protected void verifyCache( Object key )
-    {
-        if ( !log.isDebugEnabled() )
-        {
-            return;
-        }
-
-        boolean found = false;
-
-        // go through the linked list looking for the key
-        for (LRUElementDescriptor<K, V> li = list.getFirst(); li != null; li = (LRUElementDescriptor<K, V>) li.next )
-        {
-            if ( li.getKey() == key )
-            {
-                found = true;
-                log.debug( "verifycache(key) key match: " + key );
-                break;
-            }
-        }
-        if ( !found )
-        {
-            log.error( "verifycache(key), couldn't find key! : " + key );
-        }
-    }
-
-    /**
-     * This is called when an item is removed from the LRU. We just log some information.
-     * <p>
-     * Children can implement this method for special behavior.
-     * @param key
-     * @param value
-     */
-    protected void processRemovedLRU(K key, V value )
-    {
-        if ( log.isDebugEnabled() )
-        {
-            log.debug( "Removing key: [" + key + "] from LRUMap store, value = [" + value + "]" );
-            log.debug( "LRUMap store size: '" + this.size() + "'." );
-        }
-    }
-
-    /**
-     * The chunk size is the number of items to remove when the max is reached. By default it is 1.
-     * <p>
-     * @param chunkSize The chunkSize to set.
-     */
-    public void setChunkSize( int chunkSize )
-    {
-        this.chunkSize = chunkSize;
-    }
-
-    /**
-     * @return Returns the chunkSize.
-     */
-    public int getChunkSize()
-    {
-        return chunkSize;
-    }
-
-    /**
-     * @return IStats
-     */
-    public IStats getStatistics()
-    {
-        IStats stats = new Stats();
-        stats.setTypeName( "LRUMap" );
-
-        ArrayList<IStatElement<?>> elems = new ArrayList<IStatElement<?>>();
-
-        elems.add(new StatElement<Integer>( "List Size", Integer.valueOf(list.size()) ) );
-        elems.add(new StatElement<Integer>( "Map Size", Integer.valueOf(map.size()) ) );
-        elems.add(new StatElement<Integer>( "Put Count", Integer.valueOf(putCnt) ) );
-        elems.add(new StatElement<Integer>( "Hit Count", Integer.valueOf(hitCnt) ) );
-        elems.add(new StatElement<Integer>( "Miss Count", Integer.valueOf(missCnt) ) );
-
-        stats.setStatElements( elems );
-
-        return stats;
-    }
-
-    /**
-     * This returns a set of entries. Our LRUMapEntry is used since the value stored in the
-     * underlying map is a node in the double linked list. We wouldn't want to return this to the
-     * client, so we construct a new entry with the payload of the node.
-     * <p>
-     * TODO we should return out own set wrapper, so we can avoid the extra object creation if it
-     * isn't necessary.
-     * <p>
-     * @see java.util.Map#entrySet()
-     */
     @Override
-    public Set<Map.Entry<K, V>> entrySet()
-    {
-        lock.lock();
-        try
-        {
-            // todo, we should return a defensive copy
-            Set<Map.Entry<K, LRUElementDescriptor<K, V>>> entries = map.entrySet();
-
-            Set<Map.Entry<K, V>> unWrapped = new HashSet<Map.Entry<K, V>>();
-
-            for (Map.Entry<K, LRUElementDescriptor<K, V>> pre : entries) {
-                Map.Entry<K, V> post = new LRUMapEntry<K, V>(pre.getKey(), pre.getValue().getPayload());
-                unWrapped.add(post);
-            }
-
-            return unWrapped;
-        }
-        finally
-        {
-            lock.unlock();
-        }
+    public boolean shouldRemove() {
+    	return maxObjects > 0 && this.size() > maxObjects; 
     }
 
-    /**
-     * @return map.keySet();
-     */
-    @Override
-    public Set<K> keySet()
-    {
-        // TODO fix this, it needs to return the keys inside the wrappers.
-        return map.keySet();
-    }
-
-    /**
-     * @return the max objects size.
-     */
-    public int getMaxObjects()
-    {
-        return maxObjects;
-    }
+    public Object getMaxCounter() {
+		return maxObjects;
+	}
 }

Modified: commons/proper/jcs/trunk/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/disk/DiskTestObject.java
URL: http://svn.apache.org/viewvc/commons/proper/jcs/trunk/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/disk/DiskTestObject.java?rev=1671552&r1=1671551&r2=1671552&view=diff
==============================================================================
--- commons/proper/jcs/trunk/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/disk/DiskTestObject.java (original)
+++ commons/proper/jcs/trunk/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/disk/DiskTestObject.java Mon Apr  6 15:28:10 2015
@@ -20,6 +20,7 @@ package org.apache.commons.jcs.auxiliary
  */
 
 import java.io.Serializable;
+import java.util.Arrays;
 
 /**
  * Resembles a cached image.
@@ -49,4 +50,15 @@ public class DiskTestObject
         this.id = id;
         this.imageBytes = imageBytes;
     }
+    
+    public boolean equals(Object other) {
+    	if (other instanceof DiskTestObject) {
+    		DiskTestObject o = (DiskTestObject)other;
+    		if (id != null)
+    			return id.equals(o.id) && Arrays.equals(imageBytes, o.imageBytes);
+    		else if (id ==null && o.id == null)
+    			return Arrays.equals(imageBytes, o.imageBytes);
+    	}
+    	return false;
+    }
 }

Modified: commons/proper/jcs/trunk/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/disk/LRUMapJCSUnitTest.java
URL: http://svn.apache.org/viewvc/commons/proper/jcs/trunk/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/disk/LRUMapJCSUnitTest.java?rev=1671552&r1=1671551&r2=1671552&view=diff
==============================================================================
--- commons/proper/jcs/trunk/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/disk/LRUMapJCSUnitTest.java (original)
+++ commons/proper/jcs/trunk/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/disk/LRUMapJCSUnitTest.java Mon Apr  6 15:28:10 2015
@@ -20,7 +20,9 @@ package org.apache.commons.jcs.auxiliary
  */
 
 import junit.framework.TestCase;
+
 import org.apache.commons.jcs.TestLogConfigurationUtil;
+import org.apache.commons.jcs.auxiliary.disk.LRUMapJCS;
 
 import java.io.StringWriter;
 
@@ -37,7 +39,7 @@ public class LRUMapJCSUnitTest
         LRUMapJCS<String, String> map = new LRUMapJCS<String, String>();
 
         // VERIFY
-        assertEquals( "Should be unlimted", -1, map.getMaxObjects() );
+        assertEquals( "Should be unlimted", -1, map.getMaxCounter() );
     }
 
     /** Verify that we default to unlimited */
@@ -50,7 +52,7 @@ public class LRUMapJCSUnitTest
         LRUMapJCS<String, String> map = new LRUMapJCS<String, String>( expected );
 
         // VERIFY
-        assertEquals( "Should be expected", expected, map.getMaxObjects() );
+        assertEquals( "Should be expected", expected, map.getMaxCounter() );
     }
 
     /** Verify that the log message. */

Modified: commons/proper/jcs/trunk/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/disk/block/BlockDiskCacheKeyStoreUnitTest.java
URL: http://svn.apache.org/viewvc/commons/proper/jcs/trunk/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/disk/block/BlockDiskCacheKeyStoreUnitTest.java?rev=1671552&r1=1671551&r2=1671552&view=diff
==============================================================================
--- commons/proper/jcs/trunk/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/disk/block/BlockDiskCacheKeyStoreUnitTest.java (original)
+++ commons/proper/jcs/trunk/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/disk/block/BlockDiskCacheKeyStoreUnitTest.java Mon Apr  6 15:28:10 2015
@@ -19,6 +19,8 @@ package org.apache.commons.jcs.auxiliary
  * under the License.
  */
 
+import org.apache.commons.jcs.auxiliary.disk.behavior.IDiskCacheAttributes.DiskLimitType;
+
 import junit.framework.TestCase;
 
 /**
@@ -41,16 +43,31 @@ public class BlockDiskCacheKeyStoreUnitT
         throws Exception
     {
         // SETUP
-        String regionName = "testPutKeys";
-        int maxKeys = 1000;
-        int bytesPerBlock = 2000;
+        BlockDiskCacheAttributes attributes = new BlockDiskCacheAttributes();
+        attributes.setCacheName( "testPutKeys" );
+        attributes.setDiskPath( rootDirName );
+        attributes.setMaxKeySize( 1000 );
+        attributes.setBlockSizeBytes( 2000 );
 
+        innerTestPutKeys(attributes);
+            }
+
+    public void testPutKeysSize()
+            throws Exception
+            {
+        // SETUP
         BlockDiskCacheAttributes attributes = new BlockDiskCacheAttributes();
-        attributes.setCacheName( regionName );
+        attributes.setCacheName( "testPutKeys" );
         attributes.setDiskPath( rootDirName );
-        attributes.setMaxKeySize( maxKeys );
-        attributes.setBlockSizeBytes( bytesPerBlock );
+        attributes.setMaxKeySize( 100000 );
+        attributes.setBlockSizeBytes( 1024 );
+        attributes.setDiskLimitType(DiskLimitType.SIZE);
 
+        innerTestPutKeys(attributes);
+            }
+
+
+    private void innerTestPutKeys(BlockDiskCacheAttributes attributes) {
         BlockDiskCache<String, String> blockDiskCache = new BlockDiskCache<String, String>( attributes );
 
         BlockDiskKeyStore<String> keyStore = new BlockDiskKeyStore<String>( attributes, blockDiskCache );
@@ -82,16 +99,31 @@ public class BlockDiskCacheKeyStoreUnitT
         throws Exception
     {
         // SETUP
-        String regionName = "testSaveLoadKeys";
-        int maxKeys = 10000;
-        int bytesPerBlock = 2000;
+        BlockDiskCacheAttributes attributes = new BlockDiskCacheAttributes();
+        attributes.setCacheName( "testSaveLoadKeys" );
+        attributes.setDiskPath( rootDirName );
+        attributes.setMaxKeySize( 10000 );
+        attributes.setBlockSizeBytes( 2000 );
 
+        testSaveLoadKeysInner(attributes);
+            }
+
+    public void testSaveLoadKeysSize()
+            throws Exception
+            {
+        // SETUP
         BlockDiskCacheAttributes attributes = new BlockDiskCacheAttributes();
-        attributes.setCacheName( regionName );
+        attributes.setCacheName( "testSaveLoadKeys" );
         attributes.setDiskPath( rootDirName );
-        attributes.setMaxKeySize( maxKeys );
-        attributes.setBlockSizeBytes( bytesPerBlock );
+        attributes.setMaxKeySize( 10000 );
+        attributes.setBlockSizeBytes( 2000 );
+
+        testSaveLoadKeysInner(attributes);
+            }
+
+
 
+    private void testSaveLoadKeysInner(BlockDiskCacheAttributes attributes) {
         BlockDiskKeyStore<String> keyStore = new BlockDiskKeyStore<String>( attributes, null );
 
         // DO WORK
@@ -126,4 +158,21 @@ public class BlockDiskCacheKeyStoreUnitT
             assertEquals( "Wrong array returned.", i, result.length );
         }
     }
+
+    public void testObjectLargerThanMaxSize() {
+        BlockDiskCacheAttributes attributes = new BlockDiskCacheAttributes();
+        attributes.setCacheName( "testObjectLargerThanMaxSize" );
+        attributes.setDiskPath( rootDirName );
+        attributes.setMaxKeySize( 1000 );
+        attributes.setBlockSizeBytes( 2000 );
+        attributes.setDiskLimitType(DiskLimitType.SIZE);
+
+        @SuppressWarnings({ "unchecked", "rawtypes" })
+        BlockDiskKeyStore<String> keyStore = new BlockDiskKeyStore<String>( attributes, new BlockDiskCache(attributes));
+
+        keyStore.put("1", new int[1000]);
+        keyStore.put("2", new int[1000]);
+        assertNull(keyStore.get("1"));
+        assertNotNull(keyStore.get("2"));
+    }
 }

Modified: commons/proper/jcs/trunk/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/disk/block/BlockDiskCacheUnitTest.java
URL: http://svn.apache.org/viewvc/commons/proper/jcs/trunk/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/disk/block/BlockDiskCacheUnitTest.java?rev=1671552&r1=1671551&r2=1671552&view=diff
==============================================================================
--- commons/proper/jcs/trunk/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/disk/block/BlockDiskCacheUnitTest.java (original)
+++ commons/proper/jcs/trunk/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/disk/block/BlockDiskCacheUnitTest.java Mon Apr  6 15:28:10 2015
@@ -29,7 +29,7 @@ import java.io.Serializable;
 import java.util.Map;
 
 /** Unit tests for the Block Disk Cache */
-public class BlockDiskCacheUnitTest
+public abstract class BlockDiskCacheUnitTest
     extends TestCase
 {
     /**
@@ -37,6 +37,9 @@ public class BlockDiskCacheUnitTest
      * <p>
      * @throws Exception
      */
+	
+	public abstract BlockDiskCacheAttributes getCacheAttributes();
+	
     public void testPutGetMatching_SmallWait()
         throws Exception
     {
@@ -44,7 +47,7 @@ public class BlockDiskCacheUnitTest
         int items = 200;
 
         String cacheName = "testPutGetMatching_SmallWait";
-        BlockDiskCacheAttributes cattr = new BlockDiskCacheAttributes();
+        BlockDiskCacheAttributes cattr = getCacheAttributes();
         cattr.setCacheName( cacheName );
         cattr.setMaxKeySize( 100 );
         cattr.setDiskPath( "target/test-sandbox/BlockDiskCacheUnitTest" );
@@ -77,7 +80,7 @@ public class BlockDiskCacheUnitTest
         int items = 200;
 
         String cacheName = "testPutGetMatching_NoWait";
-        BlockDiskCacheAttributes cattr = new BlockDiskCacheAttributes();
+        BlockDiskCacheAttributes cattr = getCacheAttributes();
         cattr.setCacheName( cacheName );
         cattr.setMaxKeySize( 100 );
         cattr.setDiskPath( "target/test-sandbox/BlockDiskCacheUnitTest" );
@@ -165,7 +168,7 @@ public class BlockDiskCacheUnitTest
 
         String cacheName = "testPutGet_BigString";
 
-        BlockDiskCacheAttributes cattr = new BlockDiskCacheAttributes();
+        BlockDiskCacheAttributes cattr = getCacheAttributes();
         cattr.setCacheName( cacheName );
         cattr.setMaxKeySize( 100 );
         cattr.setBlockSizeBytes( 200 );
@@ -208,7 +211,7 @@ public class BlockDiskCacheUnitTest
 
         String cacheName = "testUTF8String";
 
-        BlockDiskCacheAttributes cattr = new BlockDiskCacheAttributes();
+        BlockDiskCacheAttributes cattr = getCacheAttributes();
         cattr.setCacheName( cacheName );
         cattr.setMaxKeySize( 100 );
         cattr.setBlockSizeBytes( 200 );
@@ -252,7 +255,7 @@ public class BlockDiskCacheUnitTest
 
         String cacheName = "testUTF8ByteArray";
 
-        BlockDiskCacheAttributes cattr = new BlockDiskCacheAttributes();
+        BlockDiskCacheAttributes cattr = getCacheAttributes();
         cattr.setCacheName( cacheName );
         cattr.setMaxKeySize( 100 );
         cattr.setBlockSizeBytes( 200 );
@@ -301,7 +304,7 @@ public class BlockDiskCacheUnitTest
 
         String cacheName = "testUTF8StringAndBytes";
 
-        BlockDiskCacheAttributes cattr = new BlockDiskCacheAttributes();
+        BlockDiskCacheAttributes cattr = getCacheAttributes();
         cattr.setCacheName( cacheName );
         cattr.setMaxKeySize( 100 );
         cattr.setBlockSizeBytes( 500 );

Added: commons/proper/jcs/trunk/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/disk/block/BlockDiskCacheUnitTestCount.java
URL: http://svn.apache.org/viewvc/commons/proper/jcs/trunk/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/disk/block/BlockDiskCacheUnitTestCount.java?rev=1671552&view=auto
==============================================================================
--- commons/proper/jcs/trunk/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/disk/block/BlockDiskCacheUnitTestCount.java (added)
+++ commons/proper/jcs/trunk/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/disk/block/BlockDiskCacheUnitTestCount.java Mon Apr  6 15:28:10 2015
@@ -0,0 +1,14 @@
+package org.apache.commons.jcs.auxiliary.disk.block;
+
+import org.apache.commons.jcs.auxiliary.disk.behavior.IDiskCacheAttributes.DiskLimitType;
+
+public class BlockDiskCacheUnitTestCount extends BlockDiskCacheUnitTest {
+
+	@Override
+	public BlockDiskCacheAttributes getCacheAttributes() {
+		BlockDiskCacheAttributes ret = new BlockDiskCacheAttributes();
+		ret.setDiskLimitType(DiskLimitType.COUNT);
+		return ret;
+	}
+
+}

Propchange: commons/proper/jcs/trunk/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/disk/block/BlockDiskCacheUnitTestCount.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: commons/proper/jcs/trunk/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/disk/block/BlockDiskCacheUnitTestSize.java
URL: http://svn.apache.org/viewvc/commons/proper/jcs/trunk/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/disk/block/BlockDiskCacheUnitTestSize.java?rev=1671552&view=auto
==============================================================================
--- commons/proper/jcs/trunk/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/disk/block/BlockDiskCacheUnitTestSize.java (added)
+++ commons/proper/jcs/trunk/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/disk/block/BlockDiskCacheUnitTestSize.java Mon Apr  6 15:28:10 2015
@@ -0,0 +1,14 @@
+package org.apache.commons.jcs.auxiliary.disk.block;
+
+import org.apache.commons.jcs.auxiliary.disk.behavior.IDiskCacheAttributes.DiskLimitType;
+
+public class BlockDiskCacheUnitTestSize extends BlockDiskCacheUnitTest {
+
+	@Override
+	public BlockDiskCacheAttributes getCacheAttributes() {
+		BlockDiskCacheAttributes ret = new BlockDiskCacheAttributes();
+		ret.setDiskLimitType(DiskLimitType.SIZE);
+		return ret;
+	}
+
+}

Propchange: commons/proper/jcs/trunk/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/disk/block/BlockDiskCacheUnitTestSize.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain