Class DistributedSet<E>

java.lang.Object
com.loomcache.server.datastructures.DistributedSet<E>
Type Parameters:
E - the type of elements in this set

public class DistributedSet<E> extends Object
Distributed Set — an unordered collection of unique elements.

Backed by ConcurrentHashMap.newKeySet() for O(1) add, remove, and contains operations under high concurrency without external locking.

Features:

  • add, remove, contains — core set operations
  • addAll — bulk add with count of new elements
  • size, isEmpty, clear
  • toSet — snapshot as unmodifiable Set
  • Entry listeners (onAdded, onRemoved)
  • addDirect/removeDirect — replication-safe, no listener notification

Thread safety: all operations are thread-safe via the underlying ConcurrentHashMap key set. Listener dispatch is fail-safe (try-catch per listener).

Since:
1.1
  • Field Details

  • Constructor Details

    • DistributedSet

      public DistributedSet(String name, int instanceNumber)
      Create a DistributedSet with the given name.
      Parameters:
      name - the name of the set (must not be null)
      instanceNumber - the node instance number
      Throws:
      NullPointerException - if name is null
  • Method Details

    • add

      public boolean add(E element)
      Add an element to the set.
      Returns:
      true if the element was added (was not already present)
    • remove

      public boolean remove(E element)
      Remove an element from the set.
      Returns:
      true if the element was removed (was present)
    • contains

      public boolean contains(E element)
      Check if the set contains the given element.
    • addAll

      public int addAll(Collection<E> elements)
      Add all elements from the given collection.
      Returns:
      the number of new elements added (not already present)
    • size

      public int size()
    • isEmpty

      public boolean isEmpty()
    • clear

      public void clear()
    • toSet

      public Set<E> toSet()
      Return an unmodifiable snapshot of the current set contents.
    • union

      public Set<E> union(DistributedSet<E> other)
      Return the union of this set with another set (all elements in either). Does NOT modify this set — returns a new snapshot. Takes a snapshot of other.store to ensure consistency against concurrent mutations.
    • intersection

      public Set<E> intersection(DistributedSet<E> other)
      Return the intersection of this set with another set (elements in both). Does NOT modify this set — returns a new snapshot. Takes a snapshot of other.store to ensure consistency against concurrent mutations.
    • difference

      public Set<E> difference(DistributedSet<E> other)
      Return the difference of this set minus another set (elements in this but not other). Does NOT modify this set — returns a new snapshot. Takes a snapshot of other.store to ensure consistency against concurrent mutations.
    • symmetricDifference

      public Set<E> symmetricDifference(DistributedSet<E> other)
      Return the symmetric difference (elements in either but not both). Does NOT modify this set — returns a new snapshot.
    • isSubsetOf

      public boolean isSubsetOf(DistributedSet<E> other)
      Check if this set is a subset of another set (all elements in this are in other).
      Returns:
      true if this is a subset of other
    • isSupersetOf

      public boolean isSupersetOf(DistributedSet<E> other)
      Check if this set is a superset of another set (all elements in other are in this).
      Returns:
      true if this is a superset of other
    • randomMember

      public @Nullable E randomMember()
      Return a random member from the set, or null if empty.
      Returns:
      a random element, or null if set is empty
    • randomMembers

      public Set<E> randomMembers(int count)
      Return N random members from the set (without replacement). If count >= size, returns all elements in arbitrary order.
      Parameters:
      count - number of elements to return
      Returns:
      a set of random elements (up to count size)
    • pop

      public @Nullable E pop()
      Remove and return a random member (pop operation).
      Returns:
      a random element that was removed, or null if set is empty
    • srandmember

      public List<E> srandmember(int count)
      Redis-style SRANDMEMBER with count parameter. Positive count: return unique random elements (up to count). Negative count: return count random elements allowing duplicates.
      Parameters:
      count - positive = unique, negative = allow duplicates
      Returns:
      list of random elements
    • removeAll

      public int removeAll(Collection<E> elements)
      Remove all elements that are also in the other set.
      Returns:
      the number of elements removed
    • retainAll

      public int retainAll(Collection<E> elements)
      Retain only elements that are also in the given collection.
      Returns:
      the number of elements removed
    • toArray

      public Object[] toArray()
      Return set contents as Object array.
      Returns:
      array snapshot of current elements
    • stream

      public Stream<E> stream()
      Return a Stream over the set elements. The stream is created from a snapshot, so it's safe from concurrent modifications.
      Returns:
      Stream of elements
    • snapshotForPersistence

      public Set<E> snapshotForPersistence()
      Unbounded snapshot intended solely for Raft/state-machine persistence. Bypasses MAX_SNAPSHOT_ITEMS because the snapshot path must faithfully capture the full set state regardless of size; user-facing collection views remain capped via toSet().
    • page

      public List<E> page(int offset, int pageSize)
      Read a page of elements without materializing the whole set.

      Pairs with toSet(), toArray(), and stream() as the paginated alternative when the set grows beyond MAX_SNAPSHOT_ITEMS.

      Ordering is weakly consistent, not stable. This method walks the underlying ConcurrentHashMap key-set iterator, whose order can change between calls as the table resizes or entries are added/removed. Offset-based pagination can therefore skip or duplicate elements across successive calls — callers that need stable, sorted iteration must use scan(long, String, int) for String sets, or snapshot via snapshotForPersistence() and page the returned immutable view themselves.

      Parameters:
      offset - starting index (0-based); clamped to size
      pageSize - page size (must be positive and ≤ MAX_SNAPSHOT_ITEMS)
      Returns:
      an immutable list of at most pageSize elements
    • forEachPage

      public void forEachPage(int pageSize, Consumer<List<E>> action)
      Iterate the whole set in bounded pages, applying action per page. Arbitrarily large sets can be consumed this way without violating MAX_SNAPSHOT_ITEMS. Each page is a snapshot taken on the live ConcurrentHashMap iterator — elements added or removed mid-iteration follow CHM's weakly-consistent iterator semantics.
      Parameters:
      pageSize - page size (must be positive and ≤ MAX_SNAPSHOT_ITEMS)
      action - callback invoked once per non-empty page
    • forEach

      public void forEach(Consumer<E> action)
      Iterate over all elements and apply the given action.
      Parameters:
      action - the action to perform on each element
    • addDirect

      public void addDirect(E element)
      Direct add without listener notification. Used for backup replication.
    • removeDirect

      public void removeDirect(E element)
      Direct remove without listener notification. Used for backup replication.
    • scan

      public ScanResult scan(long cursor, @Nullable String pattern, int count)
      Scan the set with cursor-based iteration (Redis-like SCAN).

      Each invocation snapshots the current set into an immutable sorted list before applying the cursor window. This gives deterministic pagination for that call while retaining Redis-style weak consistency: concurrent writes between SCAN calls may still cause later pages to reflect newer data.

      Type contract: this method is wire-protocol-facing and only supports DistributedSet<String>. Non-String element types are rejected with IllegalStateException rather than silently flattening distinct elements through toString() collisions.

      Parameters:
      cursor - starting position (0 = start from beginning)
      pattern - optional glob pattern (* = any chars, ? = single char), or null to match all
      count - maximum number of elements to return
      Returns:
      ScanResult containing next cursor and matched elements
      Throws:
      IllegalStateException - if the set contains non-String elements
    • getSetStatistics

      public DistributedSet.SetStatistics getSetStatistics()
      Get a snapshot of current set statistics.
      Returns:
      SetStatistics record with aggregated stats
    • addSetListener

      public void addSetListener(DistributedSet.SetListener<E> listener)
    • removeSetListener

      public void removeSetListener(DistributedSet.SetListener<E> listener)
    • beginBufferedSideEffects

      public void beginBufferedSideEffects()
    • flushBufferedSideEffects

      public void flushBufferedSideEffects()
    • discardBufferedSideEffects

      public void discardBufferedSideEffects()
    • toString

      public String toString()
      Overrides:
      toString in class Object