Class LoomMap<K,V>

java.lang.Object
com.loomcache.client.LoomMap<K,V>
Type Parameters:
K - the type of keys in the map
V - the type of values in the map

public final class LoomMap<K,V> extends Object
Client-side distributed map proxy.

Provides transparent access to a distributed map stored in the LoomCache cluster. All operations are routed through the connected LoomClient and may raise LoomException if the cluster becomes unavailable or a timeout occurs.

Thread Safety

This class is thread-safe. Multiple threads may call methods concurrently; the underlying LoomClient handles synchronization and connection pooling.

Async API

This class provides both synchronous and asynchronous methods. Async methods return CompletableFuture for non-blocking operations.

Usage Example

org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger("loom-map");
LoomClient client = LoomClient.builder()
    .addSeed("127.0.0.1:5701")
    .build();
client.connect();

LoomMap<String, String> users = client.getMap("users");
users.put("user1", "Alice");
String name = users.get("user1");  // "Alice"
users.delete("user1");

// Async variant
users.putAsync("user2", "Bob")
    .thenCompose(v -> users.getAsync("user2"))
    .thenAccept(name -> log.info("Got: {}", name))
    .join();
Since:
1.0
  • Nested Class Summary

    Nested Classes
    Modifier and Type
    Class
    Description
    static final record 
    Statistics snapshot for a LoomMap operation.
  • Method Summary

    Modifier and Type
    Method
    Description
    void
    Adds or replaces an index for this map through the client SQL DDL path.
    Asynchronously adds or replaces an index for this map.
    void
    Remove all entries from this distributed map with a single server-side command.
    computeIfAbsent(K key, Function<K,V> mappingFunction)
    Compute and store a value if the key is absent, using server-side putIfAbsent for safe concurrent insertion.
    boolean
    Checks whether a key exists in the distributed map.
    boolean
    containsKey(K key, Duration timeout)
    Checks whether a key exists with a custom timeout.
    Asynchronously checks whether a key exists in the distributed map.
    boolean
    delete(K key)
    Removes a key-value pair from the distributed map.
    boolean
    delete(K key, Duration timeout)
    Removes a key-value pair with a custom timeout.
    Asynchronously removes a key-value pair from the distributed map.
    <R> CompletionStage<@Nullable R>
    executeOnKey(K key, EntryProcessor<K,V,R> processor)
    Execute a registered entry processor against a single key through Raft.
    @Nullable V
    get(K key)
    Retrieves the value associated with a key.
    @Nullable V
    get(K key, Duration timeout)
    Retrieves the value associated with a key with a custom timeout.
    Map<K, @Nullable V>
    Batch retrieve multiple values by their keys.
    @Nullable V
    Atomically retrieve and remove a key from the distributed map.
    getAsync(K key)
    Asynchronously retrieves the value associated with a key.
    Returns a snapshot of operational statistics for this map.
    @Nullable V
    put(K key, V value)
    Stores a key-value pair in the distributed map.
    @Nullable V
    put(K key, V value, Duration timeout)
    Stores a key-value pair with a custom timeout.
    void
    putAll(Map<K,V> entries)
    Batch store multiple key-value pairs in the distributed map.
    putAsync(K key, V value)
    Asynchronously stores a key-value pair in the distributed map.
    @Nullable V
    putIfAbsent(K key, V value)
    Atomically stores a key-value pair only if the key is not already present.
    @Nullable V
    putWithTtl(K key, V value, long ttl, TimeUnit timeUnit)
    Stores a key-value pair with server-owned entry TTL.
    @Nullable V
    putWithTtl(K key, V value, Duration ttl)
    Stores a key-value pair with server-owned entry TTL.
    @Nullable V
    putWithTTL(K key, V value, long ttl, TimeUnit timeUnit)
    Backward-friendly alias for codebases that use TTL as an acronym in method names.
    @Nullable V
    putWithTTL(K key, V value, Duration ttl)
    Backward-friendly alias for codebases that use TTL as an acronym in method names.
    scan(long cursor)
    Scans the map using cursor-based iteration (Redis-like SCAN).
    scan(long cursor, @Nullable String pattern)
    Scans the map using cursor-based iteration with a glob pattern filter.
    scan(long cursor, @Nullable String pattern, int count)
    Scans the map using cursor-based iteration with full control.
    Returns a cursor-based iterator for scanning map entries.
    scanner(@Nullable String pattern)
    Returns a cursor-based iterator for scanning map entries with a glob pattern filter.
    scanner(@Nullable String pattern, int pageSize)
    Returns a cursor-based iterator for scanning map entries with full control.
    int
    Returns the number of key-value pairs in the distributed map.
    Asynchronously returns the number of key-value pairs in the distributed map.

    Methods inherited from class Object

    clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
  • Method Details

    • get

      public @Nullable V get(K key)
      Retrieves the value associated with a key.
      Parameters:
      key - the key to look up (serialized via ClientSerializer)
      Returns:
      the value associated with the key, or null if not found
      Throws:
      LoomException - if the operation fails or the cluster is unavailable
    • put

      public @Nullable V put(K key, V value)
      Stores a key-value pair in the distributed map.

      If the key already exists, its value is replaced. Returns the previous value if one existed, or null if this is a new key.

      Parameters:
      key - the key to store (serialized via ClientSerializer)
      value - the value to associate with the key
      Returns:
      the previous value, or null if the key was not present
      Throws:
      LoomException - if the operation fails or the cluster is unavailable
    • putWithTtl

      public @Nullable V putWithTtl(K key, V value, Duration ttl)
      Stores a key-value pair with server-owned entry TTL.

      This controls entry expiration and is not a request timeout. A negative TTL uses the map default TTL, if any; zero stores the entry without an explicit expiry.

    • putWithTtl

      public @Nullable V putWithTtl(K key, V value, long ttl, TimeUnit timeUnit)
      Stores a key-value pair with server-owned entry TTL.
    • putWithTTL

      public @Nullable V putWithTTL(K key, V value, Duration ttl)
      Backward-friendly alias for codebases that use TTL as an acronym in method names.
    • putWithTTL

      public @Nullable V putWithTTL(K key, V value, long ttl, TimeUnit timeUnit)
      Backward-friendly alias for codebases that use TTL as an acronym in method names.
    • putIfAbsent

      public @Nullable V putIfAbsent(K key, V value)
      Atomically stores a key-value pair only if the key is not already present.
      Parameters:
      key - the key to store (serialized via ClientSerializer)
      value - the value to associate with the key
      Returns:
      the existing value if the key was already present, or null if inserted
      Throws:
      LoomException - if the operation fails or the cluster is unavailable
    • delete

      public boolean delete(K key)
      Removes a key-value pair from the distributed map.
      Parameters:
      key - the key to remove
      Returns:
      true if the key was present and removed; false if the key was not found
      Throws:
      LoomException - if the operation fails or the cluster is unavailable
    • clear

      public void clear()
      Remove all entries from this distributed map with a single server-side command.
    • containsKey

      public boolean containsKey(K key)
      Checks whether a key exists in the distributed map.
      Parameters:
      key - the key to check for
      Returns:
      true if the key exists; false otherwise
      Throws:
      LoomException - if the operation fails or the cluster is unavailable
    • size

      public int size()
      Returns the number of key-value pairs in the distributed map.
      Returns:
      the number of entries in the map
      Throws:
      LoomException - if the operation fails or the cluster is unavailable
    • addIndex

      public void addIndex(IndexConfig config)
      Adds or replaces an index for this map through the client SQL DDL path.
      Parameters:
      config - index metadata to add for this map
      Throws:
      LoomException - if the cluster rejects the index DDL or is unavailable
    • scan

      public ScanResult scan(long cursor)
      Scans the map using cursor-based iteration (Redis-like SCAN). Starts from the beginning with default count of 10.
      Parameters:
      cursor - the cursor position (0 to start from beginning)
      Returns:
      a ScanResult containing the next cursor and matched keys
      Throws:
      LoomException - if the operation fails or the cluster is unavailable
    • scan

      public ScanResult scan(long cursor, @Nullable String pattern)
      Scans the map using cursor-based iteration with a glob pattern filter. Default count of 10 keys per iteration.
      Parameters:
      cursor - the cursor position (0 to start from beginning)
      pattern - optional glob pattern (* = any chars, ? = single char), null = match all
      Returns:
      a ScanResult containing the next cursor and matched keys
      Throws:
      LoomException - if the operation fails or the cluster is unavailable
    • scan

      public ScanResult scan(long cursor, @Nullable String pattern, int count)
      Scans the map using cursor-based iteration with full control.
      Parameters:
      cursor - the cursor position (0 to start from beginning)
      pattern - optional glob pattern (* = any chars, ? = single char), null = match all
      count - maximum number of keys to return per iteration
      Returns:
      a ScanResult containing the next cursor and matched keys
      Throws:
      LoomException - if the operation fails or the cluster is unavailable
    • scanner

      public Iterable<Map.Entry<K,V>> scanner()
      Returns a cursor-based iterator for scanning map entries.

      This method provides a clean, idiomatic Java iterator API that handles cursor management and pagination transparently. Useful for iterating over large maps without loading all entries into memory.

      Usage Example:

      org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger("loom-map-scan");
      
      // Simple iteration
      for (Map.Entry<String, String> entry : users.scanner()) {
          log.info("{} = {}", entry.getKey(), entry.getValue());
      }
      
      // With Stream API
      users.scanner()
          .stream()
          .filter(e -> e.getKey().startsWith("user_"))
          .forEach(e -> log.info("{}", e.getValue()));
      
      Returns:
      an Iterable for iterating over all map entries with default page size (10)
      Since:
      1.3
    • scanner

      public Iterable<Map.Entry<K,V>> scanner(@Nullable String pattern)
      Returns a cursor-based iterator for scanning map entries with a glob pattern filter.
      Parameters:
      pattern - optional glob pattern (* = any chars, ? = single char), null = match all
      Returns:
      an Iterable for iterating over matching entries with default page size (10)
      Since:
      1.3
    • scanner

      public Iterable<Map.Entry<K,V>> scanner(@Nullable String pattern, int pageSize)
      Returns a cursor-based iterator for scanning map entries with full control.

      This is the most flexible scanner method, allowing control over both pattern matching and page size for optimal performance.

      Parameters:
      pattern - optional glob pattern (* = any chars, ? = single char), null = match all
      pageSize - number of entries to fetch per scan operation (1-10000 recommended)
      Returns:
      an Iterable for iterating over matching entries with the specified page size
      Throws:
      IllegalArgumentException - if pageSize invalid input: '<'= 0
      Since:
      1.3
    • getAsync

      public CompletableFuture<V> getAsync(K key)
      Asynchronously retrieves the value associated with a key.
      Parameters:
      key - the key to look up (serialized via ClientSerializer)
      Returns:
      a CompletableFuture with the value, or null if not found
    • putAsync

      public CompletableFuture<Void> putAsync(K key, V value)
      Asynchronously stores a key-value pair in the distributed map.

      If the key already exists, its value is replaced.

      Parameters:
      key - the key to store (serialized via ClientSerializer)
      value - the value to associate with the key
      Returns:
      a CompletableFuture that completes when the put operation is done
    • deleteAsync

      public CompletableFuture<Boolean> deleteAsync(K key)
      Asynchronously removes a key-value pair from the distributed map.
      Parameters:
      key - the key to remove
      Returns:
      a CompletableFuture with true if the key was present and removed; false if not found
    • executeOnKey

      public <R> CompletionStage<@Nullable R> executeOnKey(K key, EntryProcessor<K,V,R> processor)
      Execute a registered entry processor against a single key through Raft.
    • containsKeyAsync

      public CompletableFuture<Boolean> containsKeyAsync(K key)
      Asynchronously checks whether a key exists in the distributed map.
      Parameters:
      key - the key to check for
      Returns:
      a CompletableFuture with true if the key exists; false otherwise
    • sizeAsync

      public CompletableFuture<Integer> sizeAsync()
      Asynchronously returns the number of key-value pairs in the distributed map.
      Returns:
      a CompletableFuture with the number of entries in the map
    • addIndexAsync

      public CompletableFuture<Void> addIndexAsync(IndexConfig config)
      Asynchronously adds or replaces an index for this map.
      Parameters:
      config - index metadata to add for this map
      Returns:
      a CompletableFuture that completes when the index metadata has been accepted
    • get

      public @Nullable V get(K key, Duration timeout)
      Retrieves the value associated with a key with a custom timeout.
      Parameters:
      key - the key to look up
      timeout - per-operation timeout; if null, uses client's default timeout
      Returns:
      the value associated with the key, or null if not found
      Throws:
      LoomException - if the operation fails or times out
    • put

      public @Nullable V put(K key, V value, Duration timeout)
      Stores a key-value pair with a custom timeout.
      Parameters:
      key - the key to store
      value - the value to associate with the key
      timeout - per-operation timeout; if null, uses client's default timeout
      Returns:
      the previous value, or null if the key was not present
      Throws:
      LoomException - if the operation fails or times out
    • delete

      public boolean delete(K key, Duration timeout)
      Removes a key-value pair with a custom timeout.
      Parameters:
      key - the key to remove
      timeout - per-operation timeout; if null, uses client's default timeout
      Returns:
      true if the key was present and removed; false if the key was not found
      Throws:
      LoomException - if the operation fails or times out
    • containsKey

      public boolean containsKey(K key, Duration timeout)
      Checks whether a key exists with a custom timeout.
      Parameters:
      key - the key to check for
      timeout - per-operation timeout; if null, uses client's default timeout
      Returns:
      true if the key exists; false otherwise
      Throws:
      LoomException - if the operation fails or times out
    • getAll

      public Map<K, @Nullable V> getAll(Collection<K> keys)
      Batch retrieve multiple values by their keys.

      Fetches all specified keys from the distributed map. Keys that do not exist are omitted from the result map.

      Usage Example:

      LoomMap<String, String> users = client.getMap("users");
      Map<String, String> results = users.getAll(List.of("user1", "user2", "user3"));
      // Returns: {"user1": "Alice", "user2": "Bob"} when user3 is absent
      
      Parameters:
      keys - the keys to retrieve (may be empty)
      Returns:
      a Map containing existing requested keys with their values
      Throws:
      LoomException - if the operation fails or the cluster is unavailable
      Since:
      1.1
    • putAll

      public void putAll(Map<K,V> entries)
      Batch store multiple key-value pairs in the distributed map.

      Stores all entries from the provided map. If a key already exists, its value is replaced. This operation is not atomic—each key-value pair is stored individually.

      Usage Example:

      Map<String, String> users = Map.of(
          "user1", "Alice",
          "user2", "Bob",
          "user3", "Charlie"
      );
      map.putAll(users);
      
      Parameters:
      entries - the map of entries to store (may be empty)
      Throws:
      LoomException - if any operation fails or the cluster is unavailable
      Since:
      1.1
    • computeIfAbsent

      public V computeIfAbsent(K key, Function<K,V> mappingFunction)
      Compute and store a value if the key is absent, using server-side putIfAbsent for safe concurrent insertion.

      If the key does not exist in the map, the provided mappingFunction is called with the key as input to compute a value. That value is then stored via putIfAbsent(Object, Object) to prevent a race where two concurrent callers both compute and overwrite each other's value. If another client inserts a value between the initial get and the putIfAbsent, the existing value is returned.

      Note: The mapping function may be called even if the key was concurrently inserted by another client. In that case the computed value is discarded and the existing server-side value is returned.

      Usage Example:

      LoomMap<String, Integer> cache = client.getMap("counter");
      Integer value = cache.computeIfAbsent("total", k -> 42);
      // First call: stores 42, returns 42
      // Second call: returns 42 (no recomputation)
      
      Parameters:
      key - the key to check and potentially compute for
      mappingFunction - function to compute the value if key is absent
      Returns:
      the value associated with the key (either existing or newly computed)
      Throws:
      LoomException - if the operation fails or the cluster is unavailable
      Since:
      1.1
    • getAndRemove

      public @Nullable V getAndRemove(K key)
      Atomically retrieve and remove a key from the distributed map.

      Issues a single server-side MAP_DELETE round-trip. The server removes the entry atomically and returns the value that was associated with the key at the moment of deletion. No concurrent writer can interleave a put between the read and the delete the way a client-side read-then-delete sequence would allow.

      Usage Example:

      LoomMap<String, String> queue = client.getMap("tasks");
      String task = queue.getAndRemove("task_123");
      // task is retrieved and immediately deleted — atomic destructive read
      
      Parameters:
      key - the key to retrieve and remove
      Returns:
      the value that was associated with the key, or null if not found
      Throws:
      LoomException - if the operation fails or the cluster is unavailable
      Since:
      1.1
    • getStats

      public LoomMap.LoomMapStats getStats()
      Returns a snapshot of operational statistics for this map.

      Tracks cache hits, remote fetches, and operation latency. Useful for monitoring and performance optimization.

      Usage Example:

      org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger("loom-map-stats");
      LoomMapStats stats = map.getStats();
      log.info("Hit rate: {}%", stats.hitRatePercent());
      log.info("Total ops: {}", stats.totalOps());
      log.info("Avg latency: {}ms", stats.avgLatencyMs());
      
      Returns:
      a LoomMapStats record with current operation statistics
      Since:
      1.1