LRUListWithSyncSorting extends AbstractEvictionList { @Override public EvictableEntry getEvictableEntry() { long numEvals = 0; for (;;) { EvictionNode aNode = this.unlinkHeadEntry(); if (logger.isTraceEnabled(LogMarker.LRU_CLOCK_VERBOSE)) { logger.trace(LogMarker.LRU_CLOCK_VERBOSE, "lru considering {}", aNode); } if (aNode == null) { getStatistics().incEvaluations(numEvals); return null; } numEvals++; if (!isEvictable(aNode)) { continue; } if (maxEntries > 0 && numEvals > maxEntries) { if (logger.isTraceEnabled(LogMarker.LRU_CLOCK_VERBOSE)) { logger.trace(LogMarker.LRU_CLOCK_VERBOSE, "greedily picking an available entry"); } getStatistics().incGreedyReturns(1); } else if (aNode.isRecentlyUsed()) { if (logger.isTraceEnabled(LogMarker.LRU_CLOCK_VERBOSE)) { logger.trace(LogMarker.LRU_CLOCK_VERBOSE, "skipping recently used entry {}", aNode); } aNode.unsetRecentlyUsed(); appendEntry(aNode); continue; } else { if (logger.isTraceEnabled(LogMarker.LRU_CLOCK_VERBOSE)) { logger.trace(LogMarker.LRU_CLOCK_VERBOSE, "returning unused entry: {}", aNode); } } getStatistics().incEvaluations(numEvals); return (EvictableEntry) aNode; } } LRUListWithSyncSorting(EvictionController controller); @Override EvictableEntry getEvictableEntry(); @Override void incrementRecentlyUsed();  }
@Test public void evictingFromEmptyListTest() throws Exception { LRUListWithSyncSorting list = new LRUListWithSyncSorting(controller); assertThat(list.getEvictableEntry()).isNull(); assertThat(list.size()).isZero(); }
@Test public void evictingFromNonEmptyListTest() throws Exception { LRUListWithSyncSorting list = new LRUListWithSyncSorting(controller); EvictionNode node = mock(EvictableEntry.class); list.appendEntry(node); assertThat(list.size()).isEqualTo(1); when(node.next()).thenReturn(list.tail); when(node.previous()).thenReturn(list.head); assertThat(list.getEvictableEntry()).isSameAs(node); assertThat(list.size()).isZero(); }
@Test public void doesNotEvictRecentlyUsed() throws Exception { LRUListWithSyncSorting list = new LRUListWithSyncSorting(controller); EvictionNode recentlyUsedNode = mock(EvictableEntry.class); list.appendEntry(recentlyUsedNode); when(recentlyUsedNode.isRecentlyUsed()).thenReturn(true); EvictionNode node = mock(EvictableEntry.class); list.appendEntry(node); when(recentlyUsedNode.next()).thenReturn(node).thenReturn(null); when(recentlyUsedNode.previous()).thenReturn(list.head); when(node.next()).thenReturn(list.tail); when(node.previous()).thenReturn(recentlyUsedNode); assertThat(list.getEvictableEntry()).isSameAs(node); assertThat(list.tail.previous()).isSameAs(recentlyUsedNode); verify(recentlyUsedNode, atLeast(1)).unsetRecentlyUsed(); assertThat(list.size()).isOne(); }
@Test public void doesNotEvictNodeInTransaction() throws Exception { LRUListWithSyncSorting list = new LRUListWithSyncSorting(controller); EvictionNode nodeInTransaction = mock(EvictableEntry.class, "nodeInTransaction"); when(nodeInTransaction.isInUseByTransaction()).thenReturn(true); EvictionNode nodeNotInTransaction = mock(EvictableEntry.class, "nodeNotInTransaction"); list.appendEntry(nodeInTransaction); list.appendEntry(nodeNotInTransaction); assertThat(list.size()).isEqualTo(2); when(nodeInTransaction.next()).thenReturn(nodeNotInTransaction); when(nodeInTransaction.previous()).thenReturn(list.head); when(nodeNotInTransaction.next()).thenReturn(list.tail); when(nodeNotInTransaction.previous()).thenReturn(list.head); assertThat(list.getEvictableEntry()).isSameAs(nodeNotInTransaction); assertThat(list.size()).isZero(); }
@Test public void doesNotEvictNodeThatIsEvicted() throws Exception { LRUListWithSyncSorting list = new LRUListWithSyncSorting(controller); EvictionNode evictedNode = mock(EvictableEntry.class); when(evictedNode.isEvicted()).thenReturn(true); EvictionNode node = mock(EvictableEntry.class); list.appendEntry(evictedNode); list.appendEntry(node); assertThat(list.size()).isEqualTo(2); when(evictedNode.next()).thenReturn(node); when(evictedNode.previous()).thenReturn(list.head); when(node.next()).thenReturn(list.tail); when(node.previous()).thenReturn(list.head); assertThat(list.getEvictableEntry()).isSameAs(node); assertThat(list.size()).isZero(); }
@Test public void verifyRecentlyUsedNodeIsGreedilyEvicted() throws Exception { System.setProperty("geode." + SystemPropertyHelper.EVICTION_SEARCH_MAX_ENTRIES, "1"); LRUListWithSyncSorting list = new LRUListWithSyncSorting(controller); EvictionNode recentlyUsedNode1 = mock(EvictableEntry.class, "RecentlyUsed1"); list.appendEntry(recentlyUsedNode1); when(recentlyUsedNode1.isRecentlyUsed()).thenReturn(true); EvictionNode recentlyUsedNode2 = mock(EvictableEntry.class, "RecentlyUsed2"); when(recentlyUsedNode2.isRecentlyUsed()).thenReturn(true); list.appendEntry(recentlyUsedNode2); when(recentlyUsedNode1.next()).thenReturn(recentlyUsedNode2).thenReturn(null); when(recentlyUsedNode1.previous()).thenReturn(list.head); when(recentlyUsedNode2.next()).thenReturn(list.tail); when(recentlyUsedNode2.previous()).thenReturn(recentlyUsedNode1); assertThat(list.getEvictableEntry()).isSameAs(recentlyUsedNode2); assertThat(list.tail.previous()).isSameAs(recentlyUsedNode1); verify(recentlyUsedNode1, atLeast(1)).unsetRecentlyUsed(); assertThat(list.size()).isOne(); }