<table cellspacing="0" cellpadding="0" border="0" ><tr><td valign="top" style="font: inherit;">Hi,<br><br>&nbsp; I have a completely in-line limit on the cache entries built on a clock cache that is an approximation to an LRU cache, and is extremely fast (O(1)). It is not a strick LRU, but chooses a not recently used item for removal. I'll provide some more details soon.<br><br>&nbsp; I'm not sure how far along you are, as some of this is in the future tense, and some in the past. But I'll dig up this code - it's been a while since I worked on the cache. :)<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;
 &nbsp; &nbsp; Alex<br><br>--- On <b>Tue, 7/5/11, Vladimir Blagojevic <i>&lt;vblagoje@redhat.com&gt;</i></b> wrote:<br><blockquote style="border-left: 2px solid rgb(16, 16, 255); margin-left: 5px; padding-left: 5px;"><br>From: Vladimir Blagojevic &lt;vblagoje@redhat.com&gt;<br>Subject: [infinispan-dev] Faster LRU<br>To: "infinispan -Dev List" &lt;infinispan-dev@lists.jboss.org&gt;<br>Date: Tuesday, July 5, 2011, 11:23 AM<br><br><div class="plainMail">Hey guys,<br><br>In the past few days I've look around how to squeeze every bit of <br>performance out of BCHM and particularly our LRU impl. What I did not <br>like about current LRU is that a search for an element in the queue is <br>not constant time operation but requires full queue traversal if we need <br>to find an element[1].<br><br>It would be be particularly nice to have a hashmap with a constant cost <br>for look up operations. Something like LinkedHashMap. LinkedHashMap <br>seems to be a good
 container for LRU as it provides constant time lookup <br>but also a hook, a callback call for eviction of the oldest entry in the <br>form of removeEldestEntry callback. So why not implement our segment <br>eviction policy by using a LinkedHashMap [2]?<br><br>I've seen about 50% performance increase for smaller caches (100K) and <br>even more for larger and more contended caches - about 75% increase. <br>After this change BCHM performance was not that much worse than CHM and <br>it was faster than synchronized hashmap.<br><br>Should we include this impl as FAST_LRU as I would not want to remove <br>current LRU just yet? We have to prove this one is correct and that it <br>does not have have any unforeseen issues.<br><br>Let me know what you think!<br><br>Vladimir<br><br><br><br><br><br><br><br><br>[1] <br><a href="https://github.com/infinispan/infinispan/blob/master/core/src/main/java/org/infinispan/util/concurrent/BoundedConcurrentHashMap.java#L467"
 target="_blank">https://github.com/infinispan/infinispan/blob/master/core/src/main/java/org/infinispan/util/concurrent/BoundedConcurrentHashMap.java#L467</a><br><br>[2] Source code snippet for LRU in BCHM.<br><br><br>static final class LRU&lt;K, V&gt; extends LinkedHashMap&lt;HashEntry&lt;K,V&gt;, V&gt; <br>implements EvictionPolicy&lt;K, V&gt; {<br>&nbsp; &nbsp; &nbsp;&nbsp;&nbsp;/** The serialVersionUID */<br>&nbsp; &nbsp; &nbsp;&nbsp;&nbsp;private static final long serialVersionUID = -6627108081544347068L;<br><br>&nbsp; &nbsp; &nbsp;&nbsp;&nbsp;private final ConcurrentLinkedQueue&lt;HashEntry&lt;K, V&gt;&gt; accessQueue;<br>&nbsp; &nbsp; &nbsp;&nbsp;&nbsp;private final Segment&lt;K,V&gt; segment;<br>&nbsp; &nbsp; &nbsp;&nbsp;&nbsp;private final int maxBatchQueueSize;<br>&nbsp; &nbsp; &nbsp;&nbsp;&nbsp;private final int trimDownSize;<br>&nbsp; &nbsp; &nbsp;&nbsp;&nbsp;private final float batchThresholdFactor;<br>&nbsp; &nbsp; &nbsp;&nbsp;&nbsp;private
 final Set&lt;HashEntry&lt;K, V&gt;&gt; evicted;<br><br>&nbsp; &nbsp; &nbsp;&nbsp;&nbsp;public LRU(Segment&lt;K,V&gt; s, int capacity, float lf, int <br>maxBatchSize, float batchThresholdFactor) {<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; super((int)(capacity*lf));<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; this.segment = s;<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; this.trimDownSize = (int)(capacity*lf);<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; this.maxBatchQueueSize = maxBatchSize &gt; MAX_BATCH_SIZE ? <br>MAX_BATCH_SIZE : maxBatchSize;<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; this.batchThresholdFactor = batchThresholdFactor;<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; this.accessQueue = new ConcurrentLinkedQueue&lt;HashEntry&lt;K, V&gt;&gt;();<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; this.evicted = new HashSet&lt;HashEntry&lt;K, V&gt;&gt;();<br>&nbsp; &nbsp; &nbsp;&nbsp;&nbsp;}<br><br>&nbsp; &nbsp; &nbsp;&nbsp;&nbsp;@Override<br>&nbsp; &nbsp; &nbsp;&nbsp;&nbsp;public
 Set&lt;HashEntry&lt;K, V&gt;&gt; execute() {<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Set&lt;HashEntry&lt;K, V&gt;&gt; evictedCopy = new HashSet&lt;HashEntry&lt;K, V&gt;&gt;();<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; for (HashEntry&lt;K, V&gt; e : accessQueue) {<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;&nbsp;put(e, e.value);<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; evictedCopy.addAll(evicted);<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; accessQueue.clear();<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; evicted.clear();<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return evictedCopy;<br>&nbsp; &nbsp; &nbsp;&nbsp;&nbsp;}<br><br><br><br>&nbsp; &nbsp; &nbsp;&nbsp;&nbsp;@Override<br>&nbsp; &nbsp; &nbsp;&nbsp;&nbsp;public Set&lt;HashEntry&lt;K, V&gt;&gt; onEntryMiss(HashEntry&lt;K, V&gt; e) {<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return Collections.emptySet();<br>&nbsp; &nbsp; &nbsp;&nbsp;&nbsp;}<br><br>&nbsp; &nbsp;
 &nbsp;&nbsp;&nbsp;/*<br>&nbsp; &nbsp; &nbsp; &nbsp; * Invoked without holding a lock on Segment<br>&nbsp; &nbsp; &nbsp; &nbsp; */<br>&nbsp; &nbsp; &nbsp;&nbsp;&nbsp;@Override<br>&nbsp; &nbsp; &nbsp;&nbsp;&nbsp;public boolean onEntryHit(HashEntry&lt;K, V&gt; e) {<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; accessQueue.add(e);<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return accessQueue.size() &gt;= maxBatchQueueSize * <br>batchThresholdFactor;<br>&nbsp; &nbsp; &nbsp;&nbsp;&nbsp;}<br><br>&nbsp; &nbsp; &nbsp;&nbsp;&nbsp;/*<br>&nbsp; &nbsp; &nbsp; &nbsp; * Invoked without holding a lock on Segment<br>&nbsp; &nbsp; &nbsp; &nbsp; */<br>&nbsp; &nbsp; &nbsp;&nbsp;&nbsp;@Override<br>&nbsp; &nbsp; &nbsp;&nbsp;&nbsp;public boolean thresholdExpired() {<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return accessQueue.size() &gt;= maxBatchQueueSize;<br>&nbsp; &nbsp; &nbsp;&nbsp;&nbsp;}<br><br>&nbsp; &nbsp; &nbsp;&nbsp;&nbsp;@Override<br>&nbsp; &nbsp; &nbsp;&nbsp;&nbsp;public void
 onEntryRemove(HashEntry&lt;K, V&gt; e) {<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; remove(e);<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // we could have multiple instances of e in accessQueue; <br>remove them all<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; while (accessQueue.remove(e)) {<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;&nbsp;continue;<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }<br>&nbsp; &nbsp; &nbsp;&nbsp;&nbsp;}<br><br>&nbsp; &nbsp; &nbsp;&nbsp;&nbsp;@Override<br>&nbsp; &nbsp; &nbsp;&nbsp;&nbsp;public void clear() {<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; super.clear();<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; accessQueue.clear();<br>&nbsp; &nbsp; &nbsp;&nbsp;&nbsp;}<br><br>&nbsp; &nbsp; &nbsp;&nbsp;&nbsp;@Override<br>&nbsp; &nbsp; &nbsp;&nbsp;&nbsp;public Eviction strategy() {<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return Eviction.LRU;<br>&nbsp; &nbsp; &nbsp;&nbsp;&nbsp;}<br><br>&nbsp; &nbsp; &nbsp;&nbsp;&nbsp;protected boolean
 removeEldestEntry(Entry&lt;HashEntry&lt;K,V&gt;,V&gt; eldest){<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; HashEntry&lt;K, V&gt; evictedEntry = eldest.getKey();<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <br>segment.evictionListener.onEntryChosenForEviction(evictedEntry.value);<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; segment.remove(evictedEntry.key, evictedEntry.hash, null);<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; evicted.add(evictedEntry);<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return size() &gt; trimDownSize;<br>&nbsp; &nbsp; &nbsp;&nbsp;&nbsp;}<br>&nbsp; &nbsp; }<br>_______________________________________________<br>infinispan-dev mailing list<br><a ymailto="mailto:infinispan-dev@lists.jboss.org" href="/mc/compose?to=infinispan-dev@lists.jboss.org">infinispan-dev@lists.jboss.org</a><br><a href="https://lists.jboss.org/mailman/listinfo/infinispan-dev" target="_blank">https://lists.jboss.org/mailman/listinfo/infinispan-dev</a><br></div></blockquote></td></tr></table>