Performance improvements

git-svn-id: https://svn.apache.org/repos/asf/commons/proper/jcs/trunk@1776744 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/utils/struct/AbstractLRUMap.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/utils/struct/AbstractLRUMap.java
index c747f4c..9effd97 100644
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/utils/struct/AbstractLRUMap.java
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs/utils/struct/AbstractLRUMap.java
@@ -64,22 +64,20 @@
     private final DoubleLinkedList<LRUElementDescriptor<K, V>> list;
 
     /** Map where items are stored by key. */
-    private Map<K, LRUElementDescriptor<K, V>> map;
+    private final Map<K, LRUElementDescriptor<K, V>> map;
 
-    /** stats */
-    int hitCnt = 0;
-
-    /** stats */
-    int missCnt = 0;
-
-    /** stats */
-    int putCnt = 0;
-
-    /** make configurable */
-    private int chunkSize = 1;
-
+    /** lock to keep map and list synchronous */
     private final Lock lock = new ReentrantLock();
 
+    /** stats */
+    private long hitCnt = 0;
+
+    /** stats */
+    private long missCnt = 0;
+
+    /** stats */
+    private long putCnt = 0;
+
     /**
      * This creates an unbounded version. Setting the max objects will result in spooling on
      * subsequent puts.
@@ -196,7 +194,7 @@
     @Override
     public V get( Object key )
     {
-        V retVal = null;
+        V retVal;
 
         if ( log.isDebugEnabled() )
         {
@@ -205,22 +203,28 @@
 
         LRUElementDescriptor<K, V> me = map.get( key );
 
-        if ( me != null )
+        if ( me == null )
         {
-            hitCnt++;
-            if ( log.isDebugEnabled() )
-            {
-                log.debug( "LRUMap hit for " + key );
-            }
-
-            retVal = me.getPayload();
-
-            list.makeFirst( me );
+            missCnt++;
+            retVal = null;
         }
         else
         {
-            missCnt++;
-            log.debug( "LRUMap miss for " + key );
+            hitCnt++;
+            retVal = me.getPayload();
+            list.makeFirst( me );
+        }
+
+        if ( log.isDebugEnabled() )
+        {
+            if ( me == null )
+            {
+                log.debug( "LRUMap miss for " + key );
+            }
+            else
+            {
+                log.debug( "LRUMap hit for " + key );
+            }
         }
 
         // verifyCache();
@@ -238,20 +242,23 @@
     public V getQuiet( Object key )
     {
         V ce = null;
-
         LRUElementDescriptor<K, V> me = map.get( key );
+
         if ( me != null )
         {
-            if ( log.isDebugEnabled() )
+            ce = me.getPayload();
+        }
+
+        if ( log.isDebugEnabled() )
+        {
+            if ( me == null )
+            {
+                log.debug( "LRUMap quiet miss for " + key );
+            }
+            else
             {
                 log.debug( "LRUMap quiet hit for " + key );
             }
-
-            ce = me.getPayload();
-        }
-        else if ( log.isDebugEnabled() )
-        {
-            log.debug( "LRUMap quiet miss for " + key );
         }
 
         return ce;
@@ -300,17 +307,16 @@
         putCnt++;
 
         LRUElementDescriptor<K, V> old = null;
+        LRUElementDescriptor<K, V> me = new LRUElementDescriptor<K, V>(key, value);
+
         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);
+            list.addFirst( me );
+            old = map.put(key, me);
 
             // If the node was the same as an existing node, remove it.
-            if ( old != null && first.getKey().equals(old.getKey()))
+            if ( old != null && key.equals(old.getKey()))
             {
                 list.remove( old );
             }
@@ -321,7 +327,6 @@
         }
 
         // If the element limit is reached, we need to spool
-
         if (shouldRemove())
         {
             if (log.isDebugEnabled())
@@ -332,7 +337,6 @@
             // 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();
@@ -366,10 +370,10 @@
             {
                 log.debug( "update: After spool map size: " + map.size() );
             }
-            if ( map.size() != dumpCacheSize() )
+            if ( map.size() != list.size() )
             {
-                log.error("update: After spool, size mismatch: map.size() = " + map.size() + ", linked list size = "
-                        + dumpCacheSize());
+                log.error("update: After spool, size mismatch: map.size() = " + map.size() +
+                        ", linked list size = " + list.size());
             }
         }
 
@@ -382,37 +386,6 @@
 
     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.
      */
@@ -458,8 +431,8 @@
         }
 
         boolean found = false;
-        log.debug( "verifycache: mapContains " + map.size() + " elements, linked list contains " + dumpCacheSize()
-            + " elements" );
+        log.debug( "verifycache: mapContains " + map.size() +
+                " elements, linked list contains " + list.size() + " elements" );
         log.debug( "verifycache: checking linked list by key " );
         for (LRUElementDescriptor<K, V> li = list.getFirst(); li != null; li = (LRUElementDescriptor<K, V>) li.next )
         {
@@ -537,37 +510,6 @@
     }
 
     /**
-     * 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.
@@ -584,24 +526,6 @@
     }
 
     /**
-     * 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()
@@ -613,9 +537,9 @@
 
         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) ) );
+        elems.add(new StatElement<Long>( "Put Count", Long.valueOf(putCnt) ) );
+        elems.add(new StatElement<Long>( "Hit Count", Long.valueOf(hitCnt) ) );
+        elems.add(new StatElement<Long>( "Miss Count", Long.valueOf(missCnt) ) );
 
         stats.setStatElements( elems );