Class RedisKeyValueStore

java.lang.Object
com.codename1.backend.kv.RedisKeyValueStore
All Implemented Interfaces:
KeyValueStore, Closeable, AutoCloseable

public final class RedisKeyValueStore extends Object implements KeyValueStore

A KeyValueStore on a Redis server -- or Valkey, KeyDB, Dragonfly, any server that speaks RESP2. No client library: the protocol is spoken directly over the backend's own sockets, so a binary that never names this class carries none of it.

  redis://[[user]:password@]host[:port][/database]
  rediss://...        # TLS, verifying the server's certificate

Connections

Calls borrow a connection from a pool, use it and give it back; a pool that has none idle opens another rather than making the caller wait, and keeps at most cn1.kv.pool.max (16) idle. A connection that failed with anything but an error reply is closed, never returned, so one dropped socket costs one call. Commands that block go on a dedicated() connection.

Subscriptions share ONE further connection and one receiving thread for the whole store. When it drops, it reconnects with a back-off and subscribes again; messages published meanwhile are lost, as pub/sub always loses them.

Atomic operations

compareAndSet(String, byte[], byte[], long) and increment(String, long, long) with an expiry are Lua scripts, loaded once per server with SCRIPT LOAD and called by digest, so a call sends the digest rather than the script. A server that forgot them (a restart, a SCRIPT FLUSH) is answered NOSCRIPT, and they are loaded again.

  • Nested Class Summary

    Nested classes/interfaces inherited from interface KeyValueStore

    KeyValueStore.MessageListener, KeyValueStore.Subscription
  • Constructor Summary

    Constructors
    Constructor
    Description
    RedisKeyValueStore(String url, int connectTimeoutMillis, int readTimeoutMillis, int maxIdle)
    A store for url (see the class description).
  • Method Summary

    Modifier and Type
    Method
    Description
    call(byte[][] args)
    call(String...) with arguments that are already bytes.
    call(String... args)
    Runs one command on a pooled connection and answers its reply, in the form RedisConnection describes -- for the commands this interface does not wrap (XADD, HSET, ...).
    void
    Closes this and releases what it holds.
    boolean
    compareAndSet(String key, byte[] expected, byte[] value, long ttlMillis)
    Replaces the value under key only while it still equals expected (null: while there is none); answers whether it did.
    A connection of its own, outside the pool, for a command that blocks.
    boolean
    Removes key; answers whether it existed.
    int
    Removes every key that starts with prefix; answers how many.
    byte[]
    get(String key)
    The value under key, or null when there is none or it expired.
    long
    increment(String key, long delta, long ttlMillis)
    Adds delta to the integer under key and answers the result; a missing key counts from zero and is given ttlMillis (zero or less: none).
    boolean
    Whether this store is shared with other processes.
    boolean
    Whether the store answers right now; what a health check asks.
    pipeline(byte[][][] commands)
    Sends several commands in one round trip and answers their replies in order; an error reply is in the array as a RedisException, not thrown.
    long
    publish(String channel, byte[] message)
    Sends message to everybody subscribed to channel, on every instance; answers how many subscribers received it (on Redis, how many connections).
    void
    set(String key, byte[] value, long ttlMillis)
    Stores value under key, replacing what was there.
    boolean
    setIfAbsent(String key, byte[] value, long ttlMillis)
    Stores value only if key holds nothing; answers whether it did.
    Calls listener for every message published to channel until the returned subscription is closed.
    long
    ttl(String key)
    How many milliseconds key has left: -1 when it never expires, -2 when it does not exist.

    Methods inherited from class Object

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

    • RedisKeyValueStore

      public RedisKeyValueStore(String url, int connectTimeoutMillis, int readTimeoutMillis, int maxIdle) throws IOException

      A store for url (see the class description).

      • connectTimeoutMillis: how long a connection may take to open
      • readTimeoutMillis: how long a reply may take; zero waits forever
      • maxIdle: how many idle connections the pool keeps
      Throws:
      IOException
  • Method Details

    • dedicated

      public RedisConnection dedicated() throws IOException
      A connection of its own, outside the pool, for a command that blocks. Its reply timeout is zero -- it waits as long as the command does. The caller closes it.
      Throws:
      IOException
    • call

      public Object call(String... args) throws IOException
      Runs one command on a pooled connection and answers its reply, in the form RedisConnection describes -- for the commands this interface does not wrap (XADD, HSET, ...).
      Throws:
      IOException
    • call

      public Object call(byte[][] args) throws IOException
      call(String...) with arguments that are already bytes.
      Throws:
      IOException
    • pipeline

      public Object[] pipeline(byte[][][] commands) throws IOException
      Sends several commands in one round trip and answers their replies in order; an error reply is in the array as a RedisException, not thrown.
      Throws:
      IOException
    • get

      public byte[] get(String key) throws IOException
      Description copied from interface: KeyValueStore
      The value under key, or null when there is none or it expired.
      Specified by:
      get in interface KeyValueStore
      Throws:
      IOException
    • set

      public void set(String key, byte[] value, long ttlMillis) throws IOException
      Description copied from interface: KeyValueStore

      Stores value under key, replacing what was there.

      • ttlMillis: how long it lives; zero or less keeps it until it is deleted
      Specified by:
      set in interface KeyValueStore
      Throws:
      IOException
    • setIfAbsent

      public boolean setIfAbsent(String key, byte[] value, long ttlMillis) throws IOException
      Description copied from interface: KeyValueStore
      Stores value only if key holds nothing; answers whether it did. This is the primitive a lock is built on.
      Specified by:
      setIfAbsent in interface KeyValueStore
      Throws:
      IOException
    • compareAndSet

      public boolean compareAndSet(String key, byte[] expected, byte[] value, long ttlMillis) throws IOException
      Description copied from interface: KeyValueStore
      Replaces the value under key only while it still equals expected (null: while there is none); answers whether it did. A null value deletes the key instead. What an optimistic read-modify-write loops on.
      Specified by:
      compareAndSet in interface KeyValueStore
      Throws:
      IOException
    • delete

      public boolean delete(String key) throws IOException
      Description copied from interface: KeyValueStore
      Removes key; answers whether it existed.
      Specified by:
      delete in interface KeyValueStore
      Throws:
      IOException
    • deleteByPrefix

      public int deleteByPrefix(String prefix) throws IOException
      Description copied from interface: KeyValueStore
      Removes every key that starts with prefix; answers how many. Walks the key space incrementally on a shared server rather than blocking it, so keys written while it runs may survive.
      Specified by:
      deleteByPrefix in interface KeyValueStore
      Throws:
      IOException
    • increment

      public long increment(String key, long delta, long ttlMillis) throws IOException
      Description copied from interface: KeyValueStore
      Adds delta to the integer under key and answers the result; a missing key counts from zero and is given ttlMillis (zero or less: none). The expiry of an existing key is left as it is, so a fixed window counts from its first request.
      Specified by:
      increment in interface KeyValueStore
      Throws:
      IOException
    • ttl

      public long ttl(String key) throws IOException
      Description copied from interface: KeyValueStore
      How many milliseconds key has left: -1 when it never expires, -2 when it does not exist.
      Specified by:
      ttl in interface KeyValueStore
      Throws:
      IOException
    • publish

      public long publish(String channel, byte[] message) throws IOException
      Description copied from interface: KeyValueStore
      Sends message to everybody subscribed to channel, on every instance; answers how many subscribers received it (on Redis, how many connections). Delivery is at most once: a subscriber that is not connected at that moment never sees it.
      Specified by:
      publish in interface KeyValueStore
      Throws:
      IOException
    • ping

      public boolean ping()
      Description copied from interface: KeyValueStore
      Whether the store answers right now; what a health check asks.
      Specified by:
      ping in interface KeyValueStore
    • isShared

      public boolean isShared()
      Description copied from interface: KeyValueStore
      Whether this store is shared with other processes. A local store's locks and counters are only good within one process.
      Specified by:
      isShared in interface KeyValueStore
    • subscribe

      public KeyValueStore.Subscription subscribe(String channel, KeyValueStore.MessageListener listener) throws IOException
      Description copied from interface: KeyValueStore
      Calls listener for every message published to channel until the returned subscription is closed. The listener runs on the store's own receiving thread, one message at a time; it should hand slow work off.
      Specified by:
      subscribe in interface KeyValueStore
      Throws:
      IOException
    • close

      public void close()
      Description copied from interface: Closeable
      Closes this and releases what it holds. Closing it again has no effect.
      Specified by:
      close in interface AutoCloseable
      Specified by:
      close in interface Closeable