Class DistributedMultiMap

java.lang.Object
com.loomcache.server.datastructures.DistributedMultiMap
All Implemented Interfaces:
Snapshotable

public class DistributedMultiMap extends Object implements Snapshotable
Distributed MultiMap — a map where each key can have multiple values.

Backed by ConcurrentHashMap with ConcurrentLinkedDeque values, providing thread-safe concurrent access to multiple values per key. Supports operations similar to Guava's Multimap.

Features:

  • put(key, value) — add a value to a key
  • get(key) → Collection — retrieve all values for a key
  • remove(key, value) — remove a specific value
  • removeAll(key) — remove all values for a key
  • containsKey, containsValue, containsEntry
  • size, keyCount, valueCount(key)
  • keys, values, entries — snapshot collections
  • clear — remove all entries
  • Entry listeners (onValueAdded, onValueRemoved)
  • Snapshotable support for persistence
  • Metrics via Micrometer (operations counter, entry count gauge)

Thread safety: All operations are thread-safe via ConcurrentHashMap and ConcurrentLinkedDeque. Compound operations use ReentrantLock for atomicity. Listener dispatch is fail-safe (try-catch per listener).

Since:
1.0
  • Field Details

    • MAX_COLLECTION_VIEW_ENTRIES

      public static final int MAX_COLLECTION_VIEW_ENTRIES
      See Also:
  • Constructor Details

    • DistributedMultiMap

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

      public DistributedMultiMap(String name, int instanceNumber, @Nullable io.micrometer.core.instrument.MeterRegistry meterRegistry)
      Create a DistributedMultiMap with metrics support.
      Parameters:
      name - the name of the multimap (must not be null)
      instanceNumber - the node instance number
      meterRegistry - the meter registry for metrics (may be null)
      Throws:
      NullPointerException - if name is null
  • Method Details

    • getTransactionLock

      public ReentrantLock getTransactionLock()
    • put

      public boolean put(String key, String value)
      Add a value to the given key. A key can have multiple values.
      Parameters:
      key - the key (must not be null)
      value - the value to add (must not be null)
      Returns:
      true if the value was added (always true for multimap)
    • get

      public Collection<String> get(String key)
      Get all values for the given key.
      Parameters:
      key - the key (must not be null)
      Returns:
      unmodifiable collection of values (empty if key not found)
    • remove

      public boolean remove(String key, String value)
      Remove a specific value from a key.
      Parameters:
      key - the key (must not be null)
      value - the value to remove (must not be null)
      Returns:
      true if the value was removed
    • removeAll

      public int removeAll(String key)
      Remove all values for a given key.
      Parameters:
      key - the key (must not be null)
      Returns:
      the number of values removed
    • containsKey

      public boolean containsKey(String key)
      Check if the multimap contains the given key.
      Parameters:
      key - the key (must not be null)
      Returns:
      true if the key exists (has at least one value)
    • containsValue

      public boolean containsValue(String value)
      Check if the multimap contains the given value (in any key).
      Parameters:
      value - the value (must not be null)
      Returns:
      true if the value exists in any key
    • containsEntry

      public boolean containsEntry(String key, String value)
      Check if the multimap contains the given key-value pair.
      Parameters:
      key - the key (must not be null)
      value - the value (must not be null)
      Returns:
      true if the entry exists
    • size

      public int size()
      Get the total number of key-value entries (sum of all values across all keys).
      Returns:
      total entry count
    • keyCount

      public int keyCount()
      Get the number of distinct keys.
      Returns:
      number of keys
    • valueCount

      public int valueCount(String key)
      Get the number of values for a specific key.
      Parameters:
      key - the key (must not be null)
      Returns:
      number of values for the key (0 if key not found)
    • keys

      public Set<String> keys()
      Get all keys in the multimap.
      Returns:
      unmodifiable set of all keys
    • values

      public Collection<String> values()
      Get all values across all keys.
      Returns:
      unmodifiable collection of all values
    • entries

      public Collection<Map.Entry<String,String>> entries()
      Get all key-value entries as Map.Entry pairs.
      Returns:
      unmodifiable collection of entries
    • keysPage

      public List<String> keysPage(int offset, int pageSize)
      Return a page of keys sorted lexicographically. Pairs with keys() as the paginated alternative for multimaps above MAX_COLLECTION_VIEW_ENTRIES.
      Parameters:
      offset - starting key index (0-based); clamped to total key count
      pageSize - page size (must be positive and ≤ MAX_COLLECTION_VIEW_ENTRIES)
    • entriesPage

      public DistributedMultiMap.EntryPage entriesPage(int offset, int pageSize)
      Return a page of key-value entries in key-sorted, insertion-order-within-key order. Callers drive pagination with DistributedMultiMap.EntryPage.nextOffset() until it returns -1.
      Parameters:
      offset - entry offset (0-based across the flat view)
      pageSize - page size (must be positive and ≤ MAX_COLLECTION_VIEW_ENTRIES)
    • clear

      public void clear()
      Clear all entries from the multimap.
    • isEmpty

      public boolean isEmpty()
      Check if the multimap is empty.
      Returns:
      true if no entries
    • getStatistics

      Get a snapshot of current multimap statistics.
      Returns:
      MultiMapStatistics record with aggregated stats
    • getStats

      Returns a compact MultiMapStats snapshot.
    • addMultiMapListener

      public void addMultiMapListener(DistributedMultiMap.MultiMapListener listener)
    • removeMultiMapListener

      public void removeMultiMapListener(DistributedMultiMap.MultiMapListener listener)
    • takeSnapshot

      public byte[] takeSnapshot()
      Description copied from interface: Snapshotable
      Serialize the current state of this data structure into a byte array.
      Specified by:
      takeSnapshot in interface Snapshotable
      Returns:
      byte array containing the serialized state
    • restoreSnapshot

      public void restoreSnapshot(byte[] data)
      Description copied from interface: Snapshotable
      Restore this data structure from a previously serialized state.

      Must restore the state atomically, clearing existing data and populating with the snapshot contents.

      Specified by:
      restoreSnapshot in interface Snapshotable
      Parameters:
      data - the serialized state to restore from
    • snapshotId

      public String snapshotId()
      Description copied from interface: Snapshotable
      Get a unique identifier for this data structure.

      Used to identify which data structure a snapshot belongs to in a full state machine snapshot.

      Specified by:
      snapshotId in interface Snapshotable
      Returns:
      unique identifier for this data structure
    • toString

      public String toString()
      Overrides:
      toString in class Object