Class RedisKeyValueStore
- All Implemented Interfaces:
KeyValueStore, Closeable, AutoCloseable
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
ConstructorsConstructorDescriptionRedisKeyValueStore(String url, int connectTimeoutMillis, int readTimeoutMillis, int maxIdle) A store forurl(see the class description). -
Method Summary
Modifier and TypeMethodDescriptioncall(byte[][] args) call(String...)with arguments that are already bytes.Runs one command on a pooled connection and answers its reply, in the formRedisConnectiondescribes -- for the commands this interface does not wrap (XADD,HSET, ...).voidclose()Closes this and releases what it holds.booleancompareAndSet(String key, byte[] expected, byte[] value, long ttlMillis) Replaces the value underkeyonly while it still equalsexpected(null: while there is none); answers whether it did.A connection of its own, outside the pool, for a command that blocks.booleanRemoveskey; answers whether it existed.intdeleteByPrefix(String prefix) Removes every key that starts withprefix; answers how many.byte[]The value underkey, or null when there is none or it expired.longAddsdeltato the integer underkeyand answers the result; a missing key counts from zero and is giventtlMillis(zero or less: none).booleanisShared()Whether this store is shared with other processes.booleanping()Whether the store answers right now; what a health check asks.Object[]pipeline(byte[][][] commands) Sends several commands in one round trip and answers their replies in order; an error reply is in the array as aRedisException, not thrown.longSendsmessageto everybody subscribed tochannel, on every instance; answers how many subscribers received it (on Redis, how many connections).voidStoresvalueunderkey, replacing what was there.booleansetIfAbsent(String key, byte[] value, long ttlMillis) Storesvalueonly ifkeyholds nothing; answers whether it did.subscribe(String channel, KeyValueStore.MessageListener listener) Callslistenerfor every message published tochanneluntil the returned subscription is closed.longHow many millisecondskeyhas left: -1 when it never expires, -2 when it does not exist.
-
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 openreadTimeoutMillis: how long a reply may take; zero waits forevermaxIdle: how many idle connections the pool keeps
- Throws:
IOException
-
-
Method Details
-
dedicated
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
Runs one command on a pooled connection and answers its reply, in the formRedisConnectiondescribes -- for the commands this interface does not wrap (XADD,HSET, ...).- Throws:
IOException
-
call
call(String...)with arguments that are already bytes.- Throws:
IOException
-
pipeline
Sends several commands in one round trip and answers their replies in order; an error reply is in the array as aRedisException, not thrown.- Throws:
IOException
-
get
Description copied from interface:KeyValueStoreThe value underkey, or null when there is none or it expired.- Specified by:
getin interfaceKeyValueStore- Throws:
IOException
-
set
Description copied from interface:KeyValueStoreStores
valueunderkey, replacing what was there.ttlMillis: how long it lives; zero or less keeps it until it is deleted
- Specified by:
setin interfaceKeyValueStore- Throws:
IOException
-
setIfAbsent
Description copied from interface:KeyValueStoreStoresvalueonly ifkeyholds nothing; answers whether it did. This is the primitive a lock is built on.- Specified by:
setIfAbsentin interfaceKeyValueStore- Throws:
IOException
-
compareAndSet
public boolean compareAndSet(String key, byte[] expected, byte[] value, long ttlMillis) throws IOException Description copied from interface:KeyValueStoreReplaces the value underkeyonly while it still equalsexpected(null: while there is none); answers whether it did. A nullvaluedeletes the key instead. What an optimistic read-modify-write loops on.- Specified by:
compareAndSetin interfaceKeyValueStore- Throws:
IOException
-
delete
Description copied from interface:KeyValueStoreRemoveskey; answers whether it existed.- Specified by:
deletein interfaceKeyValueStore- Throws:
IOException
-
deleteByPrefix
Description copied from interface:KeyValueStoreRemoves every key that starts withprefix; 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:
deleteByPrefixin interfaceKeyValueStore- Throws:
IOException
-
increment
Description copied from interface:KeyValueStoreAddsdeltato the integer underkeyand answers the result; a missing key counts from zero and is giventtlMillis(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:
incrementin interfaceKeyValueStore- Throws:
IOException
-
ttl
Description copied from interface:KeyValueStoreHow many millisecondskeyhas left: -1 when it never expires, -2 when it does not exist.- Specified by:
ttlin interfaceKeyValueStore- Throws:
IOException
-
publish
Description copied from interface:KeyValueStoreSendsmessageto everybody subscribed tochannel, 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:
publishin interfaceKeyValueStore- Throws:
IOException
-
ping
public boolean ping()Description copied from interface:KeyValueStoreWhether the store answers right now; what a health check asks.- Specified by:
pingin interfaceKeyValueStore
-
subscribe
public KeyValueStore.Subscription subscribe(String channel, KeyValueStore.MessageListener listener) throws IOException Description copied from interface:KeyValueStoreCallslistenerfor every message published tochanneluntil 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:
subscribein interfaceKeyValueStore- Throws:
IOException
-
close
public void close()Description copied from interface:CloseableCloses this and releases what it holds. Closing it again has no effect.- Specified by:
closein interfaceAutoCloseable- Specified by:
closein interfaceCloseable
-