boolean inStack = inStack(); moveToStackTop(); hot(); owner.stackBottom().migrateToQueue(); owner.pruneStack( evicted ); cold();
/** * Records a cache hit. */ public void hit(Set<HashEntry<K, V>> evicted) { switch ( state ) { case LIR_RESIDENT: hotHit( evicted ); break; case HIR_RESIDENT: coldHit( evicted ); break; case HIR_NONRESIDENT: throw new IllegalStateException( "Can't hit a non-resident entry!" ); default: throw new AssertionError( "Hit with unknown status: " + state ); } }
/** * Records a cache miss. This is how new entries join the LIRS stack and * queue. This is called both when a new entry is first created, and when a * non-resident entry is re-computed. */ private Set<HashEntry<K, V>> miss() { Set<HashEntry<K, V>> evicted = Collections.emptySet(); if ( owner.hotSize < owner.maximumHotSize ) { warmupMiss(); } else { evicted = new HashSet<HashEntry<K, V>>(); fullMiss( evicted ); } // now the missed item is in the cache owner.size++; return evicted; }
boolean inStack = inStack(); moveToStackTop(); hot(); owner.stackBottom().migrateToQueue(); owner.pruneStack( evicted ); cold();
/** * Records a cache hit on a cold block. */ private void coldHit(Set<HashEntry<K, V>> evicted) { // See section 3.3 case 2: // "Upon accessing an HIR resident block X: // This is a hit in the cache." // "We move it to the top of stack S." boolean inStack = inStack(); moveToStackTop(); // "There are two cases for block X:" if ( inStack ) { // "(1) If X is in the stack S, we change its status to LIR." hot(); // "This block is also removed from list Q." removeFromQueue(); // "The LIR block in the bottom of S is moved to the end of list Q // with its status changed to HIR." owner.stackBottom().migrateToQueue(); // "A stack pruning is then conducted." owner.pruneStack( evicted ); } else { // "(2) If X is not in stack S, we leave its status in HIR and move // it to the end of list Q." moveToQueueEnd(); } }
/** * Removes this entry from the cache. This operation is not specified in * the paper, which does not account for forced eviction. */ private V remove() { boolean wasHot = ( state == Recency.LIR_RESIDENT ); V result = value; LIRSHashEntry<K, V> end = owner != null ? owner.queueEnd() : null; evict(); // attempt to maintain a constant number of hot entries if ( wasHot ) { if ( end != null ) { end.migrateToStack(); } } return result; } }
/** * Records a cache miss. This is how new entries join the LIRS stack and * queue. This is called both when a new entry is first created, and when a * non-resident entry is re-computed. */ private Set<HashEntry<K, V>> miss() { Set<HashEntry<K, V>> evicted = Collections.emptySet(); if ( owner.hotSize < owner.maximumHotSize ) { warmupMiss(); } else { evicted = new HashSet<HashEntry<K, V>>(); fullMiss( evicted ); } // now the missed item is in the cache owner.size++; return evicted; }
@Override public Set<HashEntry<K, V>> execute() { Set<HashEntry<K, V>> evicted = new HashSet<HashEntry<K, V>>(); try { for ( LIRSHashEntry<K, V> e : accessQueue ) { if ( e.isResident() ) { e.hit( evicted ); } } removeFromSegment( evicted ); } finally { accessQueue.clear(); } return evicted; }
/** * Records a cache hit. */ public void hit(Set<HashEntry<K, V>> evicted) { switch ( state ) { case LIR_RESIDENT: hotHit( evicted ); break; case HIR_RESIDENT: coldHit( evicted ); break; case HIR_NONRESIDENT: throw new IllegalStateException( "Can't hit a non-resident entry!" ); default: throw new AssertionError( "Hit with unknown status: " + state ); } }
/** * Moves this entry to the top of the stack. */ private void moveToStackTop() { tempRemoveFromStack(); addToStackBefore( owner.header.nextInStack ); }
/** * Moves this entry to the bottom of the stack. */ private void moveToStackBottom() { tempRemoveFromStack(); addToStackBefore( owner.header ); }
/** * Moves this entry to the end of the queue. */ private void moveToQueueEnd() { tempRemoveFromQueue(); addToQueueBefore( owner.header ); }
@Override public HashEntry<K, V> createNewEntry(K key, int hash, HashEntry<K, V> next, V value) { return new LIRSHashEntry<K, V>( this, key, hash, next, value ); } }
/** * Moves this entry from the queue to the stack, marking it hot (as cold * resident entries must remain in the queue). */ private void migrateToStack() { removeFromQueue(); if ( !inStack() ) { moveToStackBottom(); } hot(); }
/** * Moves this entry from the stack to the queue, marking it cold * (as hot entries must remain in the stack). This should only be called * on resident entries, as non-resident entries should not be made resident. * The bottom entry on the queue is always hot due to stack pruning. */ private void migrateToQueue() { removeFromStack(); cold(); }
/** * Records a miss when the hot entry set is not full. */ private void warmupMiss() { // See section 3.3: // "When LIR block set is not full, all the referenced blocks are // given an LIR status until its size reaches L_lirs." hot(); moveToStackTop(); }
/** * Records a cache hit on a cold block. */ private void coldHit(Set<HashEntry<K, V>> evicted) { // See section 3.3 case 2: // "Upon accessing an HIR resident block X: // This is a hit in the cache." // "We move it to the top of stack S." boolean inStack = inStack(); moveToStackTop(); // "There are two cases for block X:" if ( inStack ) { // "(1) If X is in the stack S, we change its status to LIR." hot(); // "This block is also removed from list Q." removeFromQueue(); // "The LIR block in the bottom of S is moved to the end of list Q // with its status changed to HIR." owner.stackBottom().migrateToQueue(); // "A stack pruning is then conducted." owner.pruneStack( evicted ); } else { // "(2) If X is not in stack S, we leave its status in HIR and move // it to the end of list Q." moveToQueueEnd(); } }
/** * Removes this entry from the cache. This operation is not specified in * the paper, which does not account for forced eviction. */ private V remove() { boolean wasHot = ( state == Recency.LIR_RESIDENT ); V result = value; LIRSHashEntry<K, V> end = owner != null ? owner.queueEnd() : null; evict(); // attempt to maintain a constant number of hot entries if ( wasHot ) { if ( end != null ) { end.migrateToStack(); } } return result; } }
@Override public Set<HashEntry<K, V>> execute() { Set<HashEntry<K, V>> evicted = new HashSet<HashEntry<K, V>>(); try { for ( LIRSHashEntry<K, V> e : accessQueue ) { if ( e.isResident() ) { e.hit( evicted ); } } removeFromSegment( evicted ); } finally { accessQueue.clear(); } return evicted; }
/** * Moves this entry from the queue to the stack, marking it hot (as cold * resident entries must remain in the queue). */ private void migrateToStack() { removeFromQueue(); if ( !inStack() ) { moveToStackBottom(); } hot(); }