Class CircularPriorityQueue<K,V,SLK extends Keyed<K>>

java.lang.Object
org.mockserver.collections.CircularPriorityQueue<K,V,SLK>

public class CircularPriorityQueue<K,V,SLK extends Keyed<K>> extends Object
Priority-ordered queue with insertion-order eviction past maxSize.

Concurrency contract: all mutating methods (add(Object), remove(Object), replaceValue(Object, Object), addPriorityKey(Object), removePriorityKey(Object), setMaxSize(int) and setEvictionListener(java.util.function.Consumer)) are single-writer — callers serialize them on the control plane (the Netty event loop / per-store synchronization). Read methods (stream(), toSortedList(), getByKey(Object), size(), keyMap()) may run concurrently with the single writer and are eventually consistent: a read concurrent with an in-flight mutation may not yet reflect it, but never returns nulls (the filter(nonNull) guard) or corrupt state.

Precondition: add(Object) must not be called for a key that already exists in the queue — use replaceValue(Object, Object) for in-place updates. Adding a duplicate key would push the key twice into the insertion-order queue and corrupt eviction accounting.

Author:
jamesdbloom
  • Constructor Details

    • CircularPriorityQueue

      public CircularPriorityQueue(int maxSize, Comparator<? super SLK> skipListComparator, Function<V,SLK> skipListKeyFunction, Function<V,K> mapKeyFunction)
  • Method Details

    • setEvictionListener

      public void setEvictionListener(Consumer<V> evictionListener)
      Registers a listener invoked once for every element evicted because the queue grew past maxSize. The listener is called AFTER the element has been removed from the insertion queue, sort skip-list and byKey map, so satellite state can be cleaned up safely. It is NOT invoked on explicit remove(Object) or replaceValue(Object, Object).
      Parameters:
      evictionListener - the listener, or null to restore the no-op default
    • setMaxSize

      public void setMaxSize(int maxSize)
    • removePriorityKey

      public void removePriorityKey(V element)
    • addPriorityKey

      public void addPriorityKey(V element)
    • add

      public void add(V element)
    • replaceValue

      public boolean replaceValue(K key, V newValue)
      Replaces the value associated with the given key in place, preserving the element's position in insertionOrderQueue (and therefore its eviction order). Because the insertion queue holds keys and the key is invariant on update, the queue is left untouched — the element keeps its exact eviction slot. Only the byKey map and the priority sort keys (old removed, new added) are updated. O(log n).
      Parameters:
      key - the key that identifies the existing element
      newValue - the replacement value
      Returns:
      true if the key was found and the value replaced
    • remove

      public boolean remove(V element)
    • size

      public int size()
    • stream

      public Stream<V> stream()
    • getByKey

      public Optional<V> getByKey(K key)
    • keyMap

      public Map<K,V> keyMap()
    • isEmpty

      public boolean isEmpty()
    • toSortedList

      public List<V> toSortedList()
      Returns a cached, unmodifiable sorted snapshot of this queue's elements. The snapshot is rebuilt lazily when any mutation nulls the cache.

      Eventually-consistent under concurrent mutation: a call to this method concurrent with a control-plane mutation (add/remove/ reconcileFromBackend) may return a snapshot that does not yet reflect the in-flight mutation. This is the existing control-plane / data-plane concurrency contract — no lock is held on the matching hot path.