static <K, V> Node<K, V> traverse(boolean ascending, Node<K, V> node) { return ascending ? node.getNextInVariableOrder() : node.getPreviousInVariableOrder(); }
@Override public String toString() { StringBuilder builder = new StringBuilder(); for (int i = 0; i < wheel.length; i++) { Map<Integer, List<K>> buckets = new TreeMap<>(); for (int j = 0; j < wheel[i].length; j++) { List<K> events = new ArrayList<>(); for (Node<K, V> node = wheel[i][j].getNextInVariableOrder(); node != wheel[i][j]; node = node.getNextInVariableOrder()) { events.add(node.getKey()); } if (!events.isEmpty()) { buckets.put(j, events); } } builder.append("Wheel #").append(i + 1).append(": ").append(buckets).append('\n'); } return builder.deleteCharAt(builder.length() - 1).toString(); }
private void checkEmpty() { for (int i = 0; i < timerWheel.wheel.length; i++) { for (int j = 0; j < timerWheel.wheel[i].length; j++) { Node<Long, Long> sentinel = timerWheel.wheel[i][j]; assertThat(sentinel.getNextInVariableOrder(), is(sentinel)); assertThat(sentinel.getPreviousInVariableOrder(), is(sentinel)); } } }
/** * Reschedules an active timer event for the node. * * @param node the entry in the cache */ public void reschedule(@NonNull Node<K, V> node) { if (node.getNextInVariableOrder() != null) { unlink(node); schedule(node); } }
/** Removes the entry from its bucket, if scheduled. */ void unlink(Node<K, V> node) { Node<K, V> next = node.getNextInVariableOrder(); if (next != null) { Node<K, V> prev = node.getPreviousInVariableOrder(); next.setPreviousInVariableOrder(prev); prev.setNextInVariableOrder(next); } }
private LongList getTimers(Node<?, ?> sentinel) { LongList timers = new LongArrayList(); for (Node<?, ?> node = sentinel.getNextInVariableOrder(); node != sentinel; node = node.getNextInVariableOrder()) { timers.add(node.getVariableTime()); } return timers; }
@Test public void expire_reschedule() { when(cache.evictEntry(captor.capture(), any(), anyLong())).thenAnswer(invocation -> { Timer timer = (Timer) invocation.getArgument(0); timer.setVariableTime(timerWheel.nanos + 100); return false; }); timerWheel.schedule(new Timer(100)); timerWheel.advance(TimerWheel.SPANS[0]); verify(cache).evictEntry(any(), any(), anyLong()); assertThat(captor.getValue().getNextInVariableOrder(), is(not(nullValue()))); assertThat(captor.getValue().getPreviousInVariableOrder(), is(not(nullValue()))); }
private void checkTimerWheel(BoundedLocalCache<K, V> cache) { if (!cache.expiresVariable()) { return; } Set<Node<K, V>> seen = Sets.newIdentityHashSet(); for (int i = 0; i < cache.timerWheel().wheel.length; i++) { for (int j = 0; j < cache.timerWheel().wheel[i].length; j++) { Node<K, V> sentinel = cache.timerWheel().wheel[i][j]; desc.expectThat("Wrong sentinel prev", sentinel.getPreviousInVariableOrder().getNextInVariableOrder(), sameInstance(sentinel)); desc.expectThat("Wrong sentinel next", sentinel.getNextInVariableOrder().getPreviousInVariableOrder(), sameInstance(sentinel)); desc.expectThat("Sentinel must be first element", sentinel, instanceOf(Sentinel.class)); for (Node<K, V> node = sentinel.getNextInVariableOrder(); node != sentinel; node = node.getNextInVariableOrder()) { Node<K, V> next = node.getNextInVariableOrder(); Node<K, V> prev = node.getPreviousInVariableOrder(); long duration = node.getVariableTime() - cache.timerWheel().nanos; desc.expectThat("Expired", duration, greaterThan(0L)); desc.expectThat("Loop detected", seen.add(node), is(true)); desc.expectThat("Wrong prev", prev.getNextInVariableOrder(), is(sameInstance(node))); desc.expectThat("Wrong next", next.getPreviousInVariableOrder(), is(sameInstance(node))); } } } desc.expectThat("Timers != Entries", seen, hasSize(cache.size())); }
Node<K, V> sentinel = timerWheel[(i & mask)]; Node<K, V> prev = sentinel.getPreviousInVariableOrder(); Node<K, V> node = sentinel.getNextInVariableOrder(); sentinel.setPreviousInVariableOrder(sentinel); sentinel.setNextInVariableOrder(sentinel); Node<K, V> next = node.getNextInVariableOrder(); node.setPreviousInVariableOrder(null); node.setNextInVariableOrder(null);
static <K, V> Node<K, V> traverse(boolean ascending, Node<K, V> node) { return ascending ? node.getNextInVariableOrder() : node.getPreviousInVariableOrder(); }
@Override public String toString() { StringBuilder builder = new StringBuilder(); for (int i = 0; i < wheel.length; i++) { Map<Integer, List<K>> buckets = new TreeMap<>(); for (int j = 0; j < wheel[i].length; j++) { List<K> events = new ArrayList<>(); for (Node<K, V> node = wheel[i][j].getNextInVariableOrder(); node != wheel[i][j]; node = node.getNextInVariableOrder()) { events.add(node.getKey()); } if (!events.isEmpty()) { buckets.put(j, events); } } builder.append("Wheel #").append(i + 1).append(": ").append(buckets).append('\n'); } return builder.deleteCharAt(builder.length() - 1).toString(); }
/** * Reschedules an active timer event for the node. * * @param node the entry in the cache */ public void reschedule(Node<K, V> node) { if (node.getNextInVariableOrder() != null) { unlink(node); schedule(node); } }
/** Removes the entry from its bucket, if scheduled. */ void unlink(Node<K, V> node) { Node<K, V> next = node.getNextInVariableOrder(); if (next != null) { Node<K, V> prev = node.getPreviousInVariableOrder(); next.setPreviousInVariableOrder(prev); prev.setNextInVariableOrder(next); } }
Node<K, V> sentinel = timerWheel[(i & mask)]; Node<K, V> prev = sentinel.getPreviousInVariableOrder(); Node<K, V> node = sentinel.getNextInVariableOrder(); sentinel.setPreviousInVariableOrder(sentinel); sentinel.setNextInVariableOrder(sentinel); Node<K, V> next = node.getNextInVariableOrder(); node.setPreviousInVariableOrder(null); node.setNextInVariableOrder(null);