You are viewing a plain text version of this content. The canonical link for it is here.
Posted to oak-commits@jackrabbit.apache.org by th...@apache.org on 2013/10/15 14:55:20 UTC
svn commit: r1532320 -
/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/cache/CacheLIRS.java
Author: thomasm
Date: Tue Oct 15 12:55:20 2013
New Revision: 1532320
URL: http://svn.apache.org/r1532320
Log:
OAK-863 - LIRS cache bugfix
Modified:
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/cache/CacheLIRS.java
Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/cache/CacheLIRS.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/cache/CacheLIRS.java?rev=1532320&r1=1532319&r2=1532320&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/cache/CacheLIRS.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/cache/CacheLIRS.java Tue Oct 15 12:55:20 2013
@@ -558,16 +558,22 @@ public class CacheLIRS<K, V> implements
/**
* The stack of recently referenced elements. This includes all hot entries,
* the recently referenced cold entries, and all non-resident cold entries.
+ * <p>
+ * There is always at least one entry: the head entry.
*/
private Entry<K, V> stack;
/**
* The queue of resident cold entries.
+ * <p>
+ * There is always at least one entry: the head entry.
*/
private Entry<K, V> queue;
/**
* The queue of non-resident cold entries.
+ * <p>
+ * There is always at least one entry: the head entry.
*/
private Entry<K, V> queue2;
@@ -575,7 +581,7 @@ public class CacheLIRS<K, V> implements
* The number of times any item was moved to the top of the stack.
*/
private int stackMoveCounter;
-
+
/**
* Create a new cache.
*
@@ -693,7 +699,7 @@ public class CacheLIRS<K, V> implements
removeFromStack(e);
if (wasEnd) {
// if moving the last entry, the last entry
- // could not be cold, which is not allowed
+ // could now be cold, which is not allowed
pruneStack();
}
addToStack(e);
@@ -706,6 +712,8 @@ public class CacheLIRS<K, V> implements
// if they are on the stack
removeFromStack(e);
// which means a hot entry needs to become cold
+ // (this entry is cold, that means there is at least one
+ // more entry in the stack, which must be hot)
convertOldestHotToCold();
} else {
// cold entries that are not on the stack
@@ -851,10 +859,10 @@ public class CacheLIRS<K, V> implements
* @param newCold a new cold entry
*/
private void evict(Entry<K, V> newCold) {
- // ensure there are not too many hot entries:
- // left shift of 5 is multiplication by 32, that means if there are less
- // than 1/32 (3.125%) cold entries, a new hot entry needs to become cold
- while ((queueSize << 5) < mapSize) {
+ // ensure there are not too many hot entries: right shift of 5 is
+ // division by 32, that means if there are only 1/32 (3.125%) or
+ // less cold entries, a hot entry needs to become cold
+ while (queueSize <= (mapSize >>> 5) && stackSize > 0) {
convertOldestHotToCold();
}
if (stackSize > 0) {
@@ -883,6 +891,11 @@ public class CacheLIRS<K, V> implements
private void convertOldestHotToCold() {
// the last entry of the stack is known to be hot
Entry<K, V> last = stack.stackPrev;
+ if (last == stack) {
+ // never remove the stack head itself (this would mean the
+ // internal structure of the cache is corrupt)
+ throw new IllegalStateException();
+ }
// remove from stack - which is done anyway in the stack pruning, but we
// can do it here as well
removeFromStack(last);
@@ -897,7 +910,10 @@ public class CacheLIRS<K, V> implements
private void pruneStack() {
while (true) {
Entry<K, V> last = stack.stackPrev;
- if (last == stack || last.isHot()) {
+ // must stop at a hot entry or the stack head,
+ // but the stack head itself is also hot, so we
+ // don't have to test it
+ if (last.isHot()) {
break;
}
// the cold entry is still in the queue