Class DistributedMap<K,V>

java.lang.Object
com.loomcache.server.datastructures.DistributedMap<K,V>
All Implemented Interfaces:
Snapshotable

public class DistributedMap<K,V> extends Object implements Snapshotable
Distributed Map — the core data structure for key-value caching.

Each node holds entries for keys it owns (primary or backup). Writes are replicated synchronously to the backup before ack.

Features: - get, put, delete, containsKey, size, keys, values, clear - putIfAbsent, replace - getAll, putAll (batch operations) - put with TTL (time-to-live) — entries auto-expire after a duration - Map change listeners (add/update/remove events) - Integrates with ReplicationManager for primary-backup sync - Integrates with CacheStore for write-through persistence - Configurable via DistributedMapConfig (max-size, eviction, metrics) - LRU eviction when max-size is reached - Cache metrics: hit/miss ratio, operation counts, eviction counts - Atomic compare-and-set (CAS) for safe concurrent mutations

Thread safety: ConcurrentHashMap as backing store. TTL expiration is lazy (checked on access) to avoid background-thread overhead. LRU tracking uses ConcurrentLinkedDeque for O(1) append and concurrent access.

  • Constructor Details

    • DistributedMap

      public DistributedMap(String name, int instanceNumber)
      Create a DistributedMap with the given name and default configuration.
      Parameters:
      name - the map name (must not be null)
      instanceNumber - the node instance number
      Throws:
      NullPointerException - if name is null
    • DistributedMap

      public DistributedMap(String name, int instanceNumber, DistributedMapConfig config)
      Create a DistributedMap with the given name and custom configuration.
      Parameters:
      name - the map name (must not be null)
      instanceNumber - the node instance number
      config - the map configuration (must not be null)
      Throws:
      NullPointerException - if name or config is null
  • Method Details

    • putForMigration

      public void putForMigration(K key, V value)
      Write a migrated entry into this map without following write redirects or firing side effects.
    • putForMigration

      public void putForMigration(K key, V value, long expirationTimeMillis)
      Write a migrated entry into this map while preserving an absolute expiration timestamp captured on the source node.
    • putForMigrationIfAbsent

      public boolean putForMigrationIfAbsent(K key, V value)
      Write a migrated entry only when the target has not already accepted a newer local/redirected write for the key.
    • putForMigrationIfAbsent

      public boolean putForMigrationIfAbsent(K key, V value, long expirationTimeMillis)
      Write a migrated entry only when absent while preserving the absolute expiration timestamp captured on the source node.
    • putForMigrationIfValueMatches

      public boolean putForMigrationIfValueMatches(K key, @Nullable V expectedCurrentValue, V value, long expirationTimeMillis)
      Write a migrated entry only when the target still contains the value that an earlier migration pass copied. This lets a rebalance sweep repair source writes that raced the first copy without overwriting a newer write already redirected to the target partition.
    • removeKeysForMigration

      public int removeKeysForMigration(Collection<K> keys)
      Remove source-side copies during partition migration without emitting delete side effects.
    • removeForMigrationIfValueMatches

      public boolean removeForMigrationIfValueMatches(K key, @Nullable V expectedValue)
      Remove a migrated source entry only if it still contains the value captured in the migration snapshot. This keeps cleanup from deleting a newer write that arrived before the ownership cutover fully quiesced on this node.
    • executeWithEntryLock

      public <R extends @Nullable Object> @Nullable R executeWithEntryLock(K key, long timeoutMillis, Supplier<@Nullable R> action)
      Execute entry-processor work while holding the map-owned per-key processor gate and the transaction lock that serializes map mutations.
    • get

      public @Nullable V get(K key)
    • put

      public @Nullable V put(K key, V value)
    • put

      public @Nullable V put(K key, V value, long ttl, TimeUnit timeUnit)
      Put a key-value pair with a time-to-live. After the TTL expires, reads treat the entry as absent until a replicated cleanup removes it.
      Parameters:
      ttl - the time-to-live duration
      timeUnit - the time unit for the TTL
    • putWithExpirationTimeMillis

      public @Nullable V putWithExpirationTimeMillis(K key, V value, long expirationTimeMillis)
      Put a key-value pair with an absolute wall-clock expiration. Replicated wire operations use this path so replay/recovery cannot extend a TTL by reinterpreting it as a fresh relative duration.
    • putIfAbsent

      public @Nullable V putIfAbsent(K key, V value)
    • putIfAbsent

      public @Nullable V putIfAbsent(K key, V value, long ttl, TimeUnit timeUnit)
      Put only if absent, with TTL. Returns null if inserted, or the existing value.
    • updateTtl

      public boolean updateTtl(K key, long ttl, TimeUnit timeUnit)
      Update the TTL of an existing entry without changing its value. Returns true if the entry exists and TTL was updated.
    • replace

      public @Nullable V replace(K key, V value)
    • replace

      public boolean replace(K key, V oldValue, V newValue)
      Replace a value only if the key exists and the old value matches. This is a CAS (compare-and-swap) variant of replace.
      Parameters:
      key - the key to replace
      oldValue - the expected current value
      newValue - the new value to set
      Returns:
      true if the replacement was successful, false if the key doesn't exist or value doesn't match
    • delete

      public @Nullable V delete(K key)
    • evictIfUnchanged

      public boolean evictIfUnchanged(K key, V expectedValue, @Nullable Long expectedExpiryNanos)
      Evict a visible entry only if it still matches the value/expiry observed by an eviction scan.

      Eviction is distinct from delete: it must not invoke delete-through MapStore callbacks, remove interceptors, or removed-entry listeners. It records eviction metrics, marks snapshot state dirty, clears local metadata, and emits an eviction event.

    • containsKey

      public boolean containsKey(K key)
    • size

      public int size()
    • isEmpty

      public boolean isEmpty()
    • keySet

      public Set<K> keySet()
    • keySet

      public Set<K> keySet(MapPredicate<K,V> predicate)
    • values

      public Collection<V> values()
    • values

      public Collection<V> values(MapPredicate<K,V> predicate)
    • entrySet

      public Set<Map.Entry<K,V>> entrySet()
      Returns an unmodifiable view of all entries in this map. Expired entries are filtered out before returning.
    • entrySet

      public Set<Map.Entry<K,V>> entrySet(MapPredicate<K,V> predicate)
      Returns an unmodifiable filtered view of visible entries. If the predicate is a PagingPredicate, the predicate's page state and comparator determine the returned slice.
    • scanVisibleEntries

      public boolean scanVisibleEntries(int maxVisibleEntries, DistributedMap.VisibleEntryVisitor<K,V> visitor)
      Streams visible entries without materializing a full entrySet() snapshot.
      Returns:
      true when all visible entries were visited or the visitor stopped early, false when maxVisibleEntries was reached before the map was exhausted
    • getAll

      public Map<K,V> getAll(Set<K> keys)
      Batch get — returns a map of key→value for all keys that exist and are not expired. Uses the same TTL filtering as get(Object), ensuring expired entries are never returned even in batch reads.
    • putAll

      public void putAll(Map<K,V> entries)
    • clear

      public void clear()
    • scan

      public ScanResult scan(long cursor, @Nullable String pattern, int count)
      Scan the map with cursor-based iteration (Redis-like SCAN).
      Parameters:
      cursor - starting position (0 = start from beginning)
      pattern - optional glob pattern (* = any chars, ? = single char), null = match all
      count - maximum number of keys to return
      Returns:
      ScanResult containing next cursor and matched keys
    • shutdown

      public void shutdown()
      Shutdown the distributed map and release TTL cleanup resources. Call this when the map is no longer needed to release resources.

      When a write-behind MapStore is wired, pending writes are flushed synchronously before the scheduler is stopped so no buffered entries are lost on orderly shutdown.

    • putDirect

      public void putDirect(K key, V value)
      Direct put without write-through or listener notification. Used for backup replication and initial data loading.
    • runWithoutMapStorePersistence

      public void runWithoutMapStorePersistence(Runnable action)
      Run a mutation without invoking configured MapStore write-through/write-behind callbacks.

      Used by WAN replication when persist-wan-replicated-data=false: the target map still changes in memory and emits normal listener events, but remote WAN traffic does not update the external backing store.

    • setLocalWriterId

      public void setLocalWriterId(String id)
      Set the node-local writer identifier used when recording new write metadata. Typically called once at map construction with clusterId + ":" + nodeId.
      Parameters:
      id - deterministic writer identifier (non-null)
    • getLocalWriterId

      public @Nullable String getLocalWriterId()
      Returns:
      the node-local writer identifier, or null if not yet set
    • getWriteMetadata

      public @Nullable DistributedMap.WriteMetadata getWriteMetadata(K key)
      Returns:
      the write metadata for key, or null if the key has no recorded metadata (either unwritten locally or cleared)
    • getHitCount

      public long getHitCount(K key)
      Returns:
      number of successful reads recorded for key
    • overrideHitCount

      public void overrideHitCount(K key, long hitCount)
      Override read-hit metadata after a WAN merge winner is applied.
      Parameters:
      key - key whose hit count should be replaced
      hitCount - non-negative hit count from the winning entry
    • getLastAccessTimeMillis

      public long getLastAccessTimeMillis(K key)
      Returns:
      epoch millis of the last successful read recorded for key, or 0 if never accessed
    • overrideLastAccessTimeMillis

      public void overrideLastAccessTimeMillis(K key, long accessTimeMillis)
      Override access-time metadata after a WAN merge winner is applied.
      Parameters:
      key - key whose access time should be replaced
      accessTimeMillis - non-negative epoch millis from the winning entry
    • getExpirationTimeMillis

      public long getExpirationTimeMillis(K key)
      Returns:
      epoch millis when key expires, Long.MAX_VALUE when it does not expire, or 0 when the key is absent or already expired
    • getExpirationDeadlineNanos

      public long getExpirationDeadlineNanos(K key)
      Return the local monotonic expiry deadline for migration verification.

      Long.MAX_VALUE means the entry has no TTL, and 0 means the entry is absent or already expired. This value is only stable on the source node and must not be used as the target-side expiry time.

    • overrideExpirationTimeMillis

      public void overrideExpirationTimeMillis(K key, long expirationTimeMillis)
      Override TTL metadata after a WAN merge winner is applied.
      Parameters:
      key - key whose expiration should be replaced
      expirationTimeMillis - epoch millis when the key expires, Long.MAX_VALUE for no TTL, or 0 to mark it expired
    • recordLocalWriteMetadata

      public void recordLocalWriteMetadata(K key)
      Record metadata for a local write. Called by putInternal(K, V, Long) and related write paths AFTER the store update succeeds. Uses System.currentTimeMillis() as the write timestamp and the node-local writer id set via setLocalWriterId(String).

      No-op if localWriterId has not been set — tests and pre- wired registries pay no cost.

    • overrideWriteMetadata

      public void overrideWriteMetadata(K key, long timestampMillis, String writerNodeId)
      Overwrite the metadata for key after a WAN merge has selected a remote-sourced winner. Called by WanConsumer when a merge policy chose an incoming value that differs from the local value.
    • maybeAdvanceWriteMetadata

      public void maybeAdvanceWriteMetadata(K key, long timestampMillis, String writerNodeId)
      Advance the recorded timestamp for key IFF the incoming tuple is strictly newer. Called by WanConsumer on the no-op case — chose local value — so subsequent merge decisions see the most recent "last observed write" across WAN.
    • clearWriteMetadata

      public void clearWriteMetadata(K key)
      Remove per-entry metadata for key. Called from local and WAN delete paths to keep metadata maps bounded alongside the store.
    • putForWanMerge

      public @Nullable V putForWanMerge(K key, V newValue)
      WAN-merge put: stores the value and fires fireEntryMerged(K, V, V) instead of ADDED/UPDATED. Used by WanConsumer when a MergePolicy resolves divergent cross-cluster histories to a canonical value.

      The MERGED event signals to listeners that the new value came from cross-cluster conflict resolution, not from a local write.

      Parameters:
      key - the key
      newValue - the merged value (not null)
      Returns:
      the previous value, or null if absent
    • deleteDirect

      public void deleteDirect(K key)
      Direct delete without write-through or listener notification. Used for backup replication.
    • compareAndSet

      public boolean compareAndSet(K key, V expectedValue, V newValue)
      Atomically sets the value for key to newValue only if the current value equals expectedValue.

      This is the distributed-cache equivalent of ConcurrentHashMap.replace(K, V, V). Essential for safe concurrent state transitions without distributed locks.

      Returns:
      true if the value was replaced, false if the current value didn't match
    • compareAndDelete

      public boolean compareAndDelete(K key, V expectedValue)
      Atomically removes key only when the current value equals expectedValue.

      This preserves delete-through and listener side effects only for the winning compare.

      Returns:
      true if the entry was removed, false if the current value didn't match
    • compute

      public @Nullable V compute(K key, BiFunction<? super K, ? super @Nullable V, ? extends @Nullable V> remappingFunction)
      Atomically compute a new value for key using the given function.

      The function receives the current value (or null if absent) and returns the new value (or null to remove the entry). The function is called under ConcurrentHashMap's segment lock, ensuring atomicity.

      Returns:
      the new value associated with the key, or null if removed
    • computeIfAbsent

      public @Nullable V computeIfAbsent(K key, BiFunction<? super K, ? super @Nullable V, ? extends V> mappingFunction)
      Compute and insert only if the key is absent. If the key already exists, returns the existing value unchanged. The function is only called if the key is not present.

      This is the equivalent of ConcurrentHashMap.computeIfAbsent.

      Returns:
      the value associated with the key after operation (either existing or newly computed)
    • computeIfPresent

      public @Nullable V computeIfPresent(K key, BiFunction<? super K, ? super V, ? extends V> remappingFunction)
      Compute and update only if the key is present. If the key doesn't exist, returns null and the function is not called. If the function returns null, the entry is removed.

      This is the equivalent of ConcurrentHashMap.computeIfPresent.

      Returns:
      the new value associated with the key, or null if the key is absent or removed
    • merge

      public @Nullable V merge(K key, V value, BiFunction<? super V, ? super V, ? extends V> remapper)
      Merge a value into the map for the given key. If the key is absent, the value is inserted directly. If the key is present, the remapper function is called with the current value and the provided value. If the remapper returns null, the entry is removed.
      Parameters:
      key - the key
      value - the value to merge in
      remapper - function to merge values
      Returns:
      the final value associated with the key, or null if removed
    • getOrDefault

      public V getOrDefault(K key, V defaultValue)
      Get the value for a key, or return the default value if the key is absent or expired. This is the equivalent of Map.getOrDefault.
      Parameters:
      key - the key
      defaultValue - the value to return if key is absent
      Returns:
      the value for the key, or defaultValue if absent
    • removeAll

      public int removeAll(Collection<K> keys)
      Remove all entries for the given keys. Entries that don't exist are silently ignored.
      Parameters:
      keys - the keys to remove
      Returns:
      the number of entries actually removed
    • replaceIfPresent

      public boolean replaceIfPresent(K key, V oldValue, V newValue)
      Replace a value only if the key exists and the old value matches. This is like replace(K, V, V) but with an alternative signature.
      Parameters:
      key - the key
      oldValue - the expected old value
      newValue - the new value to set
      Returns:
      true if replaced successfully, false otherwise
    • entries

      public Map<K,V> entries(String prefix)
      Get all entries with keys matching a given prefix. Returns a map of matching key→value pairs.
      Parameters:
      prefix - the prefix to match
      Returns:
      a map of matching entries
    • keysByPattern

      public Set<K> keysByPattern(String pattern)
      Get all keys matching a given glob/regex pattern. Supports glob patterns: * (any sequence), ? (single char).
      Parameters:
      pattern - the glob pattern to match
      Returns:
      a set of matching keys
    • assertProductionMutationAllowed

      public void assertProductionMutationAllowed(K key, String operation)
      Preflight a key before multi-entry mutations start applying partial state.

      Single-key mutation methods call the same production guard internally. Bulk callers use this method to validate every target key first, so a later TTL/max-idle rejection cannot leave earlier keys committed without their invalidations.

    • ttlEntryCount

      public int ttlEntryCount()
      Return the number of entries with TTL set (for diagnostics).
    • getRemainingTtlSeconds

      public long getRemainingTtlSeconds(K key)
      Return the remaining TTL for a key in seconds. Returns -1 if the key exists but has no TTL, -2 if the key does not exist.
    • getRemainingTtlMillis

      public long getRemainingTtlMillis(K key)
      Return the remaining TTL for a key in milliseconds. Returns -1 if the key exists but has no TTL, -2 if the key does not exist.
    • removeTtl

      public boolean removeTtl(K key)
      Remove the TTL from a key (persist it).
      Returns:
      true if the key had a TTL that was removed
    • putWithTTL

      public @Nullable V putWithTTL(K key, V value, long ttlMillis)
      Store a key-value pair with a TTL (Time-To-Live) in milliseconds. After the TTL expires, reads treat the entry as absent until cleanup removes it.
      Parameters:
      key - the key
      value - the value
      ttlMillis - TTL duration in milliseconds (0 or negative = no TTL)
      Returns:
      the previous value associated with the key, or null if there was none
    • getWithTTL

      public @Nullable V getWithTTL(K key)
      Get a value only if it exists and has not expired. Expired entries are hidden on reads (same as regular get()).
      Parameters:
      key - the key
      Returns:
      the value, or null if the key doesn't exist or has expired
    • refreshTTL

      public boolean refreshTTL(K key, long newTtlMillis)
      Refresh the TTL for an existing key without changing its value. Equivalent to updateTtl().
      Parameters:
      key - the key
      newTtlMillis - new TTL duration in milliseconds (0 or negative = remove TTL)
      Returns:
      true if the key exists and TTL was updated, false if key doesn't exist
    • setDefaultTTL

      public void setDefaultTTL(long ttlMillis)
      Set a default TTL for all new entries added via put() and putIfAbsent(). Entries with explicit TTL (via putWithTTL or put with TimeUnit) are not affected.
      Parameters:
      ttlMillis - default TTL in milliseconds (0 = disable default TTL)
    • getDefaultTTL

      public long getDefaultTTL()
      Get the default TTL setting.
      Returns:
      default TTL in milliseconds, 0 if not set
    • getTimeToLive

      public long getTimeToLive(K key)
      Get the remaining time-to-live for a key.
      Parameters:
      key - the key
      Returns:
      remaining TTL in milliseconds, -1 if no TTL is set or key doesn't exist
    • evictExpired

      public int evictExpired()
      Bulk eviction of all expired entries. Scans the entire map and removes entries whose TTL has passed. This is an explicit cleanup operation; regular reads only filter expired entries.
      Returns:
      the number of entries evicted
    • getMapStatistics

      public DistributedMap.MapStatistics getMapStatistics()
      Get a snapshot of current map statistics. Includes hit/miss counts, operation counts, and eviction counts.
      Returns:
      a MapStatistics record with current metrics
    • setWriteThrough

      public void setWriteThrough(@Nullable BiConsumer<K,V> writeThrough)
    • setDeleteThrough

      public void setDeleteThrough(@Nullable Consumer<K> deleteThrough)
    • setMapStore

      public void setMapStore(MapStore<K,V> store, MapStoreConfig config)
      Wire a pluggable MapStore as the backing store for this map.

      Supersedes the legacy single-purpose setWriteThrough(BiConsumer) / setDeleteThrough(Consumer) pair: internally, this method wires both callbacks to adapters that invoke store.store(k,v) and store.delete(k). Write-through MapStore calls are fail-close: persistence failures are rethrown and the entry state is restored before callers observe success.

      Modes:

      • writeThrough — synchronous: every local write calls mapStore.store(key, value) / .delete(key) before emitting listener side effects; failures abort the visible write.
      • writeBehind — asynchronous: writes are coalesced into a bounded per-key queue and flushed on a scheduled virtual-thread executor. Same-key updates before flush collapse into a single store/delete call.

      Load mode:

      • DISABLED — no reads are issued to the backing store.
      • LAZY — values are fetched from the store on get() miss and inserted into the map (cache-aside).
      • EAGERMapStore.loadAllKeys() is invoked asynchronously on a virtual thread and each returned key is fetched and inserted.
      Parameters:
      store - the backing store (not null)
      config - wire-up options (not null)
      Throws:
      IllegalStateException - if a MapStore is already wired
    • getMapStore

      public @Nullable MapStore<K,V> getMapStore()
      Get the wired MapStore, or null if none has been configured.
      Returns:
      the backing store, or null
    • getMapStoreConfig

      public @Nullable MapStoreConfig getMapStoreConfig()
      Get the active MapStoreConfig, or null if no store is wired.
      Returns:
      the map-store config, or null
    • flushWriteBehindNow

      public void flushWriteBehindNow()
      Force a synchronous flush of the write-behind queue. Intended for tests and graceful-shutdown paths.
    • addInterceptor

      public void addInterceptor(MapInterceptor interceptor)
      Register a map interceptor. Interceptors execute in registration order before and after get/put/remove operations.
      Parameters:
      interceptor - the interceptor to register (must not be null)
    • removeInterceptor

      public boolean removeInterceptor(MapInterceptor interceptor)
      Remove a previously registered map interceptor.
      Parameters:
      interceptor - the interceptor to remove (must not be null)
      Returns:
      true if the interceptor was found and removed
    • registerMapListener

      public void registerMapListener(DistributedMap.MapChangeListener<K,V> listener)
    • registerMapListener

      public void registerMapListener(DistributedMap.MapChangeListener<K,V> listener, EntryPredicate<K,V> predicate)
    • registerLocalMapListener

      public void registerLocalMapListener(DistributedMap.MapChangeListener<K,V> listener)
      Register a listener that fires only for events originating on THIS node.

      A "local" event is one produced by a direct call to put, remove, compute, eviction, or TTL expiration on this instance — i.e. the current thread is the one mutating the store. Events replayed via Raft apply / backup replication (putDirect(K, V)/deleteDirect(K)) are NOT local and do not fire local listeners.

      Useful when you need to react exactly once per cluster write (on the leader) — cluster-wide listeners fire on every replica, which causes duplicate reactions for side-effectful handlers.

      Parameters:
      listener - the listener to register
    • registerLocalMapListener

      public void registerLocalMapListener(DistributedMap.MapChangeListener<K,V> listener, EntryPredicate<K,V> predicate)
      Register a local-only listener filtered by a predicate. See registerLocalMapListener(MapChangeListener) and registerMapListener(MapChangeListener, EntryPredicate).
      Parameters:
      listener - the listener to register
      predicate - event filter
    • deregisterMapListener

      public void deregisterMapListener(DistributedMap.MapChangeListener<K,V> listener)
    • fireEntryMerged

      public void fireEntryMerged(K key, @Nullable V oldValue, V newValue)
      Fire a MERGED event — used by WAN replication when two divergent histories are reconciled and a single canonical value is chosen. Unlike UPDATED, this signals that the new value came from a cross-cluster merge rather than a local write.

      Fires on cluster-wide listeners only (MERGED is never a local-originated event — it always comes from WAN apply).

      Parameters:
      key - the merged key (not null)
      oldValue - the value before the merge, or null when this node had none
      newValue - the winning value after the merge (not null)
    • beginBufferedSideEffects

      public void beginBufferedSideEffects()
    • flushBufferedSideEffects

      public void flushBufferedSideEffects()
    • discardBufferedSideEffects

      public void discardBufferedSideEffects()
    • captureEntryRollbackState

      public DistributedMap.EntryRollbackState<V> captureEntryRollbackState(K key)
      Capture the exact current state for a single key so callers can restore it without advancing revisions or replaying user-visible side effects.
    • restoreEntryRollbackState

      public void restoreEntryRollbackState(K key, DistributedMap.EntryRollbackState<V> state)
      Restore a previously captured entry state without incrementing revisions, invoking write-through callbacks, or notifying listeners.
    • toString

      public String toString()
      Overrides:
      toString in class Object
    • stopCleanup

      public void stopCleanup()
      Stop the background TTL cleanup thread.
    • setMaxMemoryBytes

      public void setMaxMemoryBytes(long maxBytes)
      Set the maximum memory limit for this map.
    • getCurrentMemoryBytes

      public long getCurrentMemoryBytes()
      Get the current memory usage in bytes (estimated).
    • processEntry

      public <R extends @Nullable Object> @Nullable R processEntry(K key, CacheEntryProcessor<K, V, @NonNull R> processor)
      Execute a processor on a single key atomically.

      The processor has exclusive access to the entry while executing.

      Type Parameters:
      R - the result type
      Parameters:
      key - the key to process
      processor - the processor to apply
      Returns:
      the result of processing
    • processEntries

      public <R extends @Nullable Object> Map<K,R> processEntries(Set<K> keys, CacheEntryProcessor<K, V, @NonNull R> processor)
      Execute a processor on multiple keys in parallel using virtual threads.

      Each key is processed independently and concurrently.

      Type Parameters:
      R - the result type
      Parameters:
      keys - the keys to process
      processor - the processor to apply
      Returns:
      a map of keys to processor results
    • executeOnAll

      public <R extends @Nullable Object> Map<K,R> executeOnAll(CacheEntryProcessor<K, V, @NonNull R> processor)
      Execute a processor on all entries in the map in parallel using virtual threads.

      All entries are processed independently and concurrently.

      Type Parameters:
      R - the result type
      Parameters:
      processor - the processor to apply
      Returns:
      a map of all keys to processor results
    • aggregate

      public <R> R aggregate(Aggregator<K,V,R> aggregator)
      Aggregate all visible entries using a single aggregator instance.
      Type Parameters:
      R - the result type
      Parameters:
      aggregator - the aggregator to accumulate into
      Returns:
      the aggregated result
    • aggregate

      public <R> R aggregate(Supplier<? extends Aggregator<K,V,R>> aggregatorFactory)
      Aggregate all visible entries with two-stage map-reduce combine semantics.
      Type Parameters:
      R - the result type
      Parameters:
      aggregatorFactory - creates a fresh aggregator for each map stage
      Returns:
      the aggregated result
    • aggregate

      public <R> R aggregate(Supplier<? extends Aggregator<K,V,R>> aggregatorFactory, MapPredicate<K,V> predicate)
      Aggregate visible entries matching predicate with two-stage map-reduce combine semantics.
      Type Parameters:
      R - the result type
      Parameters:
      aggregatorFactory - creates a fresh aggregator for each map stage
      predicate - filters entries before accumulation
      Returns:
      the aggregated result
    • 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
    • captureSnapshot

      public Snapshotable.SnapshotCapture captureSnapshot()
      Description copied from interface: Snapshotable
      Capture a full snapshot and atomically advance dirty tracking for the captured state.

      Implementations that detach dirty state must return a token so the caller can restore it if snapshot serialization or persistence later fails.

      Specified by:
      captureSnapshot in interface Snapshotable
      Returns:
      captured snapshot data and optional rollback token
    • 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
    • supportsDeltaSnapshot

      public boolean supportsDeltaSnapshot()
      Description copied from interface: Snapshotable
      Whether this data structure supports delta (incremental) snapshots.

      Structures that return true must also implement Snapshotable.takeDeltaSnapshot() and Snapshotable.clearDirtyState().

      Specified by:
      supportsDeltaSnapshot in interface Snapshotable
      Returns:
      true if delta snapshots are supported
    • takeDeltaSnapshot

      public byte[] takeDeltaSnapshot()
      Description copied from interface: Snapshotable
      Serialize only the changed state since the last snapshot into a byte array.

      Only called when Snapshotable.supportsDeltaSnapshot() returns true. The default implementation falls back to a full snapshot.

      Specified by:
      takeDeltaSnapshot in interface Snapshotable
      Returns:
      byte array containing only changed state, or empty if no changes
    • captureDeltaSnapshot

      public Snapshotable.SnapshotCapture captureDeltaSnapshot()
      Description copied from interface: Snapshotable
      Capture a delta snapshot and atomically advance dirty tracking for the captured state.

      Implementations that detach dirty state must return a token so the caller can restore it if snapshot serialization or persistence later fails.

      Specified by:
      captureDeltaSnapshot in interface Snapshotable
      Returns:
      captured delta data and optional rollback token
    • clearDirtyState

      public void clearDirtyState()
      Description copied from interface: Snapshotable
      Clear the dirty-tracking state after a delta snapshot has been persisted.

      Called after a successful delta snapshot to reset change tracking. Default implementation is a no-op.

      Specified by:
      clearDirtyState in interface Snapshotable
    • rollbackDirtyState

      public void rollbackDirtyState(@Nullable Object dirtyStateToken)
      Description copied from interface: Snapshotable
      Restore dirty-tracking state that was detached during snapshot capture.

      Called only when snapshot persistence fails after a capture completed successfully.

      Specified by:
      rollbackDirtyState in interface Snapshotable
      Parameters:
      dirtyStateToken - implementation-specific token returned by captureSnapshot/captureDeltaSnapshot
    • hasDirtyState

      public boolean hasDirtyState()
      Description copied from interface: Snapshotable
      Whether any data has changed since the last snapshot.

      Used by the snapshot scheduler to skip structures with no changes during delta snapshots.

      Specified by:
      hasDirtyState in interface Snapshotable
      Returns:
      true if changes exist since last clearDirtyState() call
    • setKryoSerializer

      public void setKryoSerializer(KryoSerializer serializer)
      Wire the Kryo serializer used for map snapshots. Called by DataStructureRegistry so that snapshot serialization shares the same registered types as the rest of the server.