Author: tv
Date: Sat Dec 31 13:47:19 2016
New Revision: 1776744
URL: http://svn.apache.org/viewvc?rev=1776744&view=rev
Log:
Performance improvements
Modified:
commons/proper/jcs/trunk/commons-jcs-core/src/main/java/org/apache/commons/jcs/utils/struct/AbstractLRUMap.java
Modified:
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=1776744&r1=1776743&r2=1776744&view=diff
==============================================================================
---
commons/proper/jcs/trunk/commons-jcs-core/src/main/java/org/apache/commons/jcs/utils/struct/AbstractLRUMap.java
(original)
+++
commons/proper/jcs/trunk/commons-jcs-core/src/main/java/org/apache/commons/jcs/utils/struct/AbstractLRUMap.java
Sat Dec 31 13:47:19 2016
@@ -64,21 +64,19 @@ public abstract class AbstractLRUMap<K,
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;
+ /** lock to keep map and list synchronous */
+ private final Lock lock = new ReentrantLock();
/** stats */
- int missCnt = 0;
+ private long hitCnt = 0;
/** stats */
- int putCnt = 0;
+ private long missCnt = 0;
- /** make configurable */
- private int chunkSize = 1;
-
- private final Lock lock = new ReentrantLock();
+ /** stats */
+ private long putCnt = 0;
/**
* This creates an unbounded version. Setting the max objects will result
in spooling on
@@ -196,7 +194,7 @@ public abstract class AbstractLRUMap<K,
@Override
public V get( Object key )
{
- V retVal = null;
+ V retVal;
if ( log.isDebugEnabled() )
{
@@ -205,22 +203,28 @@ public abstract class AbstractLRUMap<K,
LRUElementDescriptor<K, V> me = map.get( key );
- if ( me != null )
+ if ( me == null )
+ {
+ missCnt++;
+ retVal = null;
+ }
+ else
{
hitCnt++;
- if ( log.isDebugEnabled() )
- {
- log.debug( "LRUMap hit for " + key );
- }
-
retVal = me.getPayload();
-
list.makeFirst( me );
}
- else
+
+ if ( log.isDebugEnabled() )
{
- missCnt++;
- log.debug( "LRUMap miss for " + key );
+ if ( me == null )
+ {
+ log.debug( "LRUMap miss for " + key );
+ }
+ else
+ {
+ log.debug( "LRUMap hit for " + key );
+ }
}
// verifyCache();
@@ -238,20 +242,23 @@ public abstract class AbstractLRUMap<K,
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() )
+
+ if ( log.isDebugEnabled() )
{
- log.debug( "LRUMap quiet miss for " + key );
+ if ( me == null )
+ {
+ log.debug( "LRUMap quiet miss for " + key );
+ }
+ else
+ {
+ log.debug( "LRUMap quiet hit for " + key );
+ }
}
return ce;
@@ -300,17 +307,16 @@ public abstract class AbstractLRUMap<K,
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 @@ public abstract class AbstractLRUMap<K,
}
// If the element limit is reached, we need to spool
-
if (shouldRemove())
{
if (log.isDebugEnabled())
@@ -332,7 +337,6 @@ public abstract class AbstractLRUMap<K,
// 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 @@ public abstract class AbstractLRUMap<K,
{
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 @@ public abstract class AbstractLRUMap<K,
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 @@ public abstract class AbstractLRUMap<K,
}
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 @@ public abstract class AbstractLRUMap<K,
}
/**
- * 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 @@ public abstract class AbstractLRUMap<K,
}
/**
- * 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 @@ public abstract class AbstractLRUMap<K,
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 );