[ https://issues.apache.org/jira/browse/SOLR-665?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=12617639#action_12617639 ]
funtick edited comment on SOLR-665 at 7/28/08 6:28 PM: ----------------------------------------------------------- This is extremely simple Concurrent LRU, I spent an hour to create it; it is based on ConcurrentHashMap. I don't use java.util.concurrent.locks, and I am trying to focus on _requirements only_ avoiding implementing unnecessary methods of Map interface (so that I am not following _contract_ ;) very sorry!) {code} import java.util.Map; import java.util.concurrent.ConcurrentHashMap; public class ConcurrentLRU<K, V> { protected ConcurrentHashMap<K, ValueWrapper<V>> map; protected int maxEntries; public ConcurrentLRU(int maxEntries) { map = new ConcurrentHashMap<K, ValueWrapper<V>>(); this.maxEntries = maxEntries; } public V put(K key, V value) { ValueWrapper<V> wrapper = map.put(key, new ValueWrapper<V>(value)); checkRemove(); return value; } void checkRemove() { if (map.size() <= maxEntries) return; Map.Entry<K, ValueWrapper<V>> eldestEntry = null; for (Map.Entry<K, ValueWrapper<V>> entry : map.entrySet()) { long popularity = entry.getValue().popularity; if (eldestEntry == null || eldestEntry.getValue().popularity > popularity) { eldestEntry = entry; } } map.remove(eldestEntry.getKey(), eldestEntry.getValue()); } public V get(Object key) { ValueWrapper<V> wrapper = map.get(key); return wrapper == null ? null : wrapper.getValue(); } public final static class ValueWrapper<V> { static volatile long popularityCounter; volatile long popularity; V value; ValueWrapper(V value) { this.value = value; popularity = popularityCounter++; } public boolean equals(Object o) { if (!(o instanceof ValueWrapper)) { return false; } return (value == null ? ((ValueWrapper) o).value == null : value.equals(((ValueWrapper) o).value)); } public int hashCode() { return value.hashCode(); } public V getValue() { popularity = popularityCounter++; return value; } } } {code} P.S. Do we need to synchronize put() or checkRemove()? The only hypothetical problem is OutOfMemoryException. But it is just first draft, very simplified... we do not need to sort array. was (Author: funtick): This is extremely simple Concurrent LRU, I spent an hour to create it; it is based on ConcurrentHashMap. I don't use java.util.concurrent.locks, and I am trying to focus on _requirements only_ avoiding implementing unnecessary methods of Map interface (so that I am not following _contract_ ;) very sorry!) {code} import java.util.Map; import java.util.concurrent.ConcurrentHashMap; public class ConcurrentLRU<K, V> { protected ConcurrentHashMap<K, ValueWrapper<V>> map; protected int maxEntries; public ConcurrentLRU(int maxEntries) { map = new ConcurrentHashMap<K, ValueWrapper<V>>(); this.maxEntries = maxEntries; } public V put(K key, V value) { ValueWrapper<V> wrapper = map.put(key, new ValueWrapper<V>(value)); checkRemove(); return value; } void checkRemove() { if (map.size() <= maxEntries) return; Map.Entry<K, ValueWrapper<V>> eldestEntry = null; for (Map.Entry<K, ValueWrapper<V>> entry : map.entrySet()) { long popularity = entry.getValue().popularity; if (eldestEntry == null || eldestEntry.getValue().popularity > popularity) { eldestEntry = entry; } } map.remove(eldestEntry.getKey(), eldestEntry.getValue()); } public V get(Object key) { ValueWrapper<V> wrapper = map.get(key); return wrapper == null ? null : wrapper.getValue(); } public final static class ValueWrapper<V> { static volatile long popularityCounter; volatile long popularity; V value; ValueWrapper(V value) { this.value = value; popularity = popularityCounter++; } public boolean equals(Object o) { if (!(o instanceof ValueWrapper)) { return false; } return (value == null ? ((ValueWrapper) o).value == null : value.equals(((ValueWrapper) o).value)); } public int hashCode() { return value.hashCode(); } public V getValue() { popularity = popularityCounter++; return value; } } } {code} > FIFO Cache (Unsynchronized): 9x times performance boost > ------------------------------------------------------- > > Key: SOLR-665 > URL: https://issues.apache.org/jira/browse/SOLR-665 > Project: Solr > Issue Type: Improvement > Affects Versions: 1.3 > Environment: JRockit R27 (Java 6) > Reporter: Fuad Efendi > Attachments: FIFOCache.java > > Original Estimate: 672h > Remaining Estimate: 672h > > Attached is modified version of LRUCache where > 1. map = new LinkedHashMap(initialSize, 0.75f, false) - so that > "reordering"/true (performance bottleneck of LRU) is replaced to > "insertion-order"/false (so that it became FIFO) > 2. Almost all (absolutely unneccessary) synchronized statements commented out > See discussion at > http://www.nabble.com/LRUCache---synchronized%21--td16439831.html > Performance metrics (taken from SOLR Admin): > LRU > Requests: 7638 > Average Time-Per-Request: 15300 > Average Request-per-Second: 0.06 > FIFO: > Requests: 3355 > Average Time-Per-Request: 1610 > Average Request-per-Second: 0.11 > Performance increased 9 times which roughly corresponds to a number of CPU in > a system, http://www.tokenizer.org/ (Shopping Search Engine at Tokenizer.org) > Current number of documents: 7494689 > name: filterCache > class: org.apache.solr.search.LRUCache > version: 1.0 > description: LRU Cache(maxSize=10000000, initialSize=1000) > stats: lookups : 15966954582 > hits : 16391851546 > hitratio : 0.102 > inserts : 4246120 > evictions : 0 > size : 2668705 > cumulative_lookups : 16415839763 > cumulative_hits : 16411608101 > cumulative_hitratio : 0.99 > cumulative_inserts : 4246246 > cumulative_evictions : 0 > Thanks -- This message is automatically generated by JIRA. - You can reply to this email to add a comment to the issue online.